Autor Thema: Wieso rebootet bei diesem Code Bochs?  (Gelesen 21392 mal)

PMTheQuick

  • Beiträge: 23
    • Profil anzeigen
Gespeichert
« am: 16. June 2007, 22:03 »
Hi  :-) ,

habe ein Problem. Bochs rebootet bei meinem Code ständig. Hier mal meine Files:

bootsec.asm
starter:

jmp 07c0h:main_entry

main_entry:
mov ax,cs
mov ds,ax
mov es,ax
cli
mov ss,ax
mov sp,9000h
sti

mov ah,02h
mov al,1
mov cl,2
mov ch,0
mov dl,0
mov dh,0
lea bx,[kernel]
int 13h

times 510-($-$$) db 0 ;wichtig: Hier die Datei mit so vielen Bytes füllen, bis es genau 510 sind
dw 0aa55h ;Bootsignatur anhängen
kernel:

kernel16.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 10011010b ;Zugriffsberechtigungen
db 11001111b ;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:

kernel32.asm
[Bits 32]
extern _main
global start
global _EnableA20Gate

start:

call _main

STOP:
jmp STOP

;#######################################################################

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);
}

link.txt
OUTPUT_FORMAT("binary")
INPUT(kernel32.obj ckernel.obj)
ENTRY(start)
SECTIONS
{
  .text  0x200 : {
    code = .; _code = .; __code = .;
    *(.text)
    . = ALIGN(1);
  }
  .data  : {
    data = .; _data = .; __data = .;
    *(.data)
    . = ALIGN(1);
  }
  .bss  :
  {
    bss = .; _bss = .; __bss = .;
    *(.bss)
    . = ALIGN(1);
  }
  end = .; _end = .; __end = .;
}

Create.bat
@echo off
echo DJGPP setzen...
set DJGPP=c:\djgpp\djgpp.env
echo ---
echo Bootloader erzeugen...
nasmw -f bin -o bootsec.bin bootsec.asm
echo ---
echo Kernel16 kompilieren...
nasmw -f bin -o kernel16.bin kernel16.asm
echo ---
echo Kernel32 kompilieren...
nasmw -f aout -o kernel32.obj kernel32.asm
echo ---
echo C-Kernel kompilieren...
gcc -ffreestanding -c -Os -o ckernel.obj kernel.c
echo ---
echo Zusammenlinken
ld -T link.txt -o c32kernel.bin
echo ---
echo Mergen
MergeKernel kernel.bin bootsec.bin kernel16.bin c32kernel.bin
echo ---
pause

Bochs-Konfig:
### Hier den Pfad anpassen für dein disk-image
floppya: 1_44=kernel.bin, status=inserted
####
romimage: file=../BIOS-bochs-latest, address=0xf0000
cpu: count=1, ips=10000000, reset_on_triple_fault=1
megs: 32
vgaromimage: file=../VGABIOS-lgpl-latest
vga: extension=vbe
boot: floppy
floppy_bootsig_check: disabled=0
log: bochsout.txt
panic: action=ask
error: action=report
info: action=report
debug: action=ignore
debugger_log: -
parport1: enabled=1, file="parport.out"
vga_update_interval: 300000
keyboard_serial_delay: 250
keyboard_paste_delay: 100000
private_colormap: enabled=0
keyboard_mapping: enabled=0, map=
i440fxsupport: enabled=1

Tools: DJGPP, MergeKernel, nasmw, Bochs

Vielen Dank im vorraus für eure Antwort  :wink: ,

