0

I currently have a bootloader and a very basic assembly file that I can use for debugging. But when I was trying to print in qemu the stirng doesn't print, and but the cursor does move. My print_int function does output the base 10 integer. Another issue that I have found is that the screen width from address [0x44A] is set to 0.

Boot.s

[org 0x7C00]
[bits 16]

KERNEL_OFFSET equ 0x1000

BDB_SKIP: db 0xEB, 0x3C, 0x90                                   ; JMP SHORT 3C NOP      3B
BDB_OEM_IDN: db 0x29, 0x3A, 0x63, 0x7E, 0x2D, 0x49, 0x48, 0x43  ; OEM identifier        8B
BDB_BYTES_PER_SECTOR: db 0x00, 0x20                             ; Bytes per Sector      2B
BDB_N_SECTORS: db 0x01                                          ; Sectors per Cluster   1B
BDB_RESERVED_SECTORS: db 0x01, 0x00                             ; Reserved Sectors      2B
BDB_N_FATS: db 0x02                                             ; # of FAT's            1B
BDB_ROOT_DIRECTORY: db 0xE0, 0x00                               ; Root Directory        2B
BDB_TOTAL_SECTORS: db 0x40, 0xB0                                ; Total Sectors         2B
BDB_MDT: db 0xF0                                                ; Media Descriptor      1B
BDB_N_SECTORS_PER_FAT: db 0x09, 0x00                            ; Sectors per Fat       2B
BDB_N_SECTORS_PER_TRACK: db 0x12, 0x00                          ; Sectors per Track     2B
BDB_N_HEADS: db 0x02, 0x00                                      ; # of Heads            2B
BDB_HIDDEN_SECTORS: db 0x00, 0x00, 0x00, 0x00                   ; # of Hidden Sectors   4B
BDB_LARGE_SECTORS: db 0x00, 0x00, 0x00, 0x00                    ; Large Sector Count    4B

EBR_DRIVE_NUMBER: db 0x00                                       ; Drive Number          1B
EBR_RESERVED: db 0x00                                           ; Reserved              1B
EBR_SIGNATURE: db 0x29                                          ; Signature             1B
EBR_ID: db 0x00, 0x00, 0x00, 0x00                               ; Volume ID             4B
EBR_LABEL: db '         OS'                                     ; Volume Label          11B
EBR_SYS_ID_STR: db 'FAT12   '                                   ; System ID String      8B

start:
    mov [BOOT_DRIVE], dl
    cld

    mov ah, 0x42
    int 0x13

    mov ax, 0x03
    int 0x10

    call load_kernel

    cli
    in al, 0x92
    or al, 0x02
    out 0x92, al

    lgdt [gdt]
    mov eax, cr0
    or eax, 1
    mov cr0, eax

    jmp CODE_SEG:init_pm

load_kernel:
    mov bx, KERNEL_OFFSET
    mov dh, 0x0F
    mov dl, [BOOT_DRIVE]
    call disk_load
    ret

disk_load:
    push dx
    mov ah, 0x02
    mov al, dh
    
    mov ch, 0x00
    mov cl, 0x02

    mov dh, 0x00
    int 0x13
    jc .disk_error

    pop dx
    cmp dh, al
    jne .disk_error
    ret

.disk_error:
    mov ah, 0x0E
    mov al, '!'
    mov bh, 0x00
    int 0x10
    hlt


gdt_start:
    null_segment:
        dd 0x00000000
        dd 0x00000000
    code_segment:
        c_limit:            dw 0xFFFF
        c_base_low:         dw 0x0000
        c_base_middle:      db 0x00
        c_access:           db 0x9A
        c_granularity:      db 0xCF
        c_base_high:        db 0x00
    data_segment:
        d_limit:            dw 0xFFFF
        d_base_low:         dw 0x0000
        d_base_middle:      db 0x00
        d_access:           db 0x92
        d_granularity:      db 0xCF
        d_base_high:        db 0x00
gdt_end:

gdt:
    dw gdt_end - gdt_start - 1
    dd gdt_start

CODE_SEG equ code_segment - gdt_start
DATA_SEG equ data_segment - gdt_start

[bits 32]
init_pm:
    mov ax, DATA_SEG
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov ss, ax
    
    mov ebp, 0x9C000
    mov esp, ebp

.done:
    call KERNEL_OFFSET
    jmp $


BOOT_DRIVE: db 0x00

times 510-($-$$) db 0x00
dw 0xAA55

Debug.s

[org 0x1000]
[bits 32]

VGA_MEM_BASE equ 0xB8000

