我正在尝试为 i386 32 位编写一个非常基本的内核。我一直在关注 JamesM 的内核教程。我的内核代码本身目前做的很少 - 我正在努力让 grub 正确加载我选择使用的高半格式。
这个答案中描述了这样做的建议,我正在粗略地使用较高的一半裸骨。我的测试环境是 bochs,带有 grub 软盘(0.97/legacy)。
为了让您了解我在做什么,我有一个非常简单的几乎什么都不做的“主要”例程:
[section .text]
align 4
; setting up entry point for linker
start equ (start_vma - 0xBFF00000)
; entry point
start_vma:
push ebx
mov eax, 0xCCCCCCCC
hlt
这种技术给了我:
bjdump -x kernel | grep "start"
start address 0x00100000
c0000000 g .text 00000000 start_vma
00100000 g .text 00000000 start
然后我所做的是使用链接器脚本将 LMA(物理地址加载点)设置为 1MB,但将 VMA 设置为 3GB,如下所示:
OUTPUT_FORMAT(elf32-i386)
ENTRY(start)
KERNEL_MBOOT = 0x400;
KERNEL_VMA = 0xC0000000;
KERNEL_LMA_OFFSET = 0xBFF00000;
PHDRS
{
headers PT_PHDR PHDRS ;
mboot PT_LOAD FILEHDR ;
text PT_LOAD FILEHDR ;
data PT_LOAD ;
}
SECTIONS
{
. = KERNEL_MBOOT;
.mboot : AT(KERNEL_VMA - KERNEL_LMA_OFFSET)
{
*(.mboot)
} : mboot
. = KERNEL_VMA;
.text : AT(ADDR(.text)+ADDR(.mboot) - KERNEL_LMA_OFFSET)
{
code = .; _code = .; __code = .;*/
*(.text)
*(.rodata*)
} : text
.data ALIGN (0x1000) : AT(ADDR(.data) - KERNEL_LMA_OFFSET)
{
data = .; _data = .; __data = .;
*(.data)
*(.rodata)
} : data
.bss : AT(ADDR(.bss) - KERNEL_LMA_OFFSET)
{
bss = .; _bss = .; __bss = .;
*(.bss)
*(COMMON)
ebss = .;
} : data
end = .; _end = .; __end = .;
}
或者至少我相信。解释。当然,这就是我的对象中的内容:
$ objdump -h kernel.bin
file format elf32-i386
Sections:
Idx Name Size VMA LMA File off Algn
0 .mboot 0000000c 00000400 00100000 00000400 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
1 .text 0000002e c0000000 00100400 00001000 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
2 .data 00000001 c0001000 00101000 00002000 2**12
CONTENTS, ALLOC, LOAD, DATA
3 .bss 00004000 c0001020 00101020 00002001 2**5
ALLOC
该.mboot
部分仅包含多重引导标头。事实上,运行 mbchk 给出:
kernel: The Multiboot header is found at the offset 1024.
kernel: Page alignment is turned on.
kernel: Memory information is turned on.
kernel: Address fields is turned off.
kernel: All checks passed.
所以总而言之,这看起来像是一个有效的,应该是引导绝对什么都不做的精灵内核。
但是,它实际上并没有启动。相反,grub 会这样抱怨:
错误 28:所选项目无法放入内存
我在 x64 fedora 上使用 gcc 4.7.2 构建,具有:
CFLAGS=-nostdlib -fno-builtin -fno-stack-protector -ffreestanding -m32
LDFLAGS=-melf_i386 -Tlink.ld
link.ld
我上面包含的脚本在哪里。
我的问题是,我在上面做错了什么让 grub 相信内核可以放入内存?我努力了:
- 更改 VMA_OFFSET 字段以使 VMA 与 LMA 匹配,即以 1MB 物理和虚拟加载所有内容没有区别,即我得到相同的错误。
- 将 LMA 降至 1MB 以下。导致 grub 错误 7:无法按预期加载低于 1MB。
- 狂饮茶和咖啡。
这些事情都没有奏效。我觉得我错过了一些非常明显的东西,但无法弄清楚它是什么。
更新:查看 grub multiboot elf 行,这就是我所看到的:
[Multiboot-elf, <0xffc00:0x40c:0x0>
至关重要的是,我相信我应该看到类似于这个问题中的那条线,即它应该有entry=
一部分!
无论如何,我看着提供一个初始化区域:
[section .init]
; setting up entry point for linker
; entry point
start:
push ebx
mov eax, 0xCCCCCCCC
; jmp later
hlt
我这样链接:
.init : AT(ADDR(.mboot) + (KERNEL_VMA - KERNEL_LMA_OFFSET))
{
*(.init)
} : init
给予:
Idx Name Size VMA LMA File off Algn
1 .init 0000000c 00100000 00100400 00001000 2**0
其 VMA/LMA 约为 1M,因此应该加载...但我仍然收到有关所选项目不适合内存的投诉。