Autor Thema: protected-mode, kernel laden, reihenfolge  (Gelesen 6585 mal)

middle_endian

  • Beiträge: 25
    • Profil anzeigen
Gespeichert
« am: 23. July 2007, 15:24 »
hi,
kurz zur ausgangslage. bis jetzt sieht der ablauf meines codes so aus:
- bootloader wird vom ersten sektor der diskette nach 0x7c00 geladen
- der kernel, der direkt hinter dem bootloader im zweiten sektor der diskette liegt, wird eingelesen
- lgdt [gdt_desc] wird ausgeführt
- jump in den protected-mode
- lidt [idt_desc] wird ausgeführt
- es wird zum zuvor geladenen kernel gesprungen
das funktioniert alles wunderbar. das problem ist jetzt folgendes. die interrupt service routinen sind bis jetzt natürlich im bootloader, da ich ja im bootloader die idt lade. nun würd ich aber gern das switchen in den protected mode, sowie das laden der gdt/idt in den kernel verlagern, damit ich meine interrupt-service-routinen im kernel definieren kann.
ich hab also den funktionierenden code hergenommen und anders auf bootloader und kernel verteilt. also:

bootloader:
- laden des kernels(nach 0x1000)
- springen zum kernel

kernel:
- interrupts deaktivieren
- lgdt [gdt_desc]                  <-- nach diesem befehl steht im gdt-register nichts drinnen(base=0, limit=0)
- jump in den protected mode (funktioniert damit natürlich nicht)
was stimmt da nicht?
würde diese "neue" reihenfolge der ausführung überhaupt funktionieren bzw macht sie sinn?

nooooooooos

  • Beiträge: 734
    • Profil anzeigen
Gespeichert
« Antwort #1 am: 23. July 2007, 19:08 »
Ich finde sie macht Sinn...Darum hab ich sie auch so implementiert und bei mir funktioniert sie...Gib uns mal etwas Code am Design kanns nicht liegen.

Gruss
Nooooooooooos

middle_endian

  • Beiträge: 25
    • Profil anzeigen
Gespeichert
« Antwort #2 am: 23. July 2007, 19:37 »
also hier der minimalistische bootloader
%include "config32.asm"

[BITS 16]
org 0x7c00

init:
                xor ax, ax
                mov ds, ax
                mov es, ax

mov ax, 0100h
mov ss, ax
mov ax, stack
mov sp, ax ; relative adressing to stack segment

mov [bootdrv], dl
                call load            ; load kernel

;; jump to kernel
mov ax, KERNEL_ADR
push ax
xor ax, ax
push ax
retf
     

;; kernel-loading routine
load:
push ds
mov ax, 0 ; reset function
mov dl, [bootdrv] ; what drive?
int 13h ; interrupt
pop ds
jc load

.loop0:
mov ax, KERNEL_ADR
mov es, ax ; buffer address for reading
xor bx, bx ;  offset = 0

;; read in sectors
mov ah, 2 ; read function
mov al, 1 ; 1 sectors
mov cx, 2 ; cylinder = 0, sector = 2
xor dx, dx ; head = 0, drive = 0
int 13h ; es:bx = 0x1000 (internal multiplication with 16)
jc .loop0
ret


bootdrv db 0

;; little realmode stack
         resd 64
stack:

times 510-($-$$) db 0
      dw 0aa55h
;; size = 512B

und hier der relevante teil vom kernel

%include "config32.asm"

[BITS 16]

start:
      ;; setup stack
      xor ax, ax
      mov ds, ax
      mov es, ax
      mov ds, ax
      mov esp, stack

  ;; set gdt
      cli
      lgdt [gdt_desc]
      mov eax, cr0
      or eax, 1
      mov cr0, eax
      jmp dword gdt_code:pmode   ; far jump reloads the cs register and flushes
                           ; the real-mode instructions from the prefetch queue     

[BITS 32]
pmode:
      ;; all register except of cs still contain 16bit values
      ;; -> put valid selectors into ds, ss and es
      ;; setup stack
      mov ax, gdt_data
      mov ds, ax
      mov ss, ax
      mov es, ax
      mov esp, stack

      lidt [idt_desc]            ; load idt

      ;; ...
      jmp $


;; ---------------------------
;; interrupt service routines
;; ---------------------------
void_isr
      mov eax, FRAME_BUFFER
      mov dword [eax], ':-( '
      jmp $
     
isr_test:
      mov eax, FRAME_BUFFER
      mov dword [eax], ':-) '
      iret



msg db "test message ..."

;; kernel stack
   resd 1024
stack:

;; ------------------------
;; global descriptor table
;; ------------------------
;; 8B/descriptor, 8192 descriptors maximum -> 64KB max size
gdt:
      dd 0
      dd 0

gdt_code equ $-gdt
      dw 0ffffh         ; limit 0:15
      dw 0              ; base 0:15
      db 0              ; base 16:23
      db 10011010b      ; present, ring 0 priv(2bit), code segment, executable, non-conforming, readable
      db 11001111b      ; page-granular, 32-bit, ..., limit 16:19(1111)
      db 0              ; base 24:31