Gruss
PMTheQuick  :-(
Alle Beiträge und aller Code:
© 2007 P. Mathis

FreakyPenguin

  • Administrator
  • Beiträge: 301
    • Profil anzeigen
    • toni.famkaufmann.info
Gespeichert
« Antwort #1 am: 16. June 2007, 22:15 »
Ich würde dir empfehlen, das ganze mal mit einem Bochs mit eingebautem Debugger zu testen. Der kann dir dann die Inhalte aller Register (für dich duerfte Vorallem EIP von Interesse sein) anzeigen, und dir genauere Auskunft zu dem Fehler geben.
Den Code habe ich mir jetzt nicht genauer angeschaut.

PMTheQuick

  • Beiträge: 23
    • Profil anzeigen
Gespeichert
« Antwort #2 am: 16. June 2007, 22:21 »
Habe mal debuggt:

check_cs: not a valid code segment !
00001325669e[CPU0 ] interrupt(): gate descriptor is not valid sys seg
00001325669e[CPU0 ] interrupt(): gate descriptor is not valid sys seg
00001325669i[CPU0 ] protected mode
00001325669i[CPU0 ] CS.d_b = 16 bit
00001325669i[CPU0 ] SS.d_b = 16 bit
00001325669i[CPU0 ] | EAX=00000011  EBX=00000200  ECX=00000002  EDX=00000000
00001325669i[CPU0 ] | ESP=00008ffe  EBP=00000000  ESI=000088ca  EDI=0000ffdf
00001325669i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df if tf sf zf af PF cf
00001325669i[CPU0 ] | SEG selector     base    limit G D
00001325669i[CPU0 ] | SEG sltr(index|ti|rpl)     base    limit G D
00001325669i[CPU0 ] |  CS:07c0( 1e00| 0|  0) 00007c00 0000ffff 0 0
00001325669i[CPU0 ] |  DS:07c0( 0000| 0|  0) 00007c00 0000ffff 0 0
00001325669i[CPU0 ] |  SS:07c0( 0000| 0|  0) 00007c00 0000ffff 0 0
00001325669i[CPU0 ] |  ES:07c0( 0000| 0|  0) 00007c00 0000ffff 0 0
00001325669i[CPU0 ] |  FS:0000( 0000| 0|  0) 00000000 0000ffff 0 0
00001325669i[CPU0 ] |  GS:0000( 0000| 0|  0) 00000000 0000ffff 0 0
00001325669i[CPU0 ] | EIP=00000263 (00000263)
00001325669i[CPU0 ] | CR0=0x00000011 CR1=0 CR2=0x00000000
00001325669i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
00001325669i[CPU0 ] >> jmp far 0008:0068 : EA68000800
00001325669e[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
00001325669i[SYS  ] bx_pc_system_c::Reset(SOFTWARE) called
00001325669i[APIC0] local apic in CPU 0 initializing
00001329409i[BIOS ] $Revision: 1.166 $ $Date: 2006/08/11 17:34:12 $
00001647564i[KBD  ] reset-disable command received
00001777395i[VBIOS]
VGABios $Id: vgabios.c,v 1.66 2006/07/10 07:47:51 vruppert Exp $

00001777466i[CLVGA] VBE known Display Interface b0c0
00001777498i[CLVGA] VBE known Display Interface b0c4
00001780423i[VBIOS] VBE Bios $Id: vbe.c,v 1.58 2006/08/19 09:39:43 vruppert Exp $
00002653162e[CPU0 ] check_cs: not a valid code segment !
00002653162e[CPU0 ] interrupt(): gate descriptor is not valid sys seg
00002653162e[CPU0 ] interrupt(): gate descriptor is not valid sys seg
00002653162i[CPU0 ] protected mode
00002653162i[CPU0 ] CS.d_b = 16 bit
00002653162i[CPU0 ] SS.d_b = 16 bit
00002653162i[CPU0 ] | EAX=00000011  EBX=00000200  ECX=00000002  EDX=00000000
00002653162i[CPU0 ] | ESP=00008ffe  EBP=00000000  ESI=000088ca  EDI=0000ffdf
00002653162i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df if tf sf zf af PF cf
00002653162i[CPU0 ] | SEG selector     base    limit G D
00002653162i[CPU0 ] | SEG sltr(index|ti|rpl)     base    limit G D
00002653162i[CPU0 ] |  CS:07c0( 1e00| 0|  0) 00007c00 0000ffff 0 0
00002653162i[CPU0 ] |  DS:07c0( 0000| 0|  0) 00007c00 0000ffff 0 0
00002653162i[CPU0 ] |  SS:07c0( 0000| 0|  0) 00007c00 0000ffff 0 0
00002653162i[CPU0 ] |  ES:07c0( 0000| 0|  0) 00007c00 0000ffff 0 0
00002653162i[CPU0 ] |  FS:0000( 0000| 0|  0) 00000000 0000ffff 0 0
00002653162i[CPU0 ] |  GS:0000( 0000| 0|  0) 00000000 0000ffff 0 0
00002653162i[CPU0 ] | EIP=00000263 (00000263)
00002653162i[CPU0 ] | CR0=0x00000011 CR1=0 CR2=0x00000000
00002653162i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
00002653162i[CPU0 ] >> jmp far 0008:0068 : EA68000800
00002653162e[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
00002653162i[SYS  ] bx_pc_system_c::Reset(SOFTWARE) called

Und das wiederholt sich x-mal. Hab jetzt mal das herausgeschnitten, ist das wichtigste. (Die Log ist nach einem Starten und 2sek laufen lassen 40KB gross  :-o ) Was will Bochs mir damit sagen?

Gruss
PMTheQuick ;)
Alle Beiträge und aller Code:
© 2007 P. Mathis

FreakyPenguin

  • Administrator
  • Beiträge: 301
    • Profil anzeigen
    • toni.famkaufmann.info
Gespeichert
« Antwort #3 am: 16. June 2007, 22:25 »
Irgendwas Löst einen GPF aus.
Was genau, wirst du genauer wissen, wenn du deine Binary diassemblierst und schaust, was an 00000263 ist, denn dort wird der GPF ausgelöst.

PMTheQuick

  • Beiträge: 23
    • Profil anzeigen
Gespeichert
« Antwort #4 am: 16. June 2007, 22:32 »
Das ist das Prob:
00000263  EA68000800        jmp 0x8:0x68

Bzw. oben bei Kernel 16...
jmp      0x8:0x10000 + PMODE2   ;Sprung in das "neue" Codesegment

Aber was is daran denn falsch? Das stammt direkt von TeeJay's Tut...

Gruss
PMTheQuick ;)
Alle Beiträge und aller Code:
© 2007 P. Mathis

FreakyPenguin

  • Administrator
  • Beiträge: 301
    • Profil anzeigen
    • toni.famkaufmann.info
Gespeichert
« Antwort #5 am: 16. June 2007, 22:46 »
Dann würde ich mal auf kaputte Deskriptoren, oder falsch geladene GDT tippen.

Ich mag jetzt nicht die ganzen Deskriptoren nachrechnen. Aber ich kann dir einen link zum SMP-Trampoline-Code von LOST geben: http://lost.famkaufmann.info/websvn/filedetails.php?repname=Lost&path=%2Ftrunk%2Fsrc%2Fkernel2%2Fsrc%2Fsmp%2Frm_trampoline.asm

Dort wird auch vom Real mode in den Protected mode gewechselt.
Wenn du dich allzu stark von dem Code inspirieren lässt, solltest du die Lizenz beachten ;-)

