我正在以实模式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
在我的bootloader中,我将文件系统加载到地址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
如果我在发帖时做了些什么,请原谅我,因为这是我的第一篇文章。
答案 0 :(得分: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...
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...
我认为应该有用 - 未经测试!啊,分段记忆的乐趣!快乐的靴子'!
答案 1 :(得分:0)
您的代码中存在多个问题。
0x1000:0000
上加载文件系统。转换为线性地址(这是最重要的形式),它是0x10000
,或简称为64KiB。 您正在地址0x2000:0000
(0x20000
,128KiB)上加载内核。
你正在做的跳跃
jmp 0x2000
是IP相对跳跃,因此您无法获得所需的位置。执行此跳转是通过将作为指令参数传递的立即值添加到IP寄存器的值来执行的,该寄存器保存(在该时间)下一条指令的地址(您的hlt
)。你需要做的就是跳远。它跳转到绝对地址。跳远的形式如下:
jmp segment:offset
用这个替换你的跳跃:
jmp 0x2000:0000
应该打印字符的内核代码使用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
用法之外的所有寻址的默认段。你应该将它用于内核的主要目的(它将节省一些字节,并且它肯定会更快)。 es
,fs
和gs
可供您进行其他内存操作。您可以使用es
处理目标,fs
表示文件系统,gs
表示视频内存。一切都取决于你。
请注意,某些说明(movs
,cmps
,scas
...)具有预先指定的寄存器和段组合(有时只能覆盖其中一个),因此在选择它们时要明智,在使用它们时要注意。