Precedent | Sommaire | Suivant

B. Code de BosoKernel en assembleur

Le code ci-dessous correspond au premier projet que j'ai realise, initialement sans utiliser le langage C.

Le fichier bootsect.asm contient le programme du secteur de boot decrit dans les chapitres precedents :

%define CS_ACCES        10011011b
%define DS_ACCES        10010011b
%define	BASE			0x100	; 0x0100:0x0 = 0x1000

[BITS 16]
[ORG 0x0]

jmp start

%include "../kernel/UTIL.INC"
%include "../kernel/GDT.INC"

start:
	mov [bootdrv],dl	; recuparation de l'unite de boot

; initialisation des segments en 0x07C0
	mov ax,0x07C0
	mov ds,ax
	mov es,ax
	mov ax,0x8000	; stack en 0xFFFF
	mov ss,ax
	mov sp, 0xf000

; affiche un msg
	mov si,msgDebut
	call afficher

; charger le noyau
	xor ax,ax
	int 0x13

	push es
	mov ax,BASE
	mov es,ax
	mov bx,0
	
	mov ah,2
	mov al,KSIZE
	mov ch,0
	mov cl,2
	mov dh,0
	mov dl,[bootdrv]
	int 0x13
	pop es

; ouverture de la porte a20
a20:
	in al,0x64	; teste si on peut envoyer une commande
	test al,2
	jnz a20

	mov al,0xD1
	out 0x64,al
	jmp .1		; temporisation
.1:
	in al,0x64	; teste si on peut envoyer une commande
	test al,2
	jnz .1

	mov al,0xDF
	out 0x60,al
a20end:


; initialisation de la gdt
; descInit base(32),limite(20/32),acces(8),flags(4/8),adresse(16)
	descInit 0,0xFFFFF,CS_ACCES,1101b,gdt_cs
	descInit 0,0xFFFFF,DS_ACCES,1101b,gdt_ds

; initialisation du pointeur sur la gdt
	mov ax,gdtend	; calcule la limite de gdt
	mov bx,gdt
	sub ax,bx
	mov word [gdtptr],ax

	xor eax,eax		; calcule l'adresse lineaire de gdt
	mov ax,ds
	mov bx,gdt
	call calcadr
	mov dword [gdtptr+2],ecx

; passage en modep
	cli
	lgdt [gdtptr]	; charge la gdt
	mov eax,cr0
	or	ax,1
	mov cr0,eax		; PE mis a 1 (CR0)

	jmp next
next:
	mov ax,0x10		; segment de donne
	mov ds,ax
	mov fs,ax
	mov gs,ax
	mov es,ax
	mov ss,ax
	mov esp,0x9F000	

	jmp dword 0x8:0x1000

end:
	jmp end


msgDebut	db	"Chargement du kernel",13,10,0

gdt:
gdt_null:
	dw 0,0,0,0
gdt_cs:
	dw 0,0,0,0
gdt_ds:
	dw 0,0,0,0
gdtend:

gdtptr:
	dw	0x0000		; limite
	dd	0			; base

bootdrv: db 0

;; NOP jusqu'a 510
times 510-($-$$) db 144
dw 0xAA55

Le fichier main.asm correspond au code du noyau. Ce noyau n'est qu'a un stade embryonnaire. Il utilise un modele d'adressage lineaire (flat model). Les interruptions sont gerees (reprogrammation du controleur d'interruption, mise en place de la table des descripteurs d'interruption, etc.). Un mecanisme d'appels systemes est en place. De nombreuses routines d'affichage sont realisees ainsi que le pilote pour le clavier (qwerty) :

%define CS_ACCES	10011011b
%define DS_ACCES	10010011b
%define SS_ACCES	10010111b

%define GDTBASE		0x800
%define	IDTBASE		0x0

%define CS_LIM		0xFFFFF	; limite en blocs de 4 ko !
%define DS_LIM		0xFFFFF	; = 4 Go comme limite superieure.
%define SS_LIM		0x10	; = 0x10000 comme limite inferieure.
%define	STACKPTR	0x1FFFF	; adresse de depart de esp

%define MAXAPPELS	100


[BITS 32]
[ORG 0x1000]

jmp start

%include "GDT.INC"
%include "aff.asm"
%include "pic.asm"
%include "irq.asm"

start:
; initialisation de la gdt 
; descInit base(32),limite(20/32),acces(8),flags(4/8),adresse(16)
	descInit 0,CS_LIM,CS_ACCES,1101b,gdt_cs
	descInit 0,DS_LIM,DS_ACCES,1101b,gdt_ds
	descInit 0,SS_LIM,SS_ACCES,1101b,gdt_ss
	descInit 0xB8000,4000,DS_ACCES,0101b,gdt_screen		; ram ecran

