2008-10-20 78 views
4

我正在試圖破解一個內核的第一部分。我現在已經將整個內核編譯爲C代碼,並且我已經設法讓它在控制檯窗口中顯示文本以及所有這些優點。現在,我想開始接受鍵盤輸入,所以我實際上可以使用一些東西並開始進行流程管理。如何使用x86裸機組件獲得鍵盤輸入?

我正在使用DJGPP進行編譯,並使用GRUB加載。我還使用了一小段程序集,它基本上直接跳轉到我編譯的C代碼中,我從那裏開心。

我所做的所有研究似乎都指向了一個$ 0x16的ISR來讀取鍵盤緩衝區中的下一個字符。從我所知道的情況來看,這應該存儲在ah中的ASCII值,以及在al中存儲的密鑰代碼,或者這個效果。我試圖在內聯彙編中使用以下例程對其進行編碼:

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例程,最好是非阻塞的,但如果谷歌幫助完成這個任務,我會感到厭煩。一旦我能做到這一點,我就可以從那裏完成剩下的工作。

我想我在這裏問的是,我在任何地方靠近正確的軌道?人們通常會如何在這個級別獲得鍵盤輸入?

編輯:OOhh ...所以我在保護模式下運行。這當然解釋了嘗試訪問真實模式功能的崩潰。

那麼我想我正在尋找如何從保護模式訪問鍵盤IO。我可以自己找到,但如果有人知道自由的話。再次感謝。

回答

4

如果你正在用gcc編譯,除非你正在使用linux內核使用的瘋狂的「.code16gcc」技巧(我非常懷疑),你不能處於真正的模式德。如果您正在使用GRUB多重引導規範,則GRUB本身將爲您切換到保護模式。所以,正如其他人指出的那樣,您將不得不直接與8042兼容的鍵盤/鼠標控制器通話。除非USB鍵盤/鼠標和8042仿真禁用,否則您需要USB堆棧(但可以使用鍵盤/鼠標的「引導」協議,這更簡單)。沒有人說寫OS內核很簡單。

+0

注意,只要你留在保護模式下,不長的模式,你應該能夠使用虛擬8086任務來執行BIOS中斷。 (原始鍵盤IO相對簡單,但直接與硬件接口可能更爲有用,正如@CesarB所建議的那樣)。 – bcat 2010-07-29 12:54:07

1

我有一塊GeekOS,這似乎做

In_Byte(KB_CMD); 

然後

In_Byte(KB_DATA); 

獲取掃描碼。我把它放在:keyboard.ckeyboard.hKB_CMDKB_DATA分別是0x64和0x60。我也許也可以指出,這是在intr:1的中斷處理程序中完成的。

4

您在那裏得到的代碼正試圖訪問實模式BIOS服務。如果你在保護模式下運行,這可能是因爲你正在編寫一個內核,那麼中斷將不起作用。你需要做以下操作之一:

  • 咚的CPU進入實模式,確保中斷向量表是正確的,並使用您的實模式代碼或
  • 寫自己的保護模式鍵盤處理程序(即使用輸入/輸出指令)。

第一個解決方案將涉及運行時性能開銷,第二個解決方案需要一些關於鍵盤IO的信息。

0

只是一個想法:看看GRUB for DOS源(asm.s),console_checkkey函數使用BIOS INT 16H Function 01,而不是函數00,因爲你正在嘗試做。也許你想檢查一個密鑰是否在等待輸入。

console_checkkey代碼將CPU設置爲實模式以便使用BIOS,如@skizz suggested

您也可以嘗試直接使用GRUB函數(如果仍然以實模式映射)。

在閱讀彙編源的說明:在該版本

movb $0x1, %ah 

裝置移動恆定字節(爲0x1),以從GRUB asm.s寄存器%ah

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 
1

你在做正確的事情,但我似乎記得,djgpp只生成保護模式輸出,您不能從中調用中斷。你能否像其他人所建議的那樣進入真實模式?或者你更願意直接對硬件進行解決?

1

出於解釋的目的,我們假設你自己編寫了一切彙編語言,引導加載程序和內核(*咳嗽*我已經這樣做了)。

在實模式中,您可以使用來自BIOS的中斷例程。您也可以用您自己的替換中斷向量。但是所有的代碼都是16位代碼,這是不是二進制兼容的與32位代碼。當您跳過幾個灼熱的環節進入保護模式時(包括重新編程中斷控制器,以避免IBM在PC中使用Intel保留的中斷這一事實),您將有機會設置16位處理器,和32位代碼段。這可以用來運行16位代碼。所以你可以用它來訪問getchar中斷!

...不完全。爲了使這個中斷正常工作,實際上需要一個鍵盤緩衝區中的數據,該緩衝區由另一個ISR放置 - 當按下某個鍵時由鍵盤觸發的數據。有各種各樣的問題幾乎阻止您在受保護模式下將BIOS ISR用作實際的硬件ISR。所以,BIOS鍵盤例程是沒用的。

另一方面,BIOS視頻通話很好,因爲沒有硬件觸發組件。你必須準備一個16位的代碼段,但如果這是受控制的,那麼你可以通過使用BIOS中斷來切換視頻模式和類似的事情。

回到鍵盤:你需要什麼(再次假設你正在編寫所有的代碼)是編寫一個鍵盤驅動程序。除非你是一個受虐狂(我是一個),否則不要去那裏。

建議:嘗試在Real模式下編寫多任務內核。 (這是16位模式。)您可以使用所有的BIOS中斷!您沒有獲得內存保護,但您仍然可以通過掛接定時器中斷來獲得先佔式多任務處理。

0

舉例輪詢鍵盤控制器:

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