Memory 汇编中的引导加载程序问题
我有一个有趣的问题,我试图制作一个简单的引导加载程序,可以引导和显示文本。当我进一步研究时,我发现引导加载程序需要为某些东西保留内存。以下是我的问题:Memory 汇编中的引导加载程序问题,memory,assembly,kernel,bootloader,Memory,Assembly,Kernel,Bootloader,我有一个有趣的问题,我试图制作一个简单的引导加载程序,可以引导和显示文本。当我进一步研究时,我发现引导加载程序需要为某些东西保留内存。以下是我的问题: 如何为引导加载程序保留内存 为什么需要保留内存 引导加载程序还需要执行哪些其他功能 如何将控制传递给内核 你真的不需要“保留”内存,只需要使用它 实际上,您需要这样做,因为您的内核希望位于可寻址内存的开头。因此,您应该做的第一件事是将引导加载程序(此时可能会从MBR运行)复制到高内存中(远远超过内核所在的位置),然后跳转到它。然后,您需要将内核加
这也可能有助于您了解启动过程的早期阶段:请记住,每台现代PC仍以16位(称为实模式)启动。因此,引导加载程序必须使用16位代码。在加载了内核的第一阶段之后,引导加载程序要做的第一件事就是切换到32位模式(称为保护模式) 首先,您应该熟悉16位PC架构,尤其是其细分模型。您需要了解如何以16位模式编写引导加载程序的第一部分。 接下来,您需要了解i386体系结构(32位模式),以便切换到保护模式并配置段寄存器、分页等 请记住,BIOS代码仅在CPU通过软件中断处于16位模式(实模式)时才可用。一旦切换到受保护模式,就不能再使用它(除非切换回16位模式,这很麻烦)。 有关BIOS中断的一个很好的参考是Ralf Brown的中断列表: 就内核开发而言,James Molloy的内核开发教程是从零开始为x86编写操作系统的一个很好的教程: 他使用GRUB加载内核,这可能是最好的做法,因为GRUB已经将CPU切换到保护模式并为您设置GDT。然后在C中加载一个简单的内核就变得简单多了 如果您决定不使用GRUB,而是自己编写所有内容,那么您必须使用16位代码,使用BIOS中的软件中断来加载内核(请参阅上面的参考资料)。此外,如果希望内核采用ELF格式,则必须编写ELF加载程序。 请记住,BIOS加载的引导扇区的长度正好为512字节。这是非常少的代码(实际上是510字节,因为最后2个字节用于引导签名)。这就是为什么引导扇区会加载没有此大小限制的第二阶段引导器
不管怎样,祝你好运 关于问题1的答案 1) 只要转到项目的链接器文件,就可以执行如下操作 2) 确保将重置向量与向量表一起移动
MEMORY
{
/* ------------------- BOOT LOADER CODE --------------------------------------*/
BOOT_cached(RX) : ORIGIN = 0x08000000, LENGTH = 32K-0x40
BOOT_uncached(RX) : ORIGIN = 0x0C000000, LENGTH = 32K-0x40
/* ------------------- USB INTERFACE -----------------------------------------*/
USB_INTERFACE_cached(RX) : ORIGIN = 0x08007FC0, LENGTH = 0x40
USB_INTERFACE_uncached(RX) : ORIGIN = 0x0C007FC0, LENGTH = 0x40
/* ------------------- APPLICATION CODE ------------------------------------- */
/* APP_cached(RX) : ORIGIN = 0x08008000, LENGTH = 256K-32K */
/* APP_uncached(RX) : ORIGIN = 0x0C008000, LENGTH = 256K-32K */
/* PSRAM_1(!RX) : ORIGIN = 0x1FFFC000, LENGTH = 0x4000 */
/* DSRAM_1_system(!RX) : ORIGIN = 0x20000000, LENGTH = 0x8000 */
/* DSRAM_2_comm(!RX) : ORIGIN = 0x20008000, LENGTH = 0x8000 */
/* SRAM_combined(!RX) : ORIGIN = 0x1FFFC000, LENGTH = 0x14000 */
DSRAM_1_system(!RX) : ORIGIN = 0x2000D000, LENGTH = 0x3000
SRAM_combined(!RX) : ORIGIN = 0x2000D000, LENGTH = 0x3000
}
stack_size = DEFINED(stack_size) ? stack_size : 4096;
no_init_size = 64;
3) 此外,您还可以通过如下检查project output.lst文件来确认向量表是否位于正确的地址
Sections:
Idx Name Size VMA LMA File off Algn
0 .usb_interface 00000024 08007fc0 0c007fc0 0000ffc0 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
1 .text 000050f0 08000000 0c000000 00008000 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
2 Stack 00001000 2000d000 2000d000 00015000 2**0
ALLOC
3 .data 00000050 2000e000 0c0050f0 0000e000 2**2
CONTENTS, ALLOC, LOAD, DATA
4 .bss 000006a8 2000e050 0c005140 0000e050 2**2
ALLOC
5 USB_RAM 00000e00 2000e6f8 2000e6f8 00015000 2**2
感谢您的回答,但我一直遇到的一个问题是,我不知道如何跳转到内存中的某个位置(或复制到内存中的某个位置)。我并不完全精通x86汇编程序,但
jmp xyz
将允许您跳转到地址xyz。要复制内存,您需要逐字将一个字加载到寄存器中,然后将其写入另一个内存地址。似乎还详细介绍了在汇编程序中快速memcpy的实现。事实上,别理我,我刚刚意识到你将用C来做这件事。使用jmp可以跳转到内存中的任意位置,与以前一样,您只需将其包装在\uuu asm\uu
块中即可。内存复制可以用memcpy完成,只需传入内存地址而不是指针,因为它们基本上是一样的。您可能不得不在某个时候开始编写汇编程序,以获得所需的结果。@JAW1025:学习用x86汇编语言编程。在进入引导加载程序/内核编程之前做好这一点。没有这些知识,写这样低级的东西将是难以忍受的。从简单的事情开始。谢谢你的提示,我会更好地学习x86汇编,谢谢你在c语言中的帮助。问题是GRUB规范非常清楚地表明你应该建立自己的GDT。:GDTR'即使段寄存器如上所述设置,“GDTR”可能无效,因此OS映像在设置自己的“GDT”之前不得加载任何段寄存器(即使只是重新加载相同的值!)。同意。但是,您可以在以后的C代码中设置GDT,这将更加方便和可读(前提是您编写了一些调用lgdt指令的asm函数)。请记住,每台现代PC仍然以16位(称为实模式)启动,但并不完全如此。现代PC使用UEFI固件,在启动后立即切换到32或64位模式。(而且开机状态并不是完全真实的模式,它是一种不真实的模式,具有很高的CS基数)。如果配置为使用16位实模式运行传统BIOS引导加载程序,则PC固件可以选择使用16位实模式运行传统BIOS引导加载程序。以及模拟一堆实际上并不存在的硬件。