![](/img/trans.png)
[英]How to read keyboard input without “consuming” it in x86 DOS assembly?
[英]How to get keyboard input with x86 bare metal assembly?
我正在試圖破解內核的第一部分。 我目前已將整個內核編譯為C代碼,並且我設法讓它在控制台窗口中顯示文本以及所有這些良好的優點。 現在,我想開始接受鍵盤輸入,這樣我就可以實際使用這個東西並繼續進行流程管理。
我正在使用DJGPP進行編譯,並使用GRUB加載。 我也使用了一小部分程序集,基本上直接跳轉到我編譯的C代碼中,我很高興。
我所做的所有研究似乎都指向一個$ 0x16的ISR來讀取鍵盤緩沖區中的下一個字符。 據我所知,這應該存儲在ah中的ASCII值,以及al中的keycode,或者那種效果。 我正在嘗試使用內聯匯編中的以下例程對此進行編碼:
char getc(void)
{
int output = 0;
//CRAZY VOODOO CODE
asm("xor %%ah, %%ah\n\t"
"int $0x16"
: "=a" (output)
: "a" (output)
:
);
return (char)output;
}
調用此代碼時,核心會立即崩潰。 (我在VirtualBox上運行它,我覺得不需要在真實硬件上嘗試這個基本功能。)
現在我實際上有幾個問題。 沒有人能告訴我(因為我的代碼是從GRUB啟動的)我現在正在以實模式或保護模式運行。 我沒有以這種或那種方式進行跳轉,我計划在實模式下運行,直到我設置了進程處理程序。
所以,假設我在實模式下運行,我做錯了什么,我該如何解決? 我只需要一個基本的getc例程,最好是非阻塞的,但是如果谷歌正在幫助這個,我會被愚弄。 一旦我能做到這一點,我可以從那里做其余的事情。
我想我在這里問的是,我是否在正確的軌道附近? 人們通常如何在這個級別上獲得鍵盤輸入?
編輯:哦......所以我在保護模式下運行。 這當然解釋了試圖訪問實模式功能的崩潰。
那么我想我正在尋找如何從保護模式訪問鍵盤IO。 我也許可以自己找到,但如果有人碰巧知道自由。 再次感謝。
您在那里獲得的代碼是嘗試訪問實模式BIOS服務。 如果您正在保護模式下運行,這可能考慮到您正在編寫內核,那么中斷將無法工作。 您需要執行以下操作之一:
第一個解決方案將涉及運行時性能開銷,第二個解決方案將需要有關鍵盤IO的一些信息。
如果你正在使用gcc編譯,除非你使用Linux內核使用的瘋狂的“.code16gcc”技巧(我非常懷疑),你不能處於實模式。 如果您正在使用GRUB多引導規范,GRUB本身將切換到保護模式。 因此,正如其他人所指出的那樣,您將不得不直接與8042兼容的鍵盤/鼠標控制器進行通信。 除非它是USB鍵盤/鼠標且禁用了8042仿真,否則你需要USB堆棧(但你可以使用鍵盤/鼠標的“啟動”協議,這更簡單)。
沒有人說編寫操作系統內核很簡單。
我有一塊似乎正在做的GeekOS
In_Byte(KB_CMD);
接着
In_Byte(KB_DATA);
獲取掃描碼。 我把它放了: keyboard.c和keyboard.h 。 KB_CMD
和KB_DATA
分別為KB_DATA
和0x60。 我或許也可以指出這是在intr:1的中斷處理程序中完成的。
你做的是正確的,但我似乎記得djgpp只生成保護模式輸出,你無法調用中斷。 您是否可以像其他人建議的那樣進入真實模式,或者您更願意直接解決硬件問題?
出於解釋的目的,讓我們假設您自己用匯編語言編寫所有內容 ,啟動加載程序和內核(*咳嗽*我已經完成了這個)。
在實模式下,您可以使用來自BIOS的中斷例程。 您也可以用自己的中斷向量替換中斷向量。 但是,所有代碼都是16位代碼,與32位代碼不是二進制兼容的 。
當你跳過幾個燃燒的箍到達保護模式(包括重新編程中斷控制器,以解決IBM在PC中使用Intel保留的中斷這一事實)時,你有機會設置16位和32位代碼段。 這可用於運行16位代碼。 所以你可以使用它來訪問getchar中斷!
... 不完全的。 要使此中斷起作用,您實際上需要鍵盤緩沖區中的數據,該緩沖區由不同的ISR放置在那里 - 按下鍵時由鍵盤觸發的ISR。 有許多問題幾乎阻止您使用BIOS ISR作為保護模式下的實際硬件ISR。 所以,BIOS鍵盤程序是沒用的。
另一方面,BIOS視頻通話很好,因為沒有硬件觸發的組件。 你必須准備一個16位的代碼段,但如果它在控制之下,那么你可以通過使用BIOS中斷來切換視頻模式和那種東西。
回到鍵盤:你需要什么(再次假設你寫的所有代碼)是寫一個鍵盤驅動程序。 除非你是一個受虐狂(我是一個),否則不要去那里。
建議:嘗試在Real模式下編寫多任務內核。 (這是16位模式。)您可以使用所有BIOS中斷! 您沒有獲得內存保護,但您仍然可以通過掛鈎定時器中斷來獲得先發制人的多任務處理。
只是一個想法:查看GRUB for DOS源(asm.s), console_checkkey
函數正在使用BIOS INT 16H Function 01
,而不是函數00,正如您嘗試的那樣。 也許你想檢查一個鍵是否等待輸入。
console_checkkey
代碼將CPU設置為實模式以便使用BIOS,如@skizz建議的那樣 。
您也可以嘗試直接使用GRUB函數(如果仍然以實模式映射)。
關於閱讀匯編源的說明:在此版本中
movb $0x1, %ah
意味着將常量字節(0x1)移動到寄存器%ah
來自GRUB asm.s的console_checkkey
:
/*
* int console_checkkey (void)
* if there is a character pending, return it; otherwise return -1
* BIOS call "INT 16H Function 01H" to check whether a character is pending
* Call with %ah = 0x1
* Return:
* If key waiting to be input:
* %ah = keyboard scan code
* %al = ASCII character
* Zero flag = clear
* else
* Zero flag = set
*/
ENTRY(console_checkkey)
push %ebp
xorl %edx, %edx
call EXT_C(prot_to_real) /* enter real mode */
.code16
sti /* checkkey needs interrupt on */
movb $0x1, %ah
int $0x16
DATA32 jz notpending
movw %ax, %dx
//call translate_keycode
call remap_ascii_char
DATA32 jmp pending
notpending:
movl $0xFFFFFFFF, %edx
pending:
DATA32 call EXT_C(real_to_prot)
.code32
mov %edx, %eax
pop %ebp
ret
輪詢鍵盤控制器的示例:
Start:
cli
mov al,2 ; dissable IRQ 1
out 21h,al
sti
;--------------------------------------
; Main-Routine
AGAIN:
in al,64h ; get the status
test al,1 ; check output buffer
jz short NOKEY
test al,20h ; check if it is a PS2Mouse-byte
jnz short NOKEY
in al,60h ; get the key
; insert your code here (maybe for converting into ASCII...)
NOKEY:
jmp AGAIN
;--------------------------------------
; At the end
cli
xor al,al ; enable IRQ 1
out 21h,al
sti
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.