;NOM = KERNEL.ASM : noyau de ESIos
;CLASSE = SYSTEME - DEVELOPPEMENT - ESIOS
;OBJET = Programme illustrant la segmentation et la pagination sous x86
;HOWTO = Exécuter le makefile pour compiler ce fichier
;AUTEUR = J.C. Jaumain
;PARTICIPATION : Mr Vanderseypen, 3G (2011-2012)
;BUGS = On ne connait pas la longueur de l'instruction qui provoque l'int GP
; = On ne teste pas RPL/DPL
; = On ne teste pas l'utilisation d'un descripteur inéxistant
; = int GP détruit EAX
; = L'adresse des routine d'int doit être en 0x1xxxx
;==========================================================================
%define DELAY 4000000000
[BITS 32]
;==========================================================================
; KERNEL CHARGE : ce programme est en 0x10000
;==========================================================================
MOV ESI,txt_kernelLoad+0x10000
CALL affmessSuite
;==========================================================================
; Affiche la table des index des interruptions (TI) et un caractère (LI)
; correspondant, si cette interruption est gérée.
; G = global protection, P = page fault, H = horloge, C = clavier,
; E : Exception autre, I : IRQ autre, S : interruption autre,
; R : exécution du programme.
;==========================================================================
MOV ESI,TI+0x10000
MOV EDI,0xB8000
MOV BH,0xF
CALL affmessColor ; TI en ligne 0
MOV ESI,LI+0x10000
MOV EDI,0xB8000+80*2 ; LI en ligne 1
MOV BH,0xF
CALL affmessColor
;===========================================================================
; Chargement de la table des interruptions
;===========================================================================
LIDT [idtptr+0x10000]
MOV ESI,txt_interruptTableLoad+0x10000
CALL affmessSuite
;===========================================================================
; Initialisation du pic
;===========================================================================
CALL InitPic
MOV ESI,txt_picInit+0x10000
CALL affmessSuite
;=========================================================================
; Creation de la directory (table des pages de niveau 1) en 0x20000
;=========================================================================
Dir: MOV EAX,0x21003 ; 0x21000 = addr TP | 3 (bits RW+P)
MOV EDI,0x20000 ; 0x20000 = addr directory
MOV [EDI],EAX
; -------------
MOV ECX,1023 ; 1023 autres
MOV EAX,0 ; entrées
.autre: ADD EDI,4 ; sont
MOV [EDI],EAX ; à zéro
LOOP .autre ; et absentes
;==========================================================================
; creation de la première table des pages de niveau 2 en 0x21000
;==========================================================================
TP: MOV ECX,1024 ; | Toutes les entrées i de cette table
MOV EAX,3 ; | sont complététes avec le numéro de page i
MOV EDI,0x21000 ; | et sont présentes en mémoire
.entree:MOV [EDI],EAX ; | et sont accesibles en R/W (valeur 3
ADD EAX,0x1000 ; | signifie que les 2 derniers bits sont à 1
ADD EDI,4 ; | => l'E.A. est en RAM aux même adesses
LOOP .entree ; | Correction : Pour notre test, la page 14
MOV dword [0x21000+4*0x14],0 ; n'est pas en mémoire (entrée à 0)
MOV ESI,txt_pageTableCreate+0x10000
CALL affmessSuite
;============================================================================
; activation de la pagination
;============================================================================
MOV EAX,0x20003 ; | adresse de la directory (20+003) dans le
MOV CR3,EAX ; | registre CR3 (3 = 11b ==> R/W et Présent)
MOV EAX,CR0 ; | mise à 1 du bit 31
OR EAX,0x80000000 ; | dans CR0 ( => bit 31 de CR0 mis à 1
MOV CR0,EAX ; | signifie pagination active)
;============================================================================
; Rétablissement des interruptions
;============================================================================
STI
MOV ESI,txt_stiPageActiv+0x10000
CALL affmessSuite
;============================================================================
; AFFICHAGE D'UN MESSAGE EN UTILISANT LE DESCRIPTEUR 3, ligne 21, position 1..4
; RAPPEL : base=0xB8000; limite=80*25*2=0xFA0 bytes; DPL 00; data; expand up; rw
;============================================================================
MOV ESI,txt_segmentBase+0x10000
CALL affmessSuite
MOV AX,11000b ; index 3, GDT, RPL=00
MOV ES,AX
MOV byte [ES:80*21*2+1*2],'3'
MOV byte [ES:80*21*2+1*2+1],0x09
MOV byte [ES:80*21*2+2*2],':'
MOV byte [ES:80*21*2+2*2+1],0x09
MOV byte [ES:80*21*2+3*2],'O'
MOV byte [ES:80*21*2+3*2+1],0x09
MOV byte [ES:80*21*2+4*2],'K'
MOV byte [ES:80*21*2+4*2+1],0x09
CALL tempo
;============================================================================
; AFFICHAGE D'UN MESSAGE EN UTILISANT LE DESCRIPTEUR 4, ligne 21, position 6..9
; RAPPEL : base=0xB8000; limite=40*25*2=0x780 bytes; DPL 00; data; expand up; rw
;============================================================================
MOV ESI,txt_segmentOutOfLimit+0x10000
CALL affmessSuite
MOV AX,100000b ; index 4, GDT, RPL=00
MOV ES,AX
MOV byte [ES:80*21*2+6*2],'4'
MOV byte [ES:80*21*2+6*2+1],0x09
MOV byte [ES:80*21*2+7*2],':'
MOV byte [ES:80*21*2+7*2+1],0x09
MOV byte [ES:80*21*2+8*2],'K'
MOV byte [ES:80*21*2+8*2+1],0x09
MOV byte [ES:80*21*2+9*2],'O'
MOV byte [ES:80*21*2+9*2+1],0x09
CALL tempo
;============================================================================
; AFFICHAGE D'UN MESSAGE EN UTILISANT LE DESCRIPTEUR 5, ligne 21, posit.11..14
; RAPPEL : base=0xB8000; limite=80*25*2=0xFA0 bytes; DPL 00; data; expand up; r
;============================================================================
MOV ESI,txt_segmentReadOnly+0x10000
CALL affmessSuite
MOV AX,101000b ; index 5, GDT, RPL=00
MOV ES,AX
MOV byte [ES:80*21*2+11*2],'5'
MOV byte [ES:80*21*2+11*2+1],0x09
MOV byte [ES:80*21*2+12*2],':'
MOV byte [ES:80*21*2+12*2+1],0x09
MOV byte [ES:80*21*2+13*2],'K'
MOV byte [ES:80*21*2+13*2+1],0x09
MOV byte [ES:80*21*2+14*2],'O'
MOV byte [ES:80*21*2+14*2+1],0x09
CALL tempo
;============================================================================
; Appel d"une procédure en 0x14000 pour provoquer le défaut de page
;============================================================================
MOV ESI,txt_programLoad+0x10000 ; Message défaut de page
CALL affmessSuite
CALL tempo
CALL 0x8:0x14000 ; appel de la procédure en page 14
;=============================================================================
; Programme principal
; boucle infinie qui affiche un compteur temporisé en ligne 2, position 78
;=============================================================================
MOV ESI,txt_backMain+0x10000
CALL affmessSuite
prog: MOV EBX,54
CALL IncrInt
CALL tempo
MOV AX,15 ; la mémoire renvoie le code de DIV CX dans RI
MOV CX,0 ; avec AX = 15, CX = 0
DIV CX ; IP est incrémenté de la longueur de l'instruction
; AX est divisé par CX, cela créer une exception de type
; division par zéro ce qui provoque une interruption
JMP prog
;=============================================================================
;ROUTINE : InitPic
;OBJECTIF : Initialise les PIC pour les adapter à l'électronique du P.C.
;=============================================================================
InitPic:MOV AL,0x11 ; 00010001 (icw4 utile)
OUT 0x20,AL ; dans icw1
OUT 0xA0,AL ; de l'esclave aussi
MOV AL,32 ; IRQ 0 en 32, ...
OUT 0x21,AL ; dans icw2
MOV AL,40 ; IRQ 8 en 40...
OUT 0xA1,AL ; de l'esclave aussi
MOV AL,0x4 ; patte 4
OUT 0x21,AL ; dans icw3
MOV AL,0x2 ; patte 4
OUT 0xA1,AL ; de l'esclave aussi
MOV AL,0x1 ; 00000001 (défaut)
OUT 0x21,AL ; dans icw4
OUT 0xA1,AL ; de l'esclave aussi
MOV AL,0x0 ; aucun masque
OUT 0x21,AL
OUT 0xA1,AL ; pour l'esclave aussi
RET
;=============================================================================
;ROUTINE : tempo
;OBJECTIF : Effectue une temporisation
;=============================================================================
tempo: PUSH ECX
MOV ECX,DELAY
.temp LOOP .temp
POP ECX
RET
;=============================================================================
;ROUTINE : affmessColor
;OBJECTIF : Affiche un texte à 0 final
;ARGUMENTS :
; ESI : adresse du message, détruit
; EDI : endroit ou commence le texte sur l'ecran, détruit
; BH : couleur du texte
;=============================================================================
affmessColor:
PUSH AX
.aff: MOV AL,[ESI]
CMP AL,0
JE .fin
MOV [EDI],AL
INC EDI
MOV byte [EDI],BH
INC EDI
INC ESI
JMP .aff
.fin: POP AX
RET
;=============================================================================
;ROUTINE : affmessSuite
;OBJECTIF : Affiche un texte à 0 final en blanc, à la ligne suivante
;ARGUMENTS : ESI : adresse du message, détruit
;VARIABLES : currentLine (initialisé à 5.)
;=============================================================================
affmessSuite:
PUSH AX
PUSH EDI
PUSH EBX
MOV EDI,[currentLine+0x10000]
MOV BH,0xF
CALL affmessColor
MOV EDI,[currentLine+0x10000]
ADD EDI,80*2
MOV [currentLine+0x10000],EDI
POP EBX
POP EDI
POP AX
RET
;=============================================================================
;ROUTINE : IncrInt
;OBJECTIF : Affiche et incrémente le compteur
;ARGUMENTS : EBX : numéro du compteur (0..54)
;VARIABLES : Cpt
;=============================================================================
IncrInt:PUSH ESI
PUSH EAX
MOV ESI,Cpt
ADD ESI,EBX
MOV AL, [ESI+0x10000] ; Le compteur numéro EBX dans AL
INC AL
CMP AL, '9'
JBE .continue
MOV AL,'0'
.continue:
MOV byte [ESI+0x10000], AL ; Modification du compteur en mémoire
MOV ESI,0xB8000+80*2*2 ; | Affichage du compteur en ligne 2,
ADD ESI,EBX ; | position EBX
ADD ESI,EBX ; | *2 car code couleur à l'affichage
MOV byte [ESI],AL ; | en couleur verte.
MOV byte [ESI+1],0x0A ; |
POP EAX
POP ESI
RET
;=============================================================================
; ROUTINES D'INTERRUPTION
;=============================================================================
defEX: PUSH EBX
MOV EBX,52 ; routine par défaut pour les exceptions
CALL IncrInt
POP EBX
IRET
defIRQ: PUSH EBX
MOV EBX,53 ; routine par défaut pour les IRQ
CALL IncrInt
MOV AL,0x20
OUT 0X20,AL ; fin d'IRQ pour le PIC
POP EBX
IRET
defSYS: PUSH EBX
MOV EBX,54 ; routine par défaut pour les appels système
CALL IncrInt
POP EBX
IRET
gp: PUSH EBX
MOV EBX,13 ; routine pour 'global protection': détruit EAX
CALL IncrInt
POP EBX
ADD ESP,4 ; Elimination du code d'erreur déposé sur la pile
POP EAX ; | Modification de l'adresse de retour pour que IRET
ADD EAX, 8 ; | retourne vers l'instruction qui suit celle qui a
PUSH EAX ; | provoqué l'interruption (assume 8 bytes (BUG))
IRET
pf: PUSH EBX
PUSH ESI
PUSH EAX
MOV EBX,14 ; routine pour page fault
CALL IncrInt
MOV ESI,txt_pageFault+0x10000 ; Message
CALL affmessSuite
MOV dword [0x21000+4*0x14],0x11003 ; La page 14 présente, en page 11
MOV EAX,0x20000 ; | Raffraichissement de la mémoire associative (cache)
MOV CR3,EAX ; | en réécrivant l'adresse de la directory.
MOV ESI,txt_pageCorrect+0x10000 ; Message
CALL affmessSuite
POP EAX
POP ESI
POP EBX
ADD ESP,4 ; Elimination du code d'erreur déposé sur la pile
IRET
divzero:
PUSH EBX
PUSH ESI
MOV EBX,0 ; routine pour 'division par zéro'
CALL IncrInt
MOV ESI,txt_divzero+0x10000 ; Message de division par zéro
CALL affmessSuite
POP ESI
POP EBX
ADD ESP,4 ; Elimination du code d'erreur déposé sur la pile
POP EAX ; | Modification de l'adresse de retour pour que IRET
ADD EAX, 8 ; | retourne vers l'instruction qui suit celle qui a
PUSH EAX ; | provoqué l'interruption (assume 8 bytes (BUG))
IRET
horlog: PUSH EBX
MOV EBX,32 ; routine pour l'IRQ horloge
CALL IncrInt
POP EBX
MOV AL,0x20
OUT 0X20,AL ; fin d'IRQ pour le PIC
IRET
clavier:PUSH EBX ; routine pour l'IRQ clavier
.checkp:IN AL,0x64 ; lecture du statut
XOR AL,0x01 ; pret?
JZ .checkp ; on boucle tant que pas pret
IN AL,0x60 ; lecture du scan code
MOV EBX,33
CALL IncrInt
POP EBX
MOV AL,0x20
OUT 0X20,AL ; fin d'IRQ pour le PIC
IRET
;=============================================================================
; TABLE D'INTERRUPTION
;=============================================================================
; table idt : 4 champs
; addresse routine : 16 derniers bits, (offset dans ce programme)
; segment CS de cette routine,
; code 'routine d'interruption'
; addresse routine : 16 premiers bits, (1 car programme en 0x10000)
; 0..31 : exceptions, 32..47 : IRQ, 48..255 : Utilisateur (INT)
idt: dw divzero,0x0008,0x8E00,0x1 ;0 division par zéro
dw defEX,0x0008,0x8E00,0x1 ;1 debug exception
dw defEX,0x0008,0x8E00,0x1 ;2 NMI
dw defEX,0x0008,0x8E00,0x1 ;3 Break point
dw defEX,0x0008,0x8E00,0x1 ;4 INTO
dw defEX,0x0008,0x8E00,0x1 ;5 Bound
dw defEX,0x0008,0x8E00,0x1 ;6 invalid opcode
dw defEX,0x0008,0x8E00,0x1 ;7 Device not available
dw defEX,0x0008,0x8E00,0x1 ;8 Double fault
dw defEX,0x0008,0x8E00,0x1 ;9 Copro segment overrun
dw defEX,0x0008,0x8E00,0x1 ;10 Invalid task state segment
dw defEX,0x0008,0x8E00,0x1 ;11 segment not present
dw defEX,0x0008,0x8E00,0x1 ;12 stack segment fault
dw gp,0x0008,0x8E00,0x1 ;13 general protection
dw pf,0x0008,0x8E00,0x1 ;14 page fault
dw defEX,0x0008,0x8E00,0x1 ;15 Reserved Intel
dw defEX,0x0008,0x8E00,0x1 ;16 Floating point error
dw defEX,0x0008,0x8E00,0x1 ;17 Alignement check
dw defEX,0x0008,0x8E00,0x1 ;18 machine check
dw defEX,0x0008,0x8E00,0x1 ;19 Reserved Intel
dw defEX,0x0008,0x8E00,0x1 ;20 Reserved Intel
dw defEX,0x0008,0x8E00,0x1 ;21 Reserved Intel
dw defEX,0x0008,0x8E00,0x1 ;22 Reserved Intel
dw defEX,0x0008,0x8E00,0x1 ;23 Reserved Intel
dw defEX,0x0008,0x8E00,0x1 ;24 Reserved Intel
dw defEX,0x0008,0x8E00,0x1 ;25 Reserved Intel
dw defEX,0x0008,0x8E00,0x1 ;26 Reserved Intel
dw defEX,0x0008,0x8E00,0x1 ;27 Reserved Intel
dw defEX,0x0008,0x8E00,0x1 ;28 Reserved Intel
dw defEX,0x0008,0x8E00,0x1 ;29 Reserved Intel
dw defEX,0x0008,0x8E00,0x1 ;30 Reserved Intel
dw defEX,0x0008,0x8E00,0x1 ;31 Reserved Intel
dw horlog,0x0008,0x8E00,0x1 ;32 Timer
dw clavier,0x0008,0x8E00,0x1 ;33 Clavier
dw defIRQ,0x0008,0x8E00,0x1 ;34 Controleur esclave
dw defIRQ,0x0008,0x8E00,0x1 ;35 série 2
dw defIRQ,0x0008,0x8E00,0x1 ;36 série 1
dw defIRQ,0x0008,0x8E00,0x1 ;37 // 2
dw defIRQ,0x0008,0x8E00,0x1 ;38 diskette
dw defIRQ,0x0008,0x8E00,0x1 ;39 // 1
dw defIRQ,0x0008,0x8E00,0x1 ;40 Reserved IRQ
dw defIRQ,0x0008,0x8E00,0x1 ;41 Reserved IRQ
dw defIRQ,0x0008,0x8E00,0x1 ;42 Reserved IRQ
dw defIRQ,0x0008,0x8E00,0x1 ;43 Reserved IRQ
dw defIRQ,0x0008,0x8E00,0x1 ;44 Reserved IRQ
dw defIRQ,0x0008,0x8E00,0x1 ;45 Copro
dw defIRQ,0x0008,0x8E00,0x1 ;46 disk
dw defIRQ,0x0008,0x8E00,0x1 ;47 Reserved IRQ------
dw defSYS,0x0008,0x8E00,0x1 ;48
dw defSYS,0x0008,0x8E00,0x1 ;49
dw defSYS,0x0008,0x8E00,0x1 ;50
idtend:
;=============================================================================
; A PLACER DANS LE REGISTRE IDTR QUI POINTE VERS LA TABLE D'INTERRUPTION
;=============================================================================
idtptr:
dw idtend - idt ; limite
dd idt + 0x10000 ; base
;=============================================================================
; VARIABLES SYSTEME
;=============================================================================
;Textes
;------
txt_kernelLoad DB 'Chargement du kernel',0
txt_interruptTableLoad DB 'Chargement de la table des interruptions',0
txt_picInit DB 'Initialisation du pic',0
txt_pageTableCreate DB 'Creation des tables de pages',0
txt_stiPageActiv DB 'Activation interruptions et pagination',0
txt_segmentBase DB 'Utilisation du descripteur 3 pour affichage',0
txt_segmentOutOfLimit DB 'Protection globale : depassement de limite',0
txt_segmentReadOnly DB 'Protection globale : ecriture interdite',0
txt_programLoad DB 'Execution du programme a la page 0x14',0
txt_pageFault DB 'Warning : PAGE FAULT',0
txt_pageCorrect DB 'Maj de la table des pages : 0x14 en 0x11',0
txt_backMain DB 'Retour au programme principal',0
txt_divzero DB 'Division par zero',0
;Variables utilitaires
;---------------------
TI DB '012345678901234567890123456789012345678901234567890----',0
LI DB '-------------GP-----------------HC-----------------EISR',0
currentLine DD 0xB8000+5*80*2 ; première ligne de message
Cpt times 55 db '0' ; Les 55 compteurs d'interruption
;=============================================================================
; Remplissage par des NOP afin que la suite se trouve à l'adresse 0x11000
; quand tout ce code sera chargé en mémoire à l'adresse 0x10000.
; (0x11000 est 0x1000 plus loin que 0x10000)
;=============================================================================
times 0x1000-($-$$) db 144
;=============================================================================
; La procédure qui se trouve en 0x11000 et qui sera appelée par CALL 0x8:0x14000
; Comme la table des pages contient 11 à l'index 14, cette routine sera exécutée
; Cette routine affiche HELLO à la ligne 22, colonne 50.
;=============================================================================
MOV byte [0xB8000+80*22*2+50*2],'H'
MOV byte [0xB8000+80*22*2+50*2+1],0x09
MOV byte [0xB8000+80*22*2+50*2+2],'E'
MOV byte [0xB8000+80*22*2+50*2+3],0x0A
MOV byte [0xB8000+80*22*2+50*2+4],'L'
MOV byte [0xB8000+80*22*2+50*2+5],0x03
MOV byte [0xB8000+80*22*2+50*2+6],'L'
MOV byte [0xB8000+80*22*2+50*2+7],0x03
MOV byte [0xB8000+80*22*2+50*2+8],'O'
MOV byte [0xB8000+80*22*2+50*2+9],0x0B
RET