Witam.
Mam dość nietypowy problem z którym nie mogę sobie poradzić. Mianowicie piszę bootloader + proste jądro systemu w c w którym docelowo chcę zrobić prymitywną konsolę. Bootloader wyświetla powitanie, odblokowuje A20, ładuję tablicę gdt, ładuje plik jądra, przechodzi w tryb chroniony a następnie przekazuje sterowanie do jądra systemu.
W moim prymitywnym jądrze mam zrobiony bufor do wypisywania tekstu na ekran. Wszystko działa ok, ale niestety tylko gdy 1 raz wykonam funkcję print(tablica). Przy kolejnym wykonaniu cały "system" się wysypuje. W QEMU wyskakuje mi naruszenie pamięci. Co ciekawe gdy zrobię for(i=0; i<20; i++) print(tablica), to ładnie wypisze mi 20 napisów na ekranie. Przy próbie wypisania kolejnego napisu (wywołania funkcji print) na ekranie pojawia się tylko litera "S" a po jakimś czasie wyskakuje naruszenie pamięci.
Myślę, że problem jest ze stosem przy 2 wywołaniu funkcji. Gdy sprawdzałem stos po 2 wywołaniu to niestety był pusty...
Kod bootloadera:
[ORG 0x7C00]
[BITS 16]
bootloader:
xor ax, ax
mov ds, ax
mov si, msg
call _showTekst ; wyswietlenie powitania "witaj w bootloaderze"
;************************ Wczytanie jadra systemu ******************
mov si, read_pocket
mov ah, 0x42 ; extension
mov dl, 0x80 ; drive number (0x80 should be drive #0)
int 0x13
;_halt: jmp _halt
jmp _odblokowanieA20
;********************* Odblokowanie A20 ****************************
_sprawdzA20:
mov ax, 0xFFFF
mov es, ax
mov di, 0x7E0E
mov al, byte[es:di]
cmp al, 0x55 ; comparing with 0x55 (first part)
jne _wys
mov si, msgA20dis
call _showTekst
ret
_odblokowanieA20:
call _sprawdzA20 ; sprawdzenie czy przypadkiem A20 nie jest aktywne
; za pomoca biosu
mov ax, 0x2401
int 0x15
call _sprawdzA20
; za pomoca kontrolera klawiatury
call _waitA20
mov al, 0xD1
out 0x64, al
call _waitA20
mov al, 0xDF
out 0x60, al
call _waitA20
call _sprawdzA20
_waitA20:
in al, 0x64
test al, 2
jnz _waitA20
ret
;**********************************************************************
;********************** Funkcja wyswietlajaca tekst ****************
_showTekst:
mov ah, 0x0E
mov bh, 0x00
mov bl, 0x07
_wypisz:
lodsb
or al, al
jz _koniecWypisz
int 0x10
jmp _wypisz
_koniecWypisz:
ret
;******************** Wyswietlenie, że a20 jest aktywna **********
_wys:
mov si, msgA20enb
call _showTekst
; Uruchomienie tryby chronionego
cli
lgdt [_gdtDesc]
mov eax, cr0
or eax, 1
mov cr0, eax
jmp 0x8:clear_pipe ; do the far jump, to clear instruction pipe
;*************** GDT ***********************************************
_gdt:
_gdtNull:
dq 0 ; it's just null..
_gdtCode:
dw 0xFFFF ; limit (4GB)
dw 0 ; base (0)
db 0 ; base (still 0)
db 10011010b ; [present][privilege level][privilege level][code segment][code segment][conforming][readable][access]
db 11001111b ; [granularity][32 bit size bit][reserved][no use][limit][limit][limit][limit]
db 0 ; base again
_gdtData:
dw 0xFFFF ; it's just same as above
dw 0 ; it's just same as above
db 0 ; it's just same as above
db 10010010b ; [present][privilege level][privilege level][data segment][data segment][expand direction][writeable][access]
db 11001111b ; it's just same as above
db 0 ; it's just same as above
_gdtEnd:
_gdtDesc:
dw _gdtEnd - _gdt ; it's size
dd _gdt ; and location
;******************* tryb 32 bitowy chroniony ********************
[BITS 32]
clear_pipe:
mov ax, 0x10 ; GDT address of data segment
mov ds, ax ; set data segment register
mov ss, ax ; set stack segment register
xor edx, edx
mov fs, dx
mov gs, dx
mov esp, 0xF0000 ; set stack
mov ebp, esp ; set bracket pointer
jmp 0xF000 ; jump to code
times 256-($-$$) db 0 ; fill rest with zeros for alignment
;*******************************************************************
;********************** Zmienne ************************************
msgA20enb:
db 'A20 -> enable',13,10,0
msgA20dis:
db 'A20 -> disable',13,10,0
msg:
db 'Witamy w bootloaderze', 13,10,0
read_pocket:
db 0x10 ; size of pocket
db 0 ; const 0
dw 10 ; number of sectors to transfer
dw 0xF000, 0x0000 ; address to write
dd 1 ; LBA
dd 0 ; upper LBA
times 510-($-$$) db 0 ; wypenienie niewykorzystanej przestrzeni 0
db 0x55
db 0xAA ; ostatnie 2 bajty musza miec wartosci AA, 55
Kod systemu:
static char bufor[25][80];
volatile char *videos = (volatile char*)0xB8000;
static void zeruj(){
int i,j;
for( i=0; i<25; i++)
for( j=0; j<80; j++)
bufor[i][j] = ' ';
}
static void przepisz(){
int i = 0;
int j = 0;
for(i=1; i<25; i++)
for( j=0; j<80; j++)
bufor[i-1][j] = bufor[i][j];
for(i=0; i<80; i++)
bufor[24][i] = ' ';
}
static void wypisz(){
volatile char *video = (volatile char*)0xB8000;
int i = 0;
int j = 0;
for(i=0; i<25; i++){
for(j=0; j<80; j++){
*video++ = bufor[i][j];
*video++ = 0x07;
}
}
}
static void print(char *tab){
przepisz();
int i = 0;
for(i=0; i<80; i++)
{
if(tab[i] == 0)
break;
bufor[24][i] = tab[i];
}
wypisz();
}
void main(void)
{
char test[] = "Przykladowy ttt 1";
char aaa[] = "Przykladowy tekst 2";
for(i=0; i<20; i++)
print(aaa);
print(aaa); // ERROR pamieci.
while(1);
};
Kompiluję to poleceniami:
nasm boot.asm -f bin -o ./bin/boot.bin
gcc -c kernel.c -O2 -o ./bin/kernel.o -m32 -nostdlib -nostartfiles -nodefaultlibs
Proszę o jakieś sugestie jak rozwiązać mój problem.
Z góry dziękuję za każdą wskazówkę.
Pozdrawiam.
ENTRY (main)
. pytanie, czy linker umieszcza entry point na początku kodu w pliku binarnym?