在这种情况下如何用 grub 加载用户空间?
Posted
技术标签:
【中文标题】在这种情况下如何用 grub 加载用户空间?【英文标题】:How to load userland with grub in this case? 【发布时间】:2021-09-15 13:51:22 【问题描述】:我通过教程学习用户模式。 在教程中,他们通过以下代码构建内核映像:
nasm -f bin -o boot.bin boot.asm
nasm -f bin -o loader.bin loader.asm
nasm -f elf64 -o kernel.o kernel.asm
nasm -f elf64 -o trapa.o trap.asm
nasm -f elf64 -o liba.o lib.asm
gcc -std=c99 -mcmodel=large -ffreestanding -fno-stack-protector -mno-red-zone -c main.c
gcc -std=c99 -mcmodel=large -ffreestanding -fno-stack-protector -mno-red-zone -c trap.c
gcc -std=c99 -mcmodel=large -ffreestanding -fno-stack-protector -mno-red-zone -c print.c
gcc -std=c99 -mcmodel=large -ffreestanding -fno-stack-protector -mno-red-zone -c debug.c
gcc -std=c99 -mcmodel=large -ffreestanding -fno-stack-protector -mno-red-zone -c memory.c
gcc -std=c99 -mcmodel=large -ffreestanding -fno-stack-protector -mno-red-zone -c process.c
gcc -std=c99 -mcmodel=large -ffreestanding -fno-stack-protector -mno-red-zone -c syscall.c
ld -nostdlib -T link.lds -o kernel kernel.o main.o trapa.o trap.o liba.o print.o debug.o memory.o process.o syscall.o
objcopy -O binary kernel kernel.bin
dd if=boot.bin of=boot.img bs=512 count=1 conv=notrunc
dd if=loader.bin of=boot.img bs=512 count=5 seek=1 conv=notrunc
dd if=kernel.bin of=boot.img bs=512 count=100 seek=6 conv=notrunc
dd if=user.bin of=boot.img bs=512 count=10 seek=106 conv=notrunc
并通过此代码构建用户空间:
nasm -f elf64 -o start.o start.asm
gcc -std=c99 -mcmodel=large -ffreestanding -fno-stack-protector -mno-red-zone -c main.c
ld -nostdlib -Tlink.lds -o user start.o main.o lib.a
objcopy -O binary user user.bin
他们使用 bochs 和自定义引导加载程序并通过此代码加载内核和用户模式:
LoadKernel:
mov si,ReadPacket
mov word[si],0x10
mov word[si+2],100
mov word[si+4],0
mov word[si+6],0x1000
mov dword[si+8],6
mov dword[si+0xc],0
mov dl,[DriveId]
mov ah,0x42
int 0x13
jc ReadError
LoadUser:
mov si,ReadPacket
mov word[si],0x10
mov word[si+2],10
mov word[si+4],0
mov word[si+6],0x2000
mov dword[si+8],106
mov dword[si+0xc],0
mov dl,[DriveId]
mov ah,0x42
int 0x13
jc ReadError
但我的内核使用 grub。我用 qemu 运行 iso。我也使用gas而不是nasm。
从我的 Makefile 制作 iso(就像在 osdev 教程中一样):
...
$(ISO_FILE): kernel
mkdir -p iso/boot/grub
cp grub.cfg iso/boot/grub/
cp kernel/kernel iso/boot/
$(GRUB_MKRESCUE) -o $(ISO_FILE) iso
如何使用 grub 加载用户空间?或者我需要在内核中编写一些代码来加载用户进程?
github链接:https://github.com/JustVic/kernel_usermode
【问题讨论】:
【参考方案1】:grub 旨在让您的操作系统加载,然后操作系统应该完成执行 user.bin 的繁重工作。我相信您的操作系统为一个进程(init_process/set_process_entry)设置了一个插槽,设置了它的堆栈和页面映射,然后使用 launch() 启动 user.bin。我在你的 github 中没有看到很多很棒的设备驱动程序:-@),所以我认为你需要让 grub 通过加载文件的可用方法之一为你加载你的 user.bin,然后获取通信的加载地址推出()。实际上,您需要与 Linux 的 /sbin/init
等效,所有这些都已预编译、预链接并加载到物理内存中,这样您就可以 pstart 它。
一旦您预编译/预链接了您的 user.bin,请尝试以下方法之一添加 grub 条目以加载它:
-
设置 root=(cd0)(如果您在 ISO 文件中提供 user.bin)并使用
chainloader --force
命令将其加载到内存中,而无需尝试验证其签名或对其执行任何“智能”操作;或
制作一个自定义 grub 模块来执行此操作,您可以使用 insmod
调用该模块;或
作弊方法是使用 gdb 将文件加载到内存中,然后让操作系统知道它是在哪个地址加载的:SO tip to load file into memory via gdb。
一旦你的操作系统有更多的设备和进程/线程支持,你可以通过在内核命令行上传递类似init=/etc/user.bin
这样的“正常”方式来做到这一点,这样内核就可以映射和执行它。即使是一个愚蠢的调度程序也支持多个进程会很棒,因为那时你实际上可以让操作系统继续运行,而不是执行到 user.bin 并在那里结束。
我能找到的最好的教程是here。幸运的是,那里有一个很好的部分关于为这类事情制作一个 grub 模块。
【讨论】:
以上是关于在这种情况下如何用 grub 加载用户空间?的主要内容,如果未能解决你的问题,请参考以下文章