Question

Je suis en train d'essayer de pirater ensemble les premiers éléments d'un noyau. J'ai actuellement le noyau entier compilé en code C, et j'ai réussi à le faire afficher du texte dans la fenêtre de la console et ainsi de suite. Maintenant, je veux commencer à accepter les entrées au clavier afin de pouvoir réellement utiliser la chose et commencer à gérer les processus.

J'utilise DJGPP pour compiler et charger avec GRUB. J'utilise également un petit peu d'assemblage qui saute directement dans mon code C compilé et je suis heureux à partir de là.

Toutes les recherches que j'ai effectuées semblent indiquer un ISR à $ 0x16 pour lire le caractère suivant dans la mémoire tampon du clavier. D'après ce que je peux dire, ceci est supposé stocker la valeur ASCII dans ah, et le keycode dans al, ou quelque chose de similaire. J'essaie de coder ceci en utilisant la routine suivante dans l'assemblage en ligne:

char getc(void) 
{
    int output = 0;

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

        );

    return (char)output;
}

Lorsque ce code est appelé, le noyau se bloque immédiatement. (Je l’utilise sur VirtualBox, je n’ai pas ressenti le besoin d’essayer quelque chose de cette base sur du matériel réel.)

Maintenant, j'ai quelques questions à vous poser. Personne n'a été capable de me dire si (depuis que mon code a été lancé par GRUB) je tourne en mode réel ou en mode protégé pour le moment. Je n'ai pas fait le saut d'une manière ou d'une autre, je prévoyais de passer en mode réel jusqu'à ce qu'un gestionnaire de processus soit configuré.

Donc, en supposant que je cours en mode réel, qu'est-ce que je fais de mal et comment puis-je le réparer? J'ai juste besoin d'une routine getc de base, de préférence non bloquante, mais je vais être foutu si Google apporte son aide à ce sujet. Une fois que je peux le faire, je peux faire le reste à partir de là.

Je suppose que ce que je demande ici est: suis-je près de la bonne piste? Comment fait-on généralement pour obtenir une saisie au clavier à ce niveau?

EDIT: OOhh ... alors je cours en mode protégé. Ceci explique certainement le crash essayant d’accéder alors aux fonctions du mode réel.

Alors je suppose que je cherche comment accéder au clavier IO en mode protégé. Je pourrais peut-être trouver cela par moi-même, mais si quelqu'un sait le savoir, n'hésitez pas. Merci encore.

Était-ce utile?

La solution

Si vous compilez avec gcc, sauf si vous utilisez le "Crazy" .code16gcc " truc que le noyau Linux utilise (ce dont je doute fort), vous ne pouvez pas être en mode réel. Si vous utilisez la spécification multiboot GRUB, GRUB lui-même passe en mode protégé pour vous. Ainsi, comme d'autres l'ont fait remarquer, vous devrez parler directement au contrôleur clavier / souris compatible 8042. Sauf si c'est un clavier / souris USB et que l'émulation 8042 est désactivée, vous aurez besoin d'une pile USB (mais vous pouvez utiliser le protocole "boot" pour le clavier / souris, ce qui est plus simple).

Personne n'a dit qu'écrire un noyau de système d'exploitation était simple.

Autres conseils

Le code que vous avez là tente d'accéder à un service BIOS en mode réel. Si vous utilisez le mode protégé, qui considère probablement que vous écrivez un noyau, l'interruption ne fonctionnera pas. Vous devrez effectuer l’une des opérations suivantes:

  • Amenez le processeur en mode réel en vous assurant que le tableau des vecteurs d'interruption est correct et utilisez le code en mode réel que vous avez ou
  • Écrivez votre propre gestionnaire de clavier en mode protégé (utilisez les instructions d'entrée / sortie).

La première solution impliquera une surcharge de performances d'exécution tandis que la seconde nécessitera des informations sur les E / S du clavier.

J'ai un morceau de GeekOS qui semble faire

In_Byte(KB_CMD);

et ensuite

In_Byte(KB_DATA);

pour récupérer un scancode. Je l'ai mis en place: keyboard.c et keyboard.h . KB_CMD et KB_DATA étant respectivement 0x64 et 0x60. Je pourrais peut-être aussi préciser que cela se fait dans un gestionnaire d'interruptions pour intr: 1.

Vous faites le bon choix, mais je crois me rappeler que djgpp génère uniquement une sortie en mode protégé, à partir de laquelle vous ne pouvez pas appeler d'interruptions. Pouvez-vous passer en mode réel comme d'autres l'ont suggéré ou préférez-vous vous adresser directement au matériel?

À des fins d’explication, supposons que vous écriviez vous-même tout dans le langage assembleur, le chargeur de démarrage et le noyau (* cough * je l’ai fait).

En mode réel, vous pouvez utiliser les routines d'interruption provenant du BIOS. Vous pouvez également remplacer les vecteurs d'interruption par les vôtres. Cependant, tout le code est un code 16 bits, ce qui n'est pas compatible binaire avec un code 32 bits.

Lorsque vous parcourez quelques étapes ardues pour accéder au mode protégé (y compris la reprogrammation du contrôleur d'interruption, afin de contourner le fait qu'IBM a utilisé des interruptions réservées par Intel sur le PC), vous avez la possibilité de configurer les paramètres 16 et Segments de code 32 bits. Ceci peut être utilisé pour exécuter du code 16 bits. Vous pouvez donc l'utiliser pour accéder à l'interruption getchar!

... pas tout à fait. Pour que cette interruption fonctionne, vous avez besoin de données dans un tampon de clavier introduit par un autre ISR, celui qui est déclenché par le clavier lorsque vous appuyez sur une touche. Plusieurs problèmes vous empêchent d'utiliser les ISR du BIOS comme des ISR matériels en mode protégé. Les routines du clavier du BIOS sont donc inutiles.

Par contre, les appels vidéo dans le BIOS sont acceptables, car il n’ya pas de composant déclenché par le matériel. Vous devez préparer un segment de code 16 bits, mais s'il est sous contrôle, vous pouvez basculer entre les modes vidéo et ce genre de choses en utilisant les interruptions du BIOS.

Retour au clavier: ce dont vous avez besoin (encore une fois en supposant que vous écrivez tout le code), c’est d’écrire un pilote de clavier. À moins que vous ne soyez masochiste (j'en suis un), n'y allez pas.

Une suggestion: essayez d’écrire un noyau multitâche en mode réel. (C'est le mode 16 bits.) Vous pouvez utiliser toutes les interruptions du BIOS! Vous ne bénéficiez pas de la protection de la mémoire, mais vous pouvez toujours effectuer un traitement multitâche préemptif en raccordant l'interruption du minuteur.

Juste une idée: en regardant la source GRUB pour DOS (asm.s), le < La fonction code> console_checkkey utilise le BIOS INT 16H, fonction 01 , et non la fonction 00, comme vous essayez de le faire. Peut-être voudriez-vous vérifier si une clé est en attente de saisie.

Le code console_checkkey définit le processeur en mode réel pour pouvoir utiliser le BIOS, comme @ skizz suggéré .

Vous pouvez également essayer d'utiliser les fonctions GRUB directement (si elles sont encore mappées en mode réel).

Remarque sur la lecture de la source de l'assembly: dans cette version

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

signifie déplacer l'octet constant (0x1) pour enregistrer % ah

La clé_checkkey console de GRUB asm.s:

<*>

Exemple d'interrogation du contrôleur de clavier:

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
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top