2

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

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

4

1 回答 1

1

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

预编译/预链接 user.bin 后,尝试以下方法之一添加 grub 条目以加载它:

  1. 设置 root=(cd0) (如果您在 ISO 文件中提供 user.bin)并使用该chainloader --force命令将其加载到内存中,而无需尝试验证其签名或对其执行任何“智能”操作;或者
  2. 制作一个自定义 grub 模块来执行此操作,您可以使用insmod; 或者
  3. 通过使用 gdb 将文件加载到内存中来作弊,然后让操作系统知道它在哪个地址被加载:所以 提示通过 gdb 将文件加载到内存中

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

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

于 2021-07-07T08:07:29.750 回答