在我的引导加载程序的第二阶段,我正在尝试将虚拟软盘中的某些扇区加载到bochs的内存中,但是在调用int 0x13
时,例程就不会返回。
我相信我的第二阶段的相关代码是:
bootsys_start:
mov %cs, %ax
mov %ax, %ds
/*
* Remap IRQs. Interrupts have been disabled in the
* bootloader already.
*/
mov i8259A_ICW1($i8259A_IC4), %al
out %al, i8259A_ICW1_ADDR($i8259A_MASTER)
out %al, i8259A_ICW1_ADDR($i8259A_SLAVE)
mov i8259A_ICW2($USER_INT_START), %al
out %al, i8259A_ICW2_ADDR($i8259A_MASTER)
mov i8259A_ICW2($USER_INT_START + 8), %al
out %al, i8259A_ICW2_ADDR($i8259A_SLAVE)
mov i8259A_ICW3($0x4), %al
out %al, i8259A_ICW3_ADDR($i8259A_MASTER)
mov i8259A_ICW3($0x2), %al
out %al, i8259A_ICW3_ADDR($i8259A_SLAVE)
mov i8259A_ICW4($i8259A_uPM & i8259A_x86), %al
out %al, i8259A_ICW4_ADDR($i8259A_MASTER)
out %al, i8259A_ICW4_ADDR($i8259A_SLAVE)
call mm_detect
/* Load the kernel now. */
xor %bp, %bp
1:
mov $KERNEL_ORG >> 0x4, %ax
mov %ax, %es
mov $KERNEL_ORG & 0xf, %bx
mov $0x200 | KERNEL_SECTORS, %ax
mov $(KERNEL_C << 0x8) | KERNEL_S, %cx
mov $(KERNEL_H << 0x8) | FLOPPY_DRV, %dx
int $0x13 /* <--- This int 0x13 doesn't seem to return */
jnc 1f
cmp $0x2, %bp
je floppy_err
inc %bp
xor %ah, %ah
int $0x13
jmp 1b
所有代码都可以在我的Github repository中找到。要构建只使用make all
,然后使用命令bochs
我做的第一件事就是验证我的所有参数都是正确的。 bochs'壳中产生r
:
CPU0:
rax: 00000000_534d0201 rcx: 00000000_00000005
rdx: 00000000_534d0000 rbx: 00000000_00000000
rsp: 00000000_00007700 rbp: 00000000_00000000
rsi: 00000000_000e0005 rdi: 00000000_00000316
r8 : 00000000_00000000 r9 : 00000000_00000000
r10: 00000000_00000000 r11: 00000000_00000000
r12: 00000000_00000000 r13: 00000000_00000000
r14: 00000000_00000000 r15: 00000000_00000000
rip: 00000000_00000036
eflags 0x00007046: id vip vif ac vm rf NT IOPL=3 of df if tf sf ZF af PF cf
ah = 0x2
(例程ID),al = 0x1
(扇区数),ch = 0x0
(柱面编号的低字节),cl = 0x5
(扇区号和高两位气缸编号),dh = 0x0
(头编号),dl = 0x0
(驱动器编号)。
sreg
打印es
:
es:0x0000
和bx = 0x0
,因此扇区加载到0x0:0x0
,就像我想要的那样。
我尝试了几件事:
加载到实际地址0x600
我认为在执行BIOS中断例程时可能无法覆盖IVT或BDA,所以我尝试将扇区加载到0x600
(es = 0x60
,bx = 0x0
)(我知道BDA的大小只有256字节)。同样的结果。
在磁盘上加载第一个扇区
也许阅读第五部门不知何故不受限制?使用int 0x13
读取我的第二阶段的代码按预期工作。我的第二阶段的int 0x13
是类似的,所以我希望它可以工作。作为测试,我改变了我的第二阶段以阅读第1部分,但它仍然无效。
将eax
我想可能BIOS例程中确实存在错误,并且使用eax
而不是ax
。eax
。我尝试将int 0x13
的高16位部分归零......但无济于事。
正如我之前所说,我已经将一些扇区从磁盘加载到内存中。 GPR r
之前的内容如下(使用bochs shell中的CPU0:
rax: 00000000_00000203 rcx: 00000000_00090002
rdx: 00000000_00000000 rbx: 00000000_00000000
rsp: 00000000_00007700 rbp: 00000000_00000000
rsi: 00000000_000e7cdd rdi: 00000000_000000e2
r8 : 00000000_00000000 r9 : 00000000_00000000
r10: 00000000_00000000 r11: 00000000_00000000
r12: 00000000_00000000 r13: 00000000_00000000
r14: 00000000_00000000 r15: 00000000_00000000
rip: 00000000_00007c59
eflags 0x00007046: id vip vif ac vm rf NT IOPL=3 of df if tf sf ZF af PF cf
获得):
sreg
es:0x8f60
产生doSomethingOne(): Observalbe<any> {
Geolocation.getCurrentPosition().then((resp) => {
return new Promise(resolve => {
return this.http.get('http://xxxxxxxxx.xxxx/api/' + resp.coords.latitude + '/' + resp.coords.longitude + '/5')
.map(res => res.json())
.subscribe(data => {
this.data = data;
return resolve(this.data);
});
});
}).catch((error) => {
console.log('Error getting location', error);
});
}
,这是EBDA之前的动态计算地址。
比较两者,我没有看到可能影响中断例程功能的显着差异,因此问题不能是通过寄存器传递的参数。
是否有人对如何做有其他建议?我有点迷失在这里......
答案 0 :(得分:6)
您的Int 13h/AH=02h软盘读取代码有几个问题:
您已在问题中找到的这个。当您在实模式下运行时,读取0x0000:0x0000之上的扇区是一个坏主意。这将破坏中断向量表(IVT)。从0x0000:0x0000到0x0040:0x0000的区域是IVT;区域0x0040:0x0000到0x0060:0x0000是BIOS Data Area(BDA)。应将BDA视为实模式BIOS例程可能使用的临时区域。
要将其加载到安全的地方,如0x0060:0x0000(物理地址0x00600)。
一旦进入保护模式,可以回收0x00000000和0x00000600之间的区域用于其他用途。 注意:不要将Extended BIOS Data Area(EBDA)内存区域用作通用内存,因为System Management Mode(SMM)和Advanced Configuration and Power Interface(ACPI)可能会写入内存区域。
您的代码重新映射8259A以准备保护模式。在这样做时,IRQ被重新映射到IVT的不同部分。 Int 13h 例程可能依赖于中断来触发和BIOS中断例程来执行软盘读取所需的工作。可以使用IRQ0(系统定时器)和IRQ6(软盘控制器)。如果将8259As的基址重新映射到其他位置,则BIOS将安装的中断例程将无法执行。这可能会导致意外行为,包括 Int 13h 永远不会返回。
要解决此问题,我建议您在保护模式下重新映射8259A PIC的基础。到那时你可能已经完成了BIOS中断,所以它不应该是一个问题。