; initialisation de gdtptr
	mov ax,gdtend	; calcule la limite de gdt
	mov bx,gdt
	sub ax,bx
	mov word [gdtptr],ax

	mov eax,GDTBASE		; adresse lineaire de gdt
	mov dword [gdtptr+2],eax

; initialisation de idtptr
	mov ax,idtend
	mov bx,idt
	sub ax,bx
	mov word [idtptr],ax

	mov eax,IDTBASE
	mov dword [idtptr+2],eax	

; recopie de la gdt a son adresse
	xor ecx,ecx
	xor esi,esi
	xor edi,edi
	mov	cx,word [gdtptr]	; charge la limite
	mov esi,gdt
	mov edi,GDTBASE
	rep movsb

; recopie de la idt a son adresse
	xor ecx,ecx
	xor esi,esi
	xor edi,edi
	mov	cx,word [idtptr]
	mov esi,idt
	mov edi,IDTBASE
	rep movsb

; chargement de la idt et de la nouvelle gdt
	lidt [idtptr]	; charge l'idt
	lgdt [gdtptr]	; charge la gdt

; initialisation des segments
	jmp next
next:
	mov ax,0x10		; segment de donne
	mov ds,ax
	mov es,ax
	mov fs,ax
	mov gs,ax
	mov ax,0x18		; pile
	mov ss,ax
	mov esp,STACKPTR

; un petit message
	call clrscr
	mov esi,msg00
	call print

; initialisation des interruptions
	cli
	call init_pic	; fichier pic.asm
	call init_irq	; fichier irq.asm
	sti

	mov esi,msg01
	call print

; initialisation des appels systemes
	gateInit 0x8,syscalls,TRAP_FLAG+PRESENT_F,0,GDTBASE+0x28		; selecteur,offset,wc,adresse

	mov esi,msg03
	call print


; KERNEL
	mov eax,2		; utilisation des appels systemes pour afficher un message
	mov esi,msg04
	int 0x80
end:
	jmp end
;-------------------------------------------------------------------


;-------------------------------------------------------------------
; ROUTINES APPELS SYSTEMES
; Entree:
;	eax -> numero de fonction
;	ebx,ecx,edx -> arguments
;	esi,edi -> autres arguments
;-------------------------------------------------------------------
syscalls:
	push ebx
	push ecx
	push edx
	call [systab+4*eax]
	pop ebx
	pop ecx
	pop edx
	iret
end_syscalls:

systab:
	dd scrollup
	dd gotoxy
	dd print
end_systab:


;-------------------------------------------------------------------
; DONNEES 
;-------------------------------------------------------------------

;-------------------------------------------------------------------
; table gdt
;-------------------------------------------------------------------
gdt:
gdt_null:			; 0x0
	dw 0,0,0,0
gdt_cs:				; 0x8
	dw 0,0,0,0
gdt_ds:				; 0x10
	dw 0,0,0,0
gdt_ss:				; 0x18
	dw 0,0,0,0
gdt_screen:			; 0x20
	dw 0,0,0,0
gdt_call_gate:		; 0x28
	dw 0,0,0,0
gdtend:

;-------------------------------------------------------------------
; table idt
;-------------------------------------------------------------------
idt:
	times 256 dw 0,0,0,0
idtend:

;-------------------------------------------------------------------
; pointeur sur gdt
;-------------------------------------------------------------------
gdtptr:
	dw	0x0000		; limite
	dd	0			; base

;-------------------------------------------------------------------
; pointeur sur idt
;-------------------------------------------------------------------
idtptr:
	dw	0x0000		; limite
	dd	0			; base

;-------------------------------------------------------------------
; MESSAGES
;-------------------------------------------------------------------
msg00: db 'mode protege',10,0
msg01: db 'interruptions etablies',10,0
msg02: db '.',0
msg03: db 'appels systemes etablis',10,0
msg04: db 'debug : ceci prouve que les appels systemes sont ok',10,0

Le fichier UTIL.INC contient des fonctions utiles en vrac :

;---------------------------------------------------------
; Synopsis:	Affiche une chaine de caracteres se terminant par 0x0
; Entree:	ds:si -> pointe sur la chaine a afficher
;---------------------------------------------------------
afficher:
	push ax
	push bx
.debut:
	lodsb		; ds:si -> al
	cmp al,0	; fin chaine ?
	jz .fin
	mov ah,0x0E	; appel au service 0x0e, int 0x10 du bios
	mov bx,0x07	; bx -> attribut, al -> caractere ascii
	int 0x10
        jmp .debut

.fin:
	pop bx
	pop ax
	ret
;---------------------------------------------------------

