[asm][c] Pisanie własnego OS

0

Witam!

Nawiązując do mojego poprzedniego tematu --> [Asembler][C] Problem z kompilacją OS
Od tamtego czasu wiele sie nauczyłem i udało mi się uruchomić os'a. Jednak mam pewien problem mianowicie wydaje mi się że system nie skacze do kernela w C. Używam zestawu narzędzi: NASM, DJGPP(gcc, ld), Notepad++, oraz windows XP. Oto moje kody źródłowe:
boot.asm

[ORG 0x7C00]
[BITS 16]
start:
  ; ustawiamy stos dla trybu rzeczywistego
  mov ax, 0x1000
  mov ss, ax
  xor esp, esp

  ; inicjujemy tryb wideo 80x25 (tekstowy)
  xor ah, ah
  mov al, 3
  int 0x10

  ; ladujemy jadro pod adres 0x1000
  xor ah, ah
  int 0x10

  mov ah, 2
  mov al, 10
  xor ch, ch
  mov cl, 2
  mov dh, 0
  mov bx, 0x1000
  mov es, bx
  mov bx, 0
  int 0x13
  gdt:
  ; NULL Descriptor
  dd 0
  dd 0
  
  ; kod, baza: 0, limit: 4GB, DPL: 0
  dw 0xFFFF    ; mlodsze slowo limitu
  dw 0	       ; mlodsze slowo bazy
  db 0	       ; wlodszy bajt starszego slowa bazy
  db 10011010b ; kod / exec-read
  db 11001111b ; flagi i 4 bity limitu
  db 0	       ; najstarszy bajt bazy
  
  ; dane (odczyt/zapis), baza: 0, limit: 4GB, DPL: 0
  dw 0xFFFF
  dw 0	      
  db 0	       
  db 10010010b 
  db 11001111b 
  db 0	       
gdt_end:    
  
; naglowek
gdt_descr:
  dw gdt_end - gdt - 1	  ; rozmiar gdt
  dd gdt		  ; adres pierwszego deskryptora
lgdt [gdt_descr]
mov ax, 0x10 ; deksryptor danych (8 * 2 = 16 = 0x10)
mov ss, ax
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov eax, cr0
or eax, 1
mov cr0, eax

jmp 0x08:start32 ; uzywamy segmentu kodu z GDT

[BITS 32]
start32:
jmp 0x08:0x10000

times 510 - ($ - start) db 0

;tworzymy znacznik bootsektora
db 0x55
db 0xAA

entry.asm

[BITS 32]

[EXTERN _k_main] ; wyjasnienie nizej
call _k_main     ; uruchamiamy kernela
hlt              ; po wyjsciu z kernela zatrzymujemy komputer 

kernel.c

static char * video_fb=(char *)0xb8000;

void putc(char c)
{
*video_fb++=c;
video_fb++;
}

void puts(char * s)
{
for(;*s;) putc(*s++);
}

void k_main(void)
{
puts("Hello World !!!");
for(;;);
}

compile.bat

nasm -f coff entry.asm -o entry.o
nasm -f bin boot.asm -o boot.bin
gcc -c kernel.c -O2 -o kernel.o
ld -Map kernel.map entry.o kernel.o -Tlink.ld -o kernel.bin
copy /b boot.bin+kernel.bin os.bin

Z góry dzięki

-----edit-----
zapomniałem dodać że używam emulatora bosh

-----edit2-----
przed chwilą zauważyłem że na bosch-u komputer pozostaje w Real Mode

0

Bochs ma wbudowany debugger. O ile znasz asemblera to możesz przejść krok po kroku i sprawdzić czy program wykonuje się tak jak chciałeś.
Z tego co zauważyłem to masz błąd w kodzie boot loadera, a właściwie w formatowaniu kodu. U ciebie jest taka sytuacja, że na początku masz trochę kodu potem masz wstawione dane i na końcu znowu trochę kodu. W takim przypadku program potraktuje dane jako instrukcje i wykona. Musisz umieścić dane w miejscu do którego nie zostanie przekazane sterowanie. Najlepiej na samym początku umieścić cały kod, a dane na samym końcu.

[ORG 0x7C00]
[BITS 16]
start:
  ; ustawiamy stos dla trybu rzeczywistego
  mov ax, 0x1000
  mov ss, ax
  xor esp, esp

  ; inicjujemy tryb wideo 80x25 (tekstowy)
  xor ah, ah
  mov al, 3
  int 0x10

  ; ladujemy jadro pod adres 0x1000
  xor ah, ah
  int 0x10

  mov ah, 2
  mov al, 10
  xor ch, ch
  mov cl, 2
  mov dh, 0
  mov bx, 0x1000
  mov es, bx
  mov bx, 0
  int 0x13