PMTheQuick

  • Beiträge: 23
    • Profil anzeigen
Gespeichert
« Antwort #6 am: 17. June 2007, 10:02 »
Habe jetzt mal versucht auf TeeJay's FAT12 Bootloader umzusteigen. Nur hab ich jetzt nen kleines Problemchen: Ich habe KEIN Disketten-Laufwerk.. Wie kann ich den Bootloader trotzdem benutzen? Wie binde ich es dann in Bochs ein?

Gruss
PMTheQuick ;)

OS: Windows XP, hier hab ich nur so nen Linux-Post gesehen wo so "dd,pc,mount,unmount" vorkommt...
Alle Beiträge und aller Code:
© 2007 P. Mathis

FreakyPenguin

  • Administrator
  • Beiträge: 301
    • Profil anzeigen
    • toni.famkaufmann.info
Gespeichert
« Antwort #7 am: 17. June 2007, 10:54 »
Du brauchst ein Disketten-Image, welches du in Bochs anstatt der kernel.bin einträgst. Wie du das unter Windows am einfachsten erstellst weiss ich auch nicht.
Wenn du mal ein rohes Imge hast, kannst du es mit VFD(http://chitchat.at.infoseek.co.jp/vmware/vfd.html) als virtuelles Diskettenlaufwerk benutzen. Damit solltest du, wenn ich mich nicht irre, sogar ein Image erstellen können, indem du keinen Pfad für das Image auswählst (Image im Ram), die Änderungen darauf machst, und es danach abspeicherst.
Auf dieses virtuelle Laufwerk schreibst du dann mit Rawwrite oder dd deinen Bootloader. Danach kannst du die Kernel.bin (oder wie du sie nennen willst) direkt mit dem Explorer auf die Diskette kopieren.

Aber ich würde dir anraten, Grub zu benutzen. Damit kannst du eine Fehlerquelle ausschliessen. Der wechselt dir auch direkt in den Protected-Mode, und du kannst von Anfang an ein brauchbares Binärformat (am besten ELF) benutzen. Später kann er dir auch schon Module beim booten mitladen. Wenn du den benutzen möchtest, nimmst du am besten ein fertiges Image (z.B. von LOST) und passt es mit VFD an.

PMTheQuick

  • Beiträge: 23
    • Profil anzeigen
Gespeichert
« Antwort #8 am: 17. June 2007, 17:42 »
ok... jetzt wollte ich grub nehmen. ich komme aber kein bisschen nach, wo es das gibt, was ich tun muss und wie ich das installen soll?  :-(

Gruss
PMTheQuick ;)
Alle Beiträge und aller Code:
© 2007 P. Mathis

Homix

  • Beiträge: 138
    • Profil anzeigen
Gespeichert
« Antwort #9 am: 17. June 2007, 17:49 »
jmp      0x8:0x10000 + PMODE2   ;Sprung in das "neue" Codesegment
0x10000 ist kein 16-Bit Wert mehr, auch wenn noch was dazu addiert wird *g*

Grüsse, Stefan

PMTheQuick

  • Beiträge: 23
    • Profil anzeigen
Gespeichert
« Antwort #10 am: 17. June 2007, 18:18 »
ich hab nun einfach probs! Ich will eigentlich weiterhin meinen oberen verwenden, aber irgendso nen Ding restartet ständig. Und zwar das:

00000263  EA68000800        jmp 0x8:0x68
Wieso geht das nicht? Vorallem kann ich nirgendwo im Code jmp 0x:0x68 finden  :? Wisst ihr vielleicht eine Lösung?

Gruss
PMTheQuick ;)