;---------------------------------------------------------
; Synopsis: conversion de chaine hexa en ascii
; Entree:
;	ds:si -> chaine hexa
;	cx -> nombre d'octets a convertir
; Sortie:
;	es:di -> chaine ascii terminee par '0x0'
;---------------------------------------------------------
hex2a:
	push ax
	push bx
	push dx
.debut:
	xor ax,ax
	xor bx,bx
	xor dx,dx
	lodsb
    ror ax,4
	mov bl,al
	mov dl,byte [tableau+bx]
	mov byte [es:di],dl
	inc di
    rol ax,4
	and al,0x0F
    mov bl,al
	mov dl,byte [tableau+bx]
	mov byte [es:di],dl
	inc di
    loop .debut
	mov byte [es:di],0

	pop dx
	pop bx
	pop ax
	ret

tableau db '0123456789ABCDEF'
;---------------------------------------------------------

Le fichier GDT.INC contient des fonctions permettant d'initialiser les descripteurs de segments et les descripteurs systemes :

;--------------------------------------------------------------------
; CalcAdr
; Entree:
;	ax -> segment
;	bx -> offset
; Sortie:
;	ecx -> adresse lineaire sur 32 bits
; Modifie: partie haute de ebx
;--------------------------------------------------------------------
calcadr:
	xor ecx,ecx
	mov cx,ax
	shl ecx,4
	and ebx,0x0000FFFF
	add ecx,ebx
	ret
;--------------------------------------------------------------------

;--------------------------------------------------------------------
; descInit
;--------------------------------------------------------------------
%macro descInit	5	; base(32),limite(20/32),acces(8),flags(4/8),adresse(32)
	push eax
; base :
	mov eax,%1
	mov word [%5+2],ax
	shr eax,16
	mov byte [%5+4],al
	shr eax,8
	mov byte [%5+7],al
; limite :
	mov eax,%2
	and eax,0x000FFFFF
	mov word [%5],ax	; ecrit (0..15)
	shr eax,16			; place (16..19) sur le nibble inferieur
	mov byte [%5+6],0	; initialise flags+lim(16..19) a 0
	or [%5+6],al		; ecrit (16..19)
; flags :
	mov al,%4
	and al,0x0F
	shl al,4
	or [%5+6],al
; acces :
	mov byte [%5+5],%3
	pop eax
%endmacro
;--------------------------------------------------------------------


%define LDT_FLAG	0x2		; ldt
%define TASK_FLAG	0x5		; task gate
%define TSS_FLAG	0x9		; TSS
%define CALL_FLAG	0xC		; call gate
%define INT_FLAG	0xE		; interrupt gate
%define TRAP_FLAG	0xF		; trap gate

%define PRESENT_F	0x80	; present flag
%define	DPL0	0x00
%define	DPL1	0x20
%define	DPL2	0x40
%define	DPL3	0x60

;--------------------------------------------------------------------
; intdesc
;--------------------------------------------------------------------
%macro gateInit	5	; selecteur(16),offset(32),type (8),wc(5/8),adresse(32)
	push eax
; selecteur :
	mov word [%5+2],%1
; offset :
	mov eax,%2
	mov word [%5],ax
	shr eax,16
	mov word [%5+6],ax
; type :
	mov byte [%5+5],%3
; wc :
	mov byte [%5+4],%4
	and byte [%5+4],00011111b
	pop eax
%endmacro
;--------------------------------------------------------------------

Le fichier aff.asm contient les routines d'affichage (affichage de chaines de caracteres, scrolling, effacage de l'ecran...) :

%define RAMSCREEN 0xB8000
%define SIZESCREEN 0xFA0; = 4000, nombres d'octets d'une page texte
%define SCREENLIM 0xFA0	; Si un octet >= SCREENLIM, il n'est pas dans 
						; la ram ecran.

;-----------------------------------------------------------------
; Entree:	
;	1er arg -> nombre de lignes a scroller (de 0 a 25)
;-----------------------------------------------------------------
scrollup:
	push ebp
	mov ebp,esp
	push eax
	push ebx
	push ecx
	push edx
	push esi
	push edi
	push ds
	push es

	xor edi,edi		; desination = 0xB8000:0
	mov eax,[ebp+8]		; nombre de lignes a scroller

; Decrementation de X
	cmp byte [ds:X],al		; si X < n
	jb .azero				; alors X->0
	sub byte [ds:X],al		; sinon X->X-n
	jmp .load
.azero:
	mov byte [ds:X],0

