diff --git a/Makefile b/Makefile index 0f120b3..b5849b0 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ -objects = entry.o kernel.o task.o handler.o interrupt.o v86.o print.o tss.o dosfs/dosfs.o -CFLAGS = -target "i686-elf" -m32 -mgeneral-regs-only -ffreestanding -march=pentium-m -fno-stack-protector -nostdlib -c +objects = entry.o kernel.o task.o handler.o interrupt.o v86.o print.o tss.o dosfs/dosfs.o gdt.o usermode.o paging.o +CFLAGS = -target "i686-elf" -m32 -mgeneral-regs-only -ffreestanding -march=pentium-m -fno-stack-protector -Wno-int-conversion -nostdlib -c %.o: %.nasm nasm -f elf32 -o $@ $< @@ -9,7 +9,7 @@ CFLAGS = -target "i686-elf" -m32 -mgeneral-regs-only -ffreestanding -march=penti all: $(objects) nasm boot.nasm -o boot.bin - gcc -Tlink.ld -m32 -ffreestanding -nostartfiles -nostdlib -o kernel.bin\ + gcc -Tlink.ld -Wl,-M -m32 -ffreestanding -nostartfiles -nostdlib -o kernel.bin\ $(objects) 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 diff --git a/boot.nasm b/boot.nasm index 7dfa109..fd9b104 100644 --- a/boot.nasm +++ b/boot.nasm @@ -7,7 +7,7 @@ mov es, ax mov ah, 0x42 mov si, addr_packet int 0x13 -jnc 0x8000 +jnc entry push 0xb800 pop es xor di, di @@ -21,6 +21,41 @@ loop err_print hlt_loop: hlt jmp hlt_loop +entry: +cli ; no interrupts +xor ax,ax +mov ds, ax +lgdt [gdt_desc] ; load gdt register +mov eax, cr0 ; set pmode bit +or al, 1 +mov cr0, eax +jmp 08h:Pmode +[BITS 32] +Pmode: +mov ax, 0x10 +mov ds, ax +mov es, ax +mov esi, 0x8000 +mov edi, 0x100000 +mov ecx, 0x10000 +rep movsb +jmp 08h:0x100000 +gdt_desc: + dw gdt_end - gdt + dd gdt +gdt: +gdt_null: dq 0 +gdt_code: dw 0xFFFF, 0 ; bits 0-15 limit (4GB), bits 0-15 base address + db 0 ; bits 16-23 base address + db 10011010b ; access byte + db 11001111b ; bits 16-19 limit (4GB), 4 bits flags + db 0 ; bits 24-31 base address +gdt_data: dw 0xFFFF, 0 ; bits 0-15 limit (4GB), bits 0-15 base address + db 0 ; bits 16-23 base address + db 10010010b ; access byte + db 11001111b ; bits 16-19 limit (4GB), 4 bits flags + db 0 ; bits 24-31 base address +gdt_end: string: db 'DISK ERROR' diff --git a/entry.nasm b/entry.nasm index ff67c47..4897fd5 100644 --- a/entry.nasm +++ b/entry.nasm @@ -1,14 +1,9 @@ -[BITS 16] global entry entry: -cli ; no interrupts -xor ax,ax -mov ds, ax lgdt [gdt_desc] ; load gdt register -mov eax, cr0 ; set pmode bit -or al, 1 -mov cr0, eax -jmp 08h:Pmodecode +jmp Pmodecode + +extern gdt_desc [BITS 32] Pmodecode: @@ -30,110 +25,3 @@ 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 -mov edi, 0x1000 -rep stosd ; zero first 3K for some reason -mov edi, 0x4000 -mov eax, 0x800007 ; 8MB + 7 -std ; fill backwards -.fill: -stosd -sub eax, 0x1000 -jge .fill -cld ; fix direction -mov dword [0x0000], 0x2000 + 7 -mov dword [0x0004], 0x3000 + 7 -mov eax, 0x1000 -mov cr3, eax ; page dir start 0x1000 -mov eax, cr0 -or eax, 0x80000000 -mov cr0, eax ; set paging bit -ret ; flushes pre-fetch queue - -user_test: -mov dword [0xb8000], 0x0f000f00 | 'U' | 's' << 16 -mov dword [0xb8004], 0x0f000f00 | 'e' | 'r' << 16 -mov dword [0xb8008], 0x0f000f00 | 'm' | 'o' << 16 -mov dword [0xb800C], 0x0f000f00 | 'd' | 'e' << 16 -mov word [0xb8010], 0x0f00 | '!' -mov edi, 0xA0000 -xor eax, eax -.loop: -mov ecx, 320 -rep stosb -inc al -cmp eax, 200 -jl .loop -mov eax, 0xA0000 -int 0x30 ; Exit -xor ebx, ebx -div bl ; Unhandled DIV0 exception - -global jmp_usermode_test -jmp_usermode_test: -pop eax ; return address -mov ecx, esp ; return stack -call save_current_task -mov esp, 0x500000 ; usermode stack -mov eax, 0x20 | 3 -mov ds, ax -mov es, ax -mov fs, ax -mov gs, ax -mov eax, esp -push 0x20 | 3 -push eax -pushfd -push 0x18 | 3 -push user_test -iret - -extern save_current_task - -global flushTSS -flushTSS: -mov ax, 0x28 -ltr ax -ret - -extern tss_data - -global ivt -ivt: dd 0x00000000 - -gdt_desc: - dw gdt_end - gdt - dd gdt -gdt: -gdt_null: dq 0 -gdt_code: dw 0xFFFF, 0 ; bits 0-15 limit (4GB), bits 0-15 base address - db 0 ; bits 16-23 base address - db 10011010b ; access byte - db 11001111b ; bits 16-19 limit (4GB), 4 bits flags - db 0 ; bits 24-31 base address -gdt_data: dw 0xFFFF, 0 ; bits 0-15 limit (4GB), bits 0-15 base address - db 0 ; bits 16-23 base address - db 10010010b ; access byte - db 11001111b ; bits 16-19 limit (4GB), 4 bits flags - db 0 ; bits 24-31 base address -gdt_r3code: dw 0xFFFF, 0 ; bits 0-15 limit (4GB), bits 0-15 base address - db 0 ; bits 16-23 base address - db 0xFA ; access byte - db 11001111b ; bits 16-19 limit (4GB), 4 bits flags - db 0 ; bits 24-31 base address -gdt_r3data: dw 0xFFFF, 0 ; bits 0-15 limit (4GB), bits 0-15 base address - db 0 ; bits 16-23 base address - db 0xF2 ; access byte - db 11001111b ; bits 16-19 limit (4GB), 4 bits flags - db 0 ; bits 24-31 base address -gdt_tss: dw 0x2080, 0x0000;26*4, tss_data ; bits 0-15 limit (4GB), bits 0-15 base address - db 0x2 ; bits 16-23 base address - db 0x89 ; access byte - db 00000000b ; bits 16-19 limit (4GB), 4 bits flags - db 0 ; bits 24-31 base address -gdt_end: diff --git a/gdt.nasm b/gdt.nasm new file mode 100644 index 0000000..d2385f4 --- /dev/null +++ b/gdt.nasm @@ -0,0 +1,35 @@ +global ivt +ivt: dd 0x00000000 + +global gdt_desc +gdt_desc: + dw gdt_end - gdt + dd gdt +gdt: +gdt_null: dq 0 +gdt_code: dw 0xFFFF, 0 ; bits 0-15 limit (4GB), bits 0-15 base address + db 0 ; bits 16-23 base address + db 10011010b ; access byte + db 11001111b ; bits 16-19 limit (4GB), 4 bits flags + db 0 ; bits 24-31 base address +gdt_data: dw 0xFFFF, 0 ; bits 0-15 limit (4GB), bits 0-15 base address + db 0 ; bits 16-23 base address + db 10010010b ; access byte + db 11001111b ; bits 16-19 limit (4GB), 4 bits flags + db 0 ; bits 24-31 base address +gdt_r3code: dw 0xFFFF, 0 ; bits 0-15 limit (4GB), bits 0-15 base address + db 0 ; bits 16-23 base address + db 0xFA ; access byte + db 11001111b ; bits 16-19 limit (4GB), 4 bits flags + db 0 ; bits 24-31 base address +gdt_r3data: dw 0xFFFF, 0 ; bits 0-15 limit (4GB), bits 0-15 base address + db 0 ; bits 16-23 base address + db 0xF2 ; access byte + db 11001111b ; bits 16-19 limit (4GB), 4 bits flags + db 0 ; bits 24-31 base address +gdt_tss: dw 0x2080, 0x0000;26*4, tss_data ; bits 0-15 limit (4GB), bits 0-15 base address + db 0x20 ; bits 16-23 base address + db 0x89 ; access byte + db 00000000b ; bits 16-19 limit (4GB), 4 bits flags + db 0 ; bits 24-31 base address +gdt_end: diff --git a/handler.nasm b/handler.nasm index 83f192a..2745e99 100644 --- a/handler.nasm +++ b/handler.nasm @@ -9,6 +9,22 @@ mov dword [0xb8008], 0x0f000f00 | 'R' | '!' << 16 hlt jmp .hlt +global pageFaultHandler +pageFaultHandler: +mov ax, 0x10 +mov ds, ax +pop eax ; error code +mov ebx, 0x0f000f00 | '0' | '!' << 16 +and eax, 0x7 ; U/S,R/W,P +add ebx, eax +mov dword [0xb8000], 0x0f000f00 | 'P' | 'G' << 16 +mov dword [0xb8004], 0x0f000f00 | 'F' | 'L' << 16 +mov dword [0xb8008], 0x0f000f00 | 'T' | ':' << 16 +mov dword [0xb800C], ebx +.hlt: +hlt +jmp .hlt + extern gpf_handler_v86 global gpfHandler gpfHandler: diff --git a/interrupt.c b/interrupt.c index 8fbfbac..83028a3 100644 --- a/interrupt.c +++ b/interrupt.c @@ -237,6 +237,7 @@ void gpf_handler_v86(struct interrupt_frame *frame, unsigned long error_code) { extern void timerHandler(); extern void keyboardHandler(); extern void gpfHandler(); +extern void pageFaultHandler(); extern void unhandled_handler(); extern void picInit(); void set_system_gate(uint8_t gate, void (*handler)()) { @@ -272,6 +273,7 @@ void setup_interrupts() { set_system_gate(0x21, keyboardHandler); //set_trap_gate(13, gpf_handler_v86); set_trap_gate(13, gpfHandler); + set_trap_gate(14, pageFaultHandler); asm volatile("lidt %0": : "m"(IDTR)); picInit(); diff --git a/kernel.c b/kernel.c index 83a9f16..5c93734 100644 --- a/kernel.c +++ b/kernel.c @@ -3,8 +3,8 @@ #include "dosfs/dosfs.h" #include "print.h" #include "interrupt.h" - #include "tss.h" +#include "paging.h" typedef unsigned short word; @@ -72,29 +72,49 @@ extern char *jmp_usermode_test(); __attribute((__no_caller_saved_registers__)) extern void kbd_wait(); +extern char _edata, _v86code, _ev86code, _bstart, _bend, _loadusercode, _usercode, _eusercode; +void setup_binary() { + // Put V86 code in proper place based on linker + char *s = &_edata; + char *d = &_v86code; + while (d < &_ev86code) + *d++ = *s++; + + // Put Usermode code in proper place based on linker + s = &_loadusercode; + d = &_usercode; + while (d < &_eusercode) + *d++ = *s++; + + // Clear BSS area + for (d = &_bstart; d < &_bend; d++) + *d = 0; +} + /* Real Mode Accessible (First MB) 00000 - 00400 IVT (1kB) 00400 - 01000 Unused (3kB) - 01000 - 04000 Paging (12kB) + 01000 - 04000 Free (12kB) 04000 - 07C00 Free (15kB) 07C00 - 08000 Boot (512B) - 08000 - 20000 Kernel Code (96kB) - 20000 - 20080 TSS (128B) - 20080 - 22080 TSS IOMAP (8kB) - 22080 - 22400 Unused (896B) - 22400 - 23000 Free (3kB) - 23000 - 30000 Disk Buffer (52kB) + 08000 - 20000 V86 Code (96kB) + 20000 - 30000 Disk Buffer (64kB) 30000 - 80000 Free (320kB) 80000 - 90000 Real Mode Stack (64kB) 90000 - A0000 Free (64kB) - A0000 - FFFFF BIOS Area (384kB) + A0000 - C0000 VGA (128kB) + C0000 - FFFFF BIOS Area (256kB) Protected Only (1MB+) -100000 - 300000 Free (2mB) +100000 - 200000 Kernel Code (1mB) +200000 - 200080 TSS (128B) +200080 - 202080 TSS IOMAP (8kB) +202080 - 300000 Free (~1mB) 300000 - 310000 Task Stack (64kB) 310000 - 320000 Interrupt Stack (64kB) 320000 - 400000 Kernel Stack (896kB) -400000 - 500000 Usermode Stack (1mB) +400000 - 700000 Usermode Code (3mB) +700000 - 800000 Usermode Stack (1mB) */ void TestV86() { @@ -218,14 +238,16 @@ void start() { if (!sse) return; enable_sse(); + setup_binary(); + // edit setup_interrupts(); setup_tss(); - print_flags(); + init_paging(); + //print_flags(); print_cr0(); - print_cr3(); - print_cr4(); - //asm ("xchgw %bx, %bx"); + //print_cr3(); + //print_cr4(); TestV86(); // has int 3 wait in v86 TestGfx(); diff --git a/link.ld b/link.ld index 56ffbbe..480846f 100644 --- a/link.ld +++ b/link.ld @@ -2,18 +2,34 @@ OUTPUT_FORMAT(binary) ENTRY(entry) SECTIONS { - . = 0x8000; + . = 0x100000; .text : ALIGN(0x1000) { - *(.text) + *(.text); } .data : ALIGN(0x1000) { - *(.data) - *(.rodata) + *(.data); + *(.rodata); + *(.rodata*); + _edata = .; } - .bss : ALIGN(0x1000) { - *(.bss) + .realmode 0x8000 : + AT ( ADDR(.data) + SIZEOF(.data) ) + { _v86code = .; *(.v86); _ev86code = .; } + + . = ADDR(.data) + SIZEOF(.data) + SIZEOF(.realmode); + .thing : { _loadusercode = .; } + + .usermode 0x400000 : + AT ( ADDR(.data) + SIZEOF(.data) + SIZEOF(.realmode) ) + { _usercode = .; *(.user); _eusercode = .; } + + . = ADDR(.data) + SIZEOF(.data) + SIZEOF(.realmode) + SIZEOF(.usermode); + + .bss : ALIGN(0x1000) + { + _bstart = .; *(.bss); _bend = .; } } diff --git a/paging.c b/paging.c new file mode 100644 index 0000000..7ce635e --- /dev/null +++ b/paging.c @@ -0,0 +1,50 @@ +#include "paging.h" + +uint32_t page_directory[1024] __attribute__((aligned(4096))); +uint32_t first_page_table[1024] __attribute__((aligned(4096))); // 0x00000000 - 0x00400000 +uint32_t second_page_table[1024] __attribute__((aligned(4096))); // 0x00400000 - 0x00800000 + +void enable_paging() { + asm( + "mov %%eax, %%cr3\n" + "mov %%cr0, %%eax\n" + "or $0x80000001, %%eax\n" + "mov %%eax, %%cr0\n" + ::"a"(page_directory)); +} + +void init_paging() { + for (int i = 0; i < 1024; i++) + // Supervisor, R/W, Not Present + page_directory[i] = 2; + + // First Page Table + // First MB: Real Mode + { + int i; + // Up to 0xC0000 + // TODO make some areas here Read Only + for (i = 0;i < 16*0xC; i++) + // User, R/W, Present + first_page_table[i] = (i * 0x1000) |4|2|1; + // Remainder of first MB BIOS Area (writable?) + for (;i < 256; i++) + // User, R/W, Present + first_page_table[i] = (i * 0x1000) |4|2|1; + } + // Next 3MB: Kernel + for (int i = 256; i < 1024; i++) + // Supervisor, R/W, Present + first_page_table[i] = (i * 0x1000) |2|1; + + // Usermode Page Table + for (int i = 0; i < 1024; i++) + // User, R/W, Present + second_page_table[i] = (i * 0x1000 + 0x400000) |4|2|1; + + // User, R/W, Present + page_directory[0] = ((uintptr_t)first_page_table)|4|2|1; + page_directory[1] = ((uintptr_t)second_page_table)|4|2|1; + + enable_paging(); +} diff --git a/paging.h b/paging.h new file mode 100644 index 0000000..dca4f26 --- /dev/null +++ b/paging.h @@ -0,0 +1,3 @@ +#include + +void init_paging(); diff --git a/task.nasm b/task.nasm index 384869e..084e9ce 100644 --- a/task.nasm +++ b/task.nasm @@ -1,3 +1,9 @@ +global flushTSS +flushTSS: +mov ax, 0x28 +ltr ax +ret + task_ptr: equ (0x310000-4) ; return address in EAX @@ -56,3 +62,42 @@ mov eax, [edx+12+16] ; ds mov ds, ax mov eax, ecx ; restore return value iret + +; extern void enter_v86(uint32_t ss, uint32_t esp, uint32_t cs, uint32_t eip); +global enter_v86 +enter_v86: +pop eax ; return address +mov ecx, esp ; return stack +call save_current_task +mov ebp, esp ; save stack pointer +push dword [ebp+0] ; ss +push dword [ebp+4] ; esp +pushfd ; eflags +or dword [esp], (1 << 17) ; set VM flags +;or dword [esp], (3 << 12) ; IOPL 3 +push dword [ebp+8] ; cs +push dword [ebp+12] ; eip +iret + +; return address in eax, return stack in ebp +;extern save_current_task + +extern user_test +global jmp_usermode_test +jmp_usermode_test: +pop eax ; return address +mov ecx, esp ; return stack +call save_current_task +mov esp, 0x800000 ; usermode stack +mov eax, 0x20 | 3 +mov ds, ax +mov es, ax +mov fs, ax +mov gs, ax +mov eax, esp +push 0x20 | 3 +push eax +pushfd +push 0x18 | 3 +push user_test +iret diff --git a/tss.c b/tss.c index 770d1eb..715c890 100644 --- a/tss.c +++ b/tss.c @@ -33,7 +33,7 @@ struct __attribute__((__packed__)) tss_entry_struct { }; struct tss_entry_struct *tss_data; void write_tss() { - tss_data = (struct tss_entry_struct *)0x20000; + tss_data = (struct tss_entry_struct *)0x200000; for (int i = 0; i < 0x2080; i++) ((uint8_t*)tss_data)[i] = 0; tss_data->ss0 = 0x10; diff --git a/usermode.nasm b/usermode.nasm new file mode 100644 index 0000000..45229e4 --- /dev/null +++ b/usermode.nasm @@ -0,0 +1,20 @@ +[SECTION .user] +global user_test +user_test: +mov dword [0xb8000], 0x0f000f00 | 'U' | 's' << 16 +mov dword [0xb8004], 0x0f000f00 | 'e' | 'r' << 16 +mov dword [0xb8008], 0x0f000f00 | 'm' | 'o' << 16 +mov dword [0xb800C], 0x0f000f00 | 'd' | 'e' << 16 +mov word [0xb8010], 0x0f00 | '!' +mov edi, 0xA0000 +xor eax, eax +.loop: +mov ecx, 320 +rep stosb +inc al +cmp eax, 200 +jl .loop +mov eax, 0xA0000 +int 0x30 ; Exit +xor ebx, ebx +div bl ; Unhandled DIV0 exception diff --git a/v86.nasm b/v86.nasm index 91f67be..a149c08 100644 --- a/v86.nasm +++ b/v86.nasm @@ -1,4 +1,5 @@ [BITS 16] +[SECTION .v86] real_hexprint: xor cx, cx mov bl, al @@ -77,23 +78,3 @@ db 0x10, 0x00 ; size, reserved dw 0x1 ; blocks dd 0x23000000 ; transfer buffer 0x23000 dq 0x1 ; start block - -[BITS 32] -; extern void enter_v86(uint32_t ss, uint32_t esp, uint32_t cs, uint32_t eip); -global enter_v86 -enter_v86: -pop eax ; return address -mov ecx, esp ; return stack -call save_current_task -mov ebp, esp ; save stack pointer -push dword [ebp+0] ; ss -push dword [ebp+4] ; esp -pushfd ; eflags -or dword [esp], (1 << 17) ; set VM flags -;or dword [esp], (3 << 12) ; IOPL 3 -push dword [ebp+8] ; cs -push dword [ebp+12] ; eip -iret - -; return address in eax, return stack in ebp -extern save_current_task