Autor Thema: Kleiner Bootloader, winziger Kernel, bitte um Hilfe  (Gelesen 6866 mal)

bscreator

  • Gast
Gespeichert
Hi OS-Coder,

hab jetzt mal mein OS, wenn man das so nennen kann, so umgeschrieben, dass es im PM starten sollte. Dazu hab ich den Bootloader aus Lowlevel Ausgabe 1 genommen, ein paar unnötige Dinge entfernt und den kurzen PMode-Code von Stefan Marcik verwendet, dann beides kombiniert.
Jedoch wird jetzt gar keine Meldung mehr ausgegeben.

Könnt ihr mir sagen, wo der Fehler im Bootloader liegt ?

Bootcode:
[BITS 16]

ORG 0x7C00 ;Startadresse

start:
cli                ;Keine Interrupts!
mov [bootdrv],dl   ;Bootlaufwerk aus DL speichern
call load          ;Lade unseren Kernel

lgdt [gdtr]
mov eax,cr0
or al,1
mov cr0,eax
jmp codesel:PMode

;Springe zu diesem Kernel
mov ax,0x1000      ;Die Adresse des Programms
mov es,ax          ;Segmentregister updaten
mov ds,ax
push ax
mov ax,0
push ax
retf

[BITS 32]
PMode:
mov ax,datasel
mov ds,ax
mov ss,ax
mov esp,0x90000
jmp $

gdtr:
dw gdt_end-gdt-1
dd gdt
gdt:
dd 0,0
codesel equ $-gdt
dw 0xFFFF
dw 0x0000
db 0x00
db 0x9A
db 0xCF
db 0x00
datasel equ $-gdt
dw 0xFFFF
dw 0x0000
db 0x00
db 0x92
db 0xCF
db 0x00
gdt_end:

;--------------------------
;Funktionen und Variablen
;--------------------------
bootdrv db 0
loadmsg db "Loading...",13,10,0

;Einen String ausgeben:
putstr:
lodsb              ;Byte laden
or al,al
jz short putstrd   ;0-Byte? -> Ende!

mov ah,0x0E        ;Funktion 0x0E
mov bx,0x0007      ;Attribut-Byte (wird nicht ben”tigt)
int 0x10           ;schreiben
jmp putstr         ;N„chstes Byte
putstrd:
retn

;Lade den Kernel vom Bootlaufwerk
load:

;Diskdrive reset (Interrupt 13h, 0)
push ds            ;Sichere DS
mov ax,0           ;Die gewnschte Funktion (reset)
mov dl,[bootdrv]   ;Dieses Laufwerk ist gewnscht
int 13h            ;den Interrupt ausfhren
pop ds             ;DS wiederherstellen
jc load            ;Geht nicht? -> Nochmal!

load1:
mov ax,0x1000      ;ES:BX=10000
mov es,ax
mov bx,0

;Sektoren lesen (Interrupt 13h, 2)
mov ah,2           ;Funktion 2 (Lesen)
mov al,5           ;Lese 5 Sektoren
mov cx,2           ;Zylinder=0, Sektor=2
mov dx,0           ;Kopf=0, Laufwerk=0
int 13h            ;ES:BX=Daten vom Laufwerk
jc load1           ;Fehler? Nochmal!
mov si,loadmsg
call putstr        ;Meldung ausgeben
retn

times 512-($-$$)-2 db 0   ;Dateil„nge: 512 Bytes
dw 0AA55h                 ;Bootsignatur


Ich schätz mal, dass der Fehler bei dem jmp $ liegt, jedoch hab ich
keine Ahnung, wo ich sonst hinspringen soll.

Beim gdt_end hat im Code ein Doppelpunkt gefehlt, oder ?
(Da sonst von NASM eine Fehlermeldung "Label alone" erscheint)


Kernel-Code
mov ax,1000h         ;Segmentregister updaten
mov ds,ax
mov es,ax

START:

;--------------------------
;Funktionen und Variablen
;--------------------------

mov BYTE [DS:0B8000h],'P'   ;Leuchtendes P ausgeben
mov BYTE [DS:0B8001h],1Bh


Traumszenario:
Der Bootloader ladet den Kernel, ähnlich wie in Lowlevel-Ausgabe 1, der Kernel gibt lediglich ein P aus, um zu zeigen, dass der Vorgang erfolgreich war.