.load:
	push eax
	mov ax,0x20		; gdt_screen
	mov ds,ax
	mov es,ax
	pop eax

	push eax
	mov eax,0
	push eax
	call getpos		; calcul l'offset en ram de la ligne a scroller
	pop eax
	pop eax
	mov esi,edx		; esi -> offset en ram ecran a ramener a l'origine.
	push esi	; valeur qui servira pour le remplissage

	mov ecx,SIZESCREEN
	sub ecx,esi		; ecx -> nombre d'octets a recopier
	push ecx	; valeur qui servira pour le remplissage

	rep movsb		; transfere esi vers edi

	pop edi
	pop ecx
.remplissage:		; rempli le bas de l'ecran avec \0
	mov byte [edi],0
	inc edi	
	dec ecx
	jnz .remplissage
	
	pop es
	pop ds
	pop edi
	pop esi
	pop edx
	pop ecx
	pop ebx
	pop eax
	pop ebp
	ret
;-----------------------------------------------------------------
; Pour afficher une chaine de caracteres 
; Entree:
;	ds:esi  -> chaine terminee par \0
;-----------------------------------------------------------------
print:
	push ebp
	mov ebp,esp
	push eax
	push ebx
	push ecx
	push edx
	push esi
	push edi
	push ds
	push es

	xor eax,eax
	mov al,byte [X]		; position du curseur en argument
	push eax
	mov al,byte [Y]		
	push eax
	call getpos		; retourne dans edx position dans la ram
	pop eax
	pop eax
	mov edi,edx		; edi -> pointe sur offset en ram ecran du curseur

	mov ax,0x20
	mov es,ax

.afficher:
	lodsb
	cmp al,0	; teste si fin de chaine
	jz .fin			; si oui, fin.
	cmp al,0xa
	jz .cr_nl
	jmp .car
.cr_nl:
	mov byte [Y],79
	jmp .fin_afficher
.car:
	mov	byte [es:edi],al	; sinon, copie d'un caractere...
	inc edi
	mov byte al,[ds:XYattr]
	mov byte [es:edi],al	; ... et de l'attribut.
	inc edi
.fin_afficher:

.incrementeXY:
	add byte [Y],1			; on incremente Y
	cmp byte [Y],80			; si Y < 80
	jb .finIncrementeXY		; alors on affiche le caractere suivant
	mov byte [Y],0			; sinon, Y->0 et X->X+1
	add byte [X],1			; Note : si X>24, le scrolling mettra X a 24
.finIncrementeXY:

.testeLimites:
	xor eax,eax
	mov al,byte [X]		; position du curseur en argument
	push eax
	mov al,byte [Y]		
	push eax
	call getpos		; retourne dans edx position dans la ram
	pop eax
	pop eax
	mov edi,edx		; edi -> pointe sur offset en ram ecran du curseur

	cmp edi,SCREENLIM	; teste si on depasse les limites de l'ecran
	jb .afficher		; si non, on continue
	sub edi,160			; si oui, scrolle d'une ligne ...
	push byte 1	
	call scrollup
	pop eax			; on recupere la variable passe par le push
	jmp .afficher	; et on continue
	
.fin:
	pop es
	pop ds
	pop edi
	pop esi
	pop edx
	pop ecx
	pop ebx
	pop eax
	pop ebp
	ret

;-----------------------------------------------------------------
; Entree: 
;	1er arg -> x (0 a 24).
;	2e arg  -> y (0 a 79).
;-----------------------------------------------------------------
gotoxy:
	push ebp
	mov ebp,esp
	push eax

	mov eax,[ebp+8]		; recupere la valeur de y
	mov byte [Y],al	; mise a jour de 'curY'
	mov eax,[ebp+12]	; recupere la valeur de x
	mov byte [X],al	; mise a jour de 'curX'

	pop eax
	pop ebp
	ret

;-----------------------------------------------------------------
; Entree: 
;	1er arg -> x (0 a 24).
;	2e arg  -> y (0 a 79).
; Retour: 
;	edx -> offset a partir du debut de la ram ecran.
;-----------------------------------------------------------------
getpos:
	push ebp
	mov ebp,esp
	push ecx
	push ebx
	push eax

	mov ebx,[ebp+8]		; recupere la valeur de y
	shl ebx,1			; y*2

	mov eax,[ebp+12]	; recupere la valeur de x
	mov ecx,eax
	shl eax,7			; x*128
	shl ecx,5			; x*32
	add eax,ecx			; x*128+x*32 = x*160

	add eax,ebx			; eax -> x*160+y*2
	mov edx,eax

	pop eax
	pop ebx
	pop ecx
	pop ebp
	ret

;-----------------------------------------------------------------
; Entree: 
;	al -> attribut
;-----------------------------------------------------------------
color:
	mov byte [XYattr],al
	ret
;-----------------------------------------------------------------

