前言
上一期,我们粗略分析了bochs中cpu执行的大体流程,并且修改了代码禁止指令的递归执行。众所周知,在众多指令中通过IO与外设进行交互的指令是in/out指令,我们这篇文章就来大体分析一下in/out指令执行流程。
在第七篇文章中,我们通过floppy外设简单分析了一下IO中断的结构体,我们将它放在这篇文章开头处,可能在分析过程中具有参考价值。

定位到out指令
在上篇文章中我们分析了BIOS的启动流程,其第三条指令为"BIOS_F:E05D out 0Dh, al",因此我们就使用该指令来作为分析指令。
BIOS_F:FFF0 jmp far ptr start_0
BIOS_F:E05B start_0: ; CODE XREF: sub_F5421+2BC↑J
BIOS_F:E05B ; start↓J
BIOS_F:E05B xor ax, ax
BIOS_F:E05D out 0Dh, al ; DMA controller, 8237A-5.
我们下面来设置软件条件断点定位到该指令处,首先必须看上篇文章将递归执行的宏给关掉。之后如下图,我们设置软件条件断点,其该指令的执行地址为0xf000:E05D,则条件断点的激活规则为 "bx_cpu.gen_reg[16].rrx == 0xe05d"。

OUT指令的执行流程
"out 0Dh,al",简单来说就是将al中存储的一个字节的数据输出到0xd端口处,至于这个字节的数据去往哪里,关键要看哪个设备连接着这个端口,这里时DMA控制器。当这个字节传输到0xd端口中,DMA会接收到该数据然后来进行内部处理。
> bochs.exe!bx_dma_c::reset_controller(unsigned int num) Line 187 C++
bochs.exe!bx_dma_c::write_handler(void * this_ptr, unsigned int address, unsigned int value, unsigned int io_len) Line 512 C++
bochs.exe!bx_devices_c::outp(unsigned short addr, unsigned int value, unsigned int io_len) Line 1044 C++
bochs.exe!BX_CPU_C::OUT_IbAL(bxInstruction_c * i) Line 748 C++
bochs.exe!BX_CPU_C::cpu_loop() Line 85 C++
上图是bochs的cpu对该指令的处理调用堆栈,其调用逻辑还是比较清晰的,我们简单整理一下该指令运行的流程图,该流程图很好理解。

IO注册过程回顾
上面我们分析了IO事件的处理办法,现在我们回顾一下IO的注册过程,之前在floppy第七篇文章中作为一个小部分来分析过,现在再来重新拿出来分析一下。
其bx_devices_c结构体中有两个成员"read_port_to_handler"与"write_port_to_handler",其指向一张由io_handler_struct结构体组成的一张表,每一个端口号各对应一个。
class BOCHSAPI bx_devices_c : public logfunctions {
private:
....
struct io_handler_struct **read_port_to_handler;
struct io_handler_struct **write_port_to_handler;
...
public:
...
}
struct io_handler_struct {
struct io_handler_struct *next;
struct io_handler_struct *prev;
void *funct; // C++ type checking is great, but annoying
void *this_ptr;
char *handler_name; // name of device
int usage_count;
Bit8u mask; // io_len mask
};
在各个设备初始化时会对每个端口来注册一个,其中写入自己的io处理函数的地,依次注册上去。如下代码是在第七篇文章中分析的floppy的注册端口号:
for (unsigned addr=0x03F2; addr<=0x03F7; addr++) {
DEV_register_ioread_handler(this, read_handler, addr, "Floppy Drive", 1);
DEV_register_iowrite_handler(this, write_handler, addr, "Floppy Drive", 1);
}
其整体的数据结构如下,还是之前的那一张图,很好理解。

总结
这篇文章比较简单,其bochs对于io的模拟没想的那么复杂,很好理解。但是,在调试过程中发现那个宏修改来禁止cpu递归执行还是存在一系列的问题,接下来我们尝试来解决这个问题,并且分析CPU在执行流程上存在的差异。
1021



被折叠的 条评论
为什么被折叠?



