2012-06-13 3 views
0

J'essaie d'écrire un chargeur de démarrage simple.Passage en mode protégé du segment chargé

Je voudrais charger boot0 en mode réel, passer à boot0 et charger le noyau complet à partir de là. Passez ensuite en mode protégé et exécutez le code noyau.

Jusqu'à présent, j'ai:

;First segment loaded by BIOS: 
bits 16 
org 0 
jmp 0x07c0:start 
start: 
mov ax, cs 
mov ds, ax 
mov es, ax 

mov al, 0x03 
mov ah, 0 
int 0x10 

mov si, welcome_msg 
call print 

mov ax, 0x500 ;load boot0 to 0x500 
mov es, ax  ;value should be in es 
mov cl, 2 ;sector number to be loaded 
mov al, 4 ;number of sectors to load 
call loadsector 

jmp 0x500:0000 

loadsector: 
mov bx, 0 
mov dl, 0 ;load from floppy=0 
mov dh, 0 
mov ch, 0 
mov ah, 2 
int 0x13 
jc error 
ret 

times 510 - ($-$$) db 0 
dw 0xaa55 

Suivant 4 segments comme boot0:

bits 16 
org 0 
mov ax, cs 
mov ds, ax 
mov es, ax 
mov ax, 0x7000 
mov ss, ax 
mov sp, ss 

;Printing from tutorial 
mov  ax,0xb800  ; Load gs to point to video memory 
mov  gs,ax   ; We intend to display a brown A in real mode 
mov  word [gs:80],0x0248 ; displaymov word [gs:0],0x641 ; display 
mov  word [gs:82],0x0145 ; displaymov word [gs:0],0x641 ; display 
mov  word [gs:84],0x034C ; displaymov word [gs:0],0x641 ; display 
mov  word [gs:86],0x044C ; displaymov word [gs:0],0x641 ; display 
mov  word [gs:88],0x054F ; displaymov word [gs:0],0x641 ; display 
;load kernel system 
mov ax, 0x2000 
mov es, ax 
mov cl, 6 ;after boot0 will be full kernel 
mov al, 4 ;for now only 4 sectors 
call loadsector ;load kernel 
jmp protected_mode_run 

loadsector: 
mov bx, 0 
mov dl, floppy 
mov dh, 0 
mov ch, 0 
mov ah, 2 
int 0x13 
jc error 
ret 

protected_mode_run: 
cli 
lgdt [gdtr] 
mov  eax,cr0 ; The lsb of cr0 is the protected mode bit 
or  al,0x01 ; Set protected mode bit 
mov  cr0,eax ; Mov modified word to the control register 
jmp  codesel:go_pm 

bits 32 
go_pm: 
mov  ax,datasel 
mov  ds,ax ; Initialise ds & es to data segment 
mov  es,ax 
mov  ax,videosel ; Initialise gs to video memory 
mov  gs,ax 
mov  word [gs:0],0x741 ; Display white A in protected mode 
spin: jmp spin ; Loop 
;TODO: instead jump to loaded code here 

bits 16 
gdtr: 
dw  gdt_end-gdt-1 ; Length of the gdt 
dd  0x500+gdt ; physical address of gdt 

gdt: 
nullsel equ $-gdt ; $->current location,so nullsel = 0h 
gdt0:   ; Null descriptor,as per convention gdt0 is 0 
dd 0  ; Each gdt entry is 8 bytes, so at 08h it is CS 
dd 0  ; In all the segment descriptor is 64 bits 

codesel equ $-gdt ; This is 8h,ie 2nd descriptor in gdt 
code_gdt: ; Code descriptor 4Gb flat segment at 0000:0000h 
dw  0x0ffff ; Limit 4Gb bits 0-15 of segment descriptor 
dw  0x0000 ; Base 0h bits 16-31 of segment descriptor (sd) 
db  0x00 ; Base addr of seg 16-23 of 32bit addr,32-39 of sd 
db  0x09a ; P,DPL(2),S,TYPE(3),A->Present bit 1,Descriptor 
; privilege level 0-3,Segment descriptor 1 ie code 
db  0x0cf ; Upper 4 bits G,D,0,AVL ->1 segment len is page 
; granular, 1 default operation size is 32bit seg 
; Lower nibble bits 16-19 of segment limit 
db  0x00 ; Base addr of seg 24-31 of 32bit addr,56-63 of sd 

