Operating system 如何从第一阶段加载第二阶段引导加载程序?

Operating system 如何从第一阶段加载第二阶段引导加载程序?,operating-system,bootloader,Operating System,Bootloader,我已经编写了简单的第一阶段引导加载程序,它使用bios中断显示“Hello world”。现在,作为编写第二阶段的下一个明显步骤,应该在哪里存在该阶段的代码,以及如何从第一阶段加载它 这是第一阶段的计划 [BITS 16] ;Tells the assembler that its a 16 bit code [ORG 0x7C00] ;Origin, tell the assembler that where the code will ;be in

我已经编写了简单的第一阶段引导加载程序,它使用bios中断显示“Hello world”。现在,作为编写第二阶段的下一个明显步骤,应该在哪里存在该阶段的代码,以及如何从第一阶段加载它

这是第一阶段的计划

[BITS 16]   ;Tells the assembler that its a 16 bit code
[ORG 0x7C00]    ;Origin, tell the assembler that where the code will
                ;be in memory after it is been loaded

MOV SI, HelloString ;Store string pointer to SI
CALL PrintString    ;Call print string procedure
JMP $       ;Infinite loop, hang it here.


PrintCharacter: ;Procedure to print character on screen
    ;Assume that ASCII value is in register AL
MOV AH, 0x0E    ;Tell BIOS that we need to print one charater on screen.
MOV BH, 0x00    ;Page no.
MOV BL, 0x07    ;Text attribute 0x07 is lightgrey font on black background

INT 0x10    ;Call video interrupt
RET     ;Return to calling procedure



PrintString:    ;Procedure to print string on screen
    ;Assume that string starting pointer is in register SI

next_character: ;Lable to fetch next character from string
MOV AL, [SI]    ;Get a byte from string and store in AL register
INC SI      ;Increment SI pointer
OR AL, AL   ;Check if value in AL is zero (end of string)
JZ exit_function ;If end then return
CALL PrintCharacter ;Else print the character which is in AL register
JMP next_character  ;Fetch next character from string
exit_function:  ;End label
RET     ;Return from procedure


;Data
HelloString db 'Hello World', 0 ;HelloWorld string ending with 0

TIMES 510 - ($ - $$) db 0   ;Fill the rest of sector with 0
DW 0xAA55           ;Add boot signature at the end of bootloader

在x86上,您将执行以下操作(简化):

  • 让引导加载程序将磁盘/软盘的第n个扇区(无论从何处引导)加载到内存中并执行它(即加载段/偏移量和do
    retf
    )。更好的替代方法是搜索文件系统中的某个文件名(例如KERNEL.BIN)——但您需要知道文件系统类型(例如,如果您是从软盘映像进行测试,则需要知道FAT12)
  • 然后内核将以实模式启动。它设置代码描述符、GDT等,激活32位寻址(您应该听说过“A20”),最后进入保护模式。然后需要跳转到32位代码段(内核文件必须以32位代码处于绝对位置的方式链接在一起,例如偏移量512,正好在16位实模式之后)
  • 然后,32位内核程序集只定义
    EXTERN\u mykernel
    (例如)并调用该符号
  • 然后,您可以开始将内核编写为C函数
    mykernel
好的,这是我几年前做的一个简短概述(从互联网上复制粘贴了大量内容)。如果这没有帮助,下面是一些关于操作系统开发的优秀web资源:

  • (wiki有许多业余操作系统开发人员,仅限德语…)

希望这有助于^ ^

了解GRUB的实现(第1阶段):

首先注意到第一个扇区的起点为0x7c00,结束签名为0xaa55。从拆解中,您可以看到:


从本质上讲,逻辑是将阶段2代码复制到内存的另一部分,然后直接跳到那里,即“引导阶段2”。换句话说,“boot stage1”在将扇区加载到内存后从BIOS有效触发,而stage2是您跳转到那里的地方-它可以在任何地方。

加载stage 2并跳转到它的最小可运行NASM BIOS示例

use16
org 0x7C00

    ; You should do further initializations here
    ; like setup the stack and segment registers.

    ; Load stage 2 to memory.
    mov ah, 0x02
    ; Number of sectors to read.
    mov al, 1
    ; This may not be necessary as many BIOS set it up as an initial state.
    mov dl, 0x80
    ; Cylinder number.
    mov ch, 0
    ; Head number.
    mov dh, 0
    ; Starting sector number. 2 because 1 was already loaded.
    mov cl, 2
    ; Where to load to.
    mov bx, stage2
    int 0x13

    jmp stage2

    ; Magic bytes.    
    times ((0x200 - 2) - ($ - $$)) db 0x00
    dw 0xAA55

stage2:

    ; Print 'a'.
    mov ax, 0x0E61
    int 0x10

    cli
    hlt

    ; Pad image to multiple of 512 bytes.
    times ((0x400) - ($ - $$)) db 0x00
编译并运行:

nasm -f bin -o main.img main.asm
qemu-system-i386 main.img
预期结果:
a
被打印到屏幕上,然后程序停止

在Ubuntu 14.04上测试


Saner GAS示例使用链接器脚本和更正确的初始化(段寄存器、堆栈)。

您使用的是C语言吗?您还可以分享其他重要信息吗?我们在第一阶段使用汇编x86指令,但我们计划用更高级的语言(如c)编写第二阶段。。我在哪里存储第二阶段二进制文件,以及如何从第一阶段引导加载程序加载第二阶段二进制文件汇编程序如何知道从磁盘加载的代码的所有标签现在都被加载到RAM的位置所偏移?如果有人能猜出为什么会进行下载,请这样做,我可以了解并改进信息。我从不报复。啊,我正在查看
bootloader
标记活动列表,我看到我们又见面了。我要说的一点是,我可能会把这个问题说得过于宽泛。尽管您提供了一个解决方案,但您断言OP将仅从MBR之后的下一个扇区加载。虽然这是一个解决方案,但我认为在讨论其他想法(如为文件系统执行文件查找)时,向上投票的方案更接近目标。这个答案假设了很多东西——是否有包含第二阶段的文件系统?它是什么文件系统?等等,@MichaelPetch嘿,又来了:-)同意这是个好答案。只是我通常喜欢先运行一些东西来看看它的美妙之处:这样以后更容易理解更深的部分。你应该确保ES寄存器为零,因为Int13h/AH=2h用于缓冲地址。我可能还会利用这个机会使用JMP stage2将CS设置为零,因此我会执行
JMP 0x0000:stage2
。我认为,为了完整性,当您处于阶段2时,您应该让他们确保DS也为零,因为任何依赖DS作为特定值的代码在BIOS可能已将DS设置为其他值的环境中可能无法正常工作。此外,我不建议您将DL设置为固定驱动器号。当传输被控制到引导加载程序时,您应该只使用从BIOS传入的。
nasm -f bin -o main.img main.asm
qemu-system-i386 main.img