diff --git a/Makefile b/Makefile index ec7a187..5a09c9f 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,15 @@ +#TODO make the makefile use targets instead of this mess all: nasm boot.nasm -o boot.bin nasm -f elf32 -o entry.o entry.nasm - clang -target "i686-elf" -ffreestanding -m32 -march=pentium-m -fno-stack-protector -nostdlib -c -o kernel.o kernel.c - #clang -target "i686-elf" -O2 -ffreestanding -m32 -march=i386 -fno-stack-protector -nostdlib -c -o kernel.o kernel.c - gcc -Tlink.ld -m32 -ffreestanding -nostartfiles -nostdlib -o kernel.bin entry.o kernel.o + nasm -f elf32 -o handler.o handler.nasm + nasm -f elf32 -o v86.o v86.nasm + clang -target "i686-elf" -ffreestanding -m32 -O2 -march=pentium-m -fno-stack-protector -nostdlib -c kernel.c + clang -target "i686-elf" -ffreestanding -m32 -O2 -mgeneral-regs-only -march=pentium-m -fno-stack-protector -nostdlib -c print.c + # not sure why but if interrupt.c has any optimization everything just breaks immediately + clang -target "i686-elf" -ffreestanding -m32 -mgeneral-regs-only -march=pentium-m -fno-stack-protector -nostdlib -c interrupt.c + #clang -target "i686-elf" -ffreestanding -m32 -mgeneral-regs-only -march=i386 -fno-stack-protector -nostdlib -c -o kernel.o kernel.c + gcc -Tlink.ld -m32 -ffreestanding -nostartfiles -nostdlib -o kernel.bin entry.o v86.o handler.o kernel.o print.o interrupt.o dd bs=256 count=1 conv=notrunc if=boot.bin of=virtdisk.bin dd bs=512 seek=1 conv=notrunc if=kernel.bin of=virtdisk.bin virtdisk: diff --git a/entry.nasm b/entry.nasm index 38c56a9..f36f21b 100644 --- a/entry.nasm +++ b/entry.nasm @@ -1,5 +1,4 @@ [BITS 16] - global entry entry: cli ; no interrupts @@ -22,12 +21,16 @@ mov esp, ebp mov eax, 0x1f001f00 mov ecx, (80*25)/2 mov edi, 0xb8000 -rep stosd +rep stosd ; clear screen call start hlt_loop: hlt jmp hlt_loop +extern start + +; currently unused first 8MB identity paging +; taken from Linux 0.01 setup_paging: mov ecx, 1024*3 ; 3K? xor eax, eax @@ -50,87 +53,6 @@ or eax, 0x80000000 mov cr0, eax ; set paging bit ret ; flushes pre-fetch queue -[BITS 16] -real_hexprint: -xor cx, cx -mov bl, al -shr al, 4 -jmp .donibble -.nibble2: -mov al, bl -inc cx -.donibble: -and al, 0x0F -cmp al, 0x0A -jl .noadjust -add al, 'A' - '0' - 10 -.noadjust: -add al, '0' -mov ah, 0x1f -stosw -test cx, cx -jz .nibble2 -ret -real_printword: -mov dx, ax -mov al, ah -call real_hexprint -mov ax, dx -call real_hexprint -ret -extern v86Code -v86Code: -mov ax, 0xb814 -mov es, ax -mov di, 20 -mov ax, sp -call real_printword -add di, 2 -mov ax, ds -call real_printword -add di, 2 -mov ax, cs -call real_printword -.loop: -inc byte [0] -;mov ax, 0x1111 -;mov ds, ax -;mov ax, 0x2222 -;mov es, ax -;mov ax, 0x3333 -;mov fs, ax -;mov ax, 0x4444 -;mov gs, ax -;mov ax, 0x5555 -;mov ss, ax -;mov ax, 0x6666 -;mov sp, ax -int 3 -;jmp .loop -mov ax, 0x13 -int 0x10 -int 0x30 ; exit -jmp $ -extern real_test -real_test: -nop -nop -nop -jmp $ -[BITS 32] -; extern void enter_v86(uint32_t ss, uint32_t esp, uint32_t cs, uint32_t eip); -global enter_v86 -enter_v86: -mov ebp, esp ; save stack pointer -push dword [ebp+4] ; ss -push dword [ebp+8] ; esp -pushfd ; eflags -or dword [esp], (1 << 17) ; set VM flags -;or dword [esp], (3 << 12) ; IOPL 3 -push dword [ebp+12] ; cs -push dword [ebp+16] ; eip -iret - user_test: mov dword [0xb8000], 0x0f000f00 | 'U' | 's' << 16 mov dword [0xb8004], 0x0f000f00 | 'e' | 'r' << 16 @@ -163,137 +85,6 @@ push 0x18 | 3 push user_test iret -extern unhandled_handler -unhandled_handler: -mov ax, 0x10 -mov ds, ax -mov dword [0xb8000], 0x0f000f00 | 'E' | 'R' << 16 -mov dword [0xb8004], 0x0f000f00 | 'R' | 'O' << 16 -mov dword [0xb8008], 0x0f000f00 | 'R' | '!' << 16 -.hlt: -hlt -jmp .hlt - -extern gpf_handler_v86 -global gpfHandler -gpfHandler: -iret -mov ax, 0x10 -mov ds, ax -;jmp gpf_handler_v86 -mov word [0xb8000], 0x0f00 | 'G' -mov word [0xb8002], 0x0f00 | 'P' -mov word [0xb8004], 0x0f00 | 'F' -.hlt: -hlt -jmp .hlt - -scancodesToAscii: db 0, 0 ; 0x00 - 0x01 -db "1234567890" ; 0x02 - 0x0B -db "-=" ; 0x0C - 0x0D -db 0, 0 ; 0x0E - 0x0F -db "qwertyuiop[]" ; 0x10 - 0x1B -db 0, 0 ; 0x1C - 0x1D -db "asdfghjkl;'`" ; 0x1E - 0x29 -db 0 ; 0x2A -db "\zxcvbnm,./" ; 0x2B - 0x35 -db 0 ; 0x36 -db '*' ; 0x37 -db 0 ; 0x38 -db ' ' ; 0x39 -db 'C' -scancodesToAsciiEnd: -cursorCurrent: dd 0xb8000 + (80*6*2) -global keyboardHandler -keyboardHandler: -push eax -push ebx -push ds -mov ax, 0x10 -mov ds, ax -xor eax, eax -in al, 0x60 -cmp eax, 0x3A -jg .done -mov al, [scancodesToAscii+eax] -test al, al -jz .done -mov ebx, [cursorCurrent] -mov byte [ebx], al -add dword [cursorCurrent], 2 -mov byte [KBDWAIT], 1 -.done: -mov al, 0x20 -out 0x20, al -pop ds -pop ebx -pop eax -iret - -KBDWAIT: db 0 -global kbd_wait -kbd_wait: -mov byte [KBDWAIT], 0 -.loop: -hlt -xor eax, eax -mov al, [KBDWAIT] -test eax, eax -jz .loop -ret - -global timerHandler -timerHandler: -push eax -push ds -mov ax, 0x10 -mov ds, ax -inc byte [(0xb8000 + (80*8*2))] -mov al, 0x20 -out 0x20, al -pop ds -pop eax -iret - -global picInit -picInit: -mov al, 0x11 ; initialization sequence -out 0x20, al ; send to 8259A-1 -jmp $+2 -jmp $+2 -out 0xA0, al ; and to 8259A-2 -jmp $+2 -jmp $+2 -mov al, 0x20 ; start of hardware ints (0x20) -out 0x21, al -jmp $+2 -jmp $+2 -mov al, 0x28 ; start of hardware ints 2 (0x28) -out 0xA1, al -jmp $+2 -jmp $+2 -mov al, 0x04 ; 8259-1 is master -out 0x21, al -jmp $+2 -jmp $+2 -mov al, 0x02 ; 8259-2 is slave -out 0xA1, al -jmp $+2 -jmp $+2 -mov al, 0x01 ; 8086 mode for both -out 0x21, al -jmp $+2 -jmp $+2 -out 0xA1, al -jmp $+2 -jmp $+2 -mov al, 0xFF ; all interrupts off for now -out 0x21, al -jmp $+2 -jmp $+2 -out 0xA1, al -ret - global flushTSS flushTSS: mov ax, 0x28 @@ -302,8 +93,6 @@ ret extern tss_data -extern start - gdt_desc: dw gdt_end - gdt dd gdt diff --git a/handler.nasm b/handler.nasm new file mode 100644 index 0000000..81aede4 --- /dev/null +++ b/handler.nasm @@ -0,0 +1,130 @@ +extern unhandled_handler +unhandled_handler: +mov ax, 0x10 +mov ds, ax +mov dword [0xb8000], 0x0f000f00 | 'E' | 'R' << 16 +mov dword [0xb8004], 0x0f000f00 | 'R' | 'O' << 16 +mov dword [0xb8008], 0x0f000f00 | 'R' | '!' << 16 +.hlt: +hlt +jmp .hlt + +extern gpf_handler_v86 +global gpfHandler +gpfHandler: +iret +mov ax, 0x10 +mov ds, ax +;jmp gpf_handler_v86 +mov word [0xb8000], 0x0f00 | 'G' +mov word [0xb8002], 0x0f00 | 'P' +mov word [0xb8004], 0x0f00 | 'F' +.hlt: +hlt +jmp .hlt + +scancodesToAscii: db 0, 0 ; 0x00 - 0x01 +db "1234567890" ; 0x02 - 0x0B +db "-=" ; 0x0C - 0x0D +db 0, 0 ; 0x0E - 0x0F +db "qwertyuiop[]" ; 0x10 - 0x1B +db 0, 0 ; 0x1C - 0x1D +db "asdfghjkl;'`" ; 0x1E - 0x29 +db 0 ; 0x2A +db "\zxcvbnm,./" ; 0x2B - 0x35 +db 0 ; 0x36 +db '*' ; 0x37 +db 0 ; 0x38 +db ' ' ; 0x39 +db 'C' +scancodesToAsciiEnd: +cursorCurrent: dd 0xb8000 + (80*6*2) +global keyboardHandler +keyboardHandler: +push eax +push ebx +push ds +mov ax, 0x10 +mov ds, ax +xor eax, eax +in al, 0x60 +cmp eax, 0x3A +jg .done +mov al, [scancodesToAscii+eax] +test al, al +jz .done +mov ebx, [cursorCurrent] +mov byte [ebx], al +add dword [cursorCurrent], 2 +mov byte [KBDWAIT], 1 +.done: +mov al, 0x20 +out 0x20, al +pop ds +pop ebx +pop eax +iret + +KBDWAIT: db 0 +global kbd_wait +kbd_wait: +mov byte [KBDWAIT], 0 +.loop: +hlt +xor eax, eax +mov al, [KBDWAIT] +test eax, eax +jz .loop +ret + +global timerHandler +timerHandler: +push eax +push ds +mov ax, 0x10 +mov ds, ax +inc byte [(0xb8000 + (80*8*2))] +mov al, 0x20 +out 0x20, al +pop ds +pop eax +iret + +global picInit +picInit: +mov al, 0x11 ; initialization sequence +out 0x20, al ; send to 8259A-1 +jmp $+2 +jmp $+2 +out 0xA0, al ; and to 8259A-2 +jmp $+2 +jmp $+2 +mov al, 0x20 ; start of hardware ints (0x20) +out 0x21, al +jmp $+2 +jmp $+2 +mov al, 0x28 ; start of hardware ints 2 (0x28) +out 0xA1, al +jmp $+2 +jmp $+2 +mov al, 0x04 ; 8259-1 is master +out 0x21, al +jmp $+2 +jmp $+2 +mov al, 0x02 ; 8259-2 is slave +out 0xA1, al +jmp $+2 +jmp $+2 +mov al, 0x01 ; 8086 mode for both +out 0x21, al +jmp $+2 +jmp $+2 +out 0xA1, al +jmp $+2 +jmp $+2 +mov al, 0xFF ; all interrupts off for now +out 0x21, al +jmp $+2 +jmp $+2 +out 0xA1, al +ret diff --git a/interrupt.c b/interrupt.c new file mode 100644 index 0000000..92e7ddc --- /dev/null +++ b/interrupt.c @@ -0,0 +1,272 @@ +#include +#include + +#include "print.h" + +#include "interrupt.h" + +struct __attribute__((__packed__)) IDTR_t { + uint16_t size; + uint32_t offset; +}; + +struct __attribute__((__packed__)) InterruptDescriptor32 { + uint16_t offset_1; // offset bits 0..15 + uint16_t selector; // a code segment selector in GDT or LDT + uint8_t zero; // unused, set to 0 + uint8_t type_attributes; // gate type, dpl, and p fields + uint16_t offset_2; // offset bits 16..31 +}; + +__attribute__((aligned(0x10))) +struct InterruptDescriptor32 IDT[256]; +struct IDTR_t IDTR; + +void outb(uint16_t port, uint8_t value) { + asm volatile("outb %%al, %%dx" : : "d"(port), "a"(value)); +} +uint8_t inb(uint16_t port) { + uint8_t value; + asm volatile("inb %%dx, %%al" : "=a"(value) : "d"(port)); + return value; +} + +FARPTR i386LinearToFp(void *ptr) +{ + unsigned seg, off; + off = (uintptr_t) ptr & 0xffff; + seg = ((uintptr_t) ptr >> 16); + return MK_FP(seg, off); +} + + +void IRQ_set_mask(char IRQline) { + uint16_t port; + uint8_t value; + if (IRQline < 8) { + port = 0x21; + } else { + port = 0xA1; + IRQline -= 8; + } + value = inb(port) | (1 << IRQline); + outb(port, value); +} +void IRQ_clear_mask(char IRQline) { + uint16_t port; + uint8_t value; + if (IRQline < 8) { + port = 0x21; + } else { + port = 0xA1; + IRQline -= 8; + } + value = inb(port) & ~(1 << IRQline); + outb(port, value); +} + +char v86_if = 0; +extern void real_test(); +extern void kbd_wait(); +#define VALID_FLAGS 0xDFF +__attribute__ ((interrupt)) +void gpf_handler_v86(struct interrupt_frame *frame, unsigned long error_code) { + asm volatile("mov %%ax,%%ds"::"a"(0x10)); + uint8_t *ip; + uint16_t *stack, *ivt; + uint32_t *stack32; + char is_operand32 = 0, is_address32 = 0; + ip = (size_t)(((frame->cs << 4) + frame->eip) & 0xFFFFF); + ivt = (uint16_t*)0x0000; + stack = FP_TO_LINEAR(frame->ss, frame->esp); + stack32 = (uint32_t*)stack; + + char *vga = (char*)0xb8000 + (160 * 10); + vga[0] = 'I'; vga[2] = 'P'; printWord(frame->eip, &vga[4]); vga += 14; + vga[0] = 'C'; vga[2] = 'S'; printWord(frame->cs, &vga[4]); vga += 14; + vga[0] = 'F'; vga[2] = 'L'; printDword(frame->eflags, &vga[4]); vga += 14; + vga = (char*)0xb8000 + (160 * 11); + vga[0] = 'S'; vga[2] = 'P'; printWord(frame->esp, &vga[4]); vga += 14; + vga[0] = 'S'; vga[2] = 'S'; printWord(frame->ss, &vga[4]); vga += 14; + vga = (char*)0xb8000 + (160 * 12); + vga[0] = 'E'; vga[2] = 'S'; printWord(frame->es, &vga[4]); vga += 14; + vga[0] = 'D'; vga[2] = 'S'; printWord(frame->ds, &vga[4]); vga += 14; + vga[0] = 'F'; vga[2] = 'S'; printWord(frame->fs, &vga[4]); vga += 14; + vga[0] = 'G'; vga[2] = 'S'; printWord(frame->gs, &vga[4]); vga += 14; + + //vga[2]++; + //printDword(frame, &vga[20]); + //vga = &vga[38]; + //uint32_t *fr = frame; + //for (int i = 0; i < sizeof(struct interrupt_frame)/sizeof(uint32_t); i++) { + // printDword(fr[i], vga); + // vga += (sizeof(uint32_t)*2+1)*2; + //} + //vga = (char*)0xb80A0; + //printDword(ip, &vga[20]); + //vga = &vga[38]; + //for (int i = 0; i < 16; i++) { + // printByte(ip[i], vga); + // vga += (sizeof(uint8_t)*2)*2; + //} + vga = (char*)0xb8000 + (160*3); + for(;;) { + switch (ip[0]) { + case 0x66: // O32 + is_operand32 = 1; + ip++; + frame->eip = (uint16_t)(frame->eip + 1); + break; + case 0x67: // A32 + is_address32 = 1; + ip++; + frame->eip = (uint16_t)(frame->eip + 1); + break; + case 0x9C: // PUSHF + if (is_operand32) { + frame->esp = ((frame->esp & 0xffff) - 4) & 0xffff; + stack32--; + stack32[0] = frame->eflags & VALID_FLAGS; + if (v86_if) + stack32[0] |= EFLAG_IF; + else + stack32[0] &= ~EFLAG_IF; + } else { + frame->esp = ((frame->esp & 0xffff) - 2) & 0xffff; + stack--; + stack[0] = (uint16_t)frame->eflags; + if (v86_if) + stack[0] |= EFLAG_IF; + else + stack[0] &= ~EFLAG_IF; + } + frame->eip = (uint16_t)(frame->eip + 1); + goto done; + case 0x9D: // POPF + if (is_operand32) { + frame->eflags = EFLAG_IF | EFLAG_VM | (stack32[0] & VALID_FLAGS); + v86_if = (stack32[0] & EFLAG_IF) != 0; + frame->esp = ((frame->esp & 0xffff) + 4) & 0xffff; + } else { + frame->eflags = EFLAG_IF | EFLAG_VM | stack[0]; + v86_if = (stack[0] & EFLAG_IF) != 0; + frame->esp = ((frame->esp & 0xffff) + 2) & 0xffff; + } + frame->eip = (uint16_t)(frame->eip + 1); + goto done; + case 0xCD: // INT n + vga[0] = 'I'; vga[2]++; if (vga[2] < '0') vga[2] = '0'; + asm volatile("nop\nnop"); + switch (ip[1]) { + case 0x30: // Exit V86 Mode? + asm volatile("nop\nnop"); + asm volatile("jmp jmp_usermode_test"); + //__builtin_unreachable(); + break; + //case 0x20: // ??? + //case 0x21: // ??? + case 0x3: // Debugger trap + kbd_wait(); + asm volatile("nop"); + default: + stack -= 3; + frame->esp = ((frame->esp & 0xffff) - 6) & 0xffff; + + stack[0] = (uint16_t) (frame->eip + 2); + stack[1] = frame->cs; + stack[2] = (uint16_t) frame->eflags; + + if (v86_if) + stack[2] |= EFLAG_IF; + else + stack[2] &= ~EFLAG_IF; + + frame->cs = ivt[ip[1] * 2 + 1]; + frame->eip = ivt[ip[1] * 2]; + asm volatile("nop"); + //frame->cs = 0; + //frame->eip = real_test; + goto done; + } + goto done; + case 0xCF: // IRET + frame->eip = stack[0]; + frame->cs = stack[1]; + frame->eflags = EFLAG_IF | EFLAG_VM | stack[2]; + v86_if = (stack[2] & EFLAG_IF) != 0; + frame->esp = ((frame->esp & 0xffff) + 6) & 0xffff; + goto done; + case 0xFA: // CLI + v86_if = 0; + frame->eip = (uint16_t) (frame->eip + 1); + goto done; + case 0xFB: // STI + v86_if = 1; + frame->eip = (uint16_t) (frame->eip + 1); + goto done; + default: + for(;;); + goto done; + } + } + done: + vga = (char*)0xb8000 + (160 * 13); + vga[0] = 'I'; vga[2] = 'P'; printWord(frame->eip, &vga[4]); vga += 14; + vga[0] = 'C'; vga[2] = 'S'; printWord(frame->cs, &vga[4]); vga += 14; + vga[0] = 'F'; vga[2] = 'L'; printDword(frame->eflags, &vga[4]); vga += 14; + vga = (char*)0xb8000 + (160 * 14); + vga[0] = 'S'; vga[2] = 'P'; printWord(frame->esp, &vga[4]); vga += 14; + vga[0] = 'S'; vga[2] = 'S'; printWord(frame->ss, &vga[4]); vga += 14; + vga = (char*)0xb8000 + (160 * 15); + vga[0] = 'E'; vga[2] = 'S'; printWord(frame->es, &vga[4]); vga += 14; + vga[0] = 'D'; vga[2] = 'S'; printWord(frame->ds, &vga[4]); vga += 14; + vga[0] = 'F'; vga[2] = 'S'; printWord(frame->fs, &vga[4]); vga += 14; + vga[0] = 'G'; vga[2] = 'S'; printWord(frame->gs, &vga[4]); vga += 14; +} + +extern void timerHandler(); +extern void keyboardHandler(); +extern void gpfHandler(); +extern void unhandled_handler(); +extern void picInit(); +void set_system_gate(uint8_t gate, void (*handler)()) { + IDT[gate].offset_1 = (uint32_t)(size_t)handler & 0xFFFF; + IDT[gate].offset_2 = ((uint32_t)(size_t)handler >> 16) & 0xFFFF; + IDT[gate].selector = 0x08; + IDT[gate].type_attributes = 0x8E; +} +void set_trap_gate(uint8_t gate, void (*handler)()) { + IDT[gate].offset_1 = (uint32_t)(size_t)handler & 0xFFFF; + IDT[gate].offset_2 = ((uint32_t)(size_t)handler >> 16) & 0xFFFF; + IDT[gate].selector = 0x08; + IDT[gate].type_attributes = 0x8F; +} +void setup_interrupts() { + IDTR.size = 256*8 - 1; + IDTR.offset = (uint32_t)(size_t)IDT; + for (int i = 0; i < 256; i++) { + *(uint64_t*)&IDT[i] = 0; + } + + for (int i = 0; i < 9; i++) { + set_trap_gate(i, unhandled_handler); + } + for (int i = 10; i < 15; i++) { + set_trap_gate(i, unhandled_handler); + } + for (int i = 16; i < 22; i++) { + set_trap_gate(i, unhandled_handler); + } + + set_system_gate(0x20, timerHandler); + set_system_gate(0x21, keyboardHandler); + set_trap_gate(13, gpf_handler_v86); + //set_trap_gate(13, gpfHandler); + + asm volatile("lidt %0": : "m"(IDTR)); + picInit(); + IRQ_clear_mask(0); + IRQ_clear_mask(1); + asm volatile("sti"); +} + diff --git a/interrupt.h b/interrupt.h new file mode 100644 index 0000000..55f31fc --- /dev/null +++ b/interrupt.h @@ -0,0 +1,35 @@ +#pragma once +#include + +struct interrupt_frame { + uint32_t eip, cs; + uint32_t eflags; + uint32_t esp, ss; + uint32_t es, ds, fs, gs; +}; + +/* Real Mode helper macros */ +/* segment:offset pair */ +typedef uint32_t FARPTR; + +/* Make a FARPTR from a segment and an offset */ +#define MK_FP(seg, off) ((FARPTR) (((uint32_t) (seg) << 16) | (uint16_t) (off))) + +/* Extract the segment part of a FARPTR */ +#define FP_SEG(fp) (((FARPTR) fp) >> 16) + +/* Extract the offset part of a FARPTR */ +#define FP_OFF(fp) (((FARPTR) fp) & 0xffff) + +/* Convert a segment:offset pair to a linear address */ +#define FP_TO_LINEAR(seg, off) ((void*)(uintptr_t)((((uint32_t)seg) << 4) + ((uint32_t)off))) + +#define EFLAG_IF ((uint32_t)1 << 9) +#define EFLAG_VM ((uint32_t)1 << 17) + + + +__attribute__ ((interrupt)) +void gpf_handler_v86(struct interrupt_frame *frame, unsigned long error_code); + +void setup_interrupts(); diff --git a/kernel.c b/kernel.c index 81e5e93..8bfbcbe 100644 --- a/kernel.c +++ b/kernel.c @@ -1,22 +1,11 @@ #include -typedef unsigned short word; +#include "print.h" +#include "interrupt.h" -char nibbleToHex(char n) { - return n > 9 ? (n - 10) + 'A' : n + '0'; -} -void printByte(char v, short *buff) { - *(char *)&buff[0] = nibbleToHex((v >> 4) & 0xF); - *(char *)&buff[1] = nibbleToHex(v & 0xF); -} -void printWord(short v, short *buff) { - printByte(v >> 8, buff); - printByte(v, &buff[2]); -} -void printDword(int v, short *buff) { - printWord(v >> 16, buff); - printWord(v, &buff[4]); -} +#include "tss.c" + +typedef unsigned short word; char check_apic() { uint32_t eax, ebx, ecx, edx; @@ -29,335 +18,6 @@ char check_sse() { return (edx & (1 << 25)) != 0; } -struct __attribute__((__packed__)) IDTR_t { - uint16_t size; - uint32_t offset; -}; - -struct __attribute__((__packed__)) InterruptDescriptor32 { - uint16_t offset_1; // offset bits 0..15 - uint16_t selector; // a code segment selector in GDT or LDT - uint8_t zero; // unused, set to 0 - uint8_t type_attributes; // gate type, dpl, and p fields - uint16_t offset_2; // offset bits 16..31 -}; - -__attribute__((aligned(0x10))) -struct InterruptDescriptor32 IDT[256]; -struct IDTR_t IDTR; - -void outb(uint16_t port, uint8_t value) { - asm volatile("outb %%al, %%dx" : : "d"(port), "a"(value)); -} -uint8_t inb(uint16_t port) { - uint8_t value; - asm volatile("inb %%dx, %%al" : "=a"(value) : "d"(port)); - return value; -} - -void IRQ_set_mask(char IRQline) { - uint16_t port; - uint8_t value; - if (IRQline < 8) { - port = 0x21; - } else { - port = 0xA1; - IRQline -= 8; - } - value = inb(port) | (1 << IRQline); - outb(port, value); -} -void IRQ_clear_mask(char IRQline) { - uint16_t port; - uint8_t value; - if (IRQline < 8) { - port = 0x21; - } else { - port = 0xA1; - IRQline -= 8; - } - value = inb(port) & ~(1 << IRQline); - outb(port, value); -} - -struct interrupt_frame { - uint32_t eip, cs; - uint32_t eflags; - uint32_t esp, ss; - uint32_t es, ds, fs, gs; -}; - -/* Real Mode helper macros */ -/* segment:offset pair */ -typedef uint32_t FARPTR; - -/* Make a FARPTR from a segment and an offset */ -#define MK_FP(seg, off) ((FARPTR) (((uint32_t) (seg) << 16) | (uint16_t) (off))) - -/* Extract the segment part of a FARPTR */ -#define FP_SEG(fp) (((FARPTR) fp) >> 16) - -/* Extract the offset part of a FARPTR */ -#define FP_OFF(fp) (((FARPTR) fp) & 0xffff) - -/* Convert a segment:offset pair to a linear address */ -#define FP_TO_LINEAR(seg, off) ((void*)(uintptr_t)((((uint32_t)seg) << 4) + ((uint32_t)off))) - -FARPTR i386LinearToFp(void *ptr) -{ - unsigned seg, off; - off = (uintptr_t) ptr & 0xffff; - seg = ((uintptr_t) ptr >> 16); - return MK_FP(seg, off); -} - -#define EFLAG_IF ((uint32_t)1 << 9) -#define EFLAG_VM ((uint32_t)1 << 17) - -char v86_if = 0; -extern void real_test(); -extern void kbd_wait(); -#define VALID_FLAGS 0xDFF -__attribute__ ((interrupt)) -void gpf_handler_v86(struct interrupt_frame *frame, uint32_t error_code) { - asm volatile("mov %%ax,%%ds"::"a"(0x10)); - uint8_t *ip; - uint16_t *stack, *ivt; - uint32_t *stack32; - char is_operand32 = 0, is_address32 = 0; - ip = ((frame->cs << 4) + frame->eip) & 0xFFFFF; - ivt = (uint16_t*)0x0000; - stack = FP_TO_LINEAR(frame->ss, frame->esp); - stack32 = (uint32_t*)stack; - - char *vga = (char*)0xb8000 + (160 * 10); - vga[0] = 'I'; vga[2] = 'P'; printWord(frame->eip, &vga[4]); vga += 14; - vga[0] = 'C'; vga[2] = 'S'; printWord(frame->cs, &vga[4]); vga += 14; - vga[0] = 'F'; vga[2] = 'L'; printDword(frame->eflags, &vga[4]); vga += 14; - vga = (char*)0xb8000 + (160 * 11); - vga[0] = 'S'; vga[2] = 'P'; printWord(frame->esp, &vga[4]); vga += 14; - vga[0] = 'S'; vga[2] = 'S'; printWord(frame->ss, &vga[4]); vga += 14; - vga = (char*)0xb8000 + (160 * 12); - vga[0] = 'E'; vga[2] = 'S'; printWord(frame->es, &vga[4]); vga += 14; - vga[0] = 'D'; vga[2] = 'S'; printWord(frame->ds, &vga[4]); vga += 14; - vga[0] = 'F'; vga[2] = 'S'; printWord(frame->fs, &vga[4]); vga += 14; - vga[0] = 'G'; vga[2] = 'S'; printWord(frame->gs, &vga[4]); vga += 14; - - //vga[2]++; - //printDword(frame, &vga[20]); - //vga = &vga[38]; - //uint32_t *fr = frame; - //for (int i = 0; i < sizeof(struct interrupt_frame)/sizeof(uint32_t); i++) { - // printDword(fr[i], vga); - // vga += (sizeof(uint32_t)*2+1)*2; - //} - //vga = (char*)0xb80A0; - //printDword(ip, &vga[20]); - //vga = &vga[38]; - //for (int i = 0; i < 16; i++) { - // printByte(ip[i], vga); - // vga += (sizeof(uint8_t)*2)*2; - //} - vga = (char*)0xb8000 + (160*3); - for(;;) { - switch (ip[0]) { - case 0x66: // O32 - is_operand32 = 1; - ip++; - frame->eip = (uint16_t)(frame->eip + 1); - break; - case 0x67: // A32 - is_address32 = 1; - ip++; - frame->eip = (uint16_t)(frame->eip + 1); - break; - case 0x9C: // PUSHF - if (is_operand32) { - frame->esp = ((frame->esp & 0xffff) - 4) & 0xffff; - stack32--; - stack32[0] = frame->eflags & VALID_FLAGS; - if (v86_if) - stack32[0] |= EFLAG_IF; - else - stack32[0] &= ~EFLAG_IF; - } else { - frame->esp = ((frame->esp & 0xffff) - 2) & 0xffff; - stack--; - stack[0] = (uint16_t)frame->eflags; - if (v86_if) - stack[0] |= EFLAG_IF; - else - stack[0] &= ~EFLAG_IF; - } - frame->eip = (uint16_t)(frame->eip + 1); - goto done; - case 0x9D: // POPF - if (is_operand32) { - frame->eflags = EFLAG_IF | EFLAG_VM | (stack32[0] & VALID_FLAGS); - v86_if = (stack32[0] & EFLAG_IF) != 0; - frame->esp = ((frame->esp & 0xffff) + 4) & 0xffff; - } else { - frame->eflags = EFLAG_IF | EFLAG_VM | stack[0]; - v86_if = (stack[0] & EFLAG_IF) != 0; - frame->esp = ((frame->esp & 0xffff) + 2) & 0xffff; - } - frame->eip = (uint16_t)(frame->eip + 1); - goto done; - case 0xCD: // INT n - vga[0] = 'I'; vga[2]++; if (vga[2] < '0') vga[2] = '0'; - asm volatile("nop\nnop"); - switch (ip[1]) { - case 0x30: // Exit V86 Mode? - asm volatile("nop\nnop"); - asm volatile("jmp jmp_usermode_test"); - //__builtin_unreachable(); - break; - //case 0x20: // ??? - //case 0x21: // ??? - case 0x3: // Debugger trap - kbd_wait(); - asm volatile("nop"); - default: - stack -= 3; - frame->esp = ((frame->esp & 0xffff) - 6) & 0xffff; - - stack[0] = (uint16_t) (frame->eip + 2); - stack[1] = frame->cs; - stack[2] = (uint16_t) frame->eflags; - - if (v86_if) - stack[2] |= EFLAG_IF; - else - stack[2] &= ~EFLAG_IF; - - frame->cs = ivt[ip[1] * 2 + 1]; - frame->eip = ivt[ip[1] * 2]; - asm volatile("nop"); - //frame->cs = 0; - //frame->eip = real_test; - goto done; - } - goto done; - case 0xCF: // IRET - frame->eip = stack[0]; - frame->cs = stack[1]; - frame->eflags = EFLAG_IF | EFLAG_VM | stack[2]; - v86_if = (stack[2] & EFLAG_IF) != 0; - frame->esp = ((frame->esp & 0xffff) + 6) & 0xffff; - goto done; - case 0xFA: // CLI - v86_if = 0; - frame->eip = (uint16_t) (frame->eip + 1); - goto done; - case 0xFB: // STI - v86_if = 1; - frame->eip = (uint16_t) (frame->eip + 1); - goto done; - default: - goto done; - } - } - done: - vga = (char*)0xb8000 + (160 * 13); - vga[0] = 'I'; vga[2] = 'P'; printWord(frame->eip, &vga[4]); vga += 14; - vga[0] = 'C'; vga[2] = 'S'; printWord(frame->cs, &vga[4]); vga += 14; - vga[0] = 'F'; vga[2] = 'L'; printDword(frame->eflags, &vga[4]); vga += 14; - vga = (char*)0xb8000 + (160 * 14); - vga[0] = 'S'; vga[2] = 'P'; printWord(frame->esp, &vga[4]); vga += 14; - vga[0] = 'S'; vga[2] = 'S'; printWord(frame->ss, &vga[4]); vga += 14; - vga = (char*)0xb8000 + (160 * 15); - vga[0] = 'E'; vga[2] = 'S'; printWord(frame->es, &vga[4]); vga += 14; - vga[0] = 'D'; vga[2] = 'S'; printWord(frame->ds, &vga[4]); vga += 14; - vga[0] = 'F'; vga[2] = 'S'; printWord(frame->fs, &vga[4]); vga += 14; - vga[0] = 'G'; vga[2] = 'S'; printWord(frame->gs, &vga[4]); vga += 14; -} - -extern void timerHandler(); -extern void keyboardHandler(); -extern void gpfHandler(); -extern void unhandled_handler(); -extern void picInit(); -void set_system_gate(uint8_t gate, void (*handler)()) { - IDT[gate].offset_1 = (uint32_t)handler & 0xFFFF; - IDT[gate].offset_2 = ((uint32_t)handler >> 16) & 0xFFFF; - IDT[gate].selector = 0x08; - IDT[gate].type_attributes = 0x8E; -} -void set_trap_gate(uint8_t gate, void (*handler)()) { - IDT[gate].offset_1 = (uint32_t)handler & 0xFFFF; - IDT[gate].offset_2 = ((uint32_t)handler >> 16) & 0xFFFF; - IDT[gate].selector = 0x08; - IDT[gate].type_attributes = 0x8F; -} -void setup_interrupts() { - IDTR.size = 256*8 - 1; - IDTR.offset = (uint32_t)IDT; - for (int i = 0; i < 256; i++) { - *(uint64_t*)&IDT[i] = 0; - } - - for (int i = 0; i < 9; i++) { - set_trap_gate(i, unhandled_handler); - } - for (int i = 10; i < 15; i++) { - set_trap_gate(i, unhandled_handler); - } - for (int i = 16; i < 22; i++) { - set_trap_gate(i, unhandled_handler); - } - - set_system_gate(0x20, timerHandler); - set_system_gate(0x21, keyboardHandler); - set_trap_gate(13, gpf_handler_v86); - //set_trap_gate(13, gpfHandler); - - asm volatile("lidt %0": : "m"(IDTR)); - picInit(); - IRQ_clear_mask(0); - IRQ_clear_mask(1); - asm volatile("sti"); -} - - -struct __attribute__((__packed__)) tss_entry_struct { - uint32_t prev_tss; - uint32_t esp0; - uint32_t ss0; - uint32_t esp1; - uint32_t ss1; - uint32_t esp2; - uint32_t ss2; - uint32_t cr3; - uint32_t eip; - uint32_t eflags; - uint32_t eax; - uint32_t ecx; - uint32_t edx; - uint32_t ebx; - uint32_t esp; - uint32_t ebp; - uint32_t esi; - uint32_t edi; - uint32_t es; - uint32_t cs; - uint32_t ss; - uint32_t ds; - uint32_t fs; - uint32_t gs; - uint32_t ldt; - uint32_t trap; - uint32_t iomap_base; -}; -struct tss_entry_struct *tss_data; -void write_tss() { - tss_data = (struct tss_entry_struct *)0x20000; - for (int i = 0; i < 0x2080; i++) - ((uint8_t*)tss_data)[i] = 0; - tss_data->ss0 = 0x10; - tss_data->esp0 = 0x400000; - tss_data->iomap_base = 0x80; -} - void enable_sse() { asm volatile( "mov %%cr0, %%eax\n" @@ -394,7 +54,6 @@ void print_cr4() { extern void enter_v86(uint32_t ss, uint32_t esp, uint32_t cs, uint32_t eip); extern void v86Code(); -extern void flushTSS(); extern void jmp_usermode_test(); /* @@ -420,9 +79,9 @@ void start() { uint32_t o; asm("mov %%esp, %%eax" : "=a"(o) : :); - printDword(o, (short *)&vga_text[80]); + printDword(o, (uint16_t *)&vga_text[80]); asm("mov %%ebp, %%eax" : "=a"(o) : :); - printDword(o, (short *)&vga_text[160]); + printDword(o, (uint16_t *)&vga_text[160]); //char c[] = "APIC support: "; //char apic; @@ -433,15 +92,14 @@ void start() { char sse_str[] = "SSE support: "; char sse; - printByte(sse = check_sse(), (short*)&vga_text[80*4 + sizeof(sse_str) - 1]); + printByte(sse = check_sse(), (uint16_t*)&vga_text[80*4 + sizeof(sse_str) - 1]); for (int i = 0; i < sizeof(sse_str); i++) *(char *)&vga_text[i+(80*4)] = sse_str[i]; if (!sse) return; enable_sse(); setup_interrupts(); - write_tss(); - flushTSS(); + setup_tss(); print_flags(); print_cr0(); print_cr3(); diff --git a/print.c b/print.c new file mode 100644 index 0000000..97f8011 --- /dev/null +++ b/print.c @@ -0,0 +1,21 @@ +#include "print.h" + +__attribute((__always_inline__)) +char nibbleToHex(uint8_t n) { + return n > 9 ? (n - 10) + 'A' : n + '0'; +} +__attribute((__always_inline__)) +void printByte(uint8_t v, uint16_t *buff) { + *(char *)&buff[0] = nibbleToHex((v >> 4) & 0xF); + *(char *)&buff[1] = nibbleToHex(v & 0xF); +} +__attribute((__always_inline__)) +void printWord(uint16_t v, uint16_t *buff) { + printByte(v >> 8, buff); + printByte(v, &buff[2]); +} +__attribute((__always_inline__)) +void printDword(uint32_t v, uint16_t *buff) { + printWord(v >> 16, buff); + printWord(v, &buff[4]); +} diff --git a/print.h b/print.h new file mode 100644 index 0000000..ade22fe --- /dev/null +++ b/print.h @@ -0,0 +1,6 @@ +#pragma once +#include + +void printByte(uint8_t v, uint16_t *buff); +void printWord(uint16_t v, uint16_t *buff); +void printDword(uint32_t v, uint16_t *buff); diff --git a/tss.c b/tss.c new file mode 100644 index 0000000..6bf164b --- /dev/null +++ b/tss.c @@ -0,0 +1,46 @@ +#include + +struct __attribute__((__packed__)) tss_entry_struct { + uint32_t prev_tss; + uint32_t esp0; + uint32_t ss0; + uint32_t esp1; + uint32_t ss1; + uint32_t esp2; + uint32_t ss2; + uint32_t cr3; + uint32_t eip; + uint32_t eflags; + uint32_t eax; + uint32_t ecx; + uint32_t edx; + uint32_t ebx; + uint32_t esp; + uint32_t ebp; + uint32_t esi; + uint32_t edi; + uint32_t es; + uint32_t cs; + uint32_t ss; + uint32_t ds; + uint32_t fs; + uint32_t gs; + uint32_t ldt; + uint32_t trap; + uint32_t iomap_base; +}; +struct tss_entry_struct *tss_data; +void write_tss() { + tss_data = (struct tss_entry_struct *)0x20000; + for (int i = 0; i < 0x2080; i++) + ((uint8_t*)tss_data)[i] = 0; + tss_data->ss0 = 0x10; + tss_data->esp0 = 0x400000; + tss_data->iomap_base = 0x80; +} +extern void flushTSS(); + +void setup_tss() { + write_tss(); + flushTSS(); +} diff --git a/v86.nasm b/v86.nasm new file mode 100644 index 0000000..ddea9b8 --- /dev/null +++ b/v86.nasm @@ -0,0 +1,81 @@ +[BITS 16] +real_hexprint: +xor cx, cx +mov bl, al +shr al, 4 +jmp .donibble +.nibble2: +mov al, bl +inc cx +.donibble: +and al, 0x0F +cmp al, 0x0A +jl .noadjust +add al, 'A' - '0' - 10 +.noadjust: +add al, '0' +mov ah, 0x1f +stosw +test cx, cx +jz .nibble2 +ret +real_printword: +mov dx, ax +mov al, ah +call real_hexprint +mov ax, dx +call real_hexprint +ret +extern v86Code +v86Code: +mov ax, 0xb814 +mov es, ax +mov di, 20 +mov ax, sp +call real_printword +add di, 2 +mov ax, ds +call real_printword +add di, 2 +mov ax, cs +call real_printword +.loop: +inc byte [0] +;mov ax, 0x1111 +;mov ds, ax +;mov ax, 0x2222 +;mov es, ax +;mov ax, 0x3333 +;mov fs, ax +;mov ax, 0x4444 +;mov gs, ax +;mov ax, 0x5555 +;mov ss, ax +;mov ax, 0x6666 +;mov sp, ax +int 3 +;jmp .loop +mov ax, 0x13 +int 0x10 +int 0x30 ; exit +jmp $ +extern real_test +real_test: +nop +nop +nop +jmp $ +[BITS 32] +; extern void enter_v86(uint32_t ss, uint32_t esp, uint32_t cs, uint32_t eip); +global enter_v86 +enter_v86: +mov ebp, esp ; save stack pointer +push dword [ebp+4] ; ss +push dword [ebp+8] ; esp +pushfd ; eflags +or dword [esp], (1 << 17) ; set VM flags +;or dword [esp], (3 << 12) ; IOPL 3 +push dword [ebp+12] ; cs +push dword [ebp+16] ; eip +iret +