0
votes

On 64-bit Ubuntu, I wrote a bootloader that loads a kernel, which provides an echo program (outputs whatever is inputted):

Bootloader Code:

    [BITS 16]
    org 0x7C00
    bootdrive db 0
    start:
            mov [bootdrive], dl
            mov ah, 0
            int 13h

            mov dx, 0
            mov ah, 2
            mov al, 0x10
            mov dl, [bootdrive]
            mov ch, 0
            mov dh, 0
            mov cl, 2
            mov bx, 0
            int 13h
            jmp 0x1000:0000
    times 510-($-$$) db 0
    dw 0xAA55

Kernel Code:

    [BITS 64]
    call _stdin
    jmp $

    _stdin:
            mov ah, 0
            int 16h
            mov ah, 0eh
            mov bx, 0
            int 10h
            ret

int 16h/ah=0 takes input and puts the buffer into al. Then, I attempt to print al through int 10h/al=0eh, but it doesn't go through. I even tried putting

    mov al, "!"

in between

    mov ah, 0eh

and

    mov bx, 0

but it doesn't seem to like the 16h interrupt. I also tried various other stdin commands using int 21h (ah = 8, ah = 1, ah = 0ah), but none of them was able to read a keystroke. I would type a key and press ENTER, but nothing would happen. More confusing was the fact that even the output command within int 21h (ah = 02h) did not print anything. I tried switching the kernel to real mode (32 bits) instead of long mode (64 bits), but int 21h still wouldn't work. To be clear, I want to be able to read keyboard input WITHOUT waiting for a return keystroke, so that I can alternate between calling the input interrupt and doing other processes. int 21h did not seem to work, not even in 32 bit mode, as well as int 16. The only interrupts that I have ever actually gotten to work were int 10h and int 13h (shown in the code), but the other interrupts don't work for some reason.

NOTE: I assembled the bootloader and kernel using nasm bootloader.asm -p kernel.asm to create a bin file named bootloader, and I used qemu-system-x86_64 to run the assembled bin file.

1
After a quick glance, there are a few things that confuse me: A) there is the bootdrive variable in the execution path B) I can't see to find where es is set before the call to int 13h/ah=02h C) The kernel is assembled with 64-bit default operand size but you don't seem to switch to 64-bit mode D) You never "reset" the video mode, though this is not the issue here, I always felt safer doing it. - Margaret Bloom
Oh huh, I never knew how to set it to long mode, apparently. Thought it was just [BITS 64] and that was it - Eagterrian Knight
bits 64 only tells the assembler to generate 64-bit instruction encodings. It is up to the programmer to place the CPU in long mode before executing 64-bit code. Once in 64-bit protected mode you can't directly access the BIOS functions anymore either (without switching back to real mode first) - Michael Petch
Margaret is pointing out that bootdrive db 0 will be executed as an instruction potentially causing issue. Place your variables after the last instruction of your bootloader and before times 510-($-$$) db 0. bootdrive db 0 should be placed after jmp 0x1000:0000 and before times 510-($-$$) db 0 in your case - Michael Petch
int 21h is not available in a bootloader. int 21h is a DOS interrupt. DOS isn't available at the stage a bootloader starts, just the BIOS and direct hardware access. - Michael Petch

1 Answers

0
votes

[EDITED]

Here is a program that I wrote that contains both the bootloader and the kernel, that works when converted to a .iso file:

    [BITS 16]
    org 0x7C00

    mov ax, 0
    mov es, ax
    mov ah, 2
    mov al, 1
    mov ch, 0
    mov dh, 0
    mov cl, 2
    mov bx, _stage2
    int 0x13
    jmp _stage2
    times 510-($-$$) db 0
    dw 0xAA55

    _stage2:
            call _stdin
            call _stdout
            jmp _stage2
    _stdin:
            mov ah, 1
            mov al, 0
            int 16h
            cmp al, 0
            je _stdin
            mov ah, 0
            int 16h
            ret
    _stdout:
            mov ah, 0eh
            mov bx, 0
            int 10h
            ret