;-----------------------------------------------------------------
; Pour afficher une chaine de caracteres 
; Entree:
;	1er argument -> caractere a afficher
;-----------------------------------------------------------------
putcar:
	push ebp
	mov ebp,esp
	push eax
	push ebx
	push ecx
	push edx
	push esi
	push edi
	push ds
	push es

	xor eax,eax
	mov al,byte [X]		; position du curseur en argument
	push eax
	mov al,byte [Y]		
	push eax
	call getpos		; retourne dans edx position dans la ram
	pop eax
	pop eax
	mov edi,edx		; edi -> pointe sur offset en ram ecran du curseur

	mov ax,0x20
	mov es,ax

.afficher:
	mov byte al,[ebp+8]		; On recupere le caractere dans al
	cmp al,0xA				; Teste si cr-nl
	jz .cr_nl
	jmp	.car
.cr_nl:					; Retour chariot + new line
	mov byte [Y],79		; On place le curseur en fin de ligne, il sera incremente
						; par la procedure .incrementeXY
	jmp .fin_afficher
.car:					; Caracter normal a afficher
	mov byte [es:edi],al	; Copie du caractere...
	inc edi
	mov byte al,[ds:XYattr]
	mov byte [es:edi],al	; ... et de l'attribut.
	inc edi
.fin_afficher:

	.incrementeXY:
	add byte [Y],1			; on incremente Y
	cmp byte [Y],80			; si Y < 80
	jb .finIncrementeXY		; alors on affiche le caractere suivant
	mov byte [Y],0			; sinon, Y->0 et X->X+1
	add byte [X],1			; Note : si X>24, le scrolling mettra X a 24
	cmp byte [X],25
	jb .finIncrementeXY
	push byte 1	
	call scrollup
	pop eax
	.finIncrementeXY:

.fin:
	pop es
	pop ds
	pop edi
	pop esi
	pop edx
	pop ecx
	pop ebx
	pop eax
	pop ebp
	ret
;-----------------------------------------------------------------


;-----------------------------------------------------------------
; clrscr
;	Synopsis: efface l'ecran
;-----------------------------------------------------------------
clrscr:
	push dword 25
	call scrollup
	pop eax
	ret

;-----------------------------------------------------------------
X: db 10
Y: db 0
XYattr: db 0x07
;-----------------------------------------------------------------

Le fichier pic.asm contient la fonction qui programme le controleur d'interruptions pour donner une valeur correcte aux vecteurs d'interruptions materielles et masquer toutes les interruptions excepter celle du clavier :

;-------------------------------------------------------------------
; init_pic
;	Synopsys: Initialisation du 8259.
;-------------------------------------------------------------------
init_pic:

	; Maitre
master:
	mov al,0x11 ; Initialisation de ICW1
	out 0x20,al
	jmp .1    ; temps d'attente
.1:
	mov al,0x20 	; Initialisation de ICW2
	out 0x21,al		; vecteur de depart = 32
	jmp .2    ; temps d'attente
.2:
	mov al,0x04 ; Initialisation de ICW3
	out 0x21,al
	jmp .3  
.3:
	mov al,0x01 ; Initialisation de ICW4
	out 0x21,al
	jmp .4   
.4:
	mov al,0xFF ; demasquage des interruptions
	out 0x21,al

	; Esclave
slave:
	mov al,0x11 ; Initialisation de ICW1
	out 0xA0,al
	jmp .1    ; temps d'attente
.1:
	mov al,0x70 ; Initialisation de ICW2
	out 0xA1,al		; vecteur depart = 96
	jmp .2    
.2:
	mov al,0x02 ; Initialisation de ICW3
	out 0xA1,al
	jmp .3    
.3:
	mov al,0x01 ; Initialisation de ICW4
	out 0xA1,al
	jmp .4   
.4:
	mov al,0xFF ; demasquage des interruptions
	out 0xA1,al

; Masquage des irqs
	mov al,0xFD		; j'autorise seulement l'irq1 (clavier).
	out 0x21,al

	ret
;-------------------------------------------------------------------

Le fichier irq.asm initialise les differents descripteurs systemes de la table IDT gerant les interruptions. Les appels systemes sont geres a partir d'un descripteur (trap gate) de cette table :

%include "kbd.asm"

