Domanda

Sto tentando di hackerare insieme i primi bit di un kernel. Attualmente ho l'intero kernel compilato come codice C, e sono riuscito a farlo visualizzare il testo nella finestra della console e tutta quella bontà. Ora voglio iniziare ad accettare l'input da tastiera in modo da poter effettivamente fare un uso della cosa e iniziare la gestione dei processi.

Sto usando DJGPP per compilare e caricare con GRUB. Sto anche usando un po 'di assembly che sostanzialmente passa direttamente al mio codice C compilato e sono felice da lì.

Tutta la ricerca che ho fatto sembra puntare a un ISR a $ 0x16 per leggere il carattere successivo dal buffer della tastiera. Da quello che posso dire, questo dovrebbe memorizzare il valore ASCII in ah, e il codice chiave in al, o qualcosa in tal senso. Sto tentando di codificare questo utilizzando la seguente routine nell'assembly inline:

char getc(void) 
{
    int output = 0;

    //CRAZY VOODOO CODE
    asm("xor %%ah, %%ah\n\t"
        "int <*>x16"
        : "=a" (output)
        : "a" (output)
        : 

        );

    return (char)output;
}

Quando viene chiamato questo codice, il core si blocca immediatamente. (Lo sto eseguendo su VirtualBox, non ho sentito il bisogno di provare qualcosa di così semplice su hardware reale.)

Ora ho un paio di domande. Nessuno è stato in grado di dirmi se (da quando il mio codice è stato lanciato da GRUB) sto correndo in modalità reale o protetta al momento. Non ho fatto il salto in un modo o nell'altro, avevo in programma di correre in modalità reale fino a quando non avessi impostato un gestore di processo.

Quindi, supponendo che sto correndo in modalità reale, cosa sto facendo di sbagliato e come posso risolverlo? Ho solo bisogno di una routine getc di base, preferibilmente non bloccante, ma sarò dannatamente se Google lo sta aiutando su questo. Una volta che posso farlo, posso fare il resto da lì.

Suppongo che quello che sto chiedendo qui sia, sono vicino alla strada giusta? Come si fa generalmente a ottenere input da tastiera a questo livello?

EDIT: OOhh ... quindi sto correndo in modalità protetta. Questo certamente spiega il crash che ha provato ad accedere alle funzioni in modalità reale allora.

Quindi penso che sto cercando come accedere all'IO della tastiera dalla modalità protetta. Potrei riuscire a trovarlo da solo, ma se qualcuno lo sa, sentiti libero. Grazie ancora.

È stato utile?

Soluzione

Se stai compilando con gcc, a meno che tu non stia usando il pazzo " .code16gcc " trucco che usa il kernel linux (di cui dubito moltissimo), non puoi essere in modalità reale. Se si utilizza la specifica multiboot di GRUB, GRUB stesso passa automaticamente alla modalità protetta. Quindi, come altri hanno sottolineato, dovrai parlare direttamente con il controller tastiera / mouse compatibile con 8042. A meno che non si tratti di una tastiera / mouse USB e l'emulazione 8042 sia disabilitata, dove sarebbe necessario uno stack USB (ma è possibile utilizzare il protocollo "boot "" per tastiera / mouse, che è più semplice).

Nessuno ha mai detto che scrivere un kernel OS fosse semplice.

Altri suggerimenti

Il codice che hai lì sta provando ad accedere a un servizio BIOS in modalità reale. Se stai eseguendo in modalità protetta, il che probabilmente sta considerando che stai scrivendo un kernel, l'interrupt non funzionerà. Dovrai effettuare una delle seguenti operazioni:

  • Metti la CPU in modalità reale, assicurandoti che la tabella vettoriale di interrupt sia corretta e usa il codice in modalità reale che hai o
  • Scrivi il tuo gestore di tastiera in modalità protetta (cioè usa le istruzioni in / out).

La prima soluzione prevede un sovraccarico delle prestazioni di runtime mentre la seconda richiederà alcune informazioni sull'IO della tastiera.