@stefan2005: Aber oben kommt ja noch vor ;) [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
;)
Alle Beiträge und aller Code:
© 2007 P. Mathis

nooooooooos

  • Beiträge: 734
    • Profil anzeigen
Gespeichert
« Antwort #11 am: 17. June 2007, 18:23 »
Du hast doch sicher irgendwo ein jmp...Und im Code steht für 0x68 einfach ein Label.

Jetzt musst du nur noch deinen Code disassemblieren und schauen was bei 0x68 für ein label steht...schon hast du deinen Befehl.

Warscheinlich ist das der PM-Jmp und wenn der nicht klappt liegts an irgendetwas mit der GDT den Segmenten und den Offsets...


Gruss
Noooooooooooos

Homix

  • Beiträge: 138
    • Profil anzeigen
Gespeichert
« Antwort #12 am: 17. June 2007, 18:25 »
hi
achso, na ja ich denke das jmp 0x8:0x68 kommt von dem Code:

db  0xea    ;FAR-JUMP zum Codesegment
dw PMODE
dw 0x8

du hast ja keine Offsetadresse ala [ORG 0x???] angegeben, dann assembliert der Assembler das so als wenn der Code an Adresse 0x00 liegt.
Zwar hast du das cs und ds segment richtig gesetzt, aber wenn es um ein direkten Wert von einem Label geht, so nützt dir das nix mehr  :-D

Grüsse,
Stefan

nooooooooos

  • Beiträge: 734
    • Profil anzeigen
Gespeichert
« Antwort #13 am: 17. June 2007, 18:33 »
hehe nein stefan2005...Der Code von TeeJay geht sowiso davon aus, dass der Kernel am Anfang eines Segmentes liegt. Und dieses Segment wird ausgelsen und in den Deskriptor geschrieben...
Deshalb solltest du den Code selber schreiben oder den Bootloader soweit anpassen, dass das stimmt...

Ich würde den Kernel und den anderen Code nach z.B. 0x9000 laden und vor dem jmp cs auf 0x9000 setzen und jmp 0 machen...(noch im Bootloader)

Gruss
Noooooooos
« Letzte Änderung: 17. June 2007, 18:36 von nooooooooos »

PMTheQuick

  • Beiträge: 23
    • Profil anzeigen
Gespeichert
« Antwort #14 am: 17. June 2007, 18:49 »
Ah ja  :oops: Aber schon wieder das nächste Prob... Dieses Tut besteht ja nur aus Fehlern... ^^

00001311251i[CPU0 ] WARNING: Encountered an unknown instruction (signalling illegal instruction)
00001311252i[CPU0 ] BxError: instruction with opcode=0xde

Was soll denn das? Hier weiss ihc nicht mal mehr von wo das kommt  :?

Gruss
PMTheQuick ;)
Alle Beiträge und aller Code:
© 2007 P. Mathis

nooooooooos

  • Beiträge: 734
    • Profil anzeigen
Gespeichert
« Antwort #15 am: 17. June 2007, 18:53 »
Das gibts nur wenn bei jmps in Daten oder nicht an den Anfang eines Befehles sonder mittendrein gesprungen wird.

Zeig mal alle Dateien wo du was verändert hast...Das Tut hat keine Fehler (!) aber es ist ein bisschen blöd und man muss beim Code drumherum sehr viel beachten...(Ist aber fast immer beim PM so...)

Gruss
Noooooooooooos