;-------------------------------------------------------------------
; init_irq
;	Synopsis: fait correspondre un handler a une ISR.
;-------------------------------------------------------------------
init_irq:
	gateInit	 0x08,interrupts,INT_FLAG+PRESENT_F,0,IDTBASE		; 0 - division par 0
	gateInit	 0x08,interrupts,INT_FLAG+PRESENT_F,0,IDTBASE+8*1	; 1 - step
	gateInit	 0x08,interrupts,INT_FLAG+PRESENT_F,0,IDTBASE+8*2 	; 2 - NMI
	gateInit	 0x08,interrupts,INT_FLAG+PRESENT_F,0,IDTBASE+8*3	; 3 - breakpoint
	gateInit	 0x08,interrupts,INT_FLAG+PRESENT_F,0,IDTBASE+8*4	; 4 - overflow
	gateInit	 0x08,interrupts,INT_FLAG+PRESENT_F,0,IDTBASE+8*5	; 5 - BOUND
	gateInit	 0x08,interrupts,INT_FLAG+PRESENT_F,0,IDTBASE+8*6	; 6 - opcode invalide
	gateInit	 0x08,interrupts,INT_FLAG+PRESENT_F,0,IDTBASE+8*7	; 7 - coproc. non valide
	gateInit	 0x08,interrupts,INT_FLAG+PRESENT_F,0,IDTBASE+8*8	; 8 - double faute
	gateInit	 0x08,interrupts,INT_FLAG+PRESENT_F,0,IDTBASE+8*9	; 9 - overrun
	gateInit	 0x08,interrupts,INT_FLAG+PRESENT_F,0,IDTBASE+8*10	;10 - task state segment invalide
	gateInit	 0x08,interrupts,INT_FLAG+PRESENT_F,0,IDTBASE+8*11	;11 - segment non present
	gateInit	 0x08,interrupts,INT_FLAG+PRESENT_F,0,IDTBASE+8*12	;12 - stack exception
	gateInit	 0x08,interrupts,INT_FLAG+PRESENT_F,0,IDTBASE+8*13	;13 - general prot. exception
	gateInit	 0x08,interrupts,INT_FLAG+PRESENT_F,0,IDTBASE+8*14	;14 - page fault
	gateInit	 0x08,interrupts,INT_FLAG+PRESENT_F,0,IDTBASE+8*15	;15 - reserve
	gateInit	 0x08,interrupts,INT_FLAG+PRESENT_F,0,IDTBASE+8*16	;16 - erreur coproc.
		; ... 
	gateInit	 0x08,irq0,INT_FLAG+PRESENT_F,0,IDTBASE+8*32	; IRQ0 - timer
	gateInit	 0x08,irq1,INT_FLAG+PRESENT_F,0,IDTBASE+8*33	; IRQ1 - keyboard
	gateInit	 0x08,irq2,INT_FLAG+PRESENT_F,0,IDTBASE+8*34	; IRQ2 cascade 
	gateInit	 0x08,irq3,INT_FLAG+PRESENT_F,0,IDTBASE+8*35	; IRQ3 - COM2 or COM4
	gateInit	 0x08,irq4,INT_FLAG+PRESENT_F,0,IDTBASE+8*36	; IRQ4 - COM1 or COM3
	gateInit	 0x08,irq5,INT_FLAG+PRESENT_F,0,IDTBASE+8*37	; IRQ5 - LPT2
	gateInit	 0x08,irq6,INT_FLAG+PRESENT_F,0,IDTBASE+8*38	; IRQ6 - floppy disk
	gateInit	 0x08,irq7,INT_FLAG+PRESENT_F,0,IDTBASE+8*39	; IRQ7 - LPT1
		; ...
	gateInit	 0x08,irq8,INT_FLAG+PRESENT_F,0,IDTBASE+8*112	; IRQ8 - real time clock
	gateInit	 0x08,irq9,INT_FLAG+PRESENT_F,0,IDTBASE+8*113	; IRQ9 - cascade
	gateInit	 0x08,irq10,INT_FLAG+PRESENT_F,0,IDTBASE+8*114	; IRQ10 - reserve
	gateInit	 0x08,irq11,INT_FLAG+PRESENT_F,0,IDTBASE+8*115	; IRQ11 - reserve
	gateInit	 0x08,irq12,INT_FLAG+PRESENT_F,0,IDTBASE+8*116	; IRQ12 - mouse
	gateInit	 0x08,irq13,INT_FLAG+PRESENT_F,0,IDTBASE+8*117	; IRQ13 - numeric coprocessor
	gateInit	 0x08,irq14,INT_FLAG+PRESENT_F,0,IDTBASE+8*118	; IRQ14 - fixed disk controller
	gateInit	 0x08,irq15,INT_FLAG+PRESENT_F,0,IDTBASE+8*119	; IRQ15 - reserve
		; ...
	gateInit	 0x08,syscalls,TRAP_FLAG+PRESENT_F,0,IDTBASE+8*128	; trap numero 0x80

	ret
;-------------------------------------------------------------------

;-------------------------------------------------------------------
; Routines interruptions (ISR)
;-------------------------------------------------------------------
interrupts:

