Autor Thema: [bootloader/kernel] eigene interrupts funktionieren nicht  (Gelesen 5751 mal)

middle_endian

  • Beiträge: 25
    • Profil anzeigen
Gespeichert
hi,
ich versuch mich(angelehnt an das 3.tutorial) an einem kleinen bootloader und kernel. klappt prinzipiell auch alles, bis auf das manipulieren der interrupt-vector-table. meine installierte interrupt-routine wird scheinbar nicht aufgerufen. ich poste mal etwas code. der bootloader
org 0x7c00

main:
cli
mov ax, cs
mov ds, ax
mov es, ax
mov ax, 0x9000
mov ss, ax
xor ax, ax
mov sp, ax ; relative adressing to stack segment
sti

mov [bootdrv], dl
mov si, loadmsg
call puts
call load

;; jump to kernel
;; emulated function call
mov si, loadmsg2
call puts
call getkey

mov ax, kerneladr
  push ax
;; only necessary for far jumps (retf)
xor ax, ax
push ax
retf ; pops kernel address 0x1000


load:
;;; loads the kernel
push ds
mov ax, 0 ; reset function
mov dl, [bootdrv] ; what drive?
int 13h ; interrupt
pop ds
jc load

load_impl:
mov ax, kerneladr
mov es, ax ; buffer address for reading
xor bx, bx ;  offset = 0

;; read in sectors
mov ah, 2 ; read function
mov al, 1 ; 1 sectors
mov cx, 2 ; cylinder = 0, sector = 2
xor dx, dx ; head = 0, drive = 0
int 13h ; es:bx = 0x1000
jc load_impl
ret

getkey:
;;; wait for keypress
xor ah, ah ; function 0
int 16h
ret

puts:
;;; string output
;;; expects the data to be in si
lodsb
or al, al
jz short puts_end ; end?
mov ah, 0x0e ; function
mov bx, 0x0 ; attribute-byte, unecessary
int 10h ; writing
jmp puts
puts_end:
ret


;; variablen
kerneladr equ 0x1000
bootdrv db 0
loadmsg db "Loading kernel ...", 13, 10, 0
loadmsg2 db "Press key to initialize kernel code ...", 13, 10, 0

times 510 - ($ - $$) db 0
dw 0xaa55
und der kernel:
;;; kernel code now
  mov ax, kerneladr
mov ds, ax
  mov es, ax

main:
mov si, msg
call puts

;; interrupts
push es
mov ax, 0x7c00
mov es, ax
cli
;; interrupts
mov word [es:21h*4], int_21h
mov [es:21h*4+2], cs
sti
pop es

;; call interrupt
mov si, msg_int
xor al, al
int 21h ; printing (**)

mov al, 1
int 21h ; waiting for key .. (**)

mov si, msg_boot
xor al, al
int 21h ; printing (**)

mov al, 1
int 21h ; waiting for key .. (**)

jmp reboot

;; interrupt handler
int_21h:
;; al = 0 -> print
;; al = 1 -> wait for key press
cmp al, 0
je int_21h_puts
cmp al, 1
je int_21h_getkey
int_21h_end:
iret

int_21h_puts:
lodsb
or al, al
jz int_21h_end ; end?
mov ah, 0x0e ; function
mov bx, 0x0008
int 10h
jmp int_21h_puts

int_21h_getkey:
xor ah, ah
int 16h
jmp int_21h_end



;; variables
kerneladr equ 0x1000
msg db "welcome", 13, 10, 0
msg_boot db "press any key to reboot ...", 13, 10, 0
msg_int db "interrupt message", 13, 10, 0

reboot:
;; now rebooting
db 0xea
dw 0x0000
dw 0xffff

times 512 - ($ - $$) db 0
ich sitzt jetzt schon ziemlich lang davor, komm aber auf keinen grünen zweig.
es wird wie gesagt weder die ausgabe vollzogen, noch auf einen tastendruck gewartet ((**) im code). rebootet wird auch nicht, was mich auch etwas wundert.

das einzige, das für mich sinn ergeben würde ist, dass der bootloader ja nach 0x7c00 geladen wird und sich die ivt ebenfalls an diesem ort befindet und überschrieben würde. aber eigentlich bin ich mir ziemlich sicher, dass die 1024Byte vom bios automatisch für die ivt freigelassen werden. würd sonst keinen sinn ergeben.

woran scheiterts bei meinem code?
danke für die hilfe

bitmaster

  • Troll
  • Beiträge: 1 138
    • Profil anzeigen
    • OS-64 = 64 Bit Operating System
Gespeichert
« Antwort #1 am: 10. July 2007, 11:28 »
Also wer hat dir denn gesagt das die IVT an 7C00h liegt? Das ist totaler quatsch. Die IVT liegt bei Null. Das heißt also dein Code müsste so aussehen:

;; interrupts
push es
xor ax, ax ;Null
mov es, ax
cli
;; interrupts
mov word [es:21h*4], int_21h
mov [es:21h*4+2], cs
sti
pop es

Ob an anderer Stelle im Code noch ein Fehler ist weiß ich jetzt nicht.

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

middle_endian

  • Beiträge: 25
    • Profil anzeigen
Gespeichert
« Antwort #2 am: 10. July 2007, 13:08 »
argl. dankeschön!

middle_endian

  • Beiträge: 25
    • Profil anzeigen
Gespeichert
« Antwort #3 am: 11. July 2007, 13:49 »
hi,
es hat sich noch eine frage bzgl der interrupt service routine ergeben.
wenn beispielsweise folgender code vorliegt, wobei int 21 die interrupt service routine int_21h aufruft:
...
push 1
push 2
push 3
int 21h
add sp, 6

...

int_21h:
   mov bp, sp
   mov ax, [bp+6]       ; <-- was steht in diesen 6 Bytes?
   cmp ax, 3
   jnz not_equal
   ; equal                    ; es wird hier her gesprungen
not_equal:
   ; equal
   ...
warum muss ich hier 6 Bytes zum aktuellen sp addieren, um an den 3er zu kommen? sollte es nicht reichen zu sp 2 zu addieren(wegen der rücksprungadresse)? hab mir schon gedacht, dass die obersten 4bytes am stack nach dem aufruf der interrupt service routine evtl die adresse des entsprechenden interrupt-eintrags in der ivt ist, dem ist aber nicht so(sofern ich mich nicht verdebugged hab).

dankeschön

bluecode

  • Beiträge: 1 391
    • Profil anzeigen
    • lightOS
Gespeichert
« Antwort #4 am: 11. July 2007, 14:14 »
Bei einem Interrupt werden im Realmode cs, ip und die flags auf den stack gepusht.
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

middle_endian

  • Beiträge: 25
    • Profil anzeigen
Gespeichert
« Antwort #5 am: 11. July 2007, 14:23 »
gut zu wissen, danke.

 

Einloggen