23. November 2024, 07:59
org 0x7C00h ;Unsere Startadresse;-----------------------------------------------------;; Erst brauchen wir einen Stack ;;-----------------------------------------------------;climov ax, 0x9000 ;Stacksegmentmov ss, ax ;Stapelsegmentmov sp, 0 ;Stapelzeigersti;-----------------------------------------------------;; V A R I A B L E N ;;-----------------------------------------------------;[bits 16]bootdrv db 0 ;Das Bootlaufwerk loadmsg db "loading trueOS-kernel v.0.1 ....",13,10,0 ;Die Load-Nachrichtsectors db 14 ;14 Sectors;-----------------------------------------------------;mov [bootdrv], dl ;Bootlaufwerk aus DL speichern;-----------------------------------------------------;call load ;Lade unseren Kernel;-----------------------------------------------------;;-----------------------------------------------------;; Springe zu diesem Kernel ;;-----------------------------------------------------;mov ax, 0x10000 ;Die Adresse des Programmsmov es, axmov ds, axpush axmov ax, 0push axretf;-----------------------------------------------------;; Einen String ausgeben ;;-----------------------------------------------------;putstr: lodsb ;Lade nächstes Zeichen nach AL ... or al,al jz short putstrd mov ah,0x0E ;Die Function 0x0Eh mov bx,0x0007 int 0x10 ;Den Interrupt 10h bitte jmp putstr ;Nächste runde ...putstrd: retn ;-----------------------------------------------------;; Lade den Kernel vom Bootlaufwerk ;;-----------------------------------------------------;load: push ds ;Sichere DS mov ax, 0x00 ;Die gewünschte Funktion (reset) mov dl, [bootdrv] ;Dieses Laufwerk ist gewünscht int 0x13 ;Den Interrupt ausführen pop ds ;DS wiederherstellen jc load ;Geht nicht? -> Noch mal!load1: mov ax,0x10000 ;ES:BX = 10000 ... mov es,ax ;... mov bx, 0 ;... ;--------------------------------------; ; Sektoren lesen (Interrupt 13h, 2) ; ;--------------------------------------; mov ah, 0x02 ;Funktion 2 (Lesen) mov al, [sectors] ;Lese n Sektoren mov cx, 2 ;Cylinder=0, Sector=2 mov dx, 0 ;Head=0, Laufwerk=0 int 0x13 ;ES:BX = Daten vom Laufwerk jc load1 ;Fehler? Noch mal! mov si,loadmsg ;Loadmsg nach SI call putstr ;Nachricht ausgeben retn ;Ende!times 512-($-$$)-2 db 0 ;die Datei soll 512 Bytes groß seindw 0AA55h ;Dieses Word muss am Ende stehen.
[Bits 16]jmp start ;die Descriptors überschpringen;-------------------------------------------------------;; Descriptors ;;-------------------------------------------------------;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) ;-------------------------------------------------------;; DER JUMP ETC ;;-------------------------------------------------------;start: cli ;Keine Interrupts mov eax, cs ;CS nach EAX mov ds, ax ;AX nach DS shl eax, 4 ;EAX um 4 Bits nach links verschieben mov [CODE_Desc+2], ax ;Den ersten Teil der Linearen Adresse eintragen mov [DATA_Desc+2], ax ;..... shr eax, 16 ;EAY um 16 Bits nach rechts verschieben mov [CODE_Desc+4], al ;Den zweiten Teil der Linearen Adresse eintragen mov [DATA_Desc+4], al ;.... mov eax, cs ;EAX aktualisieren shl eax, 4 ;Wieder um 4 Bits nach link verschieben add eax, NULL_Desc ;Zu OFFSET von NULL_Desc adden mov [Base], eax ;Die Segmentbasisadresse von EAX nach [Base] mov [Limit], WORD gdt - NULL_Desc - 1 ;Die Größe lgdt [gdt] ;Die GDT laden ... ;-------------------------; ; PMode einschalten ; ;-------------------------; mov eax, cr0 ;Das CR0 Register in EAX laden or eax, 1 ;Das erste Bit (PE Bit) auf 1 setzen mov eax, cr0 ;Das CR0 Register mit dem neuen Wert laden ;-------------------------; ; FAR-JUMP ; ;-------------------------; db 0xea ;Bitmuster für einen FAR JUMP dw MAIN_F ;Angabe des Offsets zu dem gesprungen werden soll dw 0x8 ;Selektor zu dem gesprungen werden soll [Bits 32];-------------------------------------------------------;; DIE MAIN FUNCTION ;;-------------------------------------------------------; MAIN_F: 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 + MAIN ;Sprung in das "neue" Codesegment MAIN: mov esi, 0 text: ;-----text ausgabe-----; mov [0xB8000+esi], byte '*' inc esi mov [0xB8000+esi], byte 1Bh inc esi cmp esi, 3840 jl text cli hlt times 512-($-$$) db 0;
...mov ax, 0x10000 ;Die Adresse des Programms...load1: mov ax,0x10000 ;ES:BX = 10000 ...
mov eax, cr0or eax, 1mov eax, cr0
mov eax, cr0or eax, 1mov cr0, eax
jmp 0x8:0x1000 + MAIN
jmp 0x8:0x10000 + MAIN