Ho un pezzo di GeekOS che sembra fare

In_Byte(KB_CMD);

e poi

In_Byte(KB_DATA);

per recuperare uno scancode. L'ho messo su: keyboard.c e keyboard.h . KB_CMD e KB_DATA sono rispettivamente 0x64 e 0x60. Potrei forse anche sottolineare che questo viene fatto in un gestore di interrupt per intr: 1.

Stai facendo la cosa giusta, ma mi sembra di ricordare che djgpp genera solo output in modalità protetta, da cui non puoi chiamare interrupt. Puoi passare alla modalità reale come altri hanno suggerito o preferiresti indirizzare direttamente l'hardware?

Ai fini della spiegazione, supponiamo che tu stia scrivendo tutto nel linguaggio assembly, boot loader e kernel (* tosse * l'ho fatto).

In modalità reale, è possibile utilizzare le routine di interruzione che provengono dal BIOS. Puoi anche sostituire i vettori di interrupt con i tuoi. Tuttavia, tutto il codice è un codice a 16 bit, che è non binario compatibile con codice a 32 bit.

Quando salti attraverso alcuni cerchi in fiamme per raggiungere la modalità protetta (inclusa la riprogrammazione del controller di interrupt, per aggirare il fatto che IBM ha utilizzato interrupt riservati Intel nel PC), hai l'opportunità di impostare 16 e Segmenti di codice a 32 bit. Questo può essere usato per eseguire codice a 16 bit. Quindi puoi usarlo per accedere all'interruzione getchar!

... non proprio. Perché questo interrupt funzioni, in realtà hai bisogno di dati in un buffer della tastiera inserito da un ISR diverso, quello che viene attivato dalla tastiera quando viene premuto un tasto. Esistono vari problemi che impediscono praticamente di utilizzare gli ISR ??del BIOS come ISR hardware effettivi in ??modalità protetta. Pertanto, le routine di tastiera del BIOS sono inutili.

Le videochiamate BIOS, d'altro canto, vanno bene, perché non esiste alcun componente attivato dall'hardware. Devi preparare un segmento di codice a 16 bit ma se è sotto controllo, puoi cambiare modalità video e quel genere di cose usando gli interrupt del BIOS.

Ritorno alla tastiera: ciò di cui hai bisogno (sempre supponendo che stai scrivendo tutto il codice) è scrivere un driver della tastiera. A meno che tu non sia un masochista (io lo sono), allora non ci andare.

Un suggerimento: prova a scrivere un kernel multitasking in modalità reale. (Questa è la modalità a 16 bit.) Puoi usare tutti gli interrupt del BIOS! Non hai protezione della memoria ma puoi comunque ottenere il multitasking preventivo agganciando l'interruzione del timer.

Solo un'idea: guardando la GRUB per DOS (asm.s), la < code> console_checkkey sta usando BIOS INT 16H Function 01 e non la funzione 00, come stai cercando di fare. Forse vorresti verificare se una chiave è in attesa di essere inserita.

Il codice console_checkkey sta impostando la CPU in modalità reale per utilizzare il BIOS, come @ skizz suggerito .

Puoi anche provare a usare direttamente le funzioni di GRUB (se ancora mappato in modalità reale).

Una nota sulla lettura della fonte dell'assembly: in questa versione

movb    
/*
 * 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  <*>x1, %ah
  int   <*>x16

  DATA32    jz  notpending

  movw  %ax, %dx
  //call    translate_keycode
  call  remap_ascii_char
  DATA32    jmp pending

notpending:
  movl  <*>xFFFFFFFF, %edx

pending:
  DATA32    call    EXT_C(real_to_prot)
  .code32

  mov   %edx, %eax

  pop   %ebp
  ret
x1, %ah

significa spostare il byte costante (0x1) per registrare %ah

Il console_checkkey da GRUB asm.s:

<*>

Esempio di polling del controller della tastiera:

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
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top