datasel equ $-gdt ; ie 10h, beginning of next 8 bytes for data sd 
data_gdt: ; Data descriptor 4Gb flat seg at 0000:0000h 
dw  0x0ffff ; Limit 4Gb 
dw  0x0000 ; Base 0000:0000h 
db  0x00 ; Descriptor format same as above 
db  0x092 
db  0x0cf 
db  0x00 

videosel equ $-gdt ; ie 18h,next gdt entry 
dw  3999 ; Limit 80*25*2-1 
dw  0x8000 ; Base 0xb8000 
db  0x0b 
db  0x92 ; present,ring 0,data,expand-up,writable 
db  0x00 ; byte granularity 16 bit 
db  0x00 
gdt_end: 

times 2048 - ($-$$) db 0 

Saisie en mode protégé fonctionne très bien lorsque je tente de le faire à partir de premier segment chargé à partir du BIOS. Toute tentative de faire des accidents de segments chargés à la ligne "jmp codesel: go_pm"

Structure d'un fichier est: 1 segment - initialisation 4 segments - boot0 (chargé à 0x500 segment) 4 segments - noyau (chargé en segment 0x2000)

J'ai seulement changé "dd 0x500 + gdt, adresse physique de gdt" dans GDT mais cela ne semble pas suffisant. Pourriez-vous me dire quoi d'autre devrais-je changer ou fournir une référence où je pourrais lire plus de détails sur GDT et passer en mode protégé?

Merci

Répondre

1

Le premier problème est ici:

gdtr: 
dw  gdt_end-gdt-1 ; Length of the gdt 
dd  0x500+gdt ; physical address of gdt 

gdt: 

0x500 est le segment en mode réel, mais où est-ce que le début de segment dans la mémoire physique? À 0x5000, n'est-ce pas? Alors, pourquoi 0x500+gdt?

Le deuxième problème est ici:

bits 16 
org 0 
... 
jmp  codesel:go_pm 

bits 32 
go_pm: 
... 
code_gdt: ; Code descriptor 4Gb flat segment at 0000:0000h 
dw  0x0ffff ; Limit 4Gb bits 0-15 of segment descriptor 
dw  0x0000 ; Base 0h bits 16-31 of segment descriptor (sd) 
db  0x00 ; Base addr of seg 16-23 of 32bit addr,32-39 of sd 
db  0x09a ; P,DPL(2),S,TYPE(3),A->Present bit 1,Descriptor 
; privilege level 0-3,Segment descriptor 1 ie code 
db  0x0cf ; Upper 4 bits G,D,0,AVL ->1 segment len is page 
; granular, 1 default operation size is 32bit seg 
; Lower nibble bits 16-19 of segment limit 
db  0x00 ; Base addr of seg 24-31 of 32bit addr,56-63 of sd 

Vous définissez le segment de code 32 bits en commençant à l'adresse physique 0, mais l'adresse de votre code 32 bits 0 correspond à 0x5000 d'adresse physique. Pourquoi? Parce que vous l'avez demandé avec org 0 et en chargeant votre code à 0x500: 0. Vous avez le même problème [en attente de se produire] avec le segment de données.

J'ai remarqué quelque chose d'autre suspect:

mov ax, 0x7000 
mov ss, ax 
mov sp, ss 

Êtes-vous sûr de vouloir SS = SP = 0x7000? Je ne peux pas dire que c'est faux (je n'ai pas fait tout le calcul), mais SS et SP ne sont pas la même chose et les charger avec la même valeur semble certainement étrange.

Tous les détails nécessaires sont décrits dans les manuels de processeurs Intel/AMD. Tout ce que vous avez à faire est de comprendre ce genre de choses et de faire attention à ce que vous faites pour éviter les bugs comme les deux ci-dessus.

Questions connexes