我正在尝试为 i386 32 位编写一个非常基本的内核。我一直在关注 JamesM 的内核教程。我的内核代码本身目前做的很少 - 我正在努力让 grub 正确加载我选择使用的上半部分格式。
这样做的建议是 described in this answer ,我正在粗略地使用 higher half bare bones 。我的测试环境是 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 = .;
}
或者至少我相信。 Explanation 。当然,这就是我的对象中的内容:
$ 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.
所以总而言之,这看起来是一个有效的,应该是引导 elf 内核,它什么都不做。
但是,它实际上并没有启动。相反,grub 会这样提示:
我在 x64 fedora 上使用 gcc 4.7.2 构建,使用:
CFLAGS=-nostdlib -fno-builtin -fno-stack-protector -ffreestanding -m32
LDFLAGS=-melf_i386 -Tlink.ld
其中
link.ld
是我上面包含的脚本。我的问题是,我在上面做错了什么让 grub 相信内核可以放入内存?我努力了:
这些事情都没有奏效。我有一种感觉,我错过了一些很明显的东西,但无法弄清楚它是什么。
更新:查看 grub multiboot elf 行,这是我看到的:
[Multiboot-elf, <0xffc00:0x40c:0x0>
至关重要的是,我相信我应该看到类似于 this question 中的行,即它应该有一个
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,所以这应该加载......但我仍然收到关于所选项目不适合内存的投诉。
最佳答案
在 grub 0.97 source code 中,此错误消息来自 stage2/common.c:89
[ERR_WONT_FIT] = "Selected item cannot fit into memory",
这段代码被使用了十几次:
stage2/char_io.c:1215: errnum = ERR_WONT_FIT;
stage2/boot.c:276: errnum = ERR_WONT_FIT;
stage2/boot.c:280: errnum = ERR_WONT_FIT;
stage2/shared.h:540: ERR_WONT_FIT,
stage2/builtins.c:1822: errnum = ERR_WONT_FIT;
stage2/builtins.c:2386: errnum = ERR_WONT_FIT;
stage2/builtins.c:2498: errnum = ERR_WONT_FIT;
stage2/builtins.c:2594: errnum = ERR_WONT_FIT;
stage2/builtins.c:2932: errnum = ERR_WONT_FIT;
stage2/builtins.c:3711: errnum = ERR_WONT_FIT;
stage2/builtins.c:3744: errnum = ERR_WONT_FIT;
既然你在启动时有这个消息,让我们更深入地看看 boot.c
if (! big_linux
&& text_len > linux_data_real_addr - (char *) LINUX_ZIMAGE_ADDR)
{
grub_printf (" linux 'zImage' kernel too big, try 'make bzImage'\n");
errnum = ERR_WONT_FIT;
}
else if (linux_data_real_addr + LINUX_SETUP_MOVE_SIZE
> RAW_ADDR ((char *) (mbi.mem_lower << 10)))
errnum = ERR_WONT_FIT;
由于您没有 grub_printf 消息,因此您可能处于以下情况:
linux_data_real_addr + LINUX_SETUP_MOVE_SIZE > RAW_ADDR ((char *) (mbi.mem_lower << 10))
=> 也许您的问题与您的 3 GB 目标有关。您可以尝试使其与 1GB 内存一起工作。计算机科学已经发现文件或内存 > 2GB 和 32 位 CPU 的许多问题。
您找到它的另一个机会在于 stage2/char_io.c:1215
if ((addr < RAW_ADDR (0x1000))
|| (addr < RAW_ADDR (0x100000)
&& RAW_ADDR (mbi.mem_lower * 1024) < (addr + len))
|| (addr >= RAW_ADDR (0x100000)
&& RAW_ADDR (mbi.mem_upper * 1024) < ((addr - 0x100000) + len)))
errnum = ERR_WONT_FIT;
您在 0x00100000 处的起始地址可能会触发此条件。
关于assembly - Grub 错误 28 : selected item cannot fit into memory when writing higher half kernel,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/17223834/