Vielen Dank im Vorraus

bitmaster

  • Troll
  • Beiträge: 1 138
    • Profil anzeigen
    • OS-64 = 64 Bit Operating System
Gespeichert
« Antwort #1 am: 03. July 2007, 12:41 »
Ich habe mir jetzt nicht alles genau angeschaut. Aber der Kernel soll nach 1000h:0000h geladen werden, oder? Dann müsstst du nach 10000h springen (Seg*16+Offet). Aber du solltest ganz oben ds und es setzen, da die nicht bei allen PC-Starts gleich sind. Dazwischen sind vielleicht auch noch Fehler, aber keine Lust das mir jetzt alles genau anzugucken. ;-)

bitmaster
In the Future everyone will need OS-64!!!

FreakyPenguin

  • Administrator
  • Beiträge: 301
    • Profil anzeigen
    • toni.famkaufmann.info
Gespeichert
« Antwort #2 am: 03. July 2007, 13:21 »
Also dieser Teil kommt mir etwas seltsam vor, der "Sprung" wird ja garnie ausgeführt?
jmp codesel:PMode

;Springe zu diesem Kernel
mov ax,0x1000      ;Die Adresse des Programms
mov es,ax          ;Segmentregister updaten
mov ds,ax
push ax
mov ax,0
push ax
retf

[BITS 32]
PMode:
mov ax,datasel
mov ds,ax
mov ss,ax
mov esp,0x90000
jmp $

Und beim jmp$ dort bleibt er ja hängen. Das müsste eher ein jmp 10000h sein.


Und ein hlt / jmp$ im "Kernel" könnte auch nicht schaden, denn sonst rennt er direkt ins Verderben, wenn er  nicht aufgehalten wird ;-)

bscreator

  • Gast
Gespeichert
« Antwort #3 am: 03. July 2007, 19:07 »
Sorry, glaub ich sollte meine Fragen konkreter stellen.

Ich hab irgendwie keine Ahnung, wie ich meinen Kernel mit diesem Bootloader laden soll.
Mein Kernel wird ja mit dem Code
;Sektoren lesen (Interrupt 13h, 2)
mov ah,2           ;Funktion 2 (Lesen)
mov al,5           ;Lese 5 Sektoren
mov cx,2           ;Zylinder=0, Sektor=2
mov dx,0           ;Kopf=0, Laufwerk=0
int 13h            ;ES:BX=Daten vom Laufwerk
jc load1           ;Fehler? Nochmal!
mov si,loadmsg
call putstr        ;Meldung ausgeben
retn
geladen (von LowLevel Ausgabe 1). Wie allerdings jeder sieht, verwendet dieser Interrupts. Allerdings kann ich ja den Kernel im oberen 16-Bit-Code ( [BITS 16] )nicht laden, da ja dann der darauffolgende 32-Bit-Code ( BITS 32] ) nicht mehr ausgeführt wird, weil der Compiler dann gleich zum Kernel-Code springt, oder ?
Und im unteren 32-Bit-Code kann ich den Kernel ja auch nicht laden, weil ja 32-Bit-Code Protected Mode bedeutet und dort keine Interrupts erlaubt sind, oder ?

Also kann ich den Kernel
a) im 16-Bit-Teil nicht laden, weil dann der Protected Mode nicht aktiviert (bzw. übersprungen) wird und
b) im 32-Bit-Teil nicht laden, weil im PMode keine Interrupts erlaubt sind

Oder bring ich da was durcheinander ?

bscreator

  • Gast
Gespeichert
« Antwort #4 am: 03. July 2007, 19:12 »
PS : Was meinst du mit
Zitat
Rennt direkt ins Verderben ?
Wenn kein Code mehr folgt, wird doch nichts mehr ausgeführt, oder ?

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #5 am: 03. July 2007, 19:19 »
Wenn nichts mehr folgt, was du als Code ansehen würdest, wird eben das als Code ausgeführt, was im Speicher mehr oder weniger zufällig dahinter steht.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

bscreator

  • Gast
Gespeichert
« Antwort #6 am: 03. July 2007, 21:45 »
OK, is klar. Aber wie kann ich meine Hauptprobleme a bzw. b (siehe oben) lösen ?
Irgendwie muss ich ja den Kernel ohne Verzicht auf Protected Mode laden können.   

