簡體   English   中英

如何使用x86裸機組件獲得鍵盤輸入?

[英]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服務。 如果您正在保護模式下運行,這可能考慮到您正在編寫內核,那么中斷將無法工作。 您需要執行以下操作之一:

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

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

如果你正在使用gcc編譯,除非你使用Linux內核使用的瘋狂的“.code16gcc”技巧(我非常懷疑),你不能處於實模式。 如果您正在使用GRUB多引導規范,GRUB本身將切換到保護模式。 因此,正如其他人所指出的那樣,您將不得不直接與8042兼容的鍵盤/鼠標控制器進行通信。 除非它是USB鍵盤/鼠標且禁用了8042仿真,否則你需要USB堆棧(但你可以使用鍵盤/鼠標的“啟動”協議,這更簡單)。

沒有人說編寫操作系統內核很簡單。

我有一塊似乎正在做的GeekOS

In_Byte(KB_CMD);

接着

In_Byte(KB_DATA);

獲取掃描碼。 我把它放了: keyboard.ckeyboard.h KB_CMDKB_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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM