前言
? ? ? ? SMM,全称为 Special Mask Mode,特殊掩码模式。在一般情况下(普通的Mask Mode),IRQ的中断请求得到响应执行,ISR相应位置位,在中断服务发起EOI命令前,ISR的位不会清位,8259会抑制优先级低的IRQ。
? ? ? ? 然而,在开启ESMM模式中,其允许在中断服务例程里动态依据IMR及IRR来响应中断请求,而不需要例会ISR。
代码分析
? ? ? ? 在《x86/x64体系探索及编程》的ex17-2中实现了这个,简单分析一下代码吧。
? ? ? ? 首先,在do_timer_handler函数中先开启键盘中断,然后再开启SMM模式,然后再关闭键盘中断,之后一直loop等待着键盘中断触发。
do_timer_handler:
call enable_keyboard
call send_smm_command
call disable_timer
sti
mov esi, t_msg2
call puts
wait_for_keyboard:
mov ecx, 0xffff
delay:
nop
loop delay
bt DWORD [keyboard_done], 0
jnc wait_for_keyboard
? ? ? ? 这时候屏幕内容如下,可以看到其正在处理IRQ0中断,并且等待键盘中断。

? ? ? ? ?此时按下键盘,进入键盘中断,键盘中断处理流程如下代码所示。该键盘中断就是简单dump了8259的IMR,IRR,ISR三个标志位。之后调用write_master_EOI函数,该函数像寄存器中写入,表示中断事件完成。
keyboard_handler:
jmp do_keyboard_handler
k_msg db 10, '>>> now: entry keyboard handler', 10, 0
k_msg1 db 'exit the keyboard handler <<<', 10, 0
do_keyboard_handler:
mov esi, k_msg
call puts
call dump_8259_imr
call dump_8259_irr
call dump_8259_isr
bts DWORD [keyboard_done], 0 ; 完成
mov esi, k_msg1
call puts
call write_master_EOI
iret
write_master_EOI:
mov al, 00100000B ; OCW2 select, EOI
out MASTER_OCW2_PORT, al
ret
? ? ? ? 我们看其8259A三个寄存器的相关属性位,内容如下。可以看到IRQ0与IRQ1同时在执行,这说明SMM模式起到效果了。

?
Bochs对键盘的实现
? ? ? ? 关于8259A芯片我们先暂时不分析了,源码一共几百行配合手册很好理解。我们现在主要来简单提一句键盘的处理流程,之后获取会分析键盘的实现,到时候为我们提供一些思路。
? ? ? ? 关于键盘的堆栈调用图如下,我们慢慢来进行分析:
> bochs.exe!bx_keyb_c::kbd_enQ(unsigned char scancode) Line 915 C++
bochs.exe!bx_keyb_c::gen_scancode(unsigned int key) Line 800 C++
bochs.exe!bx_devices_c::gen_scancode(unsigned int key) Line 1151 C++
bochs.exe!bx_win32_gui_c::handle_events() Line 1555 C++
bochs.exe!bx_devices_c::timer() Line 575 C++
bochs.exe!bx_devices_c::timer_handler(void * this_ptr) Line 568 C++
bochs.exe!bx_pc_system_c::countdownEvent() Line 381 C++
bochs.exe!bx_pc_system_c::tick1() Line 110 C++
bochs.exe!BX_CPU_C::cpu_loop() Line 120 C++
? ? ? ? 通过函数堆栈调用图,我们可以了解其键盘事件是由设备时钟来触发的。
void bx_devices_c::timer()
{
SIM->periodic();
if (!bx_pc_system.kill_bochs_request)
bx_gui->handle_events();
}
? ? ? ? 在handle_events( )中来处理界面的各种事件,核心函数如下,可以看到其来处理WIN_GUI发来的鼠标移动,键盘按下,弹起,滚动条移动等各种事件。
while (head != tail) {
QueueEvent* queue_event = deq_key_event();
if (!queue_event)
break;
key = queue_event->key_event;
if (key == MOUSE_MOTION)
{
DEV_mouse_motion(queue_event->mouse_x, queue_event->mouse_y,
queue_event->mouse_z, queue_event->mouse_button_state, win32MouseModeAbsXY);
}
else if (key == FOCUS_CHANGED) {
DEV_kbd_release_keys();
}
// Check for mouse buttons first
else if (key & MOUSE_PRESSED) {
DEV_mouse_motion(0, 0, 0, LOWORD(key), 0);
}
else if (key & TOOLBAR_CLICKED) {
win32_toolbar_click(LOWORD(key));
}
else {
key_event = win32_to_bx_key[(key & 0x100) ? 1 : 0][key & 0xff];
if (key & BX_KEY_RELEASED) key_event |= BX_KEY_RELEASED;
DEV_kbd_gen_scancode(key_event);
}
}
? ? ? ? 之后其会生成对应的码,指出对应的按键。之后如果分析键盘这部分,我们会回过头来详细分析,现在只是在这里稍微提一下。
unsigned char *scancode;
总结
? ? ? ? 8259A芯片的内容就到这里了,这部分芯片实物也没真正编写过,但是通过bochs代码深刻了解了ISR,IMR,IRR三个寄存器以及其对应的主从芯片,之后我们会来深入学习AIPC,这个是重点。
|