PMTheQuick

  • Beiträge: 23
    • Profil anzeigen
Gespeichert
« Antwort #16 am: 17. June 2007, 19:00 »
Habs jetzt mal ganz grob gemacht ^^ Einfach alles hochgeladen ;)

Size: 616 KB
Type: RAR
URL: http://web56.login-1.loginserver.ch/QuickOS.rar

Ich hoffe das helft euch,

Gruss
PMTheQuick ;)

EDIT: Eigentlich ist alles gleich, ausser bootsec.asm, das hab ich verändert, denn ich will keinen FAT12, sondern einen normaler Loader der Kernel16 dann aufruft ^^
« Letzte Änderung: 17. June 2007, 19:05 von PMTheQuick »
Alle Beiträge und aller Code:
© 2007 P. Mathis

nooooooooos

  • Beiträge: 734
    • Profil anzeigen
Gespeichert
« Antwort #17 am: 17. June 2007, 19:06 »
Was hast du denn am bootsec verändert? Die Datei im Web ist identisch mit der die du mal gepostet hast....

Gruss
Noooooooooos

PMTheQuick

  • Beiträge: 23
    • Profil anzeigen
Gespeichert
« Antwort #18 am: 17. June 2007, 19:18 »
Das am Anfang war nicht das Original!

Original ist:
;#######################################################################
;BOOTSECTOR zum laden einer binären Kernel-Datei aus dem Root-Verzeichnis

;Copyright by TeeJay (masta_ace_inc@gmx.de)

;Bei Fragen oder Problemen einfach eine Mail schreiben
;Auf Anfrage gibts auch ein eigenes DEUTSCHES Tutorial zum Thema FAT12

;#######################################################################
;INCLUDE_START

%include "Macros.asm" ;Hier sind Macors um die einzelnen lokalen Variablen und Parameter
;bequem ansprechen zu können
;Diese gelten aber nur für einen 16-Bit Stack!!!

;INCLUDE_END
;#######################################################################
;BOOTSECTOR_INFOBLOCK

jmp BOOTINFOBLOCK_END
OSName db "JAY-OS  "
BytesPerSec dw 512
SecPerClus db 1
ResvdSecCnt dw 1
NumFATs db 2
RootEntCnt dw 224
TotSec dw 2880
MediaType db 0xF0
FATSize dw 9
SecPerTrack dw 18
NumHeads dw 2
HiddenSec dd 0
TotSec32 dd 0
DrvNum db 0x00
Reserved db 0
BootSig db 0x29
VolumeID dd 1
VolumeLavel db "NO NAME    "
FileSysType db "FAT12   "
BOOTINFOBLOCK_END:

;########################################################################
;BOOTSECTOR_CODE_START

org 0x7C00 ;Code-Start-Adresse auf 0x7C00 setzen

cli ;Interruptflag löschen (keine Interrupts zulassen)
mov ax, 0x9000
mov ss, ax ;Stacksegment auf AX(0x9000) setzen
xor sp, sp ;Stackpointer auf 0 setzen
sti ;Interruptflag setzen (Interrupts wieder zulassen)



call func_FindFileSector ;Startsektor der Kerneldatei finden lassen (Rückgabe in AX)
or ax, ax ;AX = 0? -> Datei nicht gefunden
jz KernelNotFound ;Zur Ausgabe (File not found) springen

call func_ReadFATTable ;FAT-Tabelle in den Speicher lesen lassen

mov bx, 0x1000 ;Segmentadresse festlegen an die der Kernel geladen werden soll
mov dx, [RootEntCnt] ;Startsektor der Datensektoren errechnen
shl dx, 5
add dx, [BytesPerSec]
dec dx
shr dx, 9
add [Temp], dx ;Und das Ergebnis in Temp-Variable speichern


LoadKernelFile:
mov dx, [Temp] ;Startsektor der Datensektoren in DX schreiben
add dx, ax ;Zum Startsektor der Datensektoren den Startsektor der Datei addieren
dec dx ;DX um 2 verringern
dec dx ;Zweimal "dec dx" braucht weniger Bytes als einmal "sub dx, 2"
push bx ;Segmentadresse an die der Sektor gelesen werden soll auf den Stack pushen
push dx ;Sektornummer die gelesen werden soll auf den Stack pushen
call func_ReadSector ;Sektor lesen lassen
add sp, 4 ;2 Parameter vom Stack löschen

push ax ;FAT-Eintrag-Nummer auf den Stack pushen
call func_ReadFATEntry ;Wert des FAT-Eintrags lesen (Rückgabe in AX)
add sp, 2 ;1 Parameter vom Stack löschen