lgdt [gdt_descr]
mov ax, 0x10 ; deksryptor danych (8 * 2 = 16 = 0x10)
mov ss, ax
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov eax, cr0
or eax, 1
mov cr0, eax

jmp 0x08:start32 ; uzywamy segmentu kodu z GDT

[BITS 32]
start32:
jmp 0x08:0x10000

  gdt:
  ; NULL Descriptor
  dd 0
  dd 0
 
  ; kod, baza: 0, limit: 4GB, DPL: 0
  dw 0xFFFF    ; mlodsze slowo limitu
  dw 0               ; mlodsze slowo bazy
  db 0               ; wlodszy bajt starszego slowa bazy
  db 10011010b ; kod / exec-read
  db 11001111b ; flagi i 4 bity limitu
  db 0               ; najstarszy bajt bazy
 
  ; dane (odczyt/zapis), baza: 0, limit: 4GB, DPL: 0
  dw 0xFFFF
  dw 0             
  db 0               
  db 10010010b
  db 11001111b
  db 0               
gdt_end:   
 
; naglowek
gdt_descr:
  dw gdt_end - gdt - 1          ; rozmiar gdt
  dd gdt                  ; adres pierwszego deskryptora


times 510 - ($ - start) db 0

;tworzymy znacznik bootsektora
db 0x55
db 0xAA

Nie zmieniałem nic w kodzie tylko poukładałem kod i dane. Tak więc sprawdź może ci się uda tak uruchomić system.

0

Dzięki
nawet nie wiedziałem że bochs ma debugera. teraz CPU jest w PM ale krzyczy że ma niepoprawne gdt:

00043657103e[CPU0 ] read_virtual_checks(): read beyond limit
00043657103e[CPU0 ] interrupt(): gate descriptor is not valid sys seg (vector=0x0d)
00043657103e[CPU0 ] interrupt(): gate descriptor is not valid sys seg (vector=0x08)
00043657103i[CPU0 ] CPU is in protected mode (active)

po tym jest wyjątek 3rd exception i reboot

Pozdrawiam Bartek

0

Przejście w tryb chroniony nie jest napisane zgodnie z dokumentacją. Powinno to być mniej więcej tak:

  • załadowanie GDT
  • przełączenie w PMode
  • przeładowanie rejestrów segmentowych

Dodatkowo trzeba też ustawić stos na jakiś wolny obszar p_amięci.

Poprawny kod boot.asm

[ORG 0x7C00]
[BITS 16]
start:
  ; ustawiamy stos dla trybu rzeczywistego
  mov ax, 0x1000
  mov ss, ax
  xor esp, esp

  ; inicjujemy tryb wideo 80x25 (tekstowy)
  xor ah, ah
  mov al, 3
  int 0x10

  ; ladujemy jadro pod adres 0x1000
  xor ah, ah
  int 0x10

  mov ah, 2
  mov al, 10
  xor ch, ch
  mov cl, 2
  mov dh, 0
  mov bx, 0x1000
  mov es, bx
  mov bx, 0
  int 0x13
  
  lgdt [gdt_descr]
  
  mov eax, cr0
  or eax, 1
  mov cr0, eax

  mov ax, 0x10 ; deksryptor danych (8 * 2 = 16 = 0x10)
  mov ds, ax
  mov es, ax
  mov fs, ax
  mov gs, ax

jmp 0x08:start32 ; uzywamy segmentu kodu z GDT

[BITS 32]
start32:
  mov ax, 0x10
  mov ss, ax
  mov esp,0x9000
jmp 0x08:0x10000

  gdt:
  ; NULL Descriptor
  dd 0
  dd 0
 
  ; kod, baza: 0, limit: 4GB, DPL: 0
  dw 0xFFFF    ; mlodsze slowo limitu
  dw 0               ; mlodsze slowo bazy
  db 0               ; wlodszy bajt starszego slowa bazy
  db 10011010b ; kod / exec-read
  db 11001111b ; flagi i 4 bity limitu
  db 0               ; najstarszy bajt bazy
 
  ; dane (odczyt/zapis), baza: 0, limit: 4GB, DPL: 0
  dw 0xFFFF
  dw 0             
  db 0               
  db 10010010b
  db 11001111b
  db 0               
gdt_end:   
 
; naglowek
gdt_descr:
  dw gdt_end - gdt - 1          ; rozmiar gdt
  dd gdt                  ; adres pierwszego deskryptora


times 510 - ($ - start) db 0

;tworzymy znacznik bootsektora
db 0x55
db 0xAA
0

Wielkie dzięki!

Działa. Sugerowałem się kursem na 4prog inawet nie wiedziałem że trzeba jeszcze ustawić stos w PM.

Teraz mogę już zostać Bilem :-)

jeszcze raz dzięki
Pozdrawiam Bartek

1 użytkowników online, w tym zalogowanych: 0, gości: 1