引导加载程序未加载第二个扇区

明星操作系统

我在汇编中编写了一个引导程序。下面是它的工作原理:

  1. 首先,BIOS正常加载引导加载程序。指示去200h。

  2. 在200h,一些代码位于200h和21Eh之间。它只需切换到VGA模式,即可使用VGA功能在坐标1,1上绘制洋红色像素。它将永远循环该代码。

但是,当我加载它时,它只是在闪烁的光标上前进,而普通的VGA .bin文件则不会,并且会显示一个像素。我检查了一个像素,但什么也没看见。我所看到的意思是VGA代码未运行,并且引导加载程序仅被加载,仅此而已。

引导加载程序的代码:

 cli
 startload:
 push 0x00000200
 ret

 times 510-($-$$) db 0
 db 0x55
 db 0xAA

您可以看到它只是转到下一个扇区(从200h开始),而代码在200h-21Eh:

BITS 16
org 200h
data:
xcoord DB '1'
ycoord DB '1'
color DB 'D'
.code:
vga:
mov ax, 13h
int 10h
mov ax, ycoord
mov bx, xcoord
mov cx, 320
mul cx
add ax, bx
mov di, ax
mov dl, color
mov [es:di],dl
jmp vga

(是的,我确实知道这不是230h字节,这是编译输出的大小,即230h。)

问题是什么?注意:这不是在讨论如何使其进入第二部门。它在问为什么它不去那里。我还没有找到任何解决方案。

迈克尔·佩奇

回答您的问题之一。这段代码:

startload:
push 0x00000200
ret

几乎等同于几乎绝对跳到CS:0x200。我们不知道CS中的值是多少,但是许多BIOS会以CS = 0和IP = 0x7c00开头(但并非总是如此)。除非您自行设置,否则您不能真正依赖CS作为特定值。在大多数情况下,CS可能为零,这意味着您可能会跳转到物理内存地址0x00200(0x0000:0x0200)。这恰好在实模式中断表的中间,该表从物理地址0x00000到0x003FF运行。跳转到该位置可能会导致某种未定义的行为。

您可以将引导加载程序加载到BOCHS中,该BOCHS具有可以理解16位实模式的合理调试器。您将可以单步执行代码并确切确定CS什么以及它跳转到的位置。


您可能要完成的工作可以通过以下代码完成。这是我先前对一个不同问题的Stackoverflow答案的简单更改要了解此代码的功能,请参阅我以前的答案。

简而言之,BIOS从磁盘的物理内存地址0x7C00开始读取单个磁盘扇区(512字节)。如果要加载其他扇区,则必须编写将其加载到内存中的代码,然后在加载后跳转到该代码。

在此示例中,第一阶段是引导加载程序,该加载程序从磁盘的扇区2(紧随引导扇区之后的扇区)加载单个扇区。在此示例中,我将通过segment:offset对0x7e0:0x0000在物理地址0x07e00的第一个扇区之后立即加载第二个扇区(0x07e0 << 4)+ 0x0000 = 0x07e00。

bootload.asm

bits 16
ORG 0x7c00      ; Bootloader starts at physical address 0x07c00

    ; At start bootloader sets DL to boot drive

    ; Since we specified an ORG(offset) of 0x7c00 we should make sure that
    ; Data Segment (DS) is set accordingly. The DS:Offset that would work
    ; in this case is DS=0 . That would map to segment:offset 0x0000:0x7c00
    ; which is physical memory address (0x0000<<4)+0x7c00 . We can't rely on
    ; DS being set to what we expect upon jumping to our code so we set it
    ; explicitly
    xor ax, ax
    mov ds, ax        ; DS=0

    cli               ; Turn off interrupts for SS:SP update
                      ; to avoid a problem with buggy 8088 CPUs
    mov ss, ax        ; SS = 0x0000
    mov sp, 0x7c00    ; SP = 0x7c00
                      ; We'll set the stack starting just below
                      ; where the bootloader is at 0x0:0x7c00. The
                      ; stack can be placed anywhere in usable and
                      ; unused RAM.
    sti               ; Turn interrupts back on

reset:                ; Resets floppy drive

    xor ax,ax         ; AH = 0 = Reset floppy disk
    int 0x13
    jc reset          ; If carry flag was set, try again

    mov ax,0x07e0     ; When we read the sector, we are going to read to
                      ;    address 0x07e0:0x0000 (phys address 0x07e00)
                      ;    right after the bootloader in memory
    mov es,ax         ; Set ES with 0x07e0
    xor bx,bx         ; Offset to read sector to