cmp ax, 0xFFF ;Ist das der letzte FAT-Eintrag der Kernel-Datei?
je ExecuteKernel ;Wenn Ja -> Springe zum Kernel
add bx, 32 ;Segmentadresse um 32 erhöhen. Dort wird der nächste Sektor hingelesen
jmp LoadKernelFile ;Springe wieder nach oben um nächsten Sektor der Kernel-Datei zu lesen

ExecuteKernel:
mov ax, 0x1000
push ax ;Segmentadresse an welcher der Kernel ist auf den Stack pushen
mov ax, 0
push ax ;Offsetadresse des Kernels (0) auf den Stack pushen
retf ;Einen FAR-Rücksprung zum Kernel machen

KernelNotFound:
push WORD MsgFileNotFound ;Offset der "File not Found" Meldung auf den Stack pushen
call func_PrintString ;Meldung ausgeben lassen
add sp, 2 ;1 Parameter vom Stack löschen


WaitForKeyToReboot:
mov ah, 0 ;Auf Tastendruck warten
int 0x16

Reboot:
db 0xEA ;Reboot
dw 0x0000
dw 0xFFFF

;BOOTSECTOR_CODE_END
;########################################################################
;DATABLOCK_START

MsgFileNotFound db "File not found.",13,10,0 ;Meldung wenn kein Kernel gefunden wurde

Filename db "KERNEL  BIN" ;Dateiname des Kernels
Temp dw 0 ;Tempvariable

;DATABLOCK_END
;########################################################################
;FUNCTIONS_START

;------------------------------------------------------------------------
;Funktion um einen NULL-Terminierten String auszugebens
;1. Paramtere: Offset an dem sich der String befindet

func_PrintString:
push bp ;BP sichern
mov bp, sp ;Stackpointer in BP übertragen

pusha ;Alle Register sichern

mov si, [Param1] ;1. Parameter(Offset des Strings) nach SI kopieren
mov ah, 0x0E ;Funktion zur Zeichenausgabe
mov bx, 0x0007 ;Farbattribut des Zeichens
.1:
lodsb ;Zeichen von SI-Pointer nach AL kopieren und SI um 1 erhöhen
or al, al ;AL = 0? String zu Ende?
jz .2 ;Wenn JA -> Springe zum Ende
int 0x10 ;Zeichen ausgeben lassen
jmp .1 ;Wieder nach oben springen um nächstes Zeichen auszugeben

.2:
popa ;Register wiederherstellen

mov sp, bp ;Stackpointer wieder in SP übertragen
pop bp ;BP wiederherstellen
ret ;Return

;------------------------------------------------------------------------
;Funktion um den Startsektor der Kernel-Datei zu finden

func_FindFileSector:
push bp ;BP sichern
mov bp, sp ;Stackpointer in BP übertragen
sub sp, 2 ;Platz für eine lokale Variable auf dem Stack schaffen

pusha ;Alle Register sichern

mov ax, 0x9200 ;Segmentadresse festlegen an die ein Sektor zwischengespeichert wird
mov es, ax

mov ax, [FATSize] ;Startsektor des Root-Directorys errechnen
mov bl, [NumFATs]
mul bl
add ax, [ResvdSecCnt]
mov [Temp], ax ;Startsektor des Root-Directorys in Temp-Variable speichern

xor dx, dx ;DX auf 0 setzen (Braucht weniger Bytes als "mov dx, 0")

.E:
cmp dx, [RootEntCnt] ;Wurden schon alle Root-Dir-Einträge durchsucht?
je .A ;Wenn JA -> Datei nicht gefunden

test dx, 15 ;DX durch 16 ohne Rest teilbar?
jnz .B ;Wenn JA -> Nächsten Sektor lesen

push es ;Segmentadresse für zwischenspeichern eines Sektors auf Stack pushen
push ax ;Sektornummer auf Stack pushen
call func_ReadSector ;Sektor lesen lassen
add sp, 4 ;2 Parameter vom Stack löschen
inc ax ;AX um 1 erhöhen (Braucht weniger Bytes als "add ax, 1")
xor bx, bx ;BX auf 0 setzen (Braucht weniger Bytes als "mov bx, 0")

.B: ;Wenn DX NICHT durch 32 OHNE Rest teilbar ist, fahre HIER fort
cmp BYTE [es:bx], 0x0E ;Erstes Zeichen des Root-Dir-Eintrags = 0x0E?
je .D ;Wenn JA -> Nächsten Eintrag lesen
cmp BYTE [es:bx], 0 ;Erstes Zeichen des Root-Dir-Eintrags = 0?
je .A ;Wenn JA -> Keine weiteren Einträge mehr. Datei nicht gefunden


