在这种情况下如何使用 grub 加载 userland?

How to load userland with grub in this case?

我通过教程学习用户模式。 在教程中,他们通过以下代码构建内核映像:

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 加载 userland?或者我需要在内核中写一些代码来加载用户进程?

github link: https://github.com/JustVic/kernel_usermode

grub 旨在让您的 OS 加载,然后 OS 应该执行执行 user.bin 的繁重工作。我相信您的 OS 为一个进程 (init_process/set_process_entry) 设置了一个插槽,设置了它的堆栈和页面映射,然后将使用 launch() 启动 user.bin。我在你的 github 中没有看到很多很棒的设备驱动程序 :-@),所以我认为你需要让 grub 通过一种可用的加载文件的方法来为你加载你的 user.bin 和然后获取传送给 launch() 的加载地址。实际上,您需要相当于 Linux 的 /sbin/init 所有预编译、预链接并加载到物理内存中,这样您就可以直接启动它。

一旦您 precompiled/prelinked 您的 user.bin,请尝试使用以下方法之一添加 grub 条目以加载它:

  1. set root=(cd0)(如果您在 ISO 文件中提供 user.bin)并使用 chainloader --force 命令将其加载到内存中,而不尝试验证其签名或做任何事情否则“聪明”;或
  2. 制作一个自定义的 grub 模块来执行此操作,您可以使用 insmod 调用它;或
  3. 通过使用 gdb 将文件加载到内存中作弊,然后让 OS 知道它加载的地址:SO tip to load file into memory via gdb.

一旦你的 OS 中有了更多的设备和 process/thread 支持,你就可以通过在内核命令行上传递 init=/etc/user.bin 之类的内容来以“正常”方式执行此操作内核可以映射并执行它。即使是一个愚蠢的调度程序也支持多个进程会很棒,因为那时你实际上可以让 OS 继续运行而不是执行到 user.bin 并有点结束。

我能找到的最好的教程是 here。幸运的是,其中有一个很好的部分是关于为这类事情制作一个 grub 模块。