FreakyPenguin

  • Administrator
  • Beiträge: 301
    • Profil anzeigen
    • toni.famkaufmann.info
Gespeichert
« Antwort #7 am: 03. July 2007, 22:34 »
Oder bring ich da was durcheinander ?

Genau ;-)

Also nach dem Booten läuft der Prozessor im Realmode (16-Bit). Das tut er so lange, bis du den Protected mode durch setzen des PM-Bits im CR0 aktivierst. Aber soweit sind wir noch nicht.
Du musst den Kernel ja jetzt nun aus dem Realmode heraus von der Diskette laden. Da du dort nix >1MB adressieren kannst, musst du ihn ja nun irgendwo im ersten MB ablegen. Das dürfte kein Problem sein. Wenn du das geschafft hast, setzt du das PM-Bit, lädst du die GDT (Ich würde dir zu einem flachen Speichermodell, mit 2 deskriptoren von 0-4GB raten), und machst einen FAR-Jump ins Code-Segment.Wenn das klappt ist der kritische Teil überstanden ;-) Jetzt musst du noch den Datenselektor in ds, es und ss laden. Danach nur noch die Adresse anspringen, an die du den kernel vorhin geladen hast. Dafür müsste eigentlich ein normaler Jump tun. Dieses Gefrickel mit dem ret brauchts da wmnat nicht.

Und wie gesagt, ein jmp $ am Ende ;-)

bscreator

  • Gast
Gespeichert
« Antwort #8 am: 03. July 2007, 23:45 »
Vielen Dank, das hat mir sehr geholfen  :-D. Mit
Zitat
Datenselektor in ds, es und ss laden
meinst du
mov ax,datasel
mov ds,ax
mov es,ax
mov ss,ax
,oder?

FreakyPenguin

  • Administrator
  • Beiträge: 301
    • Profil anzeigen
    • toni.famkaufmann.info
Gespeichert
« Antwort #9 am: 03. July 2007, 23:51 »
Genau das meine ich  :-D

bscreator

  • Gast
Gespeichert
« Antwort #10 am: 04. July 2007, 23:15 »
Also, Ich hab jetzt mal alles noch mals versucht und seltsamerweise wird nicht mal die Message 'Loading...' mit der Fkt. putstr ausgegeben.
Der Code ist von mir jetzt gegliedert und ziemlich übersichtlich.
Desweiteren ist er relativ leicht verständlich aber wie gesagt der Teufel steckt im Detail.

Liegt der Fehler vielleicht bei
a) den für mich unverständlichen Befehlen
    codesel equ $-gdt und datasel equ $-gdt ?
b) dem komischen Label am Ende des Codes gdt_end: ?


[BITS 16]  ;Zuerst der 16-Bit-Code

ORG 0x7C00 ;Startadresse

start:

mov [bootdrv],dl  ;Bootlaufwerk aus DL speichern

call load         ;Kernel von Diskette laden

mov ax, 0x1000    ;Die Adresse des Kernels
mov es, ax
mov ds, ax
push ax
mov ax, 0
push ax
;retf


cli
lgdt [gdtr]
mov eax, cr0
or al, 1
mov cr0, eax         ;Setzen des PM-Bits
jmp codesel:PMode    ;FAR Jump ins Codesegment

[BITS 32]
PMode:
      mov ax, datasel    ;Datenselektor in ds,es und ss laden
      mov ds, ax
      mov ss, ax
      mov esp, 0x90000
      jmp 0x10000        ;Sprung zur Adresse des Kernel



;Variablen
bootdrv db 0
loadmsg db 'Loading...',13,10,0



;------------------------
;Funktion String ausgeben
putstr:
lodsb
or al,al
jz short putstrd
mov ah,0x0E
mov bx,0x0007
int 0x10
jmp putstr
putstrd:
retn
;Ende Funktion String ausgeben


;---------------------
;Funktion Kernel laden
load:

;Zuerst mit Interrupt 13h, Funktion 0 ein Diskdrive-Reset
push ds
mov ax, 0
mov dl, [bootdrv]
int 13h
pop ds
jc load