mov si, Filename ;Offset des Dateinamens nach SI kopieren
mov di, bx ;Offset des Root-Dir-Eintrags nach DI kopieren
mov cx, 11 ;11 Zeichen sollen verglichen werden
repe cmpsb ;Solange vergleichen bis CX = 0 oder ungleiche Zeichen
or cx, cx ;CX = 0?
jz .C ;Wenn JA -> Alle Zeichen stimmen überein. Datei gefunden

.D:
inc dx ;DX um 1 erhöhen
add bx, 32 ;BX um 32 erhöhen (Offset des nächsten Root-Dir-Eintrags)
jmp .E ;Wieder nach oben springen um nächsten Eintrag zu vergleichen

.A: ;Wenn die NICHT Datei gefunden wurde, HIER fortfahren
popa ;Alle Register wiederherstellen
xor ax, ax ;AX auf 0 setzen (Braucht weniger Bytes als "mov ax, 0")
jmp .Ende ;Zum Ende Springen

.C: ;Wenn die Datei gefunden wurde, HIER fortfahren
push WORD [es:bx+26] ;Startsektornummer der Datei auf den Stack pushen
pop WORD [Var1] ;Startsektornummer in lokale Variable popen
popa ;Alle Register wiederherstellen
mov ax, [Var1] ;Startsektornummer der Datei nach AX kopieren

.Ende:
mov sp, bp ;Stackpointer in SP übertragen
pop bp ;BP wiederherstellen
ret ;Return

;------------------------------------------------------------------------
;Funktion um einen Sektor zu lesen
;1. Parameter: Logische Sektornummer des Sektors welcher gelesen werden soll
;2. Parameter: Segmentadresse an die der Sektor gespeichert werden soll

func_ReadSector:
push bp ;BP sichern
mov bp, sp ;Stackpointer in BP übertragen
sub sp, 6 ;Platz für 3 lokale Variablen auf dem Stack schaffen

pusha ;Alle Register sichern

;Aus Logischer Sektornummer die CHS Adresse errechnen
mov ax, [Param1] ;Aus logischer Sektornummer den Cylinder errechnen
mov bx, 36
mov dx, 0
div bx
mov [Var1], ax

mov ax, dx ;Aus logischer Sektornummer den Head errechnen
push ax
mov bx, 18
mov dx, 0
div bx
mov [Var2], ax

pop ax ;Aus logischer Sektornummer den Sektor errechnen
mov dx, 0
div bx
mov ax, dx
add ax, 1
mov [Var3], ax


.1:
mov ax, [Param2] ;Segmentadresse zum speichern des Sektors festlegen
mov es, ax
mov bx, 0 ;Offset zum speichern des Sektors festlegen
mov ah, 2 ;Funktion zum Sektorlesen
mov al, 1 ;1 Sektor soll gelesen werden
mov ch, [Var1] ;Angabe des Cylinders an dem der Sektor gelesen werden soll
mov cl, [Var3] ;Angabe des Sektors an dem der Sektor gelesen werden soll
mov dh, [Var2] ;Angabe des Heads an dem der Sektor gelesen werden soll
mov dl, 0 ;Von Laufwerk A: lesen
int 0x13 ;Sektor lesen lassen
jc .1 ;Bei Fehler nochmal versuchen

popa ;Alle Register wiederherstellen

mov sp, bp ;Stackpointer in SP übertragen
pop bp ;BP wiederherstellen
ret ;Return

;------------------------------------------------------------------------
;Funktion um einen FAT-Eintrag zu lesen
;1. Parameter: Nummer des Eintrags der gelesen werden soll
;In AX wird der Wert des gelesenen FAT-Eintrag zurückgegeben

func_ReadFATEntry:
push bp ;BP sichern
mov bp, sp ;Stackpointer in BP übertragen
sub sp, 2 ;Platz für eine lokale Variable auf dem Stack schaffen

pusha ;Alle Register sichern

mov ax, [Param1] ;Offset errechnen an dem sich der FAT-Eintrag im Speicher befindet
mov bx, 3
mul bx
mov bx, 2
xor dx, dx
div bx

mov bx, 0x9200 ;Segmentadresse angeben an der die FAT-Tabelle im Speicher liegt
mov es, bx
mov bx, ax
mov ax, [es:bx]
mov [Var1], ax ;FAT-Eintrag (16 Bit) in lokale Variable speichern

