加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > Linux > 正文

Linux x86 bootloader

发布时间:2020-12-14 02:13:13 所属栏目:Linux 来源:网络整理
导读:我试图在nasm中构建一个简单的x86 Linux引导程序. Linux bzImage从第一个扇区开始存储在磁盘分区sda1上. 我从bzImage(15个扇区)读取实际模式代码到0x7E00开始的内存中. 但是,当我跳入代码时,它只是挂起,没有任何反应. 我已经在sda上为主启动记录创建了代码.
我试图在nasm中构建一个简单的x86 Linux引导程序.

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     start
start:
    ; 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 halt
bad:
    mov     al,"B"
    call    putc
    jmp     halt

; Param: char in al 
putc:
    mov     ah,0X0E    
    mov     bh,0x0F
    xor     bl,bl  
    int     0x10
    ret

halt:
    hlt
    jmp     halt

; Begin data section
dap:                ; 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 section

times 446-($-$$) db 0   ; Padding to make the MBR 512 bytes

; Hardcoded partition entries
part_boot:
    dw 0x0180,0x0001,0xFE83,0x3c3f,0x003F,0x0000,0xF3BE,0x000E
part_sda2:
    dw 0x0000,0x3D01,0xFFFF,0xF3FD,0x000E,0x5AF0,0x01B3
part_sda3:
    dw 0xFE00,0x4EED,0x01C2,0xb113,0x001D
part_sda4:
    dw 0x0000,0x0000

dw 0xAA55   ; Magic number at relative address 510
mbrend:     ; 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单步执行看看正在执行什么,等等.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读