loadl:
mov ax, 0x1000  ;ES:BX=10000
mov es, ax
mov bx, 0

;Sektoren lesen (Interrupt 13h, 2)
mov ah, 2
mov al, 5
mov cx, 2
mov dx, 0
int 13h
jc loadl
mov si, loadmsg
call putstr    ;Meldung 'Loading...' ausgeben
retn
;Ende Funktion Kernel laden


gdtr:
   dw gdt_end-gdt-1
   dd gdt
gdt:
   dd 0,0
codesel equ $-gdt
   dw 0xFFFF
   dw 0x0000
   db 0x00
   db 0x9A
   db 0xCF
   db 0x00
datasel equ $-gdt
   dw 0xFFFF
   dw 0x0000
   db 0x00
   db 0x92
   db 0xCF
   db 0x00
gdt_end:

times 512-($-$$)-2 db 0
dw 0AA55h


Vielen Dank für jeden einzelnen Blick, den ihr darauf werft

MNemo

  • Beiträge: 547
    • Profil anzeigen
Gespeichert
« Antwort #11 am: 05. July 2007, 11:31 »
Ich schätze mal, dass das Problem ist, das pushstr als 32-Bit assembliert wird aber noch im 16-Bit RM aufgerufen wird.
Du müsstest also nur den teil
[BITS 32]
PMode:
      mov ax, datasel    ;Datenselektor in ds,es und ss laden
      mov ds, ax
      mov ss, ax
      mov esp, 0x90000
      jmp 0x10000        ;Sprung zur Adresse des Kernel
hinter deine pushstr(und load) setzen oder vor pushstr wieder auf 16-Bit umstellen( [BITS 16] ).

Edit:
Als FreakyPenguin von dem "Gefrickel mit dem ret" geredet hat, hat er nicht nur das retf selbst gemeint sondern den kompletten Part:
mov ax, 0x1000    ;Die Adresse des Kernels
mov es, ax
mov ds, ax
push ax
mov ax, 0
push ax
retf
der ohne ret nicht nur nutzlos ist sondern auch Fehler verursacht weil das DS & ES Register mit unpassenden werten belegt werden.
« Letzte Änderung: 05. July 2007, 12:52 von M.Nemo »
„Wichtig ist nicht, besser zu sein als alle anderen. Wichtig ist, besser zu sein als du gestern warst!“

bitmaster

  • Troll
  • Beiträge: 1 138
    • Profil anzeigen
    • OS-64 = 64 Bit Operating System
Gespeichert
« Antwort #12 am: 05. July 2007, 12:28 »
[BITS 16]  ;Zuerst der 16-Bit-Code

ORG 0x7C00 ;Startadresse

start:

xor ax,ax
mov ds,ax ;da ds und es nicht auf allen PCs standardmäßig Null sind
mov es,ax

mov ax,0100h
mov ss,ax
mov sp,6BFEh ;viele machen den Stack nach 2000h:0000h aber ich glaube das mag Virtual PC nicht

mov [bootdrv],dl  ;Bootlaufwerk aus DL speichern

call load         ;Kernel von Diskette laden

cli
lgdt [gdtr]
mov eax, cr0
or al, 1
mov cr0, eax         ;Setzen des PM-Bits
jmp codesel:PMode    ;FAR Jump ins Codesegment


;Variablen
bootdrv db 0
loadmsg db 'Loading...',13,10,0



;------------------------
;Funktion String ausgeben
putstr:
lodsb
or al,al
jz short putstrd
mov ah,0x0E
mov bx,0x0007
int 0x10
jmp putstr
putstrd:
retn
;Ende Funktion String ausgeben


;---------------------
;Funktion Kernel laden
load:

;Zuerst mit Interrupt 13h, Funktion 0 ein Diskdrive-Reset
push ds
mov ax, 0
mov dl, [bootdrv]
int 13h
pop ds
jc load

loadl:
mov ax, 0x1000  ;ES:BX=10000
mov es, ax
mov bx, 0

;Sektoren lesen (Interrupt 13h, 2)
mov ah, 2
mov al, 5
mov cx, 2
mov dx, 0
int 13h
jc loadl
mov si, loadmsg
call putstr    ;Meldung 'Loading...' ausgeben
retn
;Ende Funktion Kernel laden

