Hallo liebe Lowlevel-Community!
Bereits vor etwa einem Jahr habe ich mich mit ein bisschen mit OS-Dev beschäftigt und hier auch schon eine Frage gestellt. Ein wenig später hab ich allerdings meine Ubuntu-Installation geschrottet. Neulich habe ich mir dann wieder Ubuntu eingerichtet und wieder begonnen.
Wie auch immer, ich stehe gerade vor einem (wahrscheinlich meiner unendlichen Dummheit zuzuschreibendem) Problem:
Nach Aktivierung der Interrupts mittels "sti" gibts einen Triple Fault -> CPU Reset. Leider lässt sich der Fehler schwer finden, denn gdb braucht offensichtlich Interrupts für Breakpoints.
Als Codebasis habe ich eine Kombination von Lowlevel-Wiki-Tutorials, OS-Dev.org-Wiki-Tutorials und was man noch alles so im Netz findet.
%macro idtentry 1
dw ((%1 - $$) + SECTIONBASE) & 0xFFFF
dw 0x08
db 0x0
db 0b10001110
dw (((%1 - $$) + SECTIONBASE) >> 16) & 0xFFFF
%endmacro
%macro handler 1
extern handler_%1
int_stub_%1:
push dword 0x0
push dword %1
push ebp
push edi
push esi
push edx
push ecx
push edx
push esp
call handler_%1
add esp, 0x4
pop eax
pop ebx
pop ecx
pop edx
pop esi
pop edi
pop ebp
add esp, 0x8
iret
%endmacro
%macro handler_errorcode 1
extern handler_%1
int_stub_%1:
push dword %1
push ebp
push edi
push esi
push edx
push ecx
push edx
push esp
call handler_%1
add esp, 0x4
pop eax
pop ebx
pop ecx
pop edx
pop esi
pop edi
pop ebp
add esp, 0x8
iret
%endmacro
%macro handler_irq_low 1
extern handler_%1
int_stub_%1:
push dword 0x0
push dword %1
push ebp
push edi
push esi
push edx
push ecx
push edx
push esp
call handler_%1
add esp, 0x4
pop eax
pop ebx
pop ecx
pop edx
pop esi
pop edi
pop ebp
add esp, 0x8
mov al, 0x20
out 0x20, al
iret
%endmacro
%macro handler_irq_high 1
extern handler_%1
int_stub_%1:
push dword 0x0
push dword %1
push ebp
push edi
push esi
push edx
push ecx
push edx
push esp
call handler_%1
add esp, 0x4
pop eax
pop ebx
pop ecx
pop edx
pop esi
pop edi
pop ebp
add esp, 0x8
mov al, 0x20
out 0xA0, al
out 0x20, al
iret
%endmacro
global loader
extern main
MODULEALIGN equ 1<<0 ; align loaded modules on page boundaries
MEMINFO equ 1<<1 ; provide memory map
FLAGS equ MODULEALIGN | MEMINFO ; this is the Multiboot 'flag' field
MAGIC equ 0x1BADB002 ; magic number
CHECKSUM equ -(MAGIC + FLAGS) ; checksum
SECTIONBASE equ 0x0100000
section .text
align 4
dd MAGIC
dd FLAGS
dd CHECKSUM
STACKSIZE equ 0x4000 ; 16k
loader:
cli
mov esp, stack + STACKSIZE
lgdt [cs:GDTR]
jmp 0x08:shortjmp
shortjmp:
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
lidt [cs:IDTR]
mov al, 0x11
out 0x20, al
call io_wait
mov al, 0x20
out 0x21, al
call io_wait
mov al, 0x04
out 0x21, al
call io_wait
mov al, 0x01
out 0x21, al
call io_wait
mov al, 0x11
out 0xa0, al
call io_wait
mov al, 0x28
out 0xa1, al
call io_wait
mov al, 0x02
out 0xa1, al
call io_wait
mov al, 0x01
out 0xa1, al
call io_wait
xor al, al
out 0x20, al
call io_wait
out 0xa0, al
call io_wait
sti
int 0x30 ; als Testinterrupt mit Textausgabe. Triple Fault gibts aber auch so (PIT)
;push eax ; Multiboot magic number
;push ebx ; Multiboot info structure
call main
hang:
hlt
jmp hang
io_wait:
jmp dly
dly: ret
handler 0
;...
handler 48
GDTR:
dw GDT_END-GDT-1
dd GDT
GDT:
dd 0x0, 0x0
db 0xFF, 0xFF, 0x0, 0x0, 0x0, 0b10011010, 0b11001111, 0x0
db 0xFF, 0xFF, 0x0, 0x0, 0x0, 0b10010010, 0b11001111, 0x0
;db 0xFF, 0xFF, 0x0, 0x0, 0x0, 0b11111010, 0b11001111, 0x0 ; zu Fehlersuchzwecken auskommentiert
;db 0xFF, 0xFF, 0x0, 0x0, 0x0, 0b11110010, 0b11001111, 0x0
GDT_END:
IDTR:
dw 49 * 8 - 1
dd IDT
IDT:
idtentry int_stub_0
;...
idtentry int_stub_48
section .bss
align 4
stack:
resb STACKSIZE
Außerdem noch: kernel.c (mit void main, nichts besonderes) und handler.c (mit Handlern, derzeit ohne wirklichen Inhalt)
Wichtig! Verwendet wird SYSLINUX, nicht GRUB!
Kompiliert mit
CC =gcc
CFLAGS =-Wall -Werror -Wextra -Wshadow -Wconversion -Wunreachable-code -Werror-implicit-function-declaration -Wuninitialized -nostdlib -nostartfiles -nodefaultlibs -ffreestanding -fno-builtin -m32 -g3
LDFLAGS =-m elf_i386
AS =nasm
LD =ld
all:kernel.bin
kernel.bin:
$(AS) -f elf -o loader.elf loader.S
$(CC) $(CFLAGS) -o kernel.elf -c kernel.c
$(CC) $(CFLAGS) -o handler.elf -c handler.c
$(LD) $(LDFLAGS) -T linker.ld -o kernel.bin loader.elf kernel.elf handler.elf
objcopy --only-keep-debug kernel.elf kernel.sym
objcopy --strip-debug kernel.elf
[...]
Der Linkerscript ist "Standard".
Zum Ausführen nehme ich eine Variante des folgenden Scriptes:
wiki.osdev.org/Bare_BonesDen Reset gibt es nur bei eingeschalteten Interrupts. Ohne wird void main ordnungsgemäß aus geführt.
Hoffe, ich habe mein Problem verständlich erklärt und keine Information vergessen.