irq0:
irq2:
irq3:
irq4:
irq5:
irq6:
irq7:
irq8:
irq9:
irq10:
irq11:
irq12:
irq13:
irq14:
irq15:
	mov al,0x20
	out 0x20,al	; EOI envoyee au PIC
	iret

irq1:
	cli
	call kbd_interrupt
	sti
	iret

end_interrupts:
;-------------------------------------------------------------------

Le fichier kbd.asm contient la routine appelee quand une interruption liee au clavier a lieu. Ce code correspond donc au driver du clavier :

; Make codes
%define LSHIFT	0x2A
%define RSHIFT	0x36
%define CTRL	0x1D
%define ALT		0x38

; Break codes
%define BRK_LSHIFT	0xAA
%define BRK_RSHIFT	0xB6
%define BRK_CTRL	0x9D
%define BRK_ALT		0xB8

;-----------------------------------------------------------------------------
; Routine d'interruption du clavier
;-----------------------------------------------------------------------------
kbd_interrupt:
	cli
	push eax
	push ebx

	xor eax,eax

.wait4buffer:		; On teste si le buffer de sortie est plein
	in al,0x64
	test byte al,1
	jz .wait4buffer	; Tant que le buffer est vide, on attend
					; REM : Il faudrait limiter le nb de loop !!!
	in al,0x60		; Lecture du scan-code
	cmp al,0x81		; On teste si c'est un breakcode
	jnb .breakcode

	.makecode:
		cmp al,LSHIFT
		jz .shift
		cmp al,RSHIFT
		jz .shift
		cmp al,CTRL
		jz .ctrl
		cmp al,0xE0
		jz .e0
		cmp al,0xE1
		jz .e1
		jmp .normal

		.normal:
			xor ebx,ebx
			dec al
			mov byte bl,[keytable+eax*4]
			push ebx
			call putcar
			pop ebx
			jmp .fin

		.shift:
			jmp .fin

		.ctrl:
			jmp .fin

		.e0:
		.e1:
			jmp .fin

	.breakcode:
		cmp al,BRK_LSHIFT
		jz .brkshift
		cmp al,BRK_RSHIFT
		jz .brkshift
		cmp al,BRK_CTRL
		jz .brkctrl
		jmp .fin

		.brkshift:
			jmp .fin

		.brkctrl:
			jmp .fin
	
.fin:
	mov al,0x20
	out 0x20,al		; EOI envoyee au PIC

	pop ebx
	pop eax
	sti

	ret

;-----------------------------------------------------------------------------
; Flags
e0flag: db 0
e1flag: db 0
sflag:	db 0	; shift
cflag:	db 0	; ctrl
aflag:	db 0	; alt