floppy:
    mov ah,0x2        ; 2 = Read floppy
    mov al,0x1        ; Reading one sector
    mov ch,0x0        ; Track(Cylinder) 1
    mov cl,0x2        ; Sector 2
    mov dh,0x0        ; Head 1
    int 0x13
    jc floppy         ; If carry flag was set, try again

    jmp 0x07e0:0x0000 ; Jump to 0x7e0:0x0000 setting CS to 0x07e0
                      ;    IP to 0 which is code in second stage
                      ;    (0x07e0<<4)+0x0000 = 0x07e00 physical address

times 510 - ($ - $$) db 0   ; Fill the rest of sector with 0
dw 0xAA55                   ; This is the boot signature

第二阶段将在内存中的引导加载程序之后立即由INT 13h / AH = 2h加载,从物理地址0x07e00开始。

stage2.asm

BITS 16

; ORG needs to be set to the offset of the far jump used to
; reach us. Jump was 0x7e0:0x0000 so ORG = Offset = 0x0000.
ORG 0x0000

main:
    ; Set DS = CS
    mov ax, cs
    mov ds, ax

    ; Set to graphics mode 0x13 (320x200x256)
    mov ax, 13h
    int 10h

    ; Set ES to the VGA video segment at 0xA000
    mov ax, 0xa000
    mov es, ax

vga:
    ; Draw pixel in middle of screen
    mov ax, [ycoord]
    mov bx, [xcoord]
    mov cx, 320
    mul cx
    add ax, bx
    mov di, ax
    mov dl, [color]
    mov [es:di],dl

    ; Put processor in an endless loop
    cli
.endloop:
    hlt
    jmp .endloop

; Put Data after the code
xcoord DW 160
ycoord DW 100
color  DB 0x0D    ; One of the magenta shades in VGA palette

上面的代码是您的VGA代码的稍有改动的版本,因为您有错误。您的VGA代码未正确将ES设置为0xA000,这是VGA图形内存的开始;它没有正确地取消引用变量(您使用的是地址而不是值);坐标的大小是BYTE而不是WORD带有ASCII字符值的变量中定义的值。我还在代码之后移动了数据。

我修改了代码以在320x200显示屏的中间绘制一个像素,然后无限循环以结束程序。


使用NASM进行组装的Linux上(或在具有Chrysocome DD的Windows上,您可以使用以下命令生成720K引导盘:

dd if=/dev/zero of=disk.img bs=1024 count=720
nasm -f bin bootload.asm -o bootload.bin
dd if=bootload.bin of=disk.img conv=notrunc

nasm -f bin stage2.asm -o stage2.bin    
dd if=stage2.bin of=disk.img bs=512 seek=1 conv=notrunc

这将bootload.bin构建并放置到磁盘映像的第一个扇区中,然后将stage2.bin构建并放置在磁盘映像的扇区2中。磁盘映像称为disk.img

您应该可以使用QEMU进行如下测试

qemu-system-i386 -fda disk.img

关于DD使用的更多信息,可以在我的其他Stackoverflow答案之一中找到巧合的是,该答案是您去年提出的一个问题。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

启用休眠第二个缓存时,@ ManyToOne无法延迟加载

如何等待第二个窗口完全加载

引导程序4:从标签页中打开标签页(第二个链接)

安装我的应用程序后,如何检查第二个dex是否已完成加载?

在一个jsp页面中,单击按钮,将第二个jsp页面作为模态加载到引导程序中

启用引导加载程序以加载USB的第二个扇区

根据Codeigniter中第一个选择器的用户输入动态加载第二个引导选择器

不清楚为什么我的第二个application.yml未加载

为什么我的引导程序没有将第二个扇区加载到内存中?

在安装第二个Linux操作系统时,在哪里安装引导加载程序?

SpriteKit:纹理图集不会加载到第二个目标上

单击按钮将第二个UIViewController加载到容器中

加载第二个shell / bin / bash后无法执行?

在segue中加载第二个应用程序界面

无法将第二个模板加载到我的Django项目中

在下一页加载之前创建第二个CSS过渡

第二个引导程序Jasny Offcanvas推菜单

无法加载第二个控制器

React Redux mapStateToProps在第二个调用中加载数据

在选择第一个引导程序选择时更新第二个引导程序选择的值

Electron webContents executeJavaScript:无法在第二个加载URL上执行脚本

为第二个 RecyclerView 加载更多内容 - android

移动引导加载程序或删除第二个驱动器中的 efi 分区

第二个 UICollectionView 没有重新加载

用于加载第二个活动的 android 应用程序存在 mainactivity.java 文件问题

如何根据第一个 DropdownButton 的选择加载第二个 DropdownButton

Javascript:测验程序:不加载第二个问题

每次加载第二个数组时图表更新:Highcharts,Javascript

Vue.js 第二个单选按钮在应用加载时被选中