【问题标题】:FASM bootloader in bochs hlpbochs hlp 中的 FASM 引导加载程序
【发布时间】:2021-11-20 16:29:25
【问题描述】:

我试图在 fasm 程序集上编写自己的引导加载程序,但没有成功。

结果: 预取:EIP 00010000 > CS.limit 0000ffff

代码:

org 0x7C00

mov ax, 0x02

int 0x10

mov si, boot_msg

call printf

mov al, 0x01 ; secror to read
mov bx, 0x7E00 ; dest
mov cx, 0x0002 ; cylinder:sector
mov dl, 0x01 ; floppy
call disk_read

mov ax, 0x7E00
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
jmp 0x7E00:0x0000

include 'disk.asm'
include 'printh.asm'

boot_msg db 'R-OS BOOTLOADER       
              ',\
'KERNEL CHS 0 0 1', 0x00

times 510-$+$$ db 0x00
dw 0xAA55
;;;;;;;;; kernel! ;;;;;;;;;;
org 0x7E00

mov ah, 0x0E
mov al, 'X'
int 0x10
cli hlt

times 4096-512-$+$$ db 0x00

磁盘.asm:

disk_read:
  pusha
  mov si, 0x02
.top:
  mov ah, 0x02
  int 0x13
  jnc .end
  xor ah, ah
  int 0x13
  jnc .top
  jc .err
.end:
  popa
  ret
.msg db 'disk rw err', 0x00
.err:
  popa
  pusha
  mov ah, 0x0E
  mov si, .msg
  jmp .l
.l:
  lodsb
  cmp al, 0x00
  je .end
  int 0x10

printh.asm 只有打印功能。

我不明白,为什么它不起作用。我尝试了很多解决方案的变体,但没有一个在这个列表中工作。

请帮忙

【问题讨论】:

  • 7E00h:0 不是线性地址 07E00h,并且你没有在磁盘读取之前初始化 es
  • jmp .l 在这里没用。 int 0x10 作为disk_read.err 中的最后一条指令意味着执行将失败。 popa 然后 pusha 这里不需要。 jnc 后跟 jc 使第二个无条件。大概您打算使用si 作为重试计数,因为它没用。如果您的磁盘读取错误处理有效,则该函数将在出错时返回给调用者,而不向调用者指示任何错误。
  • cli \ hlt 应该在两行(也许 FASM 是宽容的),然后是无条件的 jmp 回到 hlt,以保持稳健性。 dl = 1 从第二个软盘驱动器读取,如果要从第一个驱动器读取,请使用零。 (或者将dl 保留为由ROM-BIOS 加载程序初始化,以使用您从中加载的相同单元。)设置ss 之后的下一条指令应该是设置sp 的指令。建议在从磁盘读取之前初始化ss:sp,因为之前的堆栈设置可能会与您的扇区读取缓冲区发生冲突。

标签: assembly bootloader boot fasm


【解决方案1】:

要成功使用 BIOS.ReadSectors 函数 02h,您需要设置它的所有参数!您没有初始化ES 段寄存器,也没有在DH 寄存器中指定头号。大概您认为所有寄存器都从零开始,但事实并非如此!引导加载程序接收的唯一寄存器是DL 寄存器,它保存引导驱动器的编号。这将是您需要提供给此函数的数字。

您正在加载偏移地址 0x7E00 处的附加扇区。因为ES=0(假设),这是分段地址0x0000:0x7E00。您可以通过多种方式jmp 到此地址,但如果您想使用零偏移量进行此操作,则段部分必须为 0x07E0。这就是分段的工作原理。

您可以在我 (https://stackoverflow.com/questions/34216893/disk-read-error-while-loading-sectors-into-memory/34382681?r=SearchResults&s=21|9.2814#34382681) 的回答和 Michael Petch 在 (https://stackoverflow.com/questions/32701854/boot-loader-doesnt-jump-to-kernel-code/32705076?r=SearchResults&s=46|10.4269#32705076) 的回答中阅读有关引导加载程序的更多信息。

这是一个改进的版本:

ORG  0x7C00

xor  ax, ax     ; Setup segment registers in accordance with the `ORG 0x7C00`
mov  ds, ax
mov  es, ax
mov  ss, ax
mov  sp, 0x7C00
cld             ; Once at the top of every program

mov  ax, 0x0003
int  0x10

mov  si, boot_msg
call printf

mov  al, 1      ; Number of sectors to read
mov  bx, 0x7E00 ; ES:BX
mov  cx, 0x0002 ; Cylinder, Sector
mov  dh, 0      ; Head, DL is bootdrive
call disk_read

mov  ax, 0x07E0 ; How segmentation works!
mov  ds, ax
mov  es, ax
jmp  0x07E0:0x0000

include 'disk.asm'
include 'printh.asm'

boot_msg db 'R-OS BOOTLOADER       
              ',\
'KERNEL CHS 0 0 1', 0

times 510-($-$$) db 0
dw 0xAA55
;;;;;;;;; kernel! ;;;;;;;;;;
ORG  0x7E00

mov  bh, 0        ; Don't forget to mention the DisplayPage
mov  ah, 0x0E
mov  al, 'X'
int  0x10

cli
hlt
jmp  $-2

times 4096-512-($-$$) db 0

disk.asm 文件中,您尝试实现重试计数,但如果发生错误,您忘记实际递减计数器。
此外,如果您在此处显示错误消息,这有点致命,因此请停止代码。

又是一个改进的版本:

disk_read:
  pusha
  mov  si, 5     ; Retry count
.top:
  mov  ah, 0x02
  int  0x13
  jnc  .OK
  mov  ah, 0x00
  int  0x13
  dec  si
  jnz  .top      ; More tries
  jmp  .fatal
.OK:
  popa
  ret

.msg db 'disk rw err', 0

.fatal:
  mov  bh, 0        ; Don't forget to mention the DisplayPage
  mov  ah, 0x0E
  mov  si, .msg
  lodsb
.next:
  int  0x10
  lodsb
  cmp  al, 0
  jne  .next

  cli
  hlt
  jmp  $-2

printh.asm 只有打印功能。

包含尽可能多的信息很重要!在我上面改进的代码中,我假设 printf 不会破坏DL 寄存器。 请确保它至少保留DX
如果您将代码包含在 printh.asm 文件中,我已经为您验证了这一点...

【讨论】:

  • 我现在尝试修改代码,但情况并没有改变。 bochs 写“CS.limit”等等。我会尝试在主题中添加图片
  • @VåñøČhêt 请检查 printf 是否保留 DL 寄存器。新代码依赖它。
  • 啊,我明白了。
  • 哇,它正在工作!我的内核打印了 X!非常感谢
  • 好的,非常感谢您的帮助
猜你喜欢
  • 2014-06-09
  • 2023-02-21
  • 2014-10-03
  • 1970-01-01
  • 2021-04-17
  • 1970-01-01
  • 1970-01-01
  • 2016-10-25
  • 2022-01-07
相关资源
最近更新 更多