1

我正在用实模式 ASM 编写一个简单的操作系统,以获得它的乐趣。我最近决定转向文件系统。我组装了代码

nasm -f bin -o boot.o boot.asm
nasm -f bin -o kernel.o kernel.asm
nasm -f bin -o fs.o fs.asm

dd if=boot.o bs=512 of=os.img
dd if=kernel.o bs=512 of=os.img seek=1
dd if=fs.o bs=512 of=os.img seek=2

在我的引导加载程序中,我将文件系统加载到地址 0x1000:0000,将内核加载到 0x2000:0000。每个都是 512 字节(到目前为止)相当小。因此,为了测试我的新文件系统,我编写了内核来打印表中第一个文件名的第一个字母。它将值 0x2000 放入 si 中,将 si 中地址处的字节移动到 al 中。然后它将 0x0e 传递给 ah 并调用 int 0x10。然后它停止。但是,当我将操作系统引导到 qemu 时,它只是向我显示 BIOS 信息,说从软盘引导,然后什么也不做。没有信。没有什么。以下是相关代码:

相关引导加载程序代码

    ;;the part that loads the file system.
    ;;The part for the kernel is identical, except that cl is 02 and bx is 0x2000
    mov ah, 02
    mov al, 01
    mov ch, 00
    mov cl, 03
    mov dh, 00
    mov dl, 00
    mov bx, 0x1000
    mov es, bx
    xor bx, bx
    int 0x13
    ;;jumps to address 0x2000 (where the kernel is)
    mov ax, 0x2000
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov ss, ax
    xor ax, ax
    jmp 0x2000
    ;;halts
    hlt

相关内核代码

    ;;gets address
    mov si, 0x1000
    ;;loads al
    mov al, [si]
    ;;prints
    mov ah, 0x0e
    int 0x10
    ;;halts
    hlt

相关文件系统代码

    ;;declares first file (it is hard coded for testing purposes)
    ;;format: [name], [sector number], [number of sectors to load]
    db 'file.bin', 4, 1

如果我在发布此内容时做错了什么,请原谅我,因为这是我的第一篇文章。

4

2 回答 2

0

您已将 fs 加载到 1000h:0。在跳转到你的内核之前,你用 2000h 加载 segregs。到目前为止,一切都很好。但是mov al, si得到 2000h:1000h。尝试类似:

push ds ; save kernel ds
push 1000h
pop ds ; set ds to filesystem's segment
mov si, 0
mov al, [si]
pop ds ; get kernel's segment back
; now print it...

我认为这应该有效 - 未经测试!啊,分段记忆的乐趣!快乐开机!

于 2013-09-05T00:47:43.183 回答
0

您的代码中有几个问题。

  1. 您正在将文件系统加载到 address 0x1000:0000。转换为线性地址(这是最重要的形式),它是0x1000064KiB。
  2. 您正在将内核加载到地址0x2000:00000x20000,128KiB)上。你正在做的跳跃

    jmp 0x2000
    

    是IP相对跳转,所以你没有得到你想要的位置。这个跳转的执行是通过将作为指令参数传递的立即值添加到 IP 寄存器的值来执行的,IP 寄存器(在那个时候)保存下一条指令(你的hlt)的地址。你需要做的是跳远。它跳转到绝对地址。远跳形式如下:

    jmp segment:offset
    

    用这个替换你的跳转:

    jmp 0x2000:0000
    
  3. 应该打印字符的内核代码使用SI寄存器使用段相对寻址,因为您正在实模式下执行代码。与 IP 相对跳转不同,您不能将有符号值作为偏移量传递(尽管它很酷,有时也很有用)。更改DS段的值,或使用段覆盖使一切更快。在您的情况下,我建议fs对所有文件系统操作使用段,因此不需要保存和恢复ds.

    mov ax, 0x1000
    mov fs, ax
    xor si, si
    mov al, byte [fs:si] ;or simply [fs:si] without byte
    

    请记住,这是除用法ds之外的所有寻址的默认段。BP您应该将它用于内核的主要目的(它会节省一些字节,而且肯定会更快)。esfsgs在这里为您进行其他内存操作。您可以es用于处理目标、fs文件系统和gs视频内存指向。一切都取决于你。

请注意,某些指令 ( movs, cmps, scas...) 具有预先分配的寄存器和段组合(有时只能覆盖其中一个),因此在选择它们时要明智,在使用它们时要注意。

于 2013-09-05T13:56:57.993 回答