mov cx, [Param1] ;Testen ob der zu lesende FAT-Eintrag gerade oder ungerade ist
test cx, 1
jz .Gerade ;Wenn GERDADE -> Springe

;Wenn der zu lesende FAT-Eintrag UNGERADE ist, HIER fortfahren
popa ;Alle Register wiederherstellen
mov ax, [Var1]
shr ax, 4 ;FAT-Eintrag(12 Bits) aus den 16 Bits extrahieren
jmp .Ende

.Gerade: ;Wenn der zu lesende FAT-Eintrag GERADE ist, HIER fortfahren
popa ;Alle Register wiederherstellen
mov ax, [Var1]
and ax, 0xFFF ;FAT-Eintrag(12 Bits) aus den 16 Bits extrahieren

.Ende:
mov sp, bp ;Stackpointer in SP übertragen
pop bp ;BP wiederherstellen
ret ;Return

;------------------------------------------------------------------------
;Funktion zum einlesen der FAT-Tabelle in den Speicher

func_ReadFATTable:
pusha ;Alle Register sichern

mov bx, 0x9200 ;Segmentadresse festelegen an welche die FAT-Tabelle gelesen werden soll
mov ax, [ResvdSecCnt] ;Startsektor der FAT-Tabelle eintragen
mov cx, [FATSize] ;Anzahl der FAT-Tabellen-Sektoren eintragen
.A:
push bx ;Segmentadresse auf den Stack pushen
push ax ;Sektornummer auf den Stack pushen
call func_ReadSector ;Sektor lesen lassen
add sp, 4 ;2 Parameter vom Stack löschen
inc ax ;Nächsten Sektor auswählen
add bx, 32 ;Segmentadresse um 32 erhöhen (Dort wird nächster Sektor gespeichert)
loop .A ;Solange wiederholen bis alle Sektoren gelesen wurden

popa ;Alle Register wiederherstellen

ret ;Return

;------------------------------------------------------------------------

;FUNCTIONS_END
;########################################################################


times 512-($-$$)-2 db 0 ;Den Rest des Bootsektors mit Nullen Füllen
dw 0AA55h ;0xAA55 am Ende des Bootsektors schreiben

;#######################################################
;Macros für den einfachen Zugriff auf die über den Stack übergebenen Parameter
;ACHTUNG! Diese Macros sind nur bei einem 16-Bit Stack korrekt!

%define Param1 bp+4
%define Param2 bp+6
%define Param3 bp+8
%define Param4 bp+10
%define Param5 bp+12

;#######################################################
;Macros für den einfachen Zugriff auf lokale Variablen innerhalb einer Funktion
;die auf dem Stack erstellt wurden
;ACHTUNG! Diese Macros sind nur bei einem 16-Bit Stack korrekt!

%define Var1 bp-2
%define Var2 bp-4
%define Var3 bp-6
%define Var4 bp-8
%define Var5 bp-10

;#######################################################

Meiner is:
org 0x7C00

starter:

jmp 07c0h:main_entry

main_entry:
mov ax,cs
mov ds,ax
mov es,ax
cli
mov ss,ax
mov sp,9000h
sti

mov ah,02h
mov al,1
mov cl,2
mov ch,0
mov dl,0
mov dh,0
lea bx,[kernel]
int 13h

times 510-($-$$) db 0 ;wichtig: Hier die Datei mit so vielen Bytes füllen, bis es genau 510 sind
dw 0aa55h ;Bootsignatur anhängen
kernel:

Gruss
PMTheQuick ;)
Alle Beiträge und aller Code:
© 2007 P. Mathis

nooooooooos

  • Beiträge: 734
    • Profil anzeigen
Gespeichert
« Antwort #19 am: 17. June 2007, 19:24 »
dann ersetz mal lea bx,[kernel] durch
mov es, 0x9000
mov bx,0x0

Dann geht die CPU aber nicht mehr direkt vom bootloader zum kernel und somit musst du ein sprung ein bauen: jmp 0x9000:0x0

Da jetzt aber alle Kernel-Dateien auf einem anderen Platz sind musst du halt überall sorgfältig schauen ob du was verändern musst... (Beim PM-umschalt-code musst du nur das jmp 0x8:0x10000+ PMODE2
durch jmp 0x8:0x9000+PMODE ersetzen...Wies bei C-Code geht weiss ich nicht...)


Gruss
Noooooooooooooooos
« Letzte Änderung: 17. June 2007, 19:26 von nooooooooos »

 

Einloggen