; Mappage des touches
; normal	shift	ctrl	alt		touche
keytable:
db 0x1B,	0x1B,	0x1B,	0x1B	; esc (0x01)
db '1',		'!',	'1',	'1'
db '2',		'@',	'2',	'2'
db '3',		'#',	'3',	'3'
db '4',		'$',	'4',	'4'
db '5',		'%',	'5',	'5'
db '6',		'^',	'6',	'6'
db '7',		'&',	'7',	'7'
db '8',		'*',	'8',	'8'
db '9',		'(',	'9',	'9'
db '0',		')',	'0',	'0'
db '-',		'_',	'-',	'-'
db '=', 	'+', 	'=', 	'='
db 0x08,	0x08,	0x7F,	0x08	; backspace
db 0x09,	0x09,	0x09,	0x09	; tab
db 'q',		'Q',	'q',	'q'
db 'w',		'W',	'w',	'w'
db 'e',		'E',	'e',	'e'
db 'r',		'R',	'r',	'r'
db 't',		'T',	't',	't'
db 'y',		'Y',	'y',	'y'
db 'u',		'U',	'u',	'u'
db 'i',		'I',	'i',	'i'
db 'o',		'O',	'o',	'o'
db 'p',		'P',	'p',	'p'
db '[',		'{',	'[',	'['
db ']',		'}',	']',	']'	
db 0x0A,	0x0A,	0x0A,	0x0A	; enter
db 0xFF,	0xFF,	0xFF,	0xFF	; ctrl
db 'a',		'A',	'a',	'a'	
db 's',		'S',	's',	's'	
db 'd',		'D',	'd',	'd'	
db 'f',		'F',	'f',	'f'	
db 'g',		'G',	'g',	'g'	
db 'h',		'H',	'h',	'h'	
db 'j',		'J',	'j',	'j'	
db 'k',		'K',	'k',	'k'	
db 'l',		'L',	'l',	'l'	
db ';',		':',	';',	';'	
db 0x27,	0x22,	0x27,	0x27	; '"
db '`',		'~',	'`',	'`'		; `~
db 0xFF,	0xFF,	0xFF,	0xFF	; Lshift (0x2a)
db '\',		'|',	'\',	'\'	
db 'z',		'Z',	'z',	'z'	
db 'x',		'X',	'x',	'x'	
db 'c',		'C',	'c',	'c'	
db 'v',		'V',	'v',	'v'	
db 'b',		'B',	'b',	'b'	
db 'n',		'N',	'n',	'n'	
db 'm',		'M',	'm',	'm'	
db 0x2C,	0x3C,	0x2C,	0x2C	;,<
db 0x2E,	0x3E,	0x2E,	0x2E	;.>
db 0x2F,	0x3F,	0x2F,	0x2F	;/?
db 0xFF,	0xFF,	0xFF,	0xFF	; Rshift (0x36)
db 0xFF,	0xFF,	0xFF,	0xFF	; (0x37)
db 0xFF,	0xFF,	0xFF,	0xFF	; (0x38)
db 0xFF,	0xFF,	0xFF,	0xFF	; (0x39)
db 0xFF,	0xFF,	0xFF,	0xFF	; (0x3a)
db 0xFF,	0xFF,	0xFF,	0xFF	; (0x3b)
db 0xFF,	0xFF,	0xFF,	0xFF	; (0x3c)
db 0xFF,	0xFF,	0xFF,	0xFF	; (0x3d)
db 0xFF,	0xFF,	0xFF,	0xFF	; (0x3e)
db 0xFF,	0xFF,	0xFF,	0xFF	; (0x3f)
db 0xFF,	0xFF,	0xFF,	0xFF	; (0x40)
db 0xFF,	0xFF,	0xFF,	0xFF	; (0x41)
db 0xFF,	0xFF,	0xFF,	0xFF	; (0x42)
db 0xFF,	0xFF,	0xFF,	0xFF	; (0x43)
db 0xFF,	0xFF,	0xFF,	0xFF	; (0x44)
db 0xFF,	0xFF,	0xFF,	0xFF	; (0x45)
db 0xFF,	0xFF,	0xFF,	0xFF	; (0x46)
db 0xFF,	0xFF,	0xFF,	0xFF	; (0x47)
db 0xFF,	0xFF,	0xFF,	0xFF	; (0x48)
db 0xFF,	0xFF,	0xFF,	0xFF	; (0x49)
db 0xFF,	0xFF,	0xFF,	0xFF	; (0x4a)
db 0xFF,	0xFF,	0xFF,	0xFF	; (0x4b)
db 0xFF,	0xFF,	0xFF,	0xFF	; (0x4c)
db 0xFF,	0xFF,	0xFF,	0xFF	; (0x4d)
db 0xFF,	0xFF,	0xFF,	0xFF	; (0x4e)
db 0xFF,	0xFF,	0xFF,	0xFF	; (0x4f)
db 0xFF,	0xFF,	0xFF,	0xFF	; (0x50)
db 0xFF,	0xFF,	0xFF,	0xFF	; (0x51)
db 0xFF,	0xFF,	0xFF,	0xFF	; (0x52)
db 0xFF,	0xFF,	0xFF,	0xFF	; (0x53)
db 0xFF,	0xFF,	0xFF,	0xFF	; (0x54)
db 0xFF,	0xFF,	0xFF,	0xFF	; (0x55)
db 0xFF,	0xFF,	0xFF,	0xFF	; (0x56)
db 0xFF,	0xFF,	0xFF,	0xFF	; (0x57)
db 0xFF,	0xFF,	0xFF,	0xFF	; (0x58)
db 0xFF,	0xFF,	0xFF,	0xFF	; (0x59)
db 0xFF,	0xFF,	0xFF,	0xFF	; (0x5a)
db 0xFF,	0xFF,	0xFF,	0xFF	; (0x5b)
db 0xFF,	0xFF,	0xFF,	0xFF	; (0x5c)
db 0xFF,	0xFF,	0xFF,	0xFF	; (0x5d)
db 0xFF,	0xFF,	0xFF,	0xFF	; (0x5e)
db 0xFF,	0xFF,	0xFF,	0xFF	; (0x5f)
db 0xFF,	0xFF,	0xFF,	0xFF	; (0x60)
db 0xFF,	0xFF,	0xFF,	0xFF	; (0x50)
db 0xFF,	0xFF,	0xFF,	0xFF
db 0xFF,	0xFF,	0xFF,	0xFF
db 0xFF,	0xFF,	0xFF,	0xFF
db 0xFF,	0xFF,	0xFF,	0xFF
db 0xFF,	0xFF,	0xFF,	0xFF
endkeytable: