Lowlevel
Lowlevel => Lowlevel-Coding => Thema gestartet von: nore am 26. December 2005, 13:06
-
Hi, sry wenn's so ne Frage schonmal gab, hab lange hier im Forum gesucht und nichts entsprechendes gefunden.
Mein Titel ist auch nicht sehr gut gewählt, aber ich wusste nicht, wie ich's ausdrücken soll.
Hier mein Problem:
ich habe zunächst den bootloader und auch den code vom kernel komplett aus dem lowlvl magazin übernommen. dann habe ich eine funktion hinzugefügt, die zeichenketten in einen puffer einliest und diese dann mit anderen zeichenketten vergleicht und entsprechend etwas tut. also wenn man "reboot" eingibt, dann startet der rechner neu, wenn man "fuck" eingibt, wird "you!" ausgebeben (waren nur kleine tests ;) ). das hat auch alles noch funktioniert.
dann hab ich mir ein paar sachen über fat12 durchgelesen und wollte einbauen, dass man eine diskette formatieren kann. dazu hab ich ersteinmal alle informationen, die in den bootsector kommen direkt in meinen assembler quelltext geschrieben, hinter die anderen variablen.
und ab da funktioniert es nicht mehr.
den bootloader hab ich ,glaub ich, so umgeändert, dass er genug von der diskette einliest.
ich hab leider nicht so viel ahnung von assembler. aber könnte es irgendwas mit den calls zu tun haben, weil die funktionen ja jetzt um einiges weiter weg von dem call sind.
wie ihr seht, bin ich noch nicht sehr weit und es ist ziemlich frustrierend für mich, dass ich nicht weiterkomme. deshalb wär ich euch sehr dankbar, wenn ihr mir helfen könntet.
-
bootloader: (fast 1 zu 1 aus dem lowlvl mag)
org 0x7C00 ; Unsere Startadresse
; -----------------------------------------
; Unser Bootloader
; -----------------------------------------
start:
; Erst brauchen wir einen Stack.
cli ; Keine Interrupts!
mov ax, 0x9000 ; Stackadresse
mov ss, ax ; SS = 9000 (unser Stack)
mov sp, 0 ; SP = 0000 (der Stackpointer)
sti ; Interrupts zulassen
; Bootlaufwerk aus DL speichern
mov [bootdrv], dl
;Lade unseren Kernel
call load
;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
; ----------------------------------------------
; Funktionen und Variablen
; ----------------------------------------------
bootdrv db 0 ;Das Bootlaufwerk
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? -> Noch mal!
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, 12 ; Lese 12 Sektoren
mov cx, 2 ; Cylinder=0, Sector=2
mov dx, 0 ; Head=0, Laufwerk=0
int 13h ; ES:BX = Daten vom Laufwerk
jc load1 ; Fehler? Noch mal!
mov si,loadmsg
call putstr ; Meldung ausgeben
retn
times 512-($-$$)-2 db 0 ; Dateilänge: 512 Bytes
dw 0AA55h ; Bootsignatur
kernel: (auch zu großen teilen ausm lowlvl mag, nur bischen umgeändert zum rumspielen)
; ---------------------------------------------------
; Makros
; ---------------------------------------------------
%macro printf 1
mov al, 0x01
mov si, %1
int 0x21
%endmacro
%macro getstr 1
mov al, 0x02
mov di, %1
int 0x21
%endmacro
%macro shcmp 1
mov di, shpuf ; string 1 = shellpuffer (muss nullterminiert sein)
mov si, %1 ; string 2 = befehl
call compstr ; strings vergleichen
cmp ah, 0 ; wenn alles gleich
%endmacro
; ---------------------------------------------------
; Unser Kernel
; ---------------------------------------------------
mov ax, 1000h ; Segmentregister updaten
mov ds, ax
mov es, ax
start:
mov si, msg
call putstr ; Schicke Bootmessage :)
call regint
printf msg_1 ; Noch eine Message :D
call shell
printf msg_2 ; Noch eine Message :D
call getkey ; Warte auf einen Tastendruck
jmp reboot ; Reboot
; -------------------------------------------------
; Funktionen und Variablen
; -------------------------------------------------
msg db 13,10,"system is booting...",13,10,0
msg_1 db "loading shell...",13,10,0
msg_2 db "press any key for reboot",13,10,0
shpuf db 0 ; shell-variablen
times 254 db 0
shellmsg db "dave shell 0.01 is ready",13,10,0
sh_reboot db "reboot",13,10,0
sh_fuck db "fuck",13,10,0
sha_you db "you!",13,10,0
sh_files db "files",13,10,0
sha_files db "Ist die Floppy-Diskette mit FAT12 formatiert? (j)a, (n)ein",13,10,0
format_start dw 0 ; diskettenformatierung
db 0 ; JmpBoot
db "noreos " ; OSName
dw 0xFF ; BystesPerSec
db 1 ; SecPerClus
dw 1 ; RsvdSecCnt
db 2 ; NumFATs
dw 224 ; RootEntCnt
dw 2880 ; TotSec
db 0xF0 ; MediaType
dw 9 ; FATSize
dw 18 ; SecPerTrack
dw 2 ; NumHeads
dd 0 ; HiddenSec
dd 0 ; TotSec32
db 0 ; DrvNum
db 0 ; Reserved
db 0x29 ; BootSig
dd 0 ; VolumeID
times 11 db 20h ; VlumeLabel
db "FAT12"
times 3 db 20h ; FileSysType
times 448 db 0 ; Dateilänge: 512 Bytes
dw 0AA55h ; Bootsignatur
times 9216 db 0 ;
; Stringausgabe
putstr:
lodsb ; Byte laden
or al,al
jz short putstrd ; 0-Byte? -> Ende!
mov ah,0x0E ; Funktion 0x0E
mov bx,0x0007 ; Atrribut-Byte
int 0x10 ; schreiben
jmp putstr ; nächstes Byte
putstrd:
retf
; Warte auf einen Tastendruck
getkey:
mov ah, 0 ; Funktion 0
int 016h ; Ausführen
retf
; Rebooten (HEX Dump).
reboot:
db 0EAh
dw 0000h
dw 0FFFFh
_int0x21:
_int_0x21_ser0x01: ; string ausgeben
cmp al, 0x01
jne _int0x21_ser0x01_end
_int0x21_ser0x01_start:
lodsb
or al, al
jz _int0x21_end
mov ah, 0x0E
mov bh, 0x00
mov bl, 0x07
int 0x10
jmp _int0x21_ser0x01_start
_int0x21_ser0x01_end:
_int_0x21_ser0x02: ; string in shpuf einlesen
cmp al, 0x02
jne _int0x21_ser0x02_end
mov cx, 0
_int0x21_ser0x02_start:
call getkey ; zeichen einlesen
mov ah,0x0E ; Funktion 0x0E
mov bx,0x0007 ; Atrribut-Byte
int 0x10 ; zeichen wieder ausgeben (echo)
stosb ; in den shell-puffer schreiben
inc cx
cmp cx, 253
jz _int0x21_ser0x02_full
cmp al, 13 ; wenn enter gedrückt wurde
jz _int0x21_ser0x02_term
jmp _int0x21_ser0x02_start
_int0x21_ser0x02_full:
mov al, 13
mov ah,0x0E ; Funktion 0x0E
mov bx,0x0007 ; Atrribut-Byte
int 0x10 ; cr ausgeben
stosb ; cr an shpuf anfügen
_int0x21_ser0x02_term:
mov al, 10
mov ah,0x0E ; Funktion 0x0E
mov bx,0x0007 ; Atrribut-Byte
int 0x10 ; nl ausgeben
stosb ; nl an shpuf anfügen
mov al, 0
stosb ; nullterminieren
jmp _int0x21_end
_int0x21_ser0x02_end:
_int0x21_end:
iret
regint:
push dx
push es
xor ax, ax
mov es, ax
cli
mov word [es:0x21*4], _int0x21
mov [es:0x21*4+2],cs
sti
pop es
pop dx
retf
shell:
printf shellmsg ; shell geladen message ausgeben
shell_start:
getstr shpuf ; load string in shellpuffer
shcmp sh_reboot
jz shell_end ; shell beenden
shcmp sh_fuck
jz shella_fuck ; fuck - you!
shcmp sh_files ; dateien
jz shella_files
jmp shell_start
shell_end:
retf
shella_fuck:
printf sha_you
jmp shell_start
shella_files:
printf sha_files
call getkey
mov ah, 6Ah
cmp ah, al
jz shella_files_fat12 ; ist Die Diskette schon mit FAT12 formatiert?
mov ah, 3
mov al, 19
mov ch, 0
mov cl, 0
xor dx, dx
mov ax, ds
mov es, ax
mov bx, format_start
int 13h
shella_files_fat12:
jmp shell_start
compstr:
compstr_start:
mov ah,[si]
mov dh,[di]
cmp ah, dh
jnz compstr_term
inc si
inc di
mov ah, [di]
or ah, ah
jz compstr_end
jmp compstr_start
compstr_term:
mov ah, 1
compstr_end:
retf
-
EDIT:
Bochs schreibt mir folgende Fehlermeldung:
====================================
Bochs is exiting with the following message:
[CPU0 ] prefetch: RIP > CS.limit
====================================
-
hi, der Fehler liegt schon im Bootloader.
Bei der Anzahl der zu ladenen Sektoren hast du 12 angeben.
Die kernel.bin Datei ist aber 10463 byte groß
d.h kernel.bin benötit 21 Sektoren (10463/512 aufgerundet)
ps: Bin auch ein Anfänger, funktioniert nun aber.
-
vielen dank für die antworten.
bin eben ausm skiurlaub angekommen und deshalb etwas KO, aber morgen werd ich mich damit befassen und hier reineditieren, ob's klappt.
EDIT: ok, hab die retf in ret umgeändert. außerdem hab ich den bootloader geändert. da hatte ich wohl einfach nur die beiden ziffern vertauscht :oops: .
aber das mit den calls und rets versteh ich nicht ganz. muss man die calls dann far machen und wie geht das? und wann muss man das überhaupt machen und wann nicht? und was ist mit near?
-
Also sobald du dem Assembler mitteilst, dass er 32-Bit-Code verwenden soll, kannst du das far/near vergessen. So mach ich es jedenfalls...
-
32bit code im 16bit real mode?
oder überseh ich da einen sprung in den pmode?
-
nein tust du nicht, ich bin im real mode und bleib da auch erstmal. ;)
-
32 Bit Code im Realmode ist durchaus möglich (ab dem 386, die Prozessoren darunter hatten ja keine 32 Bit Register). Nur wird dann jedem Befehl ein Prefix vorangestellt, und man kann weiterhin nur 20 Bit Addressieren (4 Bit Segmente, 16 Bit Offsets).