kernel_entry:
    push esi

    xor eax, eax
    mov al, byte [0x450]
    mov byte [X_POS], al

    mov al, byte [0x451]
    mov byte [Y_POS], al

    mov ax, word [0x44A]
    mov word [SCREEN_WIDTH], ax

    mov esi, dword [SCREEN_WIDTH]
    call print_int

    mov eax, dword [Y_POS]
    mov ebx, dword [X_POS]
    call set_cursor

    mov esi, message
    call puts
    ; call puts
    ; call puts
    ; call puts

    pop esi
    ret


;
; Prints a integer onto the screen
;    - Params:
;        - ESI - Integer that you want to print.
;    - No Return
;
print_int:
    push eax
    push ebx
    push ecx
    push edx

    mov eax, esi
    mov ecx, 0x0A
    mov ebx, 0x00

.num_loop:
    test eax, eax
    jz .end_num_loop

    xor edx, edx
    div ecx

    add dl, 0x30
    mov dh, byte [VGA_LETTER_COLOR]
    push dx

    inc ebx
    jmp .num_loop

.print_zero:
    xor edx, edx
    mov dh, byte [VGA_LETTER_COLOR]
    mov dl, 0x30
    push dx
    inc ebx
    jmp .print_loop

.end_num_loop:
    mov ecx, VGA_MEM_BASE

    test ebx, ebx
    jz .print_zero

.print_loop:
    test ebx, ebx
    jz .done

    pop ax
    mov [ecx], ax

    add ecx, 0x02
    dec ebx
    jmp .print_loop

.done:
    pop edx
    pop ecx
    pop ebx
    pop eax
    ret


;
; Sets the cursor to the current row and column.
;    - Params:
;        AL - Y_POS
;        BL - X_POS
;    - No Return
;
set_cursor:
    push edx

    mov dx, word [SCREEN_WIDTH]
    mul dx
    add bx, ax

    mov dx, 0x03D4
    mov al, 0x0F
    out dx, al

    inc dl
    mov al, bl
    out dx, al

    dec dl
    mov al, 0x0E
    out dx, al

    inc dl
    mov al, bh
    out dx, al

    pop edx
    ret


;
; Gets the position of the cursor
;    - No Params
;    - Return:
;        EAX - The position of the Cursor
;              Y_POS * SCREEN_WIDTH + X_POS
;
get_cursor_position:
    push edx

    xor dx, dx
    xor ax, ax

    mov dx, 0x03D4
    mov al, 0x0E
    out dx, al

    inc dx
    in al, dx
    shl ax, 0x08

    dec dx
    mov al, 0x0F
    out dx, al

    inc dx
    in al, dx

    pop edx
    ret


; 
; Prints a string onto the screen
;    - Params:
;        - ESI - String that you want to print.
;                Always ending in '\0'.
;    - No Return
;
puts:
    push eax
    push ebx
    push edx
    push edi
    push esi

    xor eax, eax
    xor ebx, ebx

    mov al, byte [Y_POS]
    mul dword [SCREEN_WIDTH]
    mov bl, byte [X_POS]
    mov dx, ax
    add ax, bx
    mov edi, [VGA_MEM_BASE + eax * 2]

    mov ah, byte [VGA_LETTER_COLOR]
.loop:
    lodsb
    cmp al, 0x20
    jl .special_char

    inc dword [X_POS]
    stosw

    jmp .loop

.special_char:
    test al, al
    jz .done

    cmp al, 0x0D
    je .carriage_return

    cmp al, 0x0A
    je .newline

    jmp .loop

.carriage_return:
    lea edi, [ebx + edx * 2]
    mov dword [X_POS], 0x00
    jmp .loop

.newline:
    mov eax, dword [SCREEN_WIDTH]
    lea edi, [edi + eax * 2]
    inc dword [Y_POS]
    inc edx

    mov ah, byte [VGA_LETTER_COLOR]
    jmp .loop

.done:
    mov eax, [Y_POS]
    mov ebx, [X_POS]
    call set_cursor

    pop esi
    pop edi
    pop edx
    pop ebx
    pop eax
    ret

VGA_LETTER_COLOR: db 0x07
SCREEN_WIDTH: dw 0x00
X_POS: db 0x00
Y_POS: db 0x00
message: db "Hello, World!", 0x0A, 0x00

I looked at this question, Assembly 32-bit print to display code runs on qemu, fails to work on real hardware but it did not help me mcuh at all.

IYBBT
  • 1
  • 2
  • 1
    For starters, you did not set `ds` or `es` in real mode. You are lucky if you can read the disk and switch to PM like that. Also that's a good recipe to get a mismatch between real and protected mode so no wonder you don't get the expected output. `mov edi, [VGA_MEM_BASE + eax * 2]` should be `lea`. Fixing these and completing the rest as I saw fit because you did not post a [mcve] makes it work here. – Jester Jun 26 '23 at 21:07

0 Answers0