I managed to load a small kernel into memory via a bootloader that performs a far jump to 0x0090:0x0000
. The kernel is loaded successfully as I print a character fr
Real mode interrupt routines have to be developed as if nothing but the CS register is known (and the interrupt flag is cleared). CS:IP is set via the interrupt vector when we get a hardware interrupt. CS will be the segment we wrote to the interrupt vector table. In your case it was 0x0090 since you did this (with DS=0x0000) to update the interrupt vector table:
mov [ds:0x86], cs
Since we can't rely on DS being what we want when our interrupt handler is called we can either push DS onto the stack, copy CS to DS and access our memory variables via DS, and then restore DS. Alternatively we can modify our memory operands so they explicitly use the CS register. We could modify the interrupt handler to look like this:
interrupt21: ; Keyboard
push ax
push bx
push di ; Save DI
push es ; Save ES
mov ax, VIDEO_ORIGIN
mov es, ax ; Set ES to video memory segment
mov di, [cs:videopos] ; Get last videopos into DI
in al, 0x60
test al, 0x80 ; high-bit set = keyup = don't print
jnz .finish
xor bh, bh ; set high byte of BX to zero
mov bl, al ; low byte of BX is scancode
mov al, [cs:keymap + bx]; Reference keymap via CS segment (not DS)
mov ah, 0x07
cld ; Set the direction flag forward
stosw
mov [cs:videopos], di ; Save current video position
.finish:
mov al, 0x20
out 0x20, al
pop es ; Restore ES
pop di ; Restore DI
pop bx
pop ax
iret
I've documented the lines I added. But important things are:
movzx
we can simply clear the upper part of the BX register to zero. movzx
is only available on 386 processors. You can keep that instruction if you are on 386+, but if you intend to target 8086/8088/80188/80286 then you can't use it.Modify your start routine to be:
start:
mov word [videopos], 0x0000 ; Initialize starting video position
sti
.progloop:
hlt
jmp .progloop
Some emulators don't always do screen refreshes if you do a tight loop with jmp $
. A better way to do it is with the HLT instruction. When interrupts are on the CPU will halt the processor until the next interrupt occurs. When one does occur it will be serviced by the interrupt handlers and eventually will fall to the next instruction. In this case we jump back and do the HLT again waiting for the next interrupt.
Since we added a new variable to keep track of the screen cell we are writing to, we will need to add videopos
to you .data
segment:
; --- DATA --- ;
drive db 0
videopos dw 0
These changes do seem to work on Bochs, QEMU, and VirtualBox. If this doesn't work for you then possibly you aren't loading the second stage (4 sectors worth) properly into 0x0090:0x0000? Since I can't see your first stage code I can't really say for certain.