gdt_data equ $-gdt
      dw 0ffffh
      dw 0
      db 0
      db 10010010b      ; data segment(bit4)
      db 11001111b
      db 0
gdt_end:

;; gdt descriptor
gdt_desc:
      dw gdt_end-gdt-1
      dd gdt

;; ---------------------------
;; interrupt descriptor table
;; ---------------------------
;; idt descriptor
idt_desc:
      dw idt_end-idt-1
      dd idt

idt:
%rep 32
      dw void_isr   
      dw gdt_code    ; gdt selector
      db 0           ; always zero
      db 8eh         ; access, attributes
      dw 0           ; void_isr >> 16 == 0
%endrep

      dw isr_test
      dw gdt_code
      db 0
      db 8eh
      dw 0
idt_end:

times ((2880*512-512)-($-$$)) db 0      ; complete floppy disk for bochs

der far-jump in den protected mode hat einen triple-fault zur folge.

00000904030e[CPU  ] fetch_raw_descriptor: GDT: index (f)1 > limit (0)
00000904030e[CPU  ] interrupt(): gate descriptor is not valid sys seg
00000904030e[CPU  ] interrupt(): gate descriptor is not valid sys seg
00000904030i[CPU  ] protected mode
00000904030i[CPU  ] CS.d_b = 16 bit
00000904030i[CPU  ] SS.d_b = 16 bit
00000904030i[CPU  ] | EAX=00000011  EBX=00000000  ECX=00130002  EDX=00000000
00000904030i[CPU  ] | ESP=00001137  EBP=00000000  ESI=000088f0  EDI=0000ffde
00000904030i[CPU  ] | IOPL=0 id vip vif ac vm RF nt of df if tf sf zf af PF cf
00000904030i[CPU  ] | SEG selector     base    limit G D
00000904030i[CPU  ] | SEG sltr(index|ti|rpl)     base    limit G D
00000904030i[CPU  ] |  CS:1000( 1e00| 0|  0) 00010000 0000ffff 0 0
00000904030i[CPU  ] |  DS:0000( 0000| 0|  0) 00000000 0000ffff 0 0
00000904030i[CPU  ] |  SS:0100( 0000| 0|  0) 00001000 0000ffff 0 0
00000904030i[CPU  ] |  ES:0000( 0000| 0|  0) 00000000 0000ffff 0 0
00000904030i[CPU  ] |  FS:0000( 0000| 0|  0) 00000000 0000ffff 0 0
00000904030i[CPU  ] |  GS:0000( 0000| 0|  0) 00000000 0000ffff 0 0
00000904030i[CPU  ] | EIP=00000020 (00000020)
00000904030i[CPU  ] | CR0=0x00000011 CR1=0 CR2=0x00000000
00000904030i[CPU  ] | CR3=0x00000000 CR4=0x00000000
00000904030i[CPU  ] >> jmp far 0008:00000028 : 66EA280000000800
00000904030e[CPU  ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
00000904030i[SYS  ] bx_pc_system_c::Reset(SOFTWARE) called
00000904030e[CPU  ] CPU_LOOP bx_guard.interrupt_requested=1
Next at t=904030
(0) [0x00010020] 1000:0020 (unk. ctxt): jmp far 0008:00000028     ; 66ea280000000800
« Letzte Änderung: 23. July 2007, 19:50 von middle_endian »

bluecode

  • Beiträge: 1 391
    • Profil anzeigen
    • lightOS
Gespeichert
« Antwort #3 am: 23. July 2007, 20:17 »
1. dein Kernel ist mit Sicherheit größer als 512Byte, dann musst du das im bootloader natürlich auch anpassen
2. du verwendest kein org im kernel, ist dein code wirklich bei 0x0?  :wink: -> org 0x1000 einfügen
lightOS
"Überlegen sie mal 'nen Augenblick, dann lösen sich die ganzen Widersprüche auf. Die Wut wird noch größer, aber die intellektuelle Verwirrung lässt nach.", Georg Schramm

middle_endian

  • Beiträge: 25
    • Profil anzeigen
Gespeichert
« Antwort #4 am: 24. July 2007, 07:33 »
der hund muss leider wo anders begraben liegen. selbst wenn ich den stack-bereich derart verkleinere (oder auf ne höhere adresse auslagere), dass die 512B grenze nicht überschritten wird, funktionierts nicht. auf das org 0x1000 ändert nichts.
fehlt mir vielleicht irgend eine initialisierung im kernel oder verändert sich durch den far jump vom bootloader in den kernel irgendwas, was vor dem laden der gdt berücksichtigt werden muss?

EDIT: habs jetzt hingekriegt. org 0x10000 zusammen mit dem korrekten setzen des datensegments am beginn des kernels haben gefehlt. also:
[BITS 16]
org KERNEL_ADR << 4   ; internal multiplication by 16

start:
      cli
      mov ax, cs
      mov ds, ax           ; set ds to cs
      mov sp, stack

  ;; set gdt
      lgdt [gdt_desc]
      mov eax, cr0
      or eax, 1
      mov cr0, eax
      jmp dword 0x8:pmode   ; far jump reloads the cs register and flushes

      ; ....
« Letzte Änderung: 24. July 2007, 08:34 von middle_endian »

bluecode

  • Beiträge: 1 391
    • Profil anzeigen
    • lightOS
Gespeichert
« Antwort #5 am: 24. July 2007, 08:31 »
Ist dein Kernel bei 0x1000 oder 0x10000? Dein Kommentar sagt 0x1000, aber dein Code sagt was anderes :wink:  Was genau ist KERNEL_ADR?
lightOS
"Überlegen sie mal 'nen Augenblick, dann lösen sich die ganzen Widersprüche auf. Die Wut wird noch größer, aber die intellektuelle Verwirrung lässt nach.", Georg Schramm

middle_endian

  • Beiträge: 25
    • Profil anzeigen
Gespeichert
« Antwort #6 am: 24. July 2007, 08:35 »
siehe oben, war zu langsam beim editieren :)

bluecode

  • Beiträge: 1 391
    • Profil anzeigen
    • lightOS
Gespeichert
« Antwort #7 am: 24. July 2007, 08:47 »
genau das hätte ich danach auch vorgeschlagen. Schön, dass du es selbst hingekriegt hast. :-)
lightOS
"Überlegen sie mal 'nen Augenblick, dann lösen sich die ganzen Widersprüche auf. Die Wut wird noch größer, aber die intellektuelle Verwirrung lässt nach.", Georg Schramm

middle_endian

  • Beiträge: 25
    • Profil anzeigen
Gespeichert
« Antwort #8 am: 24. July 2007, 09:11 »
hab jetzt allerdings noch ein problem mit der idt. meine isr wird nämlich nicht aufgerufen

%include "config32.asm"

[BITS 16]
org KERNEL_ADR << 4    ; internal multiplication by 16

start:
      cli
      mov ax, cs
      mov ds, ax           ; set ds to cs
      mov sp, STACK_ADR

   ;; set gdt
      lgdt [gdt_desc]
      mov eax, cr0
      or eax, 1
      mov cr0, eax
      jmp dword gdt_code:pmode   ; far jump reloads the cs register and flushes


[BITS 32]
pmode:
      ;; all register except of cs still contain 16bit values
      ;; -> put valid selectors into ds, ss and es
      ;; setup stack
      mov ax, gdt_data
      mov ds, ax
      mov ss, ax
      mov es, ax
      mov esp, STACK_ADR

      lidt [idt_desc]            ; load idt
      int 20h                     
      jmp $


;; ---------------------------
;; interrupt service routines
;; ---------------------------
void_isr
      mov eax, FRAME_BUFFER
      mov dword [eax], ':-( '
      jmp $
     
isr_test:
      mov eax, FRAME_BUFFER
      mov dword [eax], ':-) '
      iret
     

;; ------------------------
;; global descriptor table
;; ------------------------
;; 8B/descriptor, 8192 descriptors maximum -> 64KB max size
gdt:
      dd 0
      dd 0

gdt_code equ $-gdt
      dw 0ffffh         ; limit 0:15
      dw 0              ; base 0:15
      db 0              ; base 16:23
      db 10011010b      ; present, ring 0 priv(2bit), code segment, executable, non-conforming, readable
      db 11001111b      ; page-granular, 32-bit, ..., limit 16:19(1111)
      db 0              ; base 24:31

gdt_data equ $-gdt
      dw 0ffffh
      dw 0
      db 0
      db 10010010b      ; data segment(bit4)
      db 11001111b
      db 0
gdt_end:

;; gdt descriptor
gdt_desc:
      dw gdt_end-gdt-1
      dd gdt


;; ---------------------------
;; interrupt descriptor table
;; ---------------------------
;; idt descriptor
idt_desc:
      dw idt_end-idt-1
      dd idt

idt:
%rep 32
      dw void_isr    ;
      dw gdt_code    ; gdt selector
      db 0           ; always zero
      db 8eh         ; access, attributes
      dw 0           ; void_isr >> 16 == 0
%endrep

      dw isr_test
      dw gdt_code
      db 0
      db 8eh
      dw 0
idt_end:


;; kernel stack
;resd 128
;stack:

msg db "test message ..."
times ((2880*512-512)-($-$$)) db 0 ;

beim aufruf des interrupts springt er mir nach 0x8:0xfd55. er sollte allerdings nach 0x8:0x1003b springen.
der code ist vom prinzip her wieder mit dem früheren code, in dem alles im bootloader gemacht wurde, identisch.
was passt da jetzt schon wieder nicht?

EDIT: problem behoben. durch den sprung des kernels nach 0x10000 reicht das einfache zuweisen der isr in der idt nicht mehr aus, da ich mit 2B adressen nicht mehr auskomm. hab also nach dem laden der idt (testweise) folgendes gemacht:

      mov eax, isr_test
      mov [idt], ax
      shr eax, 16
      mov [idt+6], ax
« Letzte Änderung: 24. July 2007, 09:25 von middle_endian »

 

Einloggen