linux 0.11 内核学习 -- keyboard.s,键盘原来是这么干的。
/*
* linux/kernel/keyboard.S
*
* (C) 1991 Linus Torvalds
*/
/*
* Thanks to Alfred Leung for US keyboard patches
* Wolfgang Thiel for German keyboard patches
* Marc Corsini for the French keyboard
*/
#include <linux/config.h> // 内核配置头文件
.text
.globl _keyboard_interrupt
/*
* these are for the keyboard read functions
*/
/* 键盘缓冲区长度 */
size = 1024 /* must be a power of two ! And MUST be the same
as in tty_io.c !!!! */
/* 缓冲队列结构中的偏移量 */
head = 4 // 缓冲区头指针偏移量
tail = 8 // 缓冲区尾指针偏移量
proc_list = 12 // 等待该缓冲区进程偏移量
buf = 16 // 缓冲区偏移量
/*
* 定义变量mode,表示特殊键按下的状态
* cap,alt,ctrl,shift
*/
mode: .byte 0 /* caps, alt, ctrl and shift mode */
/*
* 数字锁定键,大小写转换键,滚动锁定键scroll-lock
* 定义变量leds
*/
leds: .byte 2 /* num-lock, caps, scroll-lock mode (nom-lock on) */
/*
* 0xe0或者是0xe1指示气候跟随的是一个或者是两个字符扫描码
*/
e0: .byte 0
/*
* con_int is the real interrupt routine that reads the
* keyboard scan-code and converts it into the appropriate
* ascii character(s).
*/
_keyboard_interrupt: // 键盘中断处理程序入口点
/* 保存寄存器 */
pushl %eax
pushl %ebx
pushl %ecx
pushl %edx
push %ds
push %es
//////////////////////////////////////////////
// ds,es设置为内核数据段
movl $0x10,%eax
mov %ax,%ds
mov %ax,%es
//////////////////////////////////////////////
xorl %al,%al /* %eax is scan code, al = 0 */
inb $0x60,%al // 现在al寄存器就是中断之后读取的键盘扫描码
/////////////////////////////////////////////
cmpb $0xe0,%al // 如果扫描码是0xe0
je set_e0 // 跳转到set_e0
/////////////////////////////////////////////
cmpb $0xe1,%al // 如果是0xe1
je set_e1
/////////////////////////////////////////////
call key_table(,%eax,4) // 调用键处理程序key_table + %eax * 4
movb $0,e0 // 复位e0标志
////////////////////////////////////////////
// 下面的代码是使硬件复位处理。首先是禁止键盘的工作,然后开启
// 键盘工作
e0_e1: inb $0x61,%al
jmp 1f // 时间延迟
1: jmp 1f
1: orb $0x80,%al
jmp 1f
1: jmp 1f
1: outb %al,$0x61
jmp 1f
1: jmp 1f
1: andb $0x7F,%al
outb %al,$0x61
///////////////////////////////////////////
movb $0x20,%al // 发送中断结束信号
outb %al,$0x20
pushl $0 // 将控制台号tty = 0压入栈
call _do_tty_interrupt // 调用_do_tty_interrupt
addl $4,%esp // 丢弃入栈参数,并返回
///////////////////////////////////////////
// 恢复上下文
pop %es
pop %ds
popl %edx
popl %ecx
popl %ebx
popl %eax
///////////////////////////////////////////
iret // 中断返回
set_e0: movb $1,e0
jmp e0_e1
set_e1: movb $2,e0
jmp e0_e1
/*
* This routine fills the buffer with max 8 bytes, taken from
* %ebx:%eax. (%edx is high). The bytes are written in the
* order %al,%ah,%eal,%eah,%bl,%bh ... until %eax is zero.
*/
/* 下面的子程序将ebx:eax中最多8个字符添加入缓冲队列,知道eax = 0 */
/* --------------------------------------------- */
/* ebx (4 char) | eax (4 char) */
/* --------------------------------------------- */
put_queue:
pushl %ecx
pushl %edx
movl _table_list,%edx # read-queue for console,得到_table_list地址
movl head(%edx),%ecx // ecx = 缓冲队列头指针
1: movb %al,buf(%edx,%ecx) // 将al中的字符放置在缓冲队列头指针位置
incl %ecx
andl $size-1,%ecx // ecx指向缓冲队列最后
cmpl tail(%edx),%ecx # buffer full - discard everything?
// 头指针 == 尾指针
je 3f // 到3处继续执行,将后面未放入的字符全部抛弃
shrdl $8,%ebx,%eax
je 2f // 还有剩余的字符吗?没有,跳转2f
shrl $8,%ebx // ebx右移
jmp 1b // 还有剩余字符,跳转到1标号
///////////////////////////////////////
// 所有字符放入了队列 //
2: movl %ecx,head(%edx) // 保存头指针
movl proc_list(%edx),%ecx // 是否存在等待进程?
testl %ecx,%ecx
je 3f // 没有等待任务,跳转
/* task_struct结构第一个字段就是state */
movl $0,(%ecx) // 有,则置进程为可运行就绪状态
//////////////////////////////////////
//////////////////////////////////////
// 中断返回 //
3: popl %edx
popl %ecx
ret
/////////////////////////////////////
/* 根据ctrl或者是alt的扫描码,设置全局变量mode */
ctrl: movb $0x04,%al
jmp 1f
alt: movb $0x10,%al
1: cmpb $0,e0
je 2f
addb %al,%al
2: orb %al,mode
ret
/* 下面的代码设置ctrl或者alt键松开时扫描码,设置mode */
unctrl: movb $0x04,%al
jmp 1f
unalt: movb $0x10,%al
1: cmpb $0,e0
je 2f
addb %al,%al
2: notb %al
andb %al,mode
ret
/* 下面的代码根据扫描码,设置mode */
lshift: // 左shift按下
orb $0x01,mode
ret
unlshift: // 左shift松开
andb $0xfe,mode
ret
rshift: // 右shift按下
orb $0x02,mode
ret
unrshift: // 右shift松开
andb $0xfd,mode
ret
/* caps键标志 */
caps: testb $0x80,mode // 测试mode中的caps键是否按下?
jne 1f // 如果已经按下,中断返回
xorb $4,leds // 设置leds变量
xorb $0x40,mode // 设置mode中的位
orb $0x80,mode
/* 下面的代码是根据leds的表示,开启或者是关闭LED灯 */
set_leds:
call kb_wait // 等待键盘控制器输入缓冲空
movb $0xed,%al /* set leds command */
outb %al,$0x60
call kb_wait // 等待键盘控制器输入缓冲空
movb leds,%al // 取leds 标志,作为参数
outb %al,$0x60 // 发送
ret
/* caps键释放,设置mode值 */
uncaps: andb $0x7f,mode
ret
/* scroll键按下,设置leds值,并调用set_leds,重新显示led */
scroll:
xorb $1,leds
jmp set_leds
/* num-lock键 */
num: xorb $2,leds
jmp set_leds
/*
* curosr-key/numeric keypad cursor keys are handled here.
* checking for numeric keypad etc.
*/
/* 处理方向键/数字小键盘方向键 */
cursor:
subb $0x47,%al // 扫描码是小数字键盘上的键(其扫描码>=0x47)发出的?
jb 1f // 如果小于则不处理,返回
cmpb $12,%al // 如果扫描码 > 0x53
ja 1f // 不处理,返回
jne cur2 /* check for ctrl-alt-del */
testb $0x0c,mode // 有ctrl 键按下吗?
je cur2 // 无,则跳转
testb $0x30,mode // 有alt按下吗?
jne reboot // 无,则跳转reboot
cur2: cmpb $0x01,e0 /* e0 forces cursor movement */
/* e0 置位表示光标移动 */
je cur // 如果置位了,跳转到cur
testb $0x02,leds /* not num-lock forces cursor */
// 测试leds 中标志num-lock 键标志是否置位
je cur // 如果没有置位(num 的LED 不亮),则也进行光标移动处理
testb $0x03,mode /* shift forces cursor */
// 测试模式标志mode 中shift 按下标志
jne cur // 如果有shift 键按下,则也进行光标移动处理
// 取对应键的数字ASCII 码 -> al
xorl %ebx,%ebx
movb num_table(%eax),%al
jmp put_queue // 将该字符放入缓冲队列中
1: ret
/* 处理光标的移动 */
cur: movb cur_table(%eax),%al // 取光标字符表中相应键的代表字符 -> al
cmpb $'9,%al // 若该字符<='9',说明是上一页、下一页、插入或删除键
ja ok_cur // 功能字符序列中要添入字符'~'
movb $'~,%ah
ok_cur: shll $16,%eax // 将ax 中内容移到eax 高字中
movw $0x5b1b,%ax // 在ax中放入$0x5b1b,与eax 高字中字符组成移动序列
xorl %ebx,%ebx
jmp put_queue // 将该字符放入缓冲队列中
#if defined(KBD_FR)
num_table:
.ascii "789 456 1230." // 数字小键盘上键对应的数字ASCII 码表
#else
num_table:
.ascii "789 456 1230,"
#endif
cur_table:
.ascii "HA5 DGC YB623" // 数字小键盘上方向键或插入删除键对应的移动表示字符表
/*
* this routine handles function keys
*/
/* 功能键 */
func:
//////////////////////////////////////
pushl %eax
pushl %ecx
pushl %edx
/////////////////////////////////////
call _show_stat // kernl/sched.c
popl %edx
popl %ecx
popl %eax
/////////////////////////////////////
subb $0x3B,%al // 功能键'F1'的扫描码是0x3B
jb end_func // 如果扫描码小于0x3b,则不处理
cmpb $9,%al // 功能键是F1-F10?
jbe ok_func // 是,则跳转
subb $18,%al // 是功能键F11,F12 吗?
cmpb $10,%al // 是功能键F11?
jb end_func // 不是,则不处理
cmpb $11,%al // 是功能键F12?
ja end_func // 不是,则不处理
ok_func:
cmpl $4,%ecx /* check that there is enough room */
jl end_func // 需要放入4 个字符序列,如果放不下,则返回
movl func_table(,%eax,4),%eax // 取功能键对应字符序列
xorl %ebx,%ebx
jmp put_queue // 放入缓冲队列中
end_func:
ret
/*
* function keys send F1:'esc [ [ A' F2:'esc [ [ B' etc.
*/
/*
* 功能键发送的扫描码,F1 键为:'esc [ [ A', F2 键为:'esc [ [ B'等
*/
func_table:
.long 0x415b5b1b,0x425b5b1b,0x435b5b1b,0x445b5b1b
.long 0x455b5b1b,0x465b5b1b,0x475b5b1b,0x485b5b1b
.long 0x495b5b1b,0x4a5b5b1b,0x4b5b5b1b,0x4c5b5b1b
/* 扫描码-ASCII 字符映射表 */
#if defined(KBD_FINNISH) // 芬兰语键盘
key_map:
.byte 0,27
.ascii "1234567890+'"
.byte 127,9
.ascii "qwertyuiop}"
.byte 0,13,0
.ascii "asdfghjkl|{"
.byte 0,0
.ascii "'zxcvbnm,.-"
.byte 0,'*,0,32 /* 36-39 */
.fill 16,1,0 /* 3A-49 */
.byte '-,0,0,0,'+ /* 4A-4E */
.byte 0,0,0,0,0,0,0 /* 4F-55 */
.byte '<
.fill 10,1,0
// shift 键同时按下时的映射表
shift_map:
.byte 0,27
.ascii "!\"#$%&/()=?`"
.byte 127,9
.ascii "QWERTYUIOP]^"
.byte 13,0
.ascii "ASDFGHJKL\\["
.byte 0,0
.ascii "*ZXCVBNM;:_"
.byte 0,'*,0,32 /* 36-39 */
.fill 16,1,0 /* 3A-49 */
.byte '-,0,0,0,'+ /* 4A-4E */
.byte 0,0,0,0,0,0,0 /* 4F-55 */
.byte '>
.fill 10,1,0
// alt 键同时按下时的映射表
alt_map:
.byte 0,0
.ascii "\0@\0$\0\0{[]}\\\0"
.byte 0,0
.byte 0,0,0,0,0,0,0,0,0,0,0
.byte '~,13,0
.byte 0,0,0,0,0,0,0,0,0,0,0
.byte 0,0
.byte 0,0,0,0,0,0,0,0,0,0,0
.byte 0,0,0,0 /* 36-39 */
.fill 16,1,0 /* 3A-49 */
.byte 0,0,0,0,0 /* 4A-4E */
.byte 0,0,0,0,0,0,0 /* 4F-55 */
.byte '|
.fill 10,1,0
#elif defined(KBD_US) // 美式键盘
key_map:
.byte 0,27
.ascii "1234567890-="
.byte 127,9
.ascii "qwertyuiop[]"
.byte 13,0
.ascii "asdfghjkl;'"
.byte '`,0
.ascii "\\zxcvbnm,./"
.byte 0,'*,0,32 /* 36-39 */
.fill 16,1,0 /* 3A-49 */
.byte '-,0,0,0,'+ /* 4A-4E */
.byte 0,0,0,0,0,0,0 /* 4F-55 */
.byte '<
.fill 10,1,0
shift_map:
.byte 0,27
.ascii "!@#$%^&*()_+"
.byte 127,9
.ascii "QWERTYUIOP{}"
.byte 13,0
.ascii "ASDFGHJKL:\""
.byte '~,0
.ascii "|ZXCVBNM<>?"
.byte 0,'*,0,32 /* 36-39 */
.fill 16,1,0 /* 3A-49 */
.byte '-,0,0,0,'+ /* 4A-4E */
.byte 0,0,0,0,0,0,0 /* 4F-55 */
.byte '>
.fill 10,1,0
alt_map:
.byte 0,0
.ascii "\0@\0$\0\0{[]}\\\0"
.byte 0,0
.byte 0,0,0,0,0,0,0,0,0,0,0
.byte '~,13,0
.byte 0,0,0,0,0,0,0,0,0,0,0
.byte 0,0
.byte 0,0,0,0,0,0,0,0,0,0,0
.byte 0,0,0,0 /* 36-39 */
.fill 16,1,0 /* 3A-49 */
.byte 0,0,0,0,0 /* 4A-4E */
.byte 0,0,0,0,0,0,0 /* 4F-55 */
.byte '|
.fill 10,1,0
#elif defined(KBD_GR) // 德语键盘
key_map:
.byte 0,27
.ascii "1234567890\\'"
.byte 127,9
.ascii "qwertzuiop@+"
.byte 13,0
.ascii "asdfghjkl[]^"
.byte 0,'#
.ascii "yxcvbnm,.-"
.byte 0,'*,0,32 /* 36-39 */
.fill 16,1,0 /* 3A-49 */
.byte '-,0,0,0,'+ /* 4A-4E */
.byte 0,0,0,0,0,0,0 /* 4F-55 */
.byte '<
.fill 10,1,0
shift_map:
.byte 0,27
.ascii "!\"#$%&/()=?`"
.byte 127,9
.ascii "QWERTZUIOP\\*"
.byte 13,0
.ascii "ASDFGHJKL{}~"
.byte 0,''
.ascii "YXCVBNM;:_"
.byte 0,'*,0,32 /* 36-39 */
.fill 16,1,0 /* 3A-49 */
.byte '-,0,0,0,'+ /* 4A-4E */
.byte 0,0,0,0,0,0,0 /* 4F-55 */
.byte '>
.fill 10,1,0
alt_map:
.byte 0,0
.ascii "\0@\0$\0\0{[]}\\\0"
.byte 0,0
.byte '@,0,0,0,0,0,0,0,0,0,0
.byte '~,13,0
.byte 0,0,0,0,0,0,0,0,0,0,0
.byte 0,0
.byte 0,0,0,0,0,0,0,0,0,0,0
.byte 0,0,0,0 /* 36-39 */
.fill 16,1,0 /* 3A-49 */
.byte 0,0,0,0,0 /* 4A-4E */
.byte 0,0,0,0,0,0,0 /* 4F-55 */
.byte '|
.fill 10,1,0
#elif defined(KBD_FR) // 法语键盘
key_map:
.byte 0,27
.ascii "&{\"'(-}_/@)="
.byte 127,9
.ascii "azertyuiop^$"
.byte 13,0
.ascii "qsdfghjklm|"
.byte '`,0,42 /* coin sup gauche, don't know, [*|mu] */
.ascii "wxcvbn,;:!"
.byte 0,'*,0,32 /* 36-39 */
.fill 16,1,0 /* 3A-49 */
.byte '-,0,0,0,'+ /* 4A-4E */
.byte 0,0,0,0,0,0,0 /* 4F-55 */
.byte '<
.fill 10,1,0
shift_map:
.byte 0,27
.ascii "1234567890]+"
.byte 127,9
.ascii "AZERTYUIOP<>"
.byte 13,0
.ascii "QSDFGHJKLM%"
.byte '~,0,'#
.ascii "WXCVBN?./\\"
.byte 0,'*,0,32 /* 36-39 */
.fill 16,1,0 /* 3A-49 */
.byte '-,0,0,0,'+ /* 4A-4E */
.byte 0,0,0,0,0,0,0 /* 4F-55 */
.byte '>
.fill 10,1,0
alt_map:
.byte 0,0
.ascii "\0~#{[|`\\^@]}"
.byte 0,0
.byte '@,0,0,0,0,0,0,0,0,0,0
.byte '~,13,0
.byte 0,0,0,0,0,0,0,0,0,0,0
.byte 0,0
.byte 0,0,0,0,0,0,0,0,0,0,0
.byte 0,0,0,0 /* 36-39 */
.fill 16,1,0 /* 3A-49 */
.byte 0,0,0,0,0 /* 4A-4E */
.byte 0,0,0,0,0,0,0 /* 4F-55 */
.byte '|
.fill 10,1,0
#else
#error "KBD-type not defined"
#endif
/*
* do_self handles "normal" keys, ie keys that don't change meaning
* and which have just one character returns.
*/
/*
* do_self handles "normal" keys
*/
do_self:
//////////////////////////////////////////////////////////////////
// 根据模式标志mode 选择alt_map、shift_map 或key_map 映射表之一 //
lea alt_map,%ebx // alt 键同时按下时的映射表基址alt_map-> ebx
testb $0x20,mode /* 右alt 键同时按下了? alt-gr */
jne 1f // 同时按下了,则向前跳转到标号1 处
lea shift_map,%ebx // shift 键同时按下时的映射表基址shift_map-> ebx
testb $0x03,mode // 有shift 键同时按下了吗?
jne 1f // 有,则向前跳转到标号1 处
lea key_map,%ebx // 否则使用普通映射表key_map
//////////////////////////////////////////////////////////////////
/* 取映射表中对应扫描码的ASCII 字符,若没有对应字符,则返回(转none) */
1: movb (%ebx,%eax),%al // 将扫描码作为索引值,取对应的ASCII 码 -> al
orb %al,%al // 检测看是否有对应的ASCII 码?
je none // 若没有(对应的ASCII 码=0),则返回
///////////////////////////////////////////////////////////////////
/* 若ctrl 键已按下或caps 键锁定,并且字符在'a'-'}'(0x61-0x7D)范围内,则将其转成大写字符 */
testb $0x4c,mode /* ctrl or caps */
je 2f
cmpb $'a,%al
jb 2f
cmpb $'},%al
ja 2f
subb $32,%al
///////////////////////////////////////////////////////////////////
/* 若ctrl 键已按下,并且字符在'`'--'_'(0x40-0x5F)之间(是大写字符),则将其转换为控制字符 */
2: testb $0x0c,mode /* ctrl */
je 3f
cmpb $64,%al
jb 3f
cmpb $64+32,%al
jae 3f
subb $64,%al
/* 若左alt 键同时按下,则将字符的位7 置位 */
3: testb $0x10,mode /* left alt */
je 4f
orb $0x80,%al
/* 将al 中的字符放入读缓冲队列 */
4: andl $0xff,%eax
xorl %ebx,%ebx
call put_queue
none: ret
/*
* minus has a routine of it's own, as a 'E0h' before
* the scan code for minus means that the numeric keypad
* slash was pushed.
*/
minus: cmpb $1,e0
jne do_self
movl $'/,%eax
xorl %ebx,%ebx
jmp put_queue
/*
* This table decides which routine to call when a scan-code has been
* gotten. Most routines just call do_self, or none, depending if
* they are make or break.
*/
key_table:
.long none,do_self,do_self,do_self /* 00-03 s0 esc 1 2 */
.long do_self,do_self,do_self,do_self /* 04-07 3 4 5 6 */
.long do_self,do_self,do_self,do_self /* 08-0B 7 8 9 0 */
.long do_self,do_self,do_self,do_self /* 0C-0F + ' bs tab */
.long do_self,do_self,do_self,do_self /* 10-13 q w e r */
.long do_self,do_self,do_self,do_self /* 14-17 t y u i */
.long do_self,do_self,do_self,do_self /* 18-1B o p } ^ */
.long do_self,ctrl,do_self,do_self /* 1C-1F enter ctrl a s */
.long do_self,do_self,do_self,do_self /* 20-23 d f g h */
.long do_self,do_self,do_self,do_self /* 24-27 j k l | */
.long do_self,do_self,lshift,do_self /* 28-2B { para lshift , */
.long do_self,do_self,do_self,do_self /* 2C-2F z x c v */
.long do_self,do_self,do_self,do_self /* 30-33 b n m , */
.long do_self,minus,rshift,do_self /* 34-37 . - rshift * */
.long alt,do_self,caps,func /* 38-3B alt sp caps f1 */
.long func,func,func,func /* 3C-3F f2 f3 f4 f5 */
.long func,func,func,func /* 40-43 f6 f7 f8 f9 */
.long func,num,scroll,cursor /* 44-47 f10 num scr home */
.long cursor,cursor,do_self,cursor /* 48-4B up pgup - left */
.long cursor,cursor,do_self,cursor /* 4C-4F n5 right + end */
.long cursor,cursor,cursor,cursor /* 50-53 dn pgdn ins del */
.long none,none,do_self,func /* 54-57 sysreq ? < f11 */
.long func,none,none,none /* 58-5B f12 ? ? ? */
.long none,none,none,none /* 5C-5F ? ? ? ? */
.long none,none,none,none /* 60-63 ? ? ? ? */
.long none,none,none,none /* 64-67 ? ? ? ? */
.long none,none,none,none /* 68-6B ? ? ? ? */
.long none,none,none,none /* 6C-6F ? ? ? ? */
.long none,none,none,none /* 70-73 ? ? ? ? */
.long none,none,none,none /* 74-77 ? ? ? ? */
.long none,none,none,none /* 78-7B ? ? ? ? */
.long none,none,none,none /* 7C-7F ? ? ? ? */
.long none,none,none,none /* 80-83 ? br br br */
.long none,none,none,none /* 84-87 br br br br */
.long none,none,none,none /* 88-8B br br br br */
.long none,none,none,none /* 8C-8F br br br br */
.long none,none,none,none /* 90-93 br br br br */
.long none,none,none,none /* 94-97 br br br br */
.long none,none,none,none /* 98-9B br br br br */
.long none,unctrl,none,none /* 9C-9F br unctrl br br */
.long none,none,none,none /* A0-A3 br br br br */
.long none,none,none,none /* A4-A7 br br br br */
.long none,none,unlshift,none /* A8-AB br br unlshift br */
.long none,none,none,none /* AC-AF br br br br */
.long none,none,none,none /* B0-B3 br br br br */
.long none,none,unrshift,none /* B4-B7 br br unrshift br */
.long unalt,none,uncaps,none /* B8-BB unalt br uncaps br */
.long none,none,none,none /* BC-BF br br br br */
.long none,none,none,none /* C0-C3 br br br br */
.long none,none,none,none /* C4-C7 br br br br */
.long none,none,none,none /* C8-CB br br br br */
.long none,none,none,none /* CC-CF br br br br */
.long none,none,none,none /* D0-D3 br br br br */
.long none,none,none,none /* D4-D7 br br br br */
.long none,none,none,none /* D8-DB br ? ? ? */
.long none,none,none,none /* DC-DF ? ? ? ? */
.long none,none,none,none /* E0-E3 e0 e1 ? ? */
.long none,none,none,none /* E4-E7 ? ? ? ? */
.long none,none,none,none /* E8-EB ? ? ? ? */
.long none,none,none,none /* EC-EF ? ? ? ? */
.long none,none,none,none /* F0-F3 ? ? ? ? */
.long none,none,none,none /* F4-F7 ? ? ? ? */
.long none,none,none,none /* F8-FB ? ? ? ? */
.long none,none,none,none /* FC-FF ? ? ? ? */
/*
* kb_wait waits for the keyboard controller buffer to empty.
* there is no timeout - if the buffer doesn't empty, we hang.
*/
/*
* 子程序kb_wait 用于等待键盘控制器缓冲空
*/
kb_wait:
pushl %eax
1: inb $0x64,%al // 读键盘控制器状态
testb $0x02,%al // 测试输入缓冲器是否为空(等于0)?
jne 1b // 若不空,则跳转循环等待
// 若空?
popl %eax
ret
/*
* This routine reboots the machine by asking the keyboard
* controller to pulse the reset-line low.
*/
reboot:
call kb_wait // 首先等待键盘控制器输入缓冲器空
movw $0x1234,0x472 /* don't do memory check */
movb $0xfc,%al /* pulse reset and A20 low */
outb %al,$0x64 // 向系统复位和A20 线输出负脉冲
die: jmp die // 死机
/*
* 整个文件实现了键盘中断处理函数_keyboard_interrupt,通过查询
* key_table来查找特定键的处理函数
*/
参考《linux内核完全注释》和网上相关知识
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?