From d5902c5a208c9a18b3ffbe256ff9fc0a1ef5693c Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 13 Aug 2016 18:21:46 -0600 Subject: [PATCH] Bootable kernel skeleton --- Cargo.toml | 9 + Makefile | 24 +++ bochs.x86_64 | 14 ++ bootloader/x86/bootsector.asm | 131 ++++++++++++ bootloader/x86/descriptor_flags.inc | 46 ++++ bootloader/x86/gdt_entry.inc | 8 + bootloader/x86/harddrive.asm | 21 ++ bootloader/x86/initialize.asm | 78 +++++++ bootloader/x86/interrupts-i386.asm | 105 +++++++++ bootloader/x86/interrupts-x86_64.asm | 130 ++++++++++++ bootloader/x86/kernel.ld | 40 ++++ bootloader/x86/memory_map.asm | 32 +++ bootloader/x86/print16.asm | 66 ++++++ bootloader/x86/startup-common.asm | 89 ++++++++ bootloader/x86/startup-i386.asm | 150 +++++++++++++ bootloader/x86/startup-x86_64.asm | 191 +++++++++++++++++ bootloader/x86/unreal.asm | 54 +++++ bootloader/x86/vesa.asm | 304 +++++++++++++++++++++++++++ bootloader/x86/vesa.inc | 90 ++++++++ src/arch/mod.rs | 4 + src/arch/x86_64/irq.rs | 8 + src/arch/x86_64/main.rs | 11 + src/arch/x86_64/mod.rs | 5 + src/lib.rs | 34 ++- src/scheme/mod.rs | 11 + x86_64-unknown-none.json | 25 +++ x86_64-unknown-redox.json | 25 +++ 27 files changed, 1702 insertions(+), 3 deletions(-) create mode 100644 Makefile create mode 100644 bochs.x86_64 create mode 100644 bootloader/x86/bootsector.asm create mode 100644 bootloader/x86/descriptor_flags.inc create mode 100644 bootloader/x86/gdt_entry.inc create mode 100644 bootloader/x86/harddrive.asm create mode 100644 bootloader/x86/initialize.asm create mode 100644 bootloader/x86/interrupts-i386.asm create mode 100644 bootloader/x86/interrupts-x86_64.asm create mode 100644 bootloader/x86/kernel.ld create mode 100644 bootloader/x86/memory_map.asm create mode 100644 bootloader/x86/print16.asm create mode 100644 bootloader/x86/startup-common.asm create mode 100644 bootloader/x86/startup-i386.asm create mode 100644 bootloader/x86/startup-x86_64.asm create mode 100644 bootloader/x86/unreal.asm create mode 100644 bootloader/x86/vesa.asm create mode 100644 bootloader/x86/vesa.inc create mode 100644 src/arch/mod.rs create mode 100644 src/arch/x86_64/irq.rs create mode 100644 src/arch/x86_64/main.rs create mode 100644 src/arch/x86_64/mod.rs create mode 100644 src/scheme/mod.rs create mode 100644 x86_64-unknown-none.json create mode 100644 x86_64-unknown-redox.json diff --git a/Cargo.toml b/Cargo.toml index eb98608..949aac2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,3 +1,12 @@ [package] name = "kernel" version = "0.1.0" + +[lib] +crate-type = ["staticlib"] + +[profile.dev] +panic = "abort" + +[profile.release] +panic = "abort" diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..cb86d75 --- /dev/null +++ b/Makefile @@ -0,0 +1,24 @@ +ARCH?=x86_64 + +run: qemu + +bochs: build/harddrive.bin + bochs -f bochs.$(ARCH) + +qemu: build/harddrive.bin + qemu-system-$(ARCH) -drive file=$<,format=raw,index=0,media=disk + +FORCE: + +build/libkernel.a: FORCE + rustc --crate-type staticlib src/lib.rs -o $@ + #--target $(ARCH)-unknown-none.json + +build/kernel.bin: build/libkernel.a + ld -m elf_$(ARCH) -o $@ -T bootloader/x86/kernel.ld -z max-page-size=0x1000 $< + +build/harddrive.bin: build/kernel.bin + nasm -f bin -o $@ -D ARCH_$(ARCH) -ibootloader/x86/ -ibuild/ bootloader/x86/harddrive.asm + +clean: + rm -rf build/* diff --git a/bochs.x86_64 b/bochs.x86_64 new file mode 100644 index 0000000..0447e73 --- /dev/null +++ b/bochs.x86_64 @@ -0,0 +1,14 @@ +ata0-master: type=disk, path="build/harddrive.bin", mode=flat +boot: disk +com1: enabled=1, mode=file, dev=build/serial.log +megs: 1024 + +magic_break: enabled=1 +display_library: x, options="gui_debug" + +log: - +debug: action=ignore +info: action=report +error: action=report +panic: action=ask +debugger_log: - diff --git a/bootloader/x86/bootsector.asm b/bootloader/x86/bootsector.asm new file mode 100644 index 0000000..cbf466f --- /dev/null +++ b/bootloader/x86/bootsector.asm @@ -0,0 +1,131 @@ +ORG 0x7C00 +SECTION .text +USE16 + +boot: ; dl comes with disk + ; initialize segment registers + xor ax, ax + mov ds, ax + mov es, ax + mov ss, ax + + ; initialize stack + mov sp, 0x7C00 + + mov [disk], dl + + mov si, name + call print + call print_line + + mov bh, 0 + mov bl, [disk] + call print_num + call print_line + + mov ax, (startup_start - boot) / 512 + mov bx, startup_start + mov cx, (startup_end - startup_start) / 512 + xor dx, dx + call load + + mov si, finished + call print + call print_line + + jmp startup + +; load some sectors from disk to a buffer in memory +; buffer has to be below 1MiB +; IN +; ax: start sector +; bx: offset of buffer +; cx: number of sectors (512 Bytes each) +; dx: segment of buffer +; CLOBBER +; ax, bx, cx, dx, si +; TODO rewrite to (eventually) move larger parts at once +; if that is done increase buffer_size_sectors in startup-common to that (max 0x80000 - startup_end) +load: + cmp cx, 64 + jbe .good_size + + pusha + mov cx, 64 + call load + popa + add ax, 64 + add dx, 64 * 512 / 16 + sub cx, 64 + + jmp load +.good_size: + mov [DAPACK.addr], ax + mov [DAPACK.buf], bx + mov [DAPACK.count], cx + mov [DAPACK.seg], dx + + mov si, loading + call print + + mov bx, [DAPACK.addr] + call print_num + + mov al, '#' + call print_char + + mov bx, [DAPACK.count] + call print_num + + mov al, ' ' + call print_char + + mov bx, [DAPACK.seg] + call print_num + + mov al, ':' + call print_char + + mov bx, [DAPACK.buf] + call print_num + + call print_line + + mov dl, [disk] + mov si, DAPACK + mov ah, 0x42 + int 0x13 + jc error + ret + +error: + mov si, errored + call print + call print_line +.halt: + cli + hlt + jmp .halt + +%include "print16.asm" + +name: db "Redox Loader",0 +loading: db "Load ",0 +errored: db "Could not read disk",0 +finished: db "Finished Loading",0 +line: db 13,10,0 + +disk: db 0 + +DAPACK: + db 0x10 + db 0 +.count: dw 0 ; int 13 resets this to # of blocks actually read/written +.buf: dw 0 ; memory buffer destination address (0:7c00) +.seg: dw 0 ; in memory page zero +.addr: dd 0 ; put the lba to read in this spot + dd 0 ; more storage bytes only for big lba's ( > 4 bytes ) + +times 510-($-$$) db 0 +db 0x55 +db 0xaa diff --git a/bootloader/x86/descriptor_flags.inc b/bootloader/x86/descriptor_flags.inc new file mode 100644 index 0000000..210c98d --- /dev/null +++ b/bootloader/x86/descriptor_flags.inc @@ -0,0 +1,46 @@ +attrib: + .present equ 1 << 7 + .ring1 equ 1 << 5 + .ring2 equ 1 << 6 + .ring3 equ 1 << 5 | 1 << 6 + .user equ 1 << 4 +;user + .code equ 1 << 3 +; code + .conforming equ 1 << 2 + .readable equ 1 << 1 +; data + .expand_down equ 1 << 2 + .writable equ 1 << 1 + .accessed equ 1 << 0 +;system +; legacy + .tssAvailabe16 equ 0x1 + .ldt equ 0x2 + .tssBusy16 equ 0x3 + .call16 equ 0x4 + .task equ 0x5 + .interrupt16 equ 0x6 + .trap16 equ 0x7 + .tssAvailabe32 equ 0x9 + .tssBusy32 equ 0xB + .call32 equ 0xC + .interrupt32 equ 0xE + .trap32 equ 0xF +; long mode + .ldt32 equ 0x2 + .tssAvailabe64 equ 0x9 + .tssBusy64 equ 0xB + .call64 equ 0xC + .interrupt64 equ 0xE + .trap64 equ 0xF + +flags: + .granularity equ 1 << 7 + .available equ 1 << 4 +;user + .default_operand_size equ 1 << 6 +; code + .long_mode equ 1 << 5 +; data + .reserved equ 1 << 5 diff --git a/bootloader/x86/gdt_entry.inc b/bootloader/x86/gdt_entry.inc new file mode 100644 index 0000000..861a78b --- /dev/null +++ b/bootloader/x86/gdt_entry.inc @@ -0,0 +1,8 @@ +struc GDTEntry + .limitl resw 1 + .basel resw 1 + .basem resb 1 + .attribute resb 1 + .flags__limith resb 1 + .baseh resb 1 +endstruc diff --git a/bootloader/x86/harddrive.asm b/bootloader/x86/harddrive.asm new file mode 100644 index 0000000..3adda0d --- /dev/null +++ b/bootloader/x86/harddrive.asm @@ -0,0 +1,21 @@ +%include "bootsector.asm" + +startup_start: +%ifdef ARCH_i386 + %include "startup-i386.asm" +%endif + +%ifdef ARCH_x86_64 + %include "startup-x86_64.asm" +%endif +align 512, db 0 +startup_end: + +kernel_file: + incbin "kernel.bin" + align 512, db 0 +.end: +.length equ kernel_file.end - kernel_file +.length_sectors equ .length / 512 + +times 1024*1024-($-$$) db 0 diff --git a/bootloader/x86/initialize.asm b/bootloader/x86/initialize.asm new file mode 100644 index 0000000..2c21e08 --- /dev/null +++ b/bootloader/x86/initialize.asm @@ -0,0 +1,78 @@ +SECTION .text +USE16 + +initialize: +.fpu: ;enable fpu + mov eax, cr0 + and al, 11110011b + or al, 00100010b + mov cr0, eax + mov eax, cr4 + or eax, 0x200 + mov cr4, eax + fninit + ret + +.sse: ;enable sse + mov eax, cr4 + or ax, 0000011000000000b + mov cr4, eax + ret + +;PIT Frequency +;If using nanoseconds, to minimize drift, one should find a frequency as close to an integer nanosecond value in wavelength +;Divider Hz Nanoseconds Properties +;2685 444.38795779019242706393 2250286.00003631746492922946 Best For Context Switching +;5370 222.19397889509621353196 4500572.00007263492985856020 +;21029 56.73981961418358774390 17624306.99991199998882825455 +;23714 50.31549576902532962244 19874592.99994831745375667118 +;26399 45.19798729749864262535 22124878.99998463491868476373 +;29084 41.02536331545408701233 24375165.00002095238361424615 +;31769 37.55804925136663623868 26625451.00005726984854313455 +;34454 34.63115071302799868423 28875737.00009358731347639618 +;50113 23.80982313305263437963 41999471.99993295237244784676 +;52798 22.59899364874932131267 44249757.99996926983737931766 +;55483 21.50535599492937776736 46500044.00000558730230583335 Lowest Drift +;58168 20.51268165772704350616 48750330.00004190476724037528 +;60853 19.60760630809765610021 51000616.00007822223218031738 + +.pit: + ;initialize the PIT + mov ax, 5370 ;this is the divider for the PIT + out 0x40, al + rol ax, 8 + out 0x40, al + ;DISABLED ;enable rtc interrupt + ;mov al, 0xB + ;out 0x70, al + ;rol ax, 8 + ;in al, 0x71 + ;rol ax, 8 + ;out 0x70, al + ;rol ax, 8 + ;or al, 0x40 + ;out 0x71, al + ret + +.pic: ;sets up IRQs at int 20-2F + mov al, 0x11 + out 0x20, al + out 0xA0, al + mov al, 0x20 ;IRQ0 vector + out 0x21, al + mov al, 0x28 ;IRQ8 vector + out 0xA1, al + mov al, 4 + out 0x21, al + mov al, 2 + out 0xA1, al + mov al, 1 + out 0x21, al + out 0xA1, al + xor al, al ;no IRQ masks + out 0x21, al + out 0xA1, al + mov al, 0x20 ;reset PIC's + out 0xA0, al + out 0x20, al + ret diff --git a/bootloader/x86/interrupts-i386.asm b/bootloader/x86/interrupts-i386.asm new file mode 100644 index 0000000..5fab08a --- /dev/null +++ b/bootloader/x86/interrupts-i386.asm @@ -0,0 +1,105 @@ +struc IDTEntry + .offsetl resw 1 + .selector resw 1 + .zero resb 1 + .attribute resb 1 + .offseth resw 1 +endstruc + +SECTION .text +USE32 + +interrupts: +.first: + mov [.entry], byte 0 + jmp dword .handle +.second: +%assign i 1 +%rep 255 + mov [.entry], byte i + jmp dword .handle +%assign i i+1 +%endrep +.handle: + push ebp + push esi + push edi + push edx + push ecx + push ebx + push eax + + push esp + push dword [.entry] + + mov eax, gdt.kernel_data + mov ds, eax + mov es, eax + mov fs, eax + mov gs, eax + + call dword [.handler] + + mov eax, gdt.user_data | 3 + mov ds, eax + mov es, eax + mov fs, eax + mov eax, gdt.user_tls | 3 + mov gs, eax + + add esp, 8 ; Skip interrupt code and reg pointer + + pop eax + pop ebx + pop ecx + pop edx + pop edi + pop esi + pop ebp + + iretd + +.handler: dd 0 +.entry: dd 0 + +idtr: + dw (idt.end - idt) + 1 + dd idt + +idt: +%assign i 0 + +;Below system call +%rep 128 + istruc IDTEntry + at IDTEntry.offsetl, dw interrupts+(interrupts.second-interrupts.first)*i + at IDTEntry.selector, dw gdt.kernel_code + at IDTEntry.zero, db 0 + at IDTEntry.attribute, db attrib.present | attrib.interrupt32 + at IDTEntry.offseth, dw 0 + iend +%assign i i+1 +%endrep + +;System call +istruc IDTEntry + at IDTEntry.offsetl, dw interrupts+(interrupts.second-interrupts.first)*i + at IDTEntry.selector, dw gdt.kernel_code + at IDTEntry.zero, db 0 + at IDTEntry.attribute, db attrib.present | attrib.ring3 | attrib.interrupt32 + at IDTEntry.offseth, dw 0 +iend +%assign i i+1 + +;Above system call +%rep 127 + istruc IDTEntry + at IDTEntry.offsetl, dw interrupts+(interrupts.second-interrupts.first)*i + at IDTEntry.selector, dw gdt.kernel_code + at IDTEntry.zero, db 0 + at IDTEntry.attribute, db attrib.present | attrib.interrupt32 + at IDTEntry.offseth, dw 0 + iend +%assign i i+1 +%endrep +.end: diff --git a/bootloader/x86/interrupts-x86_64.asm b/bootloader/x86/interrupts-x86_64.asm new file mode 100644 index 0000000..c2305f6 --- /dev/null +++ b/bootloader/x86/interrupts-x86_64.asm @@ -0,0 +1,130 @@ +struc IDTEntry + .offsetl resw 1 + .selector resw 1 + .ist resb 1 + .attribute resb 1 + .offsetm resw 1 + .offseth resd 1 + .reserved resd 1 +endstruc + +SECTION .text +USE64 +interrupts: +.first: + mov [.entry], byte 0 + jmp qword .handle +.second: +%assign i 1 +%rep 255 + mov [.entry], byte i + jmp qword .handle +%assign i i+1 +%endrep +.handle: + push rbp + push r15 + push r14 + push r13 + push r12 + push r11 + push r10 + push r9 + push r8 + push rsi + push rdi + push rdx + push rcx + push rbx + push rax + + mov rsi, rsp + push rsi + mov rdi, qword [.entry] + push rdi + + mov rax, gdt.kernel_data + mov ds, rax + mov es, rax + mov fs, rax + mov gs, rax + + call qword [.handler] + + mov rax, gdt.user_data | 3 + mov ds, rax + mov es, rax + mov gs, rax + mov rax, gdt.user_tls | 3 + mov fs, rax + + add rsp, 16 ; Skip interrupt code and reg pointer + + pop rax + pop rbx + pop rcx + pop rdx + pop rdi + pop rsi + pop r8 + pop r9 + pop r10 + pop r11 + pop r12 + pop r13 + pop r14 + pop r15 + pop rbp + + iretq + +.handler: dq 0 +.entry: dq 0 + +idtr: + dw (idt.end - idt) + 1 + dq idt + +idt: +%assign i 0 + +;Below syscall +%rep 128 + istruc IDTEntry + at IDTEntry.offsetl, dw interrupts+(interrupts.second-interrupts.first)*i + at IDTEntry.selector, dw gdt.kernel_code + at IDTEntry.ist, db 0 + at IDTEntry.attribute, db attrib.present | attrib.interrupt64 + at IDTEntry.offsetm, dw 0 + at IDTEntry.offseth, dd 0 + at IDTEntry.reserved, dd 0 + iend +%assign i i+1 +%endrep + +;Syscall +istruc IDTEntry + at IDTEntry.offsetl, dw interrupts+(interrupts.second-interrupts.first)*i + at IDTEntry.selector, dw gdt.kernel_code + at IDTEntry.ist, db 0 + at IDTEntry.attribute, db attrib.present | attrib.ring3 | attrib.interrupt64 + at IDTEntry.offsetm, dw 0 + at IDTEntry.offseth, dd 0 + at IDTEntry.reserved, dd 0 +iend +%assign i i+1 + +;Above syscall +%rep 127 + istruc IDTEntry + at IDTEntry.offsetl, dw interrupts+(interrupts.second-interrupts.first)*i + at IDTEntry.selector, dw gdt.kernel_code + at IDTEntry.ist, db 0 + at IDTEntry.attribute, db attrib.present | attrib.interrupt64 + at IDTEntry.offsetm, dw 0 + at IDTEntry.offseth, dd 0 + at IDTEntry.reserved, dd 0 + iend +%assign i i+1 +%endrep +.end: diff --git a/bootloader/x86/kernel.ld b/bootloader/x86/kernel.ld new file mode 100644 index 0000000..f19fe7f --- /dev/null +++ b/bootloader/x86/kernel.ld @@ -0,0 +1,40 @@ +ENTRY(kmain) + +SECTIONS { + kernel_base = 0x101000; + . = kernel_base; + + .text : AT(ADDR(.text) - kernel_base) { + __text_start = .; + *(.text*) + . = ALIGN(4096); + __text_end = .; + } + + .rodata : AT(ADDR(.rodata) - kernel_base) { + __rodata_start = .; + *(.rodata*) + . = ALIGN(4096); + __rodata_end = .; + } + + .data : AT(ADDR(.data) - kernel_base) { + __data_start = .; + *(.data*) + . = ALIGN(4096); + __data_end = .; + } + + .bss : AT(ADDR(.bss) - kernel_base) { + __bss_start = .; + *(.bss*) + . = ALIGN(4096); + __bss_end = .; + } + + /DISCARD/ : { + *(.comment) + *(.eh_frame) + *(.rel.eh_frame) + } +} diff --git a/bootloader/x86/memory_map.asm b/bootloader/x86/memory_map.asm new file mode 100644 index 0000000..a5cdc70 --- /dev/null +++ b/bootloader/x86/memory_map.asm @@ -0,0 +1,32 @@ +SECTION .text +USE16 +;Generate a memory map at 0x500 to 0x5000 (available memory not used for kernel or bootloader) +memory_map: +.start equ 0x0500 +.end equ 0x5000 +.length equ .end - .start + + xor eax, eax + mov di, .start + mov ecx, .length / 4 ; moving 4 Bytes at once + cld + rep stosd + + mov di, .start + mov edx, 0x534D4150 + xor ebx, ebx +.lp: + mov eax, 0xE820 + mov ecx, 24 + + int 0x15 + jc .done ; Error or finished + + cmp ebx, 0 + je .done ; Finished + + add di, 24 + cmp di, .end + jb .lp ; Still have buffer space +.done: + ret diff --git a/bootloader/x86/print16.asm b/bootloader/x86/print16.asm new file mode 100644 index 0000000..32dc69d --- /dev/null +++ b/bootloader/x86/print16.asm @@ -0,0 +1,66 @@ +SECTION .text +USE16 +; provide function for printing in x86 real mode + + +; a newline +newline: db 0xD, 0xA, 0 + +; print a string and a newline +; IN +; si: points at zero-terminated String +; CLOBBER +; ax +print_line: + mov si, newline + call print + ret + +; print a string +; IN +; si: points at zero-terminated String +; CLOBBER +; ax +print: + lodsb + test al, al + jz .done + call print_char + jmp print +.done: + ret + +; print a character +; IN +; al: character to print +; CLOBBER +; ah +print_char: + mov ah, 0x0e + int 0x10 + ret + +; print a number in hex +; IN +; bx: the number +; CLOBBER +; cx, ax +print_num: + mov cx, 4 +.lp: + mov al, bh + shr al, 4 + + cmp al, 0xA + jb .below_0xA + + add al, 'A' - 0xA - '0' +.below_0xA: + add al, '0' + + call print_char + + shl bx, 4 + loop .lp + + ret diff --git a/bootloader/x86/startup-common.asm b/bootloader/x86/startup-common.asm new file mode 100644 index 0000000..5389a06 --- /dev/null +++ b/bootloader/x86/startup-common.asm @@ -0,0 +1,89 @@ +SECTION .text +USE16 + +startup: + ; enable A20-Line via IO-Port 92, might not work on all motherboards + in al, 0x92 + or al, 2 + out 0x92, al + +; loading kernel to 1MiB +; move part of kernel to startup_end via bootsector#load and then copy it up +; repeat until all of the kernel is loaded + +; buffersize in multiple of sectors (512 Bytes) +; min 1 +; max (0x70000 - startup_end) / 512 +buffer_size_sectors equ 1 +; buffer size in Bytes +buffer_size_bytes equ buffer_size_sectors * 512 + +kernel_base equ 0x100000 + + ; how often do we need to call load and move memory + mov ecx, kernel_file.length_sectors / buffer_size_sectors + + mov ax, (kernel_file - boot) / 512 + mov edi, kernel_base + cld +.lp: + ; saving counter + push cx + + ; populating buffer + mov cx, buffer_size_sectors + mov bx, startup_end + mov dx, 0x0 + + push ax + call load + + ; moving buffer + call unreal + pop ax + + mov esi, startup_end + mov ecx, buffer_size_bytes / 4 + a32 rep movsd + + ; preparing next iteration + add ax, buffer_size_sectors + + pop cx + loop .lp + + ; load the part of the kernel that does not fill the buffer completely + mov cx, kernel_file.length_sectors % buffer_size_sectors + test cx, cx + jz finished_loading ; if cx = 0 => skip + + mov bx, startup_end + mov dx, 0x0 + call load + + ; moving remnants of kernel + call unreal + + mov esi, startup_end + mov ecx, (kernel_file.length_sectors % buffer_size_bytes) / 4 + a32 rep movsd +finished_loading: + + + call memory_map + + call vesa + + call initialize.fpu + call initialize.sse + call initialize.pit + call initialize.pic + + jmp startup_arch + +%include "descriptor_flags.inc" +%include "gdt_entry.inc" +%include "unreal.asm" +%include "memory_map.asm" +%include "vesa.asm" +%include "initialize.asm" diff --git a/bootloader/x86/startup-i386.asm b/bootloader/x86/startup-i386.asm new file mode 100644 index 0000000..2466346 --- /dev/null +++ b/bootloader/x86/startup-i386.asm @@ -0,0 +1,150 @@ +%include "startup-common.asm" + +startup_arch: + ; load protected mode GDT and IDT + cli + lgdt [gdtr] + lidt [idtr] + ; set protected mode bit of cr0 + mov eax, cr0 + or eax, 1 + mov cr0, eax + + ; far jump to load CS with 32 bit segment + jmp gdt.kernel_code:protected_mode + +USE32 +protected_mode: + ; load all the other segments with 32 bit data segments + mov eax, gdt.kernel_data + mov ds, eax + mov es, eax + mov fs, eax + mov gs, eax + mov ss, eax + + mov esp, 0x800000 - 128 + + mov eax, gdt.tss + ltr ax + + ;rust init + mov eax, [kernel_base + 0x18] + mov [interrupts.handler], eax + mov eax, gdtr + mov ebx, idtr + mov ecx, tss + int 255 +.lp: + sti + hlt + jmp .lp + +gdtr: + dw gdt.end + 1 ; size + dd gdt ; offset + +gdt: +.null equ $ - gdt + dq 0 + +.kernel_code equ $ - gdt + istruc GDTEntry + at GDTEntry.limitl, dw 0xFFFF + at GDTEntry.basel, dw 0 + at GDTEntry.basem, db 0 + at GDTEntry.attribute, db attrib.present | attrib.user | attrib.code | attrib.readable + at GDTEntry.flags__limith, db 0xFF | flags.granularity | flags.default_operand_size + at GDTEntry.baseh, db 0 + iend + +.kernel_data equ $ - gdt + istruc GDTEntry + at GDTEntry.limitl, dw 0xFFFF + at GDTEntry.basel, dw 0 + at GDTEntry.basem, db 0 + at GDTEntry.attribute, db attrib.present | attrib.user | attrib.writable + at GDTEntry.flags__limith, db 0xFF | flags.granularity | flags.default_operand_size + at GDTEntry.baseh, db 0 + iend + +.user_code equ $ - gdt + istruc GDTEntry + at GDTEntry.limitl, dw 0xFFFF + at GDTEntry.basel, dw 0 + at GDTEntry.basem, db 0 + at GDTEntry.attribute, db attrib.present | attrib.ring3 | attrib.user | attrib.code | attrib.readable + at GDTEntry.flags__limith, db 0xFF | flags.granularity | flags.default_operand_size + at GDTEntry.baseh, db 0 + iend + +.user_data equ $ - gdt + istruc GDTEntry + at GDTEntry.limitl, dw 0xFFFF + at GDTEntry.basel, dw 0 + at GDTEntry.basem, db 0 + at GDTEntry.attribute, db attrib.present | attrib.ring3 | attrib.user | attrib.writable + at GDTEntry.flags__limith, db 0xFF | flags.granularity | flags.default_operand_size + at GDTEntry.baseh, db 0 + iend + +.user_tls equ $ - gdt + istruc GDTEntry + at GDTEntry.limitl, dw 0xFFFF + at GDTEntry.basel, dw 0 + at GDTEntry.basem, db 0 + at GDTEntry.attribute, db attrib.present | attrib.ring3 | attrib.user | attrib.writable + at GDTEntry.flags__limith, db 0xFF | flags.granularity | flags.default_operand_size + at GDTEntry.baseh, db 0 + iend + +.tss equ $ - gdt + istruc GDTEntry + at GDTEntry.limitl, dw (tss.end - tss) & 0xFFFF + at GDTEntry.basel, dw (tss-$$+0x7C00) & 0xFFFF + at GDTEntry.basem, db ((tss-$$+0x7C00) >> 16) & 0xFF + at GDTEntry.attribute, db attrib.present | attrib.ring3 | attrib.tssAvailabe32 + at GDTEntry.flags__limith, db ((tss.end - tss) >> 16) & 0xF + at GDTEntry.baseh, db ((tss-$$+0x7C00) >> 24) & 0xFF + iend +.end equ $ - gdt + +struc TSS + .prev_tss resd 1 ;The previous TSS - if we used hardware task switching this would form a linked list. + .esp0 resd 1 ;The stack pointer to load when we change to kernel mode. + .ss0 resd 1 ;The stack segment to load when we change to kernel mode. + .esp1 resd 1 ;everything below here is unused now.. + .ss1 resd 1 + .esp2 resd 1 + .ss2 resd 1 + .cr3 resd 1 + .eip resd 1 + .eflags resd 1 + .eax resd 1 + .ecx resd 1 + .edx resd 1 + .ebx resd 1 + .esp resd 1 + .ebp resd 1 + .esi resd 1 + .edi resd 1 + .es resd 1 + .cs resd 1 + .ss resd 1 + .ds resd 1 + .fs resd 1 + .gs resd 1 + .ldt resd 1 + .trap resw 1 + .iomap_base resw 1 +endstruc + +tss: + istruc TSS + at TSS.esp0, dd 0x800000 - 128 + at TSS.ss0, dd gdt.kernel_data + at TSS.iomap_base, dw 0xFFFF + iend +.end: + +%include "interrupts-i386.asm" diff --git a/bootloader/x86/startup-x86_64.asm b/bootloader/x86/startup-x86_64.asm new file mode 100644 index 0000000..8dd738d --- /dev/null +++ b/bootloader/x86/startup-x86_64.asm @@ -0,0 +1,191 @@ +%include "startup-common.asm" + +startup_arch: + cli + ; setting up Page Tables + ; Identity Mapping first GB + mov ax, 0x7000 + mov es, ax + + xor edi, edi + xor eax, eax + mov ecx, 3 * 4096 / 4 ;PML4, PDP, PD / moves 4 Bytes at once + cld + rep stosd + + xor edi, edi + ;Link first PML4 to PDP + mov DWORD [es:edi], 0x71000 | 1 << 1 | 1 + add edi, 0x1000 + ;Link first PDP to PD + mov DWORD [es:edi], 0x72000 | 1 << 1 | 1 + add edi, 0x1000 + ;Link all PD's (512 per PDP, 2MB each)y + mov ebx, 1 << 7 | 1 << 1 | 1 + mov ecx, 512 +.setpd: + mov [es:edi], ebx + add ebx, 0x200000 + add edi, 8 + loop .setpd + + xor ax, ax + mov es, ax + + ;cr3 holds pointer to PML4 + mov edi, 0x70000 + mov cr3, edi + + ;enable Page Address Extension and Page Size Extension + mov eax, cr4 + or eax, 1 << 5 | 1 << 4 + mov cr4, eax + + ; load protected mode GDT + lgdt [gdtr] + + mov ecx, 0xC0000080 ; Read from the EFER MSR. + rdmsr + or eax, 0x00000100 ; Set the Long-Mode-Enable bit. + wrmsr + + ;enabling paging and protection simultaneously + mov ebx, cr0 + or ebx, 0x80000001 ;Bit 31: Paging, Bit 0: Protected Mode + mov cr0, ebx + + ; far jump to enable Long Mode and load CS with 64 bit segment + jmp gdt.kernel_code:long_mode + +USE64 +long_mode: + ; load all the other segments with 64 bit data segments + mov rax, gdt.kernel_data + mov ds, rax + mov es, rax + mov fs, rax + mov gs, rax + mov ss, rax + + ; load long mode IDT + lidt [idtr] + + mov rsp, 0x800000 - 128 + + mov rax, gdt.tss + ltr ax + + ;rust init + mov eax, [kernel_base + 0x18] + mov [interrupts.handler], rax + mov rax, gdtr + mov rbx, idtr + mov rcx, tss + int 0xFF +.lp: + sti + hlt + jmp .lp + + gdtr: + dw gdt.end + 1 ; size + dq gdt ; offset + + gdt: + .null equ $ - gdt + dq 0 + + .kernel_code equ $ - gdt + istruc GDTEntry + at GDTEntry.limitl, dw 0 + at GDTEntry.basel, dw 0 + at GDTEntry.basem, db 0 + at GDTEntry.attribute, db attrib.present | attrib.user | attrib.code + at GDTEntry.flags__limith, db flags.long_mode + at GDTEntry.baseh, db 0 + iend + + .kernel_data equ $ - gdt + istruc GDTEntry + at GDTEntry.limitl, dw 0 + at GDTEntry.basel, dw 0 + at GDTEntry.basem, db 0 + ; AMD System Programming Manual states that the writeable bit is ignored in long mode, but ss can not be set to this descriptor without it + at GDTEntry.attribute, db attrib.present | attrib.user | attrib.writable + at GDTEntry.flags__limith, db 0 + at GDTEntry.baseh, db 0 + iend + + .user_code equ $ - gdt + istruc GDTEntry + at GDTEntry.limitl, dw 0 + at GDTEntry.basel, dw 0 + at GDTEntry.basem, db 0 + at GDTEntry.attribute, db attrib.present | attrib.ring3 | attrib.user | attrib.code + at GDTEntry.flags__limith, db flags.long_mode + at GDTEntry.baseh, db 0 + iend + + .user_data equ $ - gdt + istruc GDTEntry + at GDTEntry.limitl, dw 0 + at GDTEntry.basel, dw 0 + at GDTEntry.basem, db 0 + ; AMD System Programming Manual states that the writeable bit is ignored in long mode, but ss can not be set to this descriptor without it + at GDTEntry.attribute, db attrib.present | attrib.ring3 | attrib.user | attrib.writable + at GDTEntry.flags__limith, db 0 + at GDTEntry.baseh, db 0 + iend + + .user_tls equ $ - gdt + istruc GDTEntry + at GDTEntry.limitl, dw 0 + at GDTEntry.basel, dw 0 + at GDTEntry.basem, db 0 + ; AMD System Programming Manual states that the writeable bit is ignored in long mode, but ss can not be set to this descriptor without it + at GDTEntry.attribute, db attrib.present | attrib.ring3 | attrib.user | attrib.writable + at GDTEntry.flags__limith, db 0 + at GDTEntry.baseh, db 0 + iend + + .tss equ $ - gdt + istruc GDTEntry + at GDTEntry.limitl, dw (tss.end - tss) & 0xFFFF + at GDTEntry.basel, dw (tss-$$+0x7C00) & 0xFFFF + at GDTEntry.basem, db ((tss-$$+0x7C00) >> 16) & 0xFF + at GDTEntry.attribute, db attrib.present | attrib.ring3 | attrib.tssAvailabe64 + at GDTEntry.flags__limith, db ((tss.end - tss) >> 16) & 0xF + at GDTEntry.baseh, db ((tss-$$+0x7C00) >> 24) & 0xFF + iend + dq 0 ;tss descriptors are extended to 16 Bytes + + .end equ $ - gdt + + struc TSS + .reserved1 resd 1 ;The previous TSS - if we used hardware task switching this would form a linked list. + .rsp0 resq 1 ;The stack pointer to load when we change to kernel mode. + .rsp1 resq 1 ;everything below here is unused now.. + .rsp2 resq 1 + .reserved2 resd 1 + .reserved3 resd 1 + .ist1 resq 1 + .ist2 resq 1 + .ist3 resq 1 + .ist4 resq 1 + .ist5 resq 1 + .ist6 resq 1 + .ist7 resq 1 + .reserved4 resd 1 + .reserved5 resd 1 + .reserved6 resw 1 + .iomap_base resw 1 + endstruc + + tss: + istruc TSS + at TSS.rsp0, dd 0x800000 - 128 + at TSS.iomap_base, dw 0xFFFF + iend + .end: + + %include "interrupts-x86_64.asm" diff --git a/bootloader/x86/unreal.asm b/bootloader/x86/unreal.asm new file mode 100644 index 0000000..691a892 --- /dev/null +++ b/bootloader/x86/unreal.asm @@ -0,0 +1,54 @@ +SECTION .text +USE16 + +; switch to unreal mode; ds and es can address up to 4GiB +unreal: + cli + + lgdt [unreal_gdtr] + + push es + push ds + + mov eax, cr0 ; switch to pmode by + or al,1 ; set pmode bit + mov cr0, eax + + jmp $+2 + +; http://wiki.osdev.org/Babystep7 +; When this register given a "selector", a "segment descriptor cache register" +; is filled with the descriptor values, including the size (or limit). After +; the switch back to real mode, these values are not modified, regardless of +; what value is in the 16-bit segment register. So the 64k limit is no longer +; valid and 32-bit offsets can be used with the real-mode addressing rules + mov bx, unreal_gdt.data + mov es, bx + mov ds, bx + + and al,0xFE ; back to realmode + mov cr0, eax ; by toggling bit again + + pop ds + pop es + sti + ret + + +unreal_gdtr: + dw unreal_gdt.end + 1 ; size + dd unreal_gdt ; offset + +unreal_gdt: +.null equ $ - unreal_gdt + dq 0 +.data equ $ - unreal_gdt + istruc GDTEntry + at GDTEntry.limitl, dw 0xFFFF + at GDTEntry.basel, dw 0x0 + at GDTEntry.basem, db 0x0 + at GDTEntry.attribute, db attrib.present | attrib.user | attrib.writable + at GDTEntry.flags__limith, db 0xFF | flags.granularity | flags.default_operand_size + at GDTEntry.baseh, db 0x0 + iend +.end equ $ - unreal_gdt diff --git a/bootloader/x86/vesa.asm b/bootloader/x86/vesa.asm new file mode 100644 index 0000000..8dadf2a --- /dev/null +++ b/bootloader/x86/vesa.asm @@ -0,0 +1,304 @@ +%include "vesa.inc" +SECTION .text +USE16 +vesa: +.getcardinfo: + mov ax, 0x4F00 + mov di, VBECardInfo + int 0x10 + cmp ax, 0x4F + je .edid + mov eax, 1 + ret +.edid: + cmp dword [.required], 0 ;if both required x and required y are set, forget this + jne near .findmode + mov ax, 0x4F15 + mov bx, 1 + xor cx, cx + xor dx, dx + mov di, VBEEDID + int 0x10 + cmp ax, 0x4F + jne near .noedid + xor di, di +.lp: + xor cx, cx + mov cl, [di+VBEEDID.standardtiming] + shl cx, 3 + add cx, 248 + push ecx + call decshowrm + mov al, 'x' + call charrm + pop ecx + mov bx, cx + inc di + mov al, [di+VBEEDID.standardtiming] + and al, 11000000b + cmp al, VBEEDID.aspect.4.3 + jne .not43 + mov ax, 3 + mul cx + mov cx, ax + shr cx, 2 + jmp .gotres +.not43: + cmp al, VBEEDID.aspect.5.4 + jne .not54 + shl cx, 2 + mov ax, cx + mov cx, 5 + xor dx, dx + div cx + mov cx, ax + jmp .gotres +.not54: + cmp al, VBEEDID.aspect.16.10 + jne .not1610 + mov ax, 10 + mul cx + mov cx, ax + shr cx, 4 + jmp .gotres +.not1610: + mov ax, 9 + mul cx + mov cx, ax + shr cx, 4 +.gotres: + call decshowrm + mov si, .edidmsg + call printrm + inc di + cmp di, 8 + jb .lp + jmp .findmode +.noedid: + mov si, .noedidmsg + call printrm + jmp .findmode + .resetlist: + ;if needed, reset mins/maxes/stuff + xor cx, cx + mov [.minx], cx + mov [.miny], cx + mov [.requiredx], cx + mov [.requiredy], cx + mov [.requiredmode], cx +.findmode: + mov si, [VBECardInfo.videomodeptr] + mov ax, [VBECardInfo.videomodeptr+2] + mov fs, ax + sub si, 2 + mov cx, [.requiredmode] + test cx, cx + jnz .getmodeinfo +.searchmodes: + add si, 2 + mov cx, [fs:si] + cmp cx, 0xFFFF + jne .getmodeinfo + cmp word [.goodmode], 0 + je .resetlist + jmp .findmode +.getmodeinfo: + push esi + mov [.currentmode], cx + mov ax, 0x4F01 + mov di, VBEModeInfo + int 0x10 + pop esi + cmp ax, 0x4F + je .foundmode + mov eax, 1 + ret +.foundmode: + ;check minimum values, really not minimums from an OS perspective but ugly for users + cmp byte [VBEModeInfo.bitsperpixel], 32 + jb .searchmodes +.testx: + mov cx, [VBEModeInfo.xresolution] + cmp word [.requiredx], 0 + je .notrequiredx + cmp cx, [.requiredx] + je .testy + jmp .searchmodes +.notrequiredx: + cmp cx, [.minx] + jb .searchmodes +.testy: + mov cx, [VBEModeInfo.yresolution] + cmp word [.requiredy], 0 + je .notrequiredy + cmp cx, [.requiredy] + jne .searchmodes ;as if there weren't enough warnings, USE WITH CAUTION + cmp word [.requiredx], 0 + jnz .setmode + jmp .testgood +.notrequiredy: + cmp cx, [.miny] + jb .searchmodes +.testgood: + mov cx, [.currentmode] + mov [.goodmode], cx + push esi + call decshowrm + mov al, ':' + call charrm + mov cx, [VBEModeInfo.xresolution] + call decshowrm + mov al, 'x' + call charrm + mov cx, [VBEModeInfo.yresolution] + call decshowrm + mov al, '@' + call charrm + xor ch, ch + mov cl, [VBEModeInfo.bitsperpixel] + call decshowrm + mov si, .modeok + call printrm + xor ax, ax + int 0x16 + pop esi + cmp al, 'y' + jne .searchmodes +.setmode: + mov bx, [.currentmode] + cmp bx, 0 + je .nomode + or bx, 0x4000 + mov ax, 0x4F02 + int 0x10 +.nomode: + cmp ax, 0x4F + je .returngood + mov eax, 1 + ret +.returngood: + xor eax, eax + ret + +.minx dw 640 +.miny dw 480 +.required: +.requiredx dw 0 ;1024 ;USE THESE WITH CAUTION +.requiredy dw 0 ;768 +.requiredmode dw 0 + +.noedidmsg db "EDID not supported.",10,13,0 +.edidmsg db " is supported.",10,13,0 +.modeok db ": Is this OK?(y/n)",10,13,0 + +.goodmode dw 0 +.currentmode dw 0 +;useful functions + +decshowrm: + mov si, .number +.clear: + mov al, "0" + mov [si], al + inc si + cmp si, .numberend + jb .clear + dec si + call convertrm + mov si, .number +.lp: + lodsb + cmp si, .numberend + jae .end + cmp al, "0" + jbe .lp +.end: + dec si + call printrm + ret + +.number times 7 db 0 +.numberend db 0 + +convertrm: + dec si + mov bx, si ;place to convert into must be in si, number to convert must be in cx +.cnvrt: + mov si, bx + sub si, 4 +.ten4: inc si + cmp cx, 10000 + jb .ten3 + sub cx, 10000 + inc byte [si] + jmp .cnvrt +.ten3: inc si + cmp cx, 1000 + jb .ten2 + sub cx, 1000 + inc byte [si] + jmp .cnvrt +.ten2: inc si + cmp cx, 100 + jb .ten1 + sub cx, 100 + inc byte [si] + jmp .cnvrt +.ten1: inc si + cmp cx, 10 + jb .ten0 + sub cx, 10 + inc byte [si] + jmp .cnvrt +.ten0: inc si + cmp cx, 1 + jb .return + sub cx, 1 + inc byte [si] + jmp .cnvrt +.return: + ret + +printrm: + mov al, [si] + test al, al + jz .return + call charrm + inc si + jmp printrm +.return: + ret + +charrm: ;char must be in al + mov bx, 7 + mov ah, 0xE + int 10h + ret + +; .bestmode: ;preference is width > height > color + ; mov bx, [VBEModeInfo.xresolution] + ; cmp bx, [.width] + ; ja .switchmode + ; jb .searchmodes + ; mov bx, [VBEModeInfo.yresolution] + ; cmp bx, [.height] + ; ja .switchmode + ; jb .searchmodes + ; mov bl, [VBEModeInfo.bitsperpixel] + ; cmp bl, [.color] + ; jb .searchmodes +; .switchmode: + ; mov cx, [.currentmode] + ; mov [.mode], cx + ; mov bx, [VBEModeInfo.xresolution] + ; mov [.width], bx + ; mov bx, [VBEModeInfo.yresolution] + ; mov [.height], bx + ; mov bl, [VBEModeInfo.bitsperpixel] + ; mov [.color], bl + ; jmp .searchmodes + +; .mode dw 0 +; .color db 0 +; .height dw 0 +; .width dw 0 diff --git a/bootloader/x86/vesa.inc b/bootloader/x86/vesa.inc new file mode 100644 index 0000000..7f85476 --- /dev/null +++ b/bootloader/x86/vesa.inc @@ -0,0 +1,90 @@ +ABSOLUTE 0x5000 +VBECardInfo: + .signature resb 4 + .version resw 1 + .oemstring resd 1 + .capabilities resd 1 + .videomodeptr resd 1 + .totalmemory resw 1 + .oemsoftwarerev resw 1 + .oemvendornameptr resd 1 + .oemproductnameptr resd 1 + .oemproductrevptr resd 1 + .reserved resb 222 + .oemdata resb 256 + +ABSOLUTE 0x5200 +VBEModeInfo: + .attributes resw 1 + .winA resb 1 + .winB resb 1 + .granularity resw 1 + .winsize resw 1 + .segmentA resw 1 + .segmentB resw 1 + .winfuncptr resd 1 + .bytesperscanline resw 1 + .xresolution resw 1 + .yresolution resw 1 + .xcharsize resb 1 + .ycharsize resb 1 + .numberofplanes resb 1 + .bitsperpixel resb 1 + .numberofbanks resb 1 + .memorymodel resb 1 + .banksize resb 1 + .numberofimagepages resb 1 + .unused resb 1 + .redmasksize resb 1 + .redfieldposition resb 1 + .greenmasksize resb 1 + .greenfieldposition resb 1 + .bluemasksize resb 1 + .bluefieldposition resb 1 + .rsvdmasksize resb 1 + .rsvdfieldposition resb 1 + .directcolormodeinfo resb 1 + .physbaseptr resd 1 + .offscreenmemoryoffset resd 1 + .offscreenmemsize resw 1 + .reserved resb 206 + +VBE.ModeAttributes: + .available equ 1 << 0 + .bios equ 1 << 2 + .color equ 1 << 3 + .graphics equ 1 << 4 + .vgacompatible equ 1 << 5 + .notbankable equ 1 << 6 + .linearframebuffer equ 1 << 7 + +ABSOLUTE 0x5400 +VBEEDID: + .header resb 8 + .manufacturer resw 1 + .productid resw 1 + .serial resd 1 + .manufactureweek resb 1 + .manufactureyear resb 1 + .version resb 1 + .revision resb 1 + .input resb 1 + .horizontalsize resb 1 + .verticalsize resb 1 + .gamma resb 1 + .displaytype resb 1 + .chromaticity resb 10 + .timingI resb 1 + .timingII resb 1 + .timingreserved resb 1 + .standardtiming: resw 8 ;format: db (horizontal-248)/8, aspectratio | verticalfrequency - 60 + .aspect.16.10 equ 0 ;mul horizontal by 10, shr 4 to get vertical resolution + .aspect.4.3 equ 1 << 6 ;mul horizontal by 3, shr 2 to get vertical resolution + .aspect.5.4 equ 2 << 6 ;shl horizontal by 2, div by 5 to get vertical resolution + .aspect.16.9 equ 3 << 6 ;mul horizontal by 9, shr by 4 to get vertical resolution + .descriptorblock1 resb 18 + .descriptorblock2 resb 18 + .descriptorblock3 resb 18 + .descriptorblock4 resb 18 + .extensionflag resb 1 + .checksum resb 1 \ No newline at end of file diff --git a/src/arch/mod.rs b/src/arch/mod.rs new file mode 100644 index 0000000..37a90c2 --- /dev/null +++ b/src/arch/mod.rs @@ -0,0 +1,4 @@ +//! Architecture specific items + +#[cfg(target_arch = "x86_64")] +pub mod x86_64; diff --git a/src/arch/x86_64/irq.rs b/src/arch/x86_64/irq.rs new file mode 100644 index 0000000..78f69b6 --- /dev/null +++ b/src/arch/x86_64/irq.rs @@ -0,0 +1,8 @@ +//! # IRQ handling +//! This module defines IRQ handling functions. These functions should all be #[naked], +//! unsafe, extern, and end in `iretq` + +#[naked] +pub unsafe extern fn irq() { + +} diff --git a/src/arch/x86_64/main.rs b/src/arch/x86_64/main.rs new file mode 100644 index 0000000..c4ca2e4 --- /dev/null +++ b/src/arch/x86_64/main.rs @@ -0,0 +1,11 @@ +/// This function is where the kernel sets up IRQ handlers +/// It is increcibly unsafe, and should be minimal in nature +/// It must create the IDT with the correct entries, those entries are +/// defined in other files inside of the `arch` module +#[naked] +#[no_mangle] +pub unsafe extern fn kmain() { + asm!("xchg bx, bx" : : : : "intel", "volatile"); + + loop{} +} diff --git a/src/arch/x86_64/mod.rs b/src/arch/x86_64/mod.rs new file mode 100644 index 0000000..530a611 --- /dev/null +++ b/src/arch/x86_64/mod.rs @@ -0,0 +1,5 @@ +/// IRQ Handling +pub mod irq; + +/// Initialization and main function +pub mod main; diff --git a/src/lib.rs b/src/lib.rs index 3781cf3..5f7b513 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,31 +11,37 @@ //! `open(path: &str, flags: usize) -> Result` //! //! Open a file, providing a path as a `&str` and flags, defined elsewhere. +//! //! Returns a number, known as a file descriptor, that is passed to other syscalls //! //! ### Close //! `close(file_descriptor: usize) -> Result<()>` //! //! Close a file descriptor, providing the file descriptor from `open` +//! //! Returns an error, `EBADF`, if the file descriptor was not found. +//! //! This potential error is often ignored by userspace //! //! ### Duplicate //! `dup(file_descriptor: usize) -> Result` //! //! Duplicate a file descriptor, providing the file descriptor from `open` +//! //! Returns a new file descriptor, or an error //! //! ### Read //! `read(file_descriptor: usize, buffer: &mut [u8]) -> Result` //! //! Read from a file descriptor, providing the file descriptor from `open` and a mutable buffer +//! //! Returns the number of bytes actually read, or an error //! //! ### Write //! `write(file_descriptor: usize, buffer: &[u8]) -> Result` //! //! Write to a file descriptor, providing the file descriptor from `open` and a const buffer +//! //! Returns the number of bytes actually written, or an error //! //! ### Stat @@ -43,12 +49,34 @@ //! //! Get information from a file descriptor, providing the file descriptor from `open` //! and a mutable Stat struct, defined elsewhere. +//! //! Returns an error if the operation failed //! //! ### Path //! `fpath(file_descriptor: usize, buffer: &mut [u8]) -> Result` //! -//! Read the path of a file descriptor, providing the file descriptor from `open` -//! and a mutable buffer. The buffer should be 4096 bytes, to ensure that the -//! entire path will fit. +//! Read the path of a file descriptor, providing the file descriptor from `open` and +//! a mutable buffer. +//! //! Returns the number of bytes actually read, or an error +//! +//! The buffer should be 4096 bytes, to ensure that the entire path will fit. +//! An error will be returned, `ENOBUFS`, if the buffer is not long enough for the name. +//! In this case, it is recommended to add one page, 4096 bytes, to the buffer and retry. + +#![feature(asm)] +#![feature(lang_items)] +#![feature(naked_functions)] +#![no_std] + +/// Architecture specific items +pub mod arch; + +#[cfg(not(test))] +#[lang = "eh_personality"] +extern "C" fn eh_personality() {} + +#[cfg(not(test))] +/// Required to handle panics +#[lang = "panic_fmt"] +extern "C" fn panic_fmt() -> ! {loop{}} diff --git a/src/scheme/mod.rs b/src/scheme/mod.rs new file mode 100644 index 0000000..7ed8fb1 --- /dev/null +++ b/src/scheme/mod.rs @@ -0,0 +1,11 @@ +/// A scheme is a primitive for handling filesystem syscalls in Redox. +/// Schemes accept paths from the kernel for `open`, and file descriptors that they generate +/// are then passed for operations like `close`, `read`, `write`, etc. +/// +/// The kernel validates paths and file descriptors before they are passed to schemes, +/// also stripping the scheme identifier of paths if necessary. +pub trait Scheme { + /// Open the file at `path` with `flags`. + /// Returns a file descriptor or an error + fn open(path: &str, flags: usize) -> Result; +} diff --git a/x86_64-unknown-none.json b/x86_64-unknown-none.json new file mode 100644 index 0000000..cc955d3 --- /dev/null +++ b/x86_64-unknown-none.json @@ -0,0 +1,25 @@ +{ + "llvm-target": "x86_64-unknown-none", + "target-endian": "little", + "target-pointer-width": "64", + "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128", + "arch": "x86_64", + "os": "none", + "env": "", + "vendor": "unknown", + "target-family": "redox", + "pre-link-args": ["-m64", "-nostdlib", "-static"], + "features": "-sse3,-ssse3,-sse4.1,-sse4.2,-3dnow,-3dnowa,-avx,-avx2", + "dynamic-linking": false, + "executables": false, + "relocation-model": "static", + "code-model": "kernel", + "disable-redzone": true, + "eliminate-frame-pointer": true, + "exe-suffix": "", + "has-rpath": false, + "no-compiler-rt": true, + "no-default-libraries": true, + "position-independent-executables": false, + "has-elf-tls": false +} diff --git a/x86_64-unknown-redox.json b/x86_64-unknown-redox.json new file mode 100644 index 0000000..fea6c75 --- /dev/null +++ b/x86_64-unknown-redox.json @@ -0,0 +1,25 @@ +{ + "llvm-target": "x86_64-unknown-redox", + "target-endian": "little", + "target-pointer-width": "64", + "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128", + "arch": "x86_64", + "os": "redox", + "env": "", + "vendor": "unknown", + "target-family": "redox", + "pre-link-args": ["-m64", "-nostdlib", "-static"], + "features": "-sse3,-ssse3,-sse4.1,-sse4.2,-3dnow,-3dnowa,-avx,-avx2", + "dynamic-linking": false, + "executables": true, + "relocation-model": "static", + "code-model": "kernel", + "disable-redzone": true, + "eliminate-frame-pointer": true, + "exe-suffix": ".bin", + "has-rpath": false, + "no-compiler-rt": true, + "no-default-libraries": true, + "position-independent-executables": false, + "has-elf-tls": false +}