C Kernel - Works fine on VM but not actual compute

2019-02-18 19:35发布

I am making a basic C kernel. (Loaded by an assembly program) I am compiling it with an i686-elf cross compiler for windows. My C code is as follows:

void cls();
void drawhappy();
void main(){
    char *vidptr = (char *)0xb8000;
    cls();
    drawhappy();
}

void cls(){
    char *vidptr = (char *)0xb8000;
    unsigned int j = 0;
    while(j < 80*2*25){
        vidptr[j] = ' ';
        vidptr[j+1] = 0x07;
        j = j+2;
    }
}

void drawhappy(){
    char *vidptr = (char *)0xb8000;
    const unsigned int linewidth = 80*2;
    vidptr[3] = 0xa7;
    vidptr[5] = 0xa7;
    vidptr[7] = 0xa7;
    vidptr[9] = 0xa7;
    vidptr[1+linewidth] = 0xa7;
    vidptr[5+linewidth] = 0xa7;
    vidptr[7+linewidth] = 0xa7;
    vidptr[11+linewidth] = 0xa7;
    vidptr[1+linewidth*2] = 0xa7;
    vidptr[3+linewidth*2] = 0xa7;
    vidptr[5+linewidth*2] = 0xa7;
    vidptr[7+linewidth*2] = 0xa7;
    vidptr[9+linewidth*2] = 0xa7;
    vidptr[11+linewidth*2] = 0xa7;
    vidptr[1+linewidth*3] = 0xa7;
    vidptr[5+linewidth*3] = 0xa7;
    vidptr[7+linewidth*3] = 0xa7;
    vidptr[11+linewidth*3] = 0xa7;
    vidptr[1+linewidth*4] = 0xa7;
    vidptr[11+linewidth*4] = 0xa7;
    vidptr[3+linewidth*5] = 0xa7;
    vidptr[5+linewidth*5] = 0xa7;
    vidptr[7+linewidth*5] = 0xa7;
    vidptr[9+linewidth*5] = 0xa7;
}

In bochs, it gives me the expected output: Yay And if I use bootice to write the bin file to the boot sector and run it as a VM on virtualbox, it works too. But if I actually boot from the USB stick, It just kinda goes crazy then puts a weird symbol by the bottom right corner of my screen. (No screenshot because I obviously can't) I have an i7-3770K CPU. Why is this happening?

EDIT: Here's my assembly code:

[org 0x7c00]
KERNEL_OFFSET equ 0x1000

    mov [BOOT_DRIVE], dl

    mov bp, 0x9000
    mov sp, bp

    mov bx, MSG_REAL_MODE
    call print_string

    call load_kernel

    call switch_to_pm

jmp $

%include "C:/Users/Aaron/Desktop/CODE_OS/print_string.asm"
; load DH sectors to ES:BX from drive DL
disk_load:
    push dx

    mov ah, 0x02
    mov al, dh
    mov ch, 0x00
    mov dh, 0x00
    mov cl, 0x02

    int 0x13

    jc disk_error

    pop dx
    cmp dh, al
    jne disk_error
    ret

disk_error:
    mov bx, DISK_ERROR_MSG
    call print_string
    jmp $

DISK_ERROR_MSG: db "Disk read error!", 0
%include "C:/Users/Aaron/Desktop/CODE_OS/print_string_pm.asm"
%include "C:/Users/Aaron/Desktop/CODE_OS/switch_to_pm.asm"
; GDT
gdt_start:

gdt_null:   ; the mandatory null descriptor
    dd 0x0
    dd 0x0

gdt_code:   ; the code segment descriptor
    dw 0xffff   ; limit
    dw 0x0      ; base
    db 0x0
    db 10011010b
    db 11001111b
    db 0x0

gdt_data:
    dw 0xffff
    dw 0x0
    db 0x0
    db 10010010b
    db 11001111b
    db 0x0

gdt_end:

gdt_descriptor:
    dw gdt_end - gdt_start - 1
    dd gdt_start

CODE_SEG equ gdt_code - gdt_start
DATA_SEG equ gdt_data - gdt_start

[bits 16]

load_kernel:
    mov bx, MSG_LOAD_KERNEL
    call print_string

    mov bx, KERNEL_OFFSET
    mov dh, 15
    mov dl, [BOOT_DRIVE]
    call disk_load

    ret

[bits 32]

BEGIN_PM:
    mov ebx, MSG_PROT_MODE
    call print_string_pm

    call KERNEL_OFFSET

    jmp $

BOOT_DRIVE db 0
MSG_REAL_MODE  db 'Started in 16-bit Real Mode',0
MSG_PROT_MODE db 'Successfully booted to 32-bit Protected Mode',0
MSG_LOAD_KERNEL db "Loading Kernel...",0

times 510-($-$$) db 0 ; Pad the boot sector out with zeros
dw 0xaa55 ; Last two bytes form the magic number

(Print-string.asm just prints strings, switch_to_pm.asm switches to protected mode, and print_string_pm.asm prints strings in protected mode.)

1条回答
爷的心禁止访问
2楼-- · 2019-02-18 19:44

You're not initializing the segment registers. Try changing the start of your bootsector to something like this:

xor ax, ax
mov bp, 0x9000
mov ds, ax
mov es, ax
mov ss, ax ; disables interrupts until the end of the next instruction
mov sp, bp
mov [BOOT_DRIVE], dl
查看更多
登录 后发表回答