[BITS 32]
PMode:
      mov ax, datasel    ;Datenselektor in ds,es und ss laden
      mov ds, ax
      mov ss, ax
      mov esp, 0x90000
      jmp 0x10000        ;Sprung zur Adresse des Kernel

gdtr:
   dw gdt_end-gdt-1
   dd gdt
gdt:
   dd 0,0
codesel equ $-gdt
   dw 0xFFFF
   dw 0x0000
   db 0x00
   db 0x9A
   db 0xCF
   db 0x00
datasel equ $-gdt
   dw 0xFFFF
   dw 0x0000
   db 0x00
   db 0x92
   db 0xCF
   db 0x00
gdt_end:

times 512-($-$$)-2 db 0
dw 0AA55h

So müsste es richtig sein. Den Code:

mov ax, 0x1000    ;Die Adresse des Kernels
mov es, ax
mov ds, ax
push ax
mov ax, 0
push ax
retf
brauchst du ja nicht, sonst würdest du ja vor den Protected-Mode Aufruf zum Kernel springen.


bitmaster
« Letzte Änderung: 06. July 2007, 13:43 von bitmaster »
In the Future everyone will need OS-64!!!

bscreator

  • Gast
Gespeichert
« Antwort #13 am: 05. July 2007, 12:47 »
Vielen Dank, das war schon mal ein großer Schritt nach vorn. Die Message "Loading..." wird jetzt schon mal ausgegeben.
Jedoch erscheint kurz nach der Message bei Virtual PC 2007 die Meldung
"Nicht behebbarer Prozessorfehler, der Prozessor wird zurückgesetzt"
und mit VMWare die Meldung
"Virtual machine kernel stack fault (hardware reset) ... a bug in the operating system"

Sorry, aber ich werd das Gefühl nicht los, dass etwas mit dem gdt_end: nicht stimmt...

MNemo

  • Beiträge: 547
    • Profil anzeigen
Gespeichert
« Antwort #14 am: 05. July 2007, 13:15 »
ich hab den code ma getestet und bei mir gibt es keine fehler(zu mindest mit nem "jmp $" kernel nicht). deshalb meine frage:
wie sieht denn dein kernel aus? hast du immer noch das kernel vom Anfang?(ich frage weil ich mir da keinen Stack-Fault vorstellen kann)
da fehlt nämlich ein "jmp $" am ende und die Segmentregister werden noch mit den RM-Werten geladen.
das müsste gehen:
kernel_start:
mov BYTE [DS:0B8000h],'P'   ;Leuchtendes P ausgeben
mov BYTE [DS:0B8001h],1Bh
jmp $    ; Aufhängen/ Anhalten

Sorry, aber ich werd das Gefühl nicht los, dass etwas mit dem gdt_end: nicht stimmt...
das stimmt schon so. Das label wird benoetigt um die groesse der GDT zu berechnen(addr[ende]-addr[anfang]).
« Letzte Änderung: 05. July 2007, 13:23 von M.Nemo »
„Wichtig ist nicht, besser zu sein als alle anderen. Wichtig ist, besser zu sein als du gestern warst!“

bluecode

  • Beiträge: 1 391
    • Profil anzeigen
    • lightOS
Gespeichert
« Antwort #15 am: 05. July 2007, 19:48 »
Du solltest irgendwann mal einen Stack aufsetzen, oder hab ich das jetzt übersehen?
lightOS
"Überlegen sie mal 'nen Augenblick, dann lösen sich die ganzen Widersprüche auf. Die Wut wird noch größer, aber die intellektuelle Verwirrung lässt nach.", Georg Schramm

bitmaster

  • Troll
  • Beiträge: 1 138
    • Profil anzeigen
    • OS-64 = 64 Bit Operating System
Gespeichert
« Antwort #16 am: 05. July 2007, 20:06 »
Du solltest irgendwann mal einen Stack aufsetzen, oder hab ich das jetzt übersehen?
mov ss, ax
mov esp, 0x90000
Damit wird doch ein Stack eingerichtet, oder was meinst du?

bitmaster
In the Future everyone will need OS-64!!!

bscreator

  • Gast
Gespeichert
« Antwort #17 am: 06. July 2007, 13:29 »
Also meinen Kernel hab ich jetzt umgeschrieben :
 
