Hallo,
ich habe versucht in Anlehnung an das C-Kernel Tutorial hier im Magazin einen Bottloader+Kernel zu programmieren. Linken und Compilen geht auch ohne Fehlermeldungen, Bochs meldet mir jedoch einfach, dass es keine 'bootable disk' wäre. Eine Debug-File will er nicht erzeugen.
Da das OS noch sehr klein ist, poste ich hier einfach mal die Quelltexte und ich hoffe das sich jemand die Mühe macht es zu lesen und den Fehler zu finden.
Der Bottloader besteht aus einer 16-bit und einer 32-bit Variante:
Erst wird der Protectet-Mode gestartet,
es ist der selbe Quellcode wie im 'PM-Grundlagen Turorial
;**************** boot16.asm ********
[BITS 16] ;16 Bit Code erstellen
jmp start ;GDT überspringen
NULL_Desc:
dd 0
dd 0
CODE_Desc:
dw 0xFFFF ;Segmentgröße Byte 0/1
dw 0 ;Segmentbasisadresse Byte 0/1
db 0 ;Segmentbasisadresse Byte 2
db 0x9A ;Zugriffsberechtigungen
db 0xCF ;Zusatz + Segmentgröße Bits 16 - 19
db 0 ;Segmentbasisadresse Byte 3
DATA_Desc:
dw 0xFFFF
dw 0
db 0
db 0x92
db 0xCF
db 0
gdt:
Limit dw 0 ;Größe der GDT (wird später eingetragen)
Base dd 0 ;Adresse der GDT (wird später eingetragen)
start:
cli ;Interrupts ausschalten
mov eax, cs ;EAX auf derzeitiges Codesegment setzen
mov ds, ax ;DS auf Codesegment setzen
shl eax, 4 ;EAX mit 16 multiplizieren (Lineare Adresse
;des Codesegments errechnen)
mov [CODE_Desc+2], ax ;Lineare Adresse des Codesegmentes als
mov [DATA_Desc+2], ax ;Startadresse des Code- und Datendeskriptors
shr eax, 16 ;eintragen
mov [CODE_Desc+4], al
mov [DATA_Desc+4], al
mov eax, cs ;Startadresse der GDT errechnen
shl eax, 4
add eax, NULL_Desc
mov [Base], eax ;Startadresse der GDT eintragen
mov [Limit], WORD gdt - NULL_Desc -1 ;Größe der GDT errechnen und eintragen
lgdt [gdt] ;GDT laden
mov eax, cr0 ;In den Protected Mode schalten,
or eax, 1 ;indem Bit 0 des CR0 Registers auf 1
mov cr0, eax ;gesetzt wird
db 0xea ;FAR-JUMP zum Codesegment
dw PMODE
dw 0x8
[BITS 32] ;32 Bit Code erstellen
PMODE:
mov WORD [CODE_Desc+2], 0 ;Code Segmentstartaddresse auf 0 setzen
mov WORD [DATA_Desc+2], 0 ;Daten Segmentstartadresse auf 0 setzen
mov BYTE [CODE_Desc+4], 0 ;Code Segmentstartaddresse auf 0 setzen
mov BYTE [DATA_Desc+4], 0 ;Daten Segmentstartadresse auf 0 setzen
mov eax, 2 ;Selektor für das Datensegment erstellen
shl eax, 3
mov ds, ax ;Daten- Stack- und Extrasegment mit
mov ss, ax ;Datensegmentdeskriptor laden
mov es, ax
mov eax, 0 ;FS und GS mit Null-Deskriptor laden
mov fs, ax
mov gs, ax
mov esp, 0x1FFFFF ;Stack auf unterhalb der 2 MB Grenze setzen
jmp 0x8:0x10000 + PMODE2 ;Sprung in das "neue" Codesegment
PMODE2:
jmp END ;Zum Ende Springen
times 512-($-$$) db 0; ;Da der Linker sich nicht mit ungeraden
;Dateigrößen verträgt, wird diese Datei auf 512
;gepaddet.
END:
Jetzt kommt der Code, der die Main-Funktion des Kernels aufruft:
Die Unterstriche vor 'main' musste ich weglassen, dazu aber gleich mehr.
;********* boo32.asm ******
[Bits 32]
extern main
global start
start:
call main
STOP:
jmp STOP
;############
So, nun der Kernel, die Minimal-Version:
/* ******* kernel.c ********** */
int main()
{
/*char *Text = "Welcome to Protected Mode";
char *VideoMem = (char*)0xB8000;
while(*Text)
{
*VideoMem = *Text;
*VideoMem++;
*VideoMem = 7;
*VideoMem++;
*Text++;
}*/
return(0);
}
Dann habe ich das ganze mit folgenden Befehlen compiliert:
Ich benutze die neuste DJGPP-Version für C und NASMW 0.98.39
nasmw -f bin -o boot16.bin boot\boot16.asm
nasmw -f aout -o boot32.obj boot\boot32.asm
set PATH=c:\djgpp\bin;%PATH%
set DJGPP=c:\djgpp\djgpp.env
gcc -fno-leading-underscore -ffreestanding -c -Os -o ckernel.obj kernel\kernel.c
ld -T link.txt -o kernel32.bin
MergeKernel testos.img boot16.bin kernel32.bin
link.txt sieht so aus:
OUTPUT_FORMAT("binary")
INPUT(boot32.obj ckernel.obj)
ENTRY(start)
SECTIONS
{
.text 0x200 : {
code = .; _code = .; __code = .;
*(.text)
. = ALIGN(1);
}
end = .; _end = .; __end = .;
}
So, als ich den Kernel zum ersten mal compiliert habe, erhielt ich die Meldung das '_main' ein unreferenziertes Objekt wäre.
Nur wenn ich in der boot32.asm den die underscores weglasse und gcc mit dem Argument -fno-leading-underscore starte gibt es diese Meldung nicht. Ich weiss ehrlich gesagt nicht warum das so ist, vielleicht ist das auch einer der Gründe das Bochs einen Fehler ausgibt. Vielleicht wird die bott32.asm auf 'meine Art' nicht richtig mit kernel.c verbunden???
Ich weiss es nicht.
So, nun starte ich das ganze mit Bochs und bekomme sofort die Fehlermeldung. In der Logfile steht Folgendes:
00000480000i[WGUI ] dimension update x=720 y=400 fontheight=16 fontwidth=9 bpp=8
00000726744e[HD ] device set to 0 which does not exist
00000727037e[HD ] device set to 1 which does not exist
00000777733i[BIOS ] Boot from Floppy 0 failed
00000799506p[BIOS ] >>PANIC<< Not a bootable disk
00000799506i[SYS ] Last time is 1133969226
00000799506i[CPU0 ] real mode
00000799506i[CPU0 ] CS.d_b = 16 bit
00000799506i[CPU0 ] SS.d_b = 16 bit
00000799506i[CPU0 ] | EAX=ffff040a EBX=0000d738 ECX=000f0001 EDX=00000402
00000799506i[CPU0 ] | ESP=0000ffa6 EBP=0000ffaa ESI=0000733c EDI=00007362
00000799506i[CPU0 ] | IOPL=0 NV UP DI PL ZR NA PE NC
00000799506i[CPU0 ] | SEG selector base limit G D
00000799506i[CPU0 ] | SEG sltr(index|ti|rpl) base limit G D
00000799506i[CPU0 ] | CS:f000( 0000| 0| 0) 000f0000 0000ffff 0 0
00000799506i[CPU0 ] | DS:0000( 0000| 0| 0) 00000000 0000ffff 0 0
00000799506i[CPU0 ] | SS:0000( 0000| 0| 0) 00000000 0000ffff 0 0
00000799506i[CPU0 ] | ES:07c0( 0000| 0| 0) 00007c00 0000ffff 0 0
00000799506i[CPU0 ] | FS:0000( 0000| 0| 0) 00000000 0000ffff 0 0
00000799506i[CPU0 ] | GS:0000( 0000| 0| 0) 00000000 0000ffff 0 0
00000799506i[CPU0 ] | EIP=00000542 (00000541)
00000799506i[CPU0 ] | CR0=0x00000010 CR1=0 CR2=0x00000000
00000799506i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
00000799506i[ ] restoring default signal behavior
00000799506i[CTRL ] quit_sim called with exit code 1
Wer weiss weiter, wo und wieso der Fehler auftritt ?? Und was heisst für Bochs eigentlich 'not bootable', es muss ja was anderes sein als einfach ein 'fatal error'??
So, ist ja ganz schön viel geworden ich hoffe jemand kann mir helfen und vielen Dank schonmal im Voraus
-fnord