Kernel Dev In assembly & C



我试图在linux上使用bochs使用汇编和C创建一个简单的内核。每次我尝试从汇编代码调用c代码时,模拟器都会给我一个错误并重置模拟的问题。当我在16位实模式下启动时,我使用以下代码

global _start
[bits 16]
_start:
mov [BOOT_DRIVE] , dl
mov bp , 0x7000
mov sp , bp
mov bx , 0x0000 ;load 5 sectors to 0x0000(ES):0x9000(BX)
mov es , bx
mov bx , KERNEL_OFFSET
mov dh , 15
mov dl , [BOOT_DRIVE]
call disk_load
mov dx , [es:KERNEL_OFFSET]
call print_hex
call switch_to_pm
jmp $

切换到保护模式后,代码为

[bits 32]
extern kmain
begin_pm:
;print a char to vram for testing and it is printed, this means the switch has suceeded
mov ebx , VRAM_ADDRESS
mov al , 'H'
mov [ebx] , al
mov al , 0x07
inc ebx
mov [ebx] , al
call kmain
jmp $

和c函数基本上什么都不做只是一个空的

关于我正在使用的命令,我使用这些

nasm $asm_file_name.asm -f elf -o $asm_file_name.o
gcc -ffreestanding -c $c_file_name.c -o $c_file_name.o
ld -o $c_file_name.bin -Ttext 0x7c00 $asm_file_name.o $c_file_name.o --oformat binary
dd status=noxfer conv=notrunc if=$c_file_name.bin of=$floppy_name.img
我不知道问题出在哪里。有什么想法吗?

注意:我正在使用以下GDT和switch_to_pm函数

    ;GDT
gdt_start:
    gdt_null:
        dd 0x0
        dd 0x0
    gdt_code: ;the code segment descriptor
        ; base = 0x0 , limit = 0xfffff ,
        ; 1 st flags : ( present )1 ( privilege )00 ( descriptor type )1 -> 1001 b
        ; type flags : ( code )1 ( conforming )0 ( readable )1 ( accessed )0 -> 1010 b
        ; 2 nd flags : ( granularity )1 (32 - bit default )1 (64 - bit seg )0 ( AVL )0 -> 1100 b
        dw 0xffff
        ; Limit (bits 0 -15)
        dw 0x0
        ; Base (bits 0 -15)
        db 0x0
        ; Base ( bits 16 -23)
        db 10011010b ; 1st flags , type flags
        db 11001111b ; 2nd flags , Limit (bits 16 -19)
        db 0x0
        ; Base ( bits 24 -31)
    gdt_data: ; the data segment descriptor
        ; Same as code segment except for the type flags :
        ; type flags : ( code )0 ( expand down )0 ( writable )1 ( accessed )0 -> 0010 b
        dw 0xffff
        ; Limit ( bits 0 -15)
        dw 0x0
        ; Base ( bits 0 -15)
        db 0x0
        ; Base ( bits 16 -23)
        db 10010010b ; 1 st flags , type flags
        db 11001111b ; 2 nd flags , Limit ( bits 16 -19)
        db 0x0
        ; Base ( bits 24 -31)
    gdt_end:
    ; The reason for putting a label at the end of the
    ; GDT is so we can have the assembler calculate
    ; the size of the GDT for the GDT decriptor ( below )
    ; GDT descriptior
    gdt_descriptor:
        dw gdt_end - gdt_start - 1
        dd gdt_start
    ; Size of our GDT , always less one
    ; of the true size
    ; Start address of our GDT
    ; Define some handy constants for the GDT segment descriptor offsets , which
    ; are what segment registers must contain when in protected mode. For example ,
    ; when we set DS = 0 x10 in PM , the CPU knows that we mean it to use the
    ; segment described at offset 0 x10 ( i.e. 16 bytes ) in our GDT , which in our
    ; case is the DATA segment (0 x0 -> NULL ; 0 x08 -> CODE ; 0 x10 -> DATA )
    CODE_SEG equ gdt_code - gdt_start
    DATA_SEG equ gdt_data - gdt_start
[bits 16]
switch_to_pm:
cli
lgdt[gdt_descriptor]
mov eax , cr0
or eax , 0x1
mov cr0 , eax
jmp CODE_SEG:init_pm
[bits 32]
init_pm:
mov ax , DATA_SEG
mov ds , ax
mov ss , ax
mov es , ax
mov fs , ax
mov gs , ax
mov ebp , 0x9000
mov esp , ebp
jmp begin_pm

call kmain将尝试在地址上找到函数,就好像整个代码是在0x7c00加载的一样。但是,整个代码是从磁盘加载到0x9000的。因此,您需要请求链接器将它用作kmain的地址。

或者更好,正如@AlexeyFrunze所建议的,将从第二个扇区开始的代码直接加载到BIOS加载第一个扇区之后的内存位置。

相关内容

  • 没有找到相关文章