kernel_start:
mov BYTE [DS:0B8000h],'P'
mov BYTE [DS:0B8001h],1Bh
jmp $

Aber so gehts auch nicht. Kann an der Behauptung mit dem Stack nicht doch was dran sein, weil der Stack ja schließlich erst im Protected Mode eingerichtet wird und ich ja schon den Stack im Real Mode verwende ?

bitmaster

  • Troll
  • Beiträge: 1 138
    • Profil anzeigen
    • OS-64 = 64 Bit Operating System
Gespeichert
« Antwort #18 am: 06. July 2007, 13:44 »
Achso, ihr meint den Stack im Rm, den habe ich ja ganz vergessen. So, ich habe den Code oben editiert. Jetzt müsste es aber stimmen.

bitmaster
In the Future everyone will need OS-64!!!

bitmaster

  • Troll
  • Beiträge: 1 138
    • Profil anzeigen
    • OS-64 = 64 Bit Operating System
Gespeichert
« Antwort #19 am: 06. July 2007, 14:11 »
So, ich war mal so fleißig und habe es ausprobiert. Zumindest unter VMware funktioniert es. Hier der Code:

boot.asm:
[BITS 16]  ;Zuerst der 16-Bit-Code

ORG 0x7C00 ;Startadresse

start:

xor ax,ax
mov ds,ax ;da ds und es nicht auf allen PCs standardmäßig Null sind
mov es,ax

mov ax,0100h
mov ss,ax
mov sp,6BFEh ;viele machen den Stack nach 2000h:0000h aber ich glaube das mag Virtual PC nicht

mov [bootdrv],dl  ;Bootlaufwerk aus DL speichern

call load         ;Kernel von Diskette laden

cli
lgdt [gdtr]
mov eax, cr0
or al, 1
mov cr0, eax         ;Setzen des PM-Bits
jmp codesel:PMode    ;FAR Jump ins Codesegment


;Variablen
bootdrv db 0
loadmsg db 'Loading...',13,10,0



;------------------------
;Funktion String ausgeben
putstr:
lodsb
or al,al
jz short putstrd
mov ah,0x0E
mov bx,0x0007
int 0x10
jmp putstr
putstrd:
retn
;Ende Funktion String ausgeben


;---------------------
;Funktion Kernel laden
load:

;Zuerst mit Interrupt 13h, Funktion 0 ein Diskdrive-Reset
push ds
mov ax, 0
mov dl, [bootdrv]
int 13h
pop ds
jc load

loadl:
mov ax, 0x1000  ;ES:BX=10000
mov es, ax
mov bx, 0

;Sektoren lesen (Interrupt 13h, 2)
mov ah, 2
mov al, 5
mov cx, 2
mov dx, 0
int 13h
jc loadl
mov si, loadmsg
call putstr    ;Meldung 'Loading...' ausgeben
retn
;Ende Funktion Kernel laden

[BITS 32]
PMode:
      mov ax, datasel    ;Datenselektor in ds,es und ss laden
      mov ds, ax
      mov es, ax
      mov ss, ax
      mov esp, 0x90000

      jmp 0x10000        ;Sprung zur Adresse des Kernel

gdtr:
   dw gdt_end-gdt-1
   dd gdt
gdt:
   dd 0,0
codesel equ $-gdt
   dw 0xFFFF
   dw 0x0000
   db 0x00
   db 0x9A
   db 0xCF
   db 0x00
datasel equ $-gdt
   dw 0xFFFF
   dw 0x0000
   db 0x00
   db 0x92
   db 0xCF
   db 0x00
gdt_end:

times 512-($-$$)-2 db 0
dw 0AA55h

kernel.asm
[BITS 32]

org 10000h

Start:

mov edi,0B8000h+80*2
mov esi,Msg

.2:
lodsb
or al,al
jz .1
stosb
mov al,07h
stosb
jmp .2

.1:
jmp $ ;Endlosschleife

Msg db "Ich bin im Protected-Mode :-)",0

Und dann:
Zitat
nasmw boot.asm -o boot.bin
nasmw kernel.asm -o kernel.bin
copy boot.bin+kernel.bin=image.img

Dann die image.img mittels VMware laden und staunen. ^^


bitmaster
In the Future everyone will need OS-64!!!

 

Einloggen