linux bzImage从第一个扇区开始存储在磁盘分区sda1上.
我从bzImage(15个扇区)读取实际模式代码到0x7E00开始的内存中.
但是,当我跳入代码时,它只是挂起,没有任何反应.
我已经在sda上为主启动记录创建了代码.如果我只是附上,我可能是最好的
整个东西.我想知道为什么它只是在跳远指令后挂起.
[BITS 16]%define BOOTSEG 0x7C0 %define BOOTADDR (BOOTSEG * 0x10)%define HDRSEG (BOOTSEG + 0x20)%define HDRADDR (HDRSEG * 0x10)%define KERNSEG (HDRSEG + 0x20)[ORG BOOTADDR]entry_section: cli jmp startstart: ; Clear segments xor ax,ax mov ds,ax mov es,ax mov gs,ax mov fs,ax mov ss,ax mov sp,BOOTADDR ; Lots of room for it to grow down from here ; Read all 15 sectors of realmode code in the kernel mov ah,0x42 mov si,dap mov dl,0x80 int 0x13 jc bad ; Test magic number of kernel header mov eax,DWord [HDRADDR + 0x202] cmp eax,'HdrS' jne bad ; Test jump instruction is there mov al,byte [KERNSEG * 16] cmp al,0xEB jne bad xor ax,ax ; Kernel entry code will set ds = ax xor bx,bx ; Will also set ss = dx jmp DWord KERNSEG:0; Simple function to report an error and haltbad: mov al,"B" call putc jmp halt; Param: char in al putc: mov ah,0X0E mov bh,0x0F xor bl,bl int 0x10 rethalt: hlt jmp halt; Begin data sectiondap: ; disk address packet db 0x10 ; Size of dap in bytes db 0 ; Unused DW 15 ; Number of sectors to read DW 0 ; Offset where to place data DW HDRSEG ; Segment where to place data dd 0x3F ; Low order of start addres in sectors dd 0 ; High order of start address in sectors; End data sectiontimes 446-($-$$) db 0 ; padding to make the MBR 512 bytes; Hardcoded partition entrIEspart_boot: DW 0x0180,0x0001,0xFE83,0x3c3f,0x003F,0x0000,0xF3BE,0x000Epart_sda2: DW 0x0000,0x3D01,0xFFFF,0xF3FD,0x000E,0x5AF0,0x01B3part_sda3: DW 0xFE00,0x4EED,0x01C2,0xb113,0x001Dpart_sda4: DW 0x0000,0x0000DW 0xAA55 ; Magic number at relative address 510mbrend: ; relative address 512解决方法 假设您的代码是引导加载程序(因此不是MBR):
>除非必须,否则永远不要禁用IRQ. BIOS需要它们才能正常工作,并且无论如何都会在某些BIOS功能中启用它们(例如,在磁盘功能中等待“扇区传输”IRQ).因为您的代码只是加载并将控制传递给更多实模式代码(例如,并且没有切换到保护模式或涉及任何内容),您没有理由在整个引导加载程序中的任何位置禁用IRQ.
>对于实模式寻址,它通常更清晰/更容易使用0x0000:0x7C00而不是0x07C0:0x0000.您似乎试图混合两者(例如,为前者设置段寄存器,但为后者定义BOOTSEG和HDRSEG).
>分区表包含“扩展分区”而不是“主分区”,因此您的分区表是错误的(并且应该是空白/空的).
>引导加载程序不应假设任何特定/硬编码的“起始LBA”(分区的“起始LBA”取决于最终用户在安装 *** 作系统时如何分区磁盘).您需要从MBR的主分区表中确定分区的“起始LBA”,这通常是希望MBR离开DS:SI指向分区的分区表条目.
>您不应该假设您从“BIOS设备0x80”启动. MBR应该将DL设置为正确的设备编号,并且如果(例如) *** 作系统安装在第二个硬盘驱动器上,则应该没有理由说明您的代码不起作用.
>你的硬编码“开始LBA阅读”(在DAP中)是错误的.由于历史原因,每个轨道可能有63个扇区,而您的分区从第64个扇区开始.这意味着LBA扇区0x3F是分区中的第一个扇区(它是您的引导加载程序),并不是内核的第一个扇区.我假设内核的第一个扇区可能是LBA扇区0x40(分区的第二个扇区).
>“扇区数”也不应该是硬编码的.您需要加载内核的开头并检查它,并确定要从中加载的扇区数.
>通常512个字节(实际上更像是446个字节)对于体面的引导加载程序来说太小了.引导加载程序的前512个字节应加载引导加载程序的其余部分(剩下的每个备用字节用于改进错误处理 – 例如puts(“尝试加载引导加载程序时读取错误”)而不仅仅是putc(‘B “)).其他所有内容(加载内核片段,设置视频模式,在“实模式内核头”字段中设置正确的值等)应该在其他扇区中,而不是在第一个扇区中.
请注意,计算机引导的方式经过精心设计,以便任何MBR都可以链接任何磁盘的任何分区上的任何 *** 作系统;并且MBR可以是允许安装多个OS的更大的(例如,引导管理器)的一部分(例如,用户可以使用漂亮的菜单或某些东西来选择MBR的代码应该链加载哪个分区).此设计允许用户随时使用任何其他内容替换MBR(或引导管理器),而不会影响任何已安装的 *** 作系统(或导致所有已安装的 *** 作系统需要修复).举一个简单的例子,用户应该能够拥有12个不同的分区,这些分区都包含你的引导加载程序和一个独立/独立的linux版本,然后安装任何引导管理器(例如GRUB,Plop,GAG,MasterBooter等)想要随时.
对于你的代码挂起的原因,考虑到所有代码都需要重写,这并不是很重要.如果你很好奇,我强烈建议在带有调试器(例如Bochs)的模拟器中运行它,以便你可以准确地检查发生了什么(例如,在0x00007E00转储内存以查看它包含的内容,将JMP单步执行看看正在执行什么,等等.
总结以上是内存溢出为你收集整理的Linux x86 bootloader全部内容,希望文章能够帮你解决Linux x86 bootloader所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)