在这种情况下如何用 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 加载用户空间?的主要内容,如果未能解决你的问题,请参考以下文章

请问在C#的Winform下如何用正则表达式限制用户只能在textBox中输入18位的身份证号码。

unix下如何用ps命令得到进程的路径

Qt中的整数用户输入

arcgis空间连接后没有值

具有共享库支持的 Grub 引导加载程序

CentOS下如何用nmon收集系统实时运行状况