我已经用C编写了内核,并且有一段汇编代码可以调用其主要功能。汇编代码如下:
bits 32
section .text
align 4
dd 0x1BADB002 ;magic
dd 0x00 ;flags
dd - (0x1BADB002 + 0x00) ;checksum. m+f+c should be zero
global start
extern kmain ;kmain is defined in the c file
start:
cli ;block interrupts
mov ebp, stack_space
mov esp, ebp ;set stack pointer
call kmain ; C "kmain" void
hlt ;halt the CPU
section .bss
resb 8192 ;8KB for stack
stack_space:
这就是我编译所有内容的方式:
sudo nasm -f elf kernel.asm -o kasm.o
sudo gcc -m32 -c kernel.c -o kc.o
sudo ld -m elf_i386 -T link.ld -o kernel.bin kasm.o kc.o
我的link.ld
文件是这样的:
OUTPUT_FORMAT(elf32-i386)
ENTRY(start)
SECTIONS
{
. = 0x100000;
.text : { *(.text) }
.data : { *(.data) }
.bss : { *(.bss) }
}
我搜索了很多有用的东西,然后在StackOverflow上找到了一个帖子,这个引导加载程序在0x1000
处加载了内核:
[org 0x7c00]
KERNEL_OFFSET equ 0x1000
call load_kernel
;Switch PM
cli
lgdt [gdt_descriptor]
mov eax, cr0
or eax, 0x1
mov cr0, eax
jmp 0x8:init_pm
[bits 32]
init_pm :
mov ax, 0x10
mov ds, ax
mov ss, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ebp, 0x90000
mov esp, ebp
call KERNEL_OFFSET
jmp $
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
[bits 16]
load_kernel:
mov bx, KERNEL_OFFSET
mov dh, 15
mov dl, 0
mov ah, 0x02
mov al, dh
mov ch, 0x00
mov dh, 0x00
mov cl, 0x02
int 0x13
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
[bits 16]
GDT:
;null :
dd 0x0
dd 0x0
;code :
dw 0xffff ;Limit
dw 0x0 ;Base
db 0x0 ;Base
db 10011010b ;1st flag, Type flag
db 11001111b ;2nd flag, Limit
db 0x0 ;Base
;data :
dw 0xffff
dw 0x0
db 0x0
db 10010010b
db 11001111b
db 0x0
gdt_descriptor :
dw $ - GDT - 1 ;16-bit size
dd GDT ;32-bit start address
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
times 510 -($-$$) db 0
dw 0xaa55
但是,我不能将KERNEL_OFFSET的值更改为0x100000
,因为它对于dx
寄存器来说太大了。如何在0x100000
加载内核并跳转到内核?
PS:我想尽可能避免GRUB,因为我想了解自己在做什么。 任何帮助表示赞赏。谢谢。
编辑:我没有显示内核的源代码,因为它无关紧要。当我使用-kernel
参数(qemu -kernel mykernel
)启动Qemu时,它确实起作用