├── .gitignore ├── kernel ├── include │ ├── tty.h │ ├── panic.h │ ├── mouse.h │ ├── smp.h │ ├── kernel.h │ ├── subleq.h │ ├── vbe_tty.h │ ├── e820.h │ ├── apic.h │ ├── paging.h │ ├── vga_textmode.h │ ├── klib.h │ ├── system.h │ ├── cio.h │ ├── graphics.h │ └── acpi.h ├── blobs │ ├── set_vbe_mode.real │ ├── dump_vga_font.real │ ├── get_vbe_mode_info.real │ ├── flush_irqs.real │ ├── get_time.real │ ├── e820.real │ ├── smp_trampoline.real │ ├── get_vbe_info.real │ └── real_init.real ├── src │ ├── drivers │ │ ├── tty.c │ │ ├── panic.c │ │ ├── pit.c │ │ ├── pic.c │ │ ├── e820.c │ │ ├── pm.c │ │ ├── exceptions.c │ │ ├── smp.c │ │ ├── graphics.c │ │ ├── apic.c │ │ ├── acpi.c │ │ ├── keyboard.c │ │ ├── vga_textmode.c │ │ ├── vbe_tty.c │ │ └── mouse.c │ ├── time.c │ ├── init.c │ ├── subleq.c │ ├── klib.c │ └── paging.c ├── startup │ ├── boot.asm │ └── startup.asm ├── asm │ ├── flush_irqs.asm │ ├── real.asm │ ├── e820.asm │ ├── smp.asm │ ├── date.asm │ ├── graphics.asm │ ├── subleq.asm │ ├── isr.asm │ └── idt.asm ├── linker.ld └── Makefile ├── bootloader ├── Makefile ├── includes │ ├── simple_print.inc │ ├── gdt.inc │ ├── disk.inc │ └── a20_enabler.inc ├── bootloader.asm └── stage2.asm ├── Makefile ├── README ├── LICENSE └── hardware.txt /.gitignore: -------------------------------------------------------------------------------- 1 | **/*.o 2 | **/*.elf 3 | **/*.bin 4 | **/*.img 5 | **/*.img.xz 6 | **/*.zip 7 | Dawn 8 | -------------------------------------------------------------------------------- /kernel/include/tty.h: -------------------------------------------------------------------------------- 1 | #ifndef __TTY_H__ 2 | #define __TTY_H__ 3 | 4 | void tty_putchar(char); 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /kernel/blobs/set_vbe_mode.real: -------------------------------------------------------------------------------- 1 | org 0x8000 2 | bits 16 3 | 4 | mov eax, 0x4f02 5 | mov ebx, ebx 6 | or ebx, 100000000000000b 7 | int 0x10 8 | ret 9 | -------------------------------------------------------------------------------- /kernel/include/panic.h: -------------------------------------------------------------------------------- 1 | #ifndef __PANIC_H__ 2 | #define __PANIC_H__ 3 | 4 | 5 | 6 | void panic(const char *msg, int code); 7 | 8 | 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /kernel/include/mouse.h: -------------------------------------------------------------------------------- 1 | #ifndef __MOUSE_H__ 2 | #define __MOUSE_H__ 3 | 4 | void put_mouse_cursor(int); 5 | void mouse_update(void); 6 | void init_mouse(void); 7 | 8 | extern int hw_mouse_enabled; 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /bootloader/Makefile: -------------------------------------------------------------------------------- 1 | AS=nasm 2 | 3 | .PHONY: all clean 4 | 5 | all: 6 | $(AS) stage2.asm -f bin -o stage2.bin 7 | $(AS) bootloader.asm -f bin -o bootloader.bin 8 | 9 | clean: 10 | rm -f bootloader.bin stage2.bin 11 | -------------------------------------------------------------------------------- /kernel/src/drivers/tty.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void tty_putchar(char c) { 6 | if (!vbe_tty_available) { 7 | text_putchar(c); 8 | } else { 9 | vbe_tty_putchar(c); 10 | } 11 | 12 | return; 13 | } 14 | -------------------------------------------------------------------------------- /kernel/include/smp.h: -------------------------------------------------------------------------------- 1 | #ifndef __SMP_H__ 2 | #define __SMP_H__ 3 | 4 | void init_smp(void); 5 | 6 | void *prepare_smp_trampoline(void *, void *, void *, void *, void *); 7 | int check_ap_flag(void); 8 | void init_cpu0_local(void *, void *); 9 | 10 | extern int cpu_count; 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /kernel/blobs/dump_vga_font.real: -------------------------------------------------------------------------------- 1 | org 0x8000 2 | bits 16 3 | 4 | push ds 5 | push ebx 6 | push es 7 | 8 | xor ebp, ebp 9 | mov eax, 0x1130 10 | xor ebx, ebx 11 | mov bh, 6 12 | int 0x10 13 | 14 | mov esi, ebp 15 | push es 16 | pop ds 17 | pop es 18 | pop edi 19 | 20 | mov ecx, 4096 21 | a32 o32 rep movsb 22 | 23 | pop ds 24 | 25 | ret 26 | -------------------------------------------------------------------------------- /kernel/blobs/get_vbe_mode_info.real: -------------------------------------------------------------------------------- 1 | org 0x8000 2 | bits 16 3 | 4 | push ebx 5 | 6 | mov ecx, dword [ebx+4] 7 | mov eax, 0x4f01 8 | mov edi, mode_info_struct 9 | int 0x10 10 | 11 | mov ecx, 256 12 | pop ebx 13 | mov edi, dword [ebx] 14 | mov esi, mode_info_struct 15 | a32 o32 rep movsb 16 | 17 | ret 18 | 19 | mode_info_struct: 20 | times 256 db 0 21 | -------------------------------------------------------------------------------- /kernel/include/kernel.h: -------------------------------------------------------------------------------- 1 | #ifndef __KERNEL_H__ 2 | #define __KERNEL_H__ 3 | 4 | #define KERNEL_PHYS_OFFSET 0xffffffffc0000000 5 | #define PHYS_MEM_OFFSET 0xffff800000000000 6 | 7 | // misc tunables 8 | 9 | #define KRNL_PIT_FREQ 1000 10 | #define MOUSE_UPDATE_FREQ 50 11 | #define SCREEN_REFRESH_FREQ 30 12 | 13 | 14 | #define MAX_MADT 128 15 | 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /kernel/startup/boot.asm: -------------------------------------------------------------------------------- 1 | extern startup 2 | extern sections_text 3 | extern sections_data_end 4 | extern sections_bss_end 5 | global _start 6 | 7 | bits 32 8 | 9 | section .startup 10 | _start: 11 | mov ecx, sections_bss_end 12 | sub ecx, sections_data_end 13 | mov edi, sections_data_end 14 | xor eax, eax 15 | rep stosb 16 | 17 | jmp startup 18 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | DEBUG = off 2 | 3 | .PHONY: all clean run 4 | 5 | all: 6 | $(MAKE) DEBUG=$(DEBUG) -C kernel 7 | $(MAKE) -C bootloader 8 | mv bootloader/bootloader.bin ./subleq.img 9 | 10 | clean: 11 | $(MAKE) clean -C kernel 12 | $(MAKE) clean -C bootloader 13 | 14 | run: 15 | qemu-system-x86_64 -net none -hda subleq.img -enable-kvm -cpu host -m 2G -smp 4 -debugcon stdio 16 | -------------------------------------------------------------------------------- /kernel/include/subleq.h: -------------------------------------------------------------------------------- 1 | #ifndef __SUBLEQ_H__ 2 | #define __SUBLEQ_H__ 3 | 4 | #include 5 | 6 | void subleq(void); 7 | void subleq_io_flush(void); 8 | void subleq_io_write(uint64_t, uint64_t); 9 | uint64_t _readram(uint64_t); 10 | void _writeram(uint64_t, uint64_t); 11 | void init_subleq(uintptr_t); 12 | void subleq_redraw_screen(void); 13 | 14 | extern int subleq_ready; 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /kernel/include/vbe_tty.h: -------------------------------------------------------------------------------- 1 | #ifndef __VBE_TTY_H__ 2 | #define __VBE_TTY_H__ 3 | 4 | #include 5 | 6 | extern int vbe_tty_available; 7 | 8 | void init_vbe_tty(void); 9 | void vbe_tty_putchar(char); 10 | void vbe_tty_enable_cursor(void); 11 | void vbe_tty_disable_cursor(void); 12 | void vbe_tty_clear(void); 13 | void vbe_tty_set_cursor_pos(int, int); 14 | void vbe_tty_refresh(void); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /kernel/include/e820.h: -------------------------------------------------------------------------------- 1 | #ifndef __E820_H__ 2 | #define __E820_H__ 3 | 4 | #include 5 | #include 6 | 7 | typedef struct { 8 | uint64_t base; 9 | uint64_t length; 10 | uint32_t type; 11 | uint32_t unused; 12 | } __attribute__((packed)) e820_entry_t; 13 | 14 | extern uint64_t memory_size; 15 | extern e820_entry_t e820_map[256]; 16 | 17 | void init_e820(void); 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /kernel/blobs/flush_irqs.real: -------------------------------------------------------------------------------- 1 | org 0x8000 2 | bits 16 3 | 4 | call await 5 | cli 6 | nop 7 | nop 8 | mov al, 0xff 9 | out 0x21, al 10 | out 0xA1, al 11 | nop 12 | nop 13 | sti 14 | call await 15 | ret 16 | 17 | await: 18 | pusha 19 | mov bx, 0xffff 20 | .loop: 21 | mov cx, 16 22 | mov di, dummy1 23 | mov si, dummy2 24 | rep movsb 25 | dec bx 26 | jnz .loop 27 | popa 28 | ret 29 | 30 | dummy1 times 16 db 0 31 | dummy2 times 16 db 0 32 | -------------------------------------------------------------------------------- /kernel/include/apic.h: -------------------------------------------------------------------------------- 1 | #ifndef __APIC_H__ 2 | #define __APIC_H__ 3 | 4 | #define APICREG_ICR0 0x300 5 | #define APICREG_ICR1 0x310 6 | 7 | 8 | void init_apic(void); 9 | 10 | void lapic_enable(void); 11 | uint32_t lapic_read(uint32_t reg); 12 | void lapic_write(uint32_t reg, uint32_t val); 13 | uint32_t ioapic_read(size_t ioapic_num, uint32_t reg); 14 | void ioapic_write(size_t ioapic_num, uint32_t reg, uint32_t val); 15 | 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /kernel/blobs/get_time.real: -------------------------------------------------------------------------------- 1 | org 0x8000 2 | bits 16 3 | 4 | clc 5 | push ebx 6 | mov ah, 0x02 7 | int 0x1a 8 | pop ebx 9 | jc err 10 | 11 | mov byte [ebx+0], dh 12 | mov byte [ebx+1], cl 13 | mov byte [ebx+2], ch 14 | 15 | clc 16 | push ebx 17 | mov ah, 0x04 18 | int 0x1a 19 | pop ebx 20 | jc err 21 | 22 | mov byte [ebx+3], dl 23 | mov byte [ebx+4], dh 24 | mov byte [ebx+5], cl 25 | mov byte [ebx+6], ch 26 | 27 | ret 28 | 29 | err: 30 | 31 | mov byte [ebx+7], 1 32 | ret 33 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Quick readme on how to build: 2 | 3 | - Get a x86_64 gcc+binutils toolchain and add it to your path. 4 | Your system GCC will be more than enough if you're using a 5 | 64 bit x86 OS. 6 | 7 | - Get nasm. 8 | 9 | - Get the latest Dawn ZIP from http://users.atw.hu/gerigeri/DawnOS/download.html 10 | Extract and move the Dawn directory to the root of the repo. 11 | 12 | - Run "make run" in the root of the repository tree. (Needs qemu-system-x86_64 to run). 13 | 14 | - Enjoy. 15 | -------------------------------------------------------------------------------- /kernel/include/paging.h: -------------------------------------------------------------------------------- 1 | #ifndef __PAGING_H__ 2 | #define __PAGING_H__ 3 | 4 | #include 5 | #include 6 | 7 | /* arch specific values */ 8 | #define PAGE_SIZE 0x200000 9 | #define PAGE_TABLE_ENTRIES 512 10 | 11 | void init_paging(uintptr_t); 12 | 13 | void *kmalloc(size_t); 14 | void kmfree(void *, size_t); 15 | 16 | typedef uint64_t pt_entry_t; 17 | 18 | int map_page(pt_entry_t *, size_t, size_t); 19 | 20 | extern pt_entry_t kernel_pagemap[]; 21 | extern pt_entry_t *subleq_pagemap; 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /kernel/include/vga_textmode.h: -------------------------------------------------------------------------------- 1 | #ifndef __VGA_TEXTMODE_H__ 2 | #define __VGA_TEXTMODE_H__ 3 | 4 | #include 5 | 6 | void init_vga_textmode(void); 7 | void text_set_cursor_palette(uint8_t c); 8 | uint8_t text_get_cursor_palette(void); 9 | void text_set_text_palette(uint8_t c); 10 | uint8_t text_get_text_palette(void); 11 | int text_get_cursor_pos_x(void); 12 | int text_get_cursor_pos_y(void); 13 | void text_set_cursor_pos(int x, int y); 14 | void text_putchar(char c); 15 | void text_disable_cursor(void); 16 | void text_enable_cursor(void); 17 | void text_clear(void); 18 | void text_putstring(const char *str); 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /bootloader/includes/simple_print.inc: -------------------------------------------------------------------------------- 1 | simple_print: 2 | 3 | ; ************************************** 4 | ; Prints a string using the BIOS 5 | ; ************************************** 6 | 7 | ; IN: 8 | ; SI = points to a 0x00 terminated string 9 | 10 | push ax ; Save registers 11 | push si 12 | mov ah, 0x0E ; int 0x10, function 0x0E (print character) 13 | .loop: 14 | lodsb ; Load character from string 15 | test al, al ; Is is the 0x00 terminator? 16 | jz .done ; If it is, exit routine 17 | int 0x10 ; Call BIOS 18 | jmp .loop ; Repeat! 19 | .done: 20 | pop si ; Restore registers 21 | pop ax 22 | ret ; Exit routine 23 | -------------------------------------------------------------------------------- /kernel/asm/flush_irqs.asm: -------------------------------------------------------------------------------- 1 | extern real_routine 2 | 3 | global flush_irqs 4 | 5 | section .data 6 | 7 | %define flush_irqs_size flush_irqs_end - flush_irqs_bin 8 | flush_irqs_bin: incbin "blobs/flush_irqs.bin" 9 | flush_irqs_end: 10 | 11 | section .text 12 | 13 | bits 64 14 | 15 | flush_irqs: 16 | ; void flush_irqs(void); 17 | push rbx 18 | push rbp 19 | push r12 20 | push r13 21 | push r14 22 | push r15 23 | 24 | mov rsi, flush_irqs_bin 25 | mov rcx, flush_irqs_size 26 | call real_routine 27 | 28 | pop r15 29 | pop r14 30 | pop r13 31 | pop r12 32 | pop rbp 33 | pop rbx 34 | ret 35 | -------------------------------------------------------------------------------- /kernel/blobs/e820.real: -------------------------------------------------------------------------------- 1 | org 0x8000 2 | bits 16 3 | 4 | push ebx 5 | xor ebx, ebx 6 | loop: 7 | mov eax, 0xe820 8 | mov ecx, 24 9 | mov edx, 0x534d4150 10 | mov edi, e820_entry 11 | int 0x15 12 | jc done_noset 13 | test ebx, ebx 14 | jz done_set 15 | pop edi 16 | mov esi, e820_entry 17 | mov ecx, 24 18 | a32 o32 rep movsb 19 | push edi 20 | jmp loop 21 | done_set: 22 | pop edi 23 | mov esi, e820_entry 24 | mov ecx, 24 25 | a32 o32 rep movsb 26 | jmp done 27 | done_noset: 28 | pop edi 29 | jmp done 30 | done: 31 | xor al, al 32 | mov ecx, 24 33 | a32 o32 rep stosb 34 | ret 35 | 36 | align 16 37 | e820_entry: 38 | times 24 db 0 39 | -------------------------------------------------------------------------------- /kernel/asm/real.asm: -------------------------------------------------------------------------------- 1 | global real_routine 2 | 3 | section .data 4 | 5 | %define real_init_size real_init_end - real_init 6 | real_init: incbin "blobs/real_init.bin" 7 | real_init_end: 8 | 9 | section .text 10 | 11 | bits 64 12 | 13 | real_routine: 14 | ; RSI = routine location 15 | ; RCX = routine size 16 | 17 | push rsi 18 | push rcx 19 | 20 | ; Real mode init blob to 0000:1000 21 | mov rsi, real_init 22 | mov rdi, 0x1000 23 | mov rcx, real_init_size 24 | rep movsb 25 | 26 | ; Routine's blob to 0000:8000 27 | pop rcx 28 | pop rsi 29 | mov rdi, 0x8000 30 | rep movsb 31 | 32 | ; Call module 33 | mov rax, 0x1000 34 | call rax 35 | 36 | ret 37 | -------------------------------------------------------------------------------- /kernel/asm/e820.asm: -------------------------------------------------------------------------------- 1 | extern real_routine 2 | 3 | global get_e820 4 | 5 | %define kernel_phys_offset 0xffffffffc0000000 6 | 7 | section .data 8 | 9 | %define e820_size e820_end - e820_bin 10 | e820_bin: incbin "blobs/e820.bin" 11 | e820_end: 12 | 13 | section .text 14 | 15 | bits 64 16 | 17 | get_e820: 18 | ; void get_e820(e820_entry_t *e820_map); 19 | push rbx 20 | push rbp 21 | push r12 22 | push r13 23 | push r14 24 | push r15 25 | 26 | mov rbx, rdi 27 | mov rdi, kernel_phys_offset 28 | sub rbx, rdi 29 | mov rsi, e820_bin 30 | mov rcx, e820_size 31 | call real_routine 32 | 33 | pop r15 34 | pop r14 35 | pop r13 36 | pop r12 37 | pop rbp 38 | pop rbx 39 | ret 40 | -------------------------------------------------------------------------------- /kernel/include/klib.h: -------------------------------------------------------------------------------- 1 | #ifndef __KLIB_H__ 2 | #define __KLIB_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | size_t kmemcpy(char *, const char *, size_t); 10 | size_t kstrcpy(char *, const char *); 11 | int kstrcmp(const char *, const char *); 12 | int kstrncmp(const char *, const char *, size_t); 13 | size_t kstrlen(const char *); 14 | void *kalloc(size_t); 15 | void kfree(void *); 16 | void *krealloc(void *, size_t); 17 | void kputs(const char *); 18 | void knputs(const char *, size_t); 19 | void kprn_ui(uint64_t); 20 | void kprn_x(uint64_t); 21 | void kprint(int type, const char *fmt, ...); 22 | 23 | #define KPRN_INFO 0 24 | #define KPRN_WARN 1 25 | #define KPRN_ERR 2 26 | #define KPRN_DBG 3 27 | 28 | 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /kernel/linker.ld: -------------------------------------------------------------------------------- 1 | ENTRY(_start) 2 | 3 | SECTIONS 4 | { 5 | . = 0xffffffffc0000000 + 0x100000; 6 | 7 | .text ALIGN(4K) : 8 | { 9 | sections_text = . - 0xffffffffc0000000; 10 | KEEP(*(.startup)) 11 | KEEP(*(.text)) 12 | sections_text_end = . - 0xffffffffc0000000; 13 | } 14 | 15 | .data ALIGN(4K) : 16 | { 17 | sections_data = . - 0xffffffffc0000000; 18 | KEEP(*(.data)) 19 | KEEP(*(.rodata)) 20 | sections_data_end = . - 0xffffffffc0000000; 21 | } 22 | 23 | .bss ALIGN(4K) : 24 | { 25 | KEEP(*(.bss)) 26 | KEEP(*(COMMON)) 27 | sections_bss_end = . - 0xffffffffc0000000; 28 | } 29 | 30 | /DISCARD/ : { 31 | *(.note .note.*) 32 | *(.eh_frame*) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /kernel/src/drivers/panic.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | void panic(const char *msg, int code) { 9 | asm volatile ("cli" ::: "memory"); 10 | kprint(KPRN_ERR, "!!! KERNEL PANIC !!!"); 11 | kprint(KPRN_ERR, "Panic info: %s", msg); 12 | kprint(KPRN_ERR, "Error code: %X", (size_t)code); 13 | /* send abort ipi to all APs */ 14 | for (int i = 0; i < cpu_count; i++) { 15 | if (i == get_cpu_number()) 16 | continue; 17 | lapic_write(APICREG_ICR1, ((uint32_t)cpu_locals[i].lapic_id) << 24); 18 | lapic_write(APICREG_ICR0, 0x81); 19 | } 20 | kprint(KPRN_ERR, "SYSTEM HALTED"); 21 | for (;;) 22 | asm volatile ("hlt" ::: "memory"); 23 | } 24 | -------------------------------------------------------------------------------- /kernel/src/drivers/pit.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | void set_pit_freq(uint32_t frequency) { 8 | kprint(KPRN_INFO, "PIT: Setting frequency to %uHz", (uint64_t)frequency); 9 | 10 | uint16_t x = 1193182 / frequency; 11 | if ((1193182 % frequency) >= (frequency / 2)) 12 | x++; 13 | 14 | port_out_b(0x40, (uint8_t)(x & 0x00ff)); 15 | port_out_b(0x40, (uint8_t)((x & 0xff00) >> 8)); 16 | 17 | kprint(KPRN_INFO, "PIT: Frequency updated"); 18 | 19 | return; 20 | } 21 | 22 | void sleep(uint64_t time) { 23 | /* implements sleep in milliseconds */ 24 | 25 | uint64_t final_time = uptime_raw + (time * (KRNL_PIT_FREQ / 1000)); 26 | 27 | while (uptime_raw < final_time); 28 | 29 | return; 30 | } 31 | -------------------------------------------------------------------------------- /kernel/include/system.h: -------------------------------------------------------------------------------- 1 | #ifndef __SYSTEM_H__ 2 | #define __SYSTEM_H__ 3 | 4 | #include 5 | #include 6 | 7 | typedef struct { 8 | int cpu_number; 9 | uint8_t *kernel_stack; 10 | uint8_t lapic_id; 11 | void *subleq_poke_vector; 12 | } cpu_local_t; 13 | 14 | extern cpu_local_t cpu_locals[]; 15 | 16 | void init_cpu0(void); 17 | 18 | int get_cpu_number(void); 19 | uint64_t get_cpu_kernel_stack(void); 20 | 21 | void map_PIC(uint8_t PIC0Offset, uint8_t PIC1Offset); 22 | void set_PIC0_mask(uint8_t mask); 23 | void set_PIC1_mask(uint8_t mask); 24 | uint8_t get_PIC0_mask(void); 25 | uint8_t get_PIC1_mask(void); 26 | 27 | void set_pit_freq(uint32_t frequency); 28 | void sleep(uint64_t time); 29 | 30 | void load_IDT(void); 31 | 32 | extern volatile uint64_t uptime_raw; 33 | extern volatile uint64_t uptime_sec; 34 | 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /kernel/src/drivers/pic.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | void map_PIC(uint8_t PIC0Offset, uint8_t PIC1Offset) { 7 | uint8_t mask0; 8 | uint8_t mask1; 9 | 10 | mask0 = get_PIC0_mask(); // save PIC 0 and 1's masks 11 | mask1 = get_PIC1_mask(); 12 | 13 | port_out_b(0x20, 0x11); // initialise 14 | port_out_b(0xA0, 0x11); 15 | 16 | port_out_b(0x21, PIC0Offset); // set offsets 17 | port_out_b(0xA1, PIC1Offset); 18 | 19 | port_out_b(0x21, 0x04); // PIC wiring info 20 | port_out_b(0xA1, 0x02); 21 | 22 | port_out_b(0x21, 0x01); // environment info 23 | port_out_b(0xA1, 0x01); 24 | 25 | set_PIC0_mask(mask0); // restore masks 26 | set_PIC1_mask(mask1); 27 | } 28 | 29 | void set_PIC0_mask(uint8_t mask) { 30 | port_out_b(0x21, mask); 31 | return; 32 | } 33 | 34 | void set_PIC1_mask(uint8_t mask) { 35 | port_out_b(0xA1, mask); 36 | return; 37 | } 38 | 39 | uint8_t get_PIC0_mask(void) { 40 | return port_in_b(0x21); 41 | } 42 | 43 | uint8_t get_PIC1_mask(void) { 44 | return port_in_b(0xA1); 45 | } 46 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018, mintsuki 2 | All rights reserved. 3 | 4 | Redistribution and use in source form, or binary form with accompanying source, 5 | with or without modification, are permitted provided that the following conditions 6 | are met: 7 | * The redistribution of the source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Modified versions of the source code MUST be licensed under a verbatim 10 | copy of the present License Agreement. 11 | 12 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 13 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 14 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 16 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 17 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 18 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 19 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | -------------------------------------------------------------------------------- /bootloader/includes/gdt.inc: -------------------------------------------------------------------------------- 1 | align 16 2 | GDT: 3 | 4 | dw .GDTEnd - .GDTStart - 1 ; GDT size 5 | dd .GDTStart + 0x10000 ; GDT start 6 | 7 | align 16 8 | .GDTStart: 9 | 10 | ; Null descriptor (required) 11 | 12 | .NullDescriptor: 13 | 14 | dw 0x0000 ; Limit 15 | dw 0x0000 ; Base (low 16 bits) 16 | db 0x00 ; Base (mid 8 bits) 17 | db 00000000b ; Access 18 | db 00000000b ; Granularity 19 | db 0x00 ; Base (high 8 bits) 20 | 21 | ; Unreal mode 22 | 23 | .UnrealCode: 24 | 25 | dw 0xFFFF ; Limit 26 | dw 0x0000 ; Base (low 16 bits) 27 | db 0x00 ; Base (mid 8 bits) 28 | db 10011010b ; Access 29 | db 10001111b ; Granularity 30 | db 0x00 ; Base (high 8 bits) 31 | 32 | .UnrealData: 33 | 34 | dw 0xFFFF ; Limit 35 | dw 0x0000 ; Base (low 16 bits) 36 | db 0x00 ; Base (mid 8 bits) 37 | db 10010010b ; Access 38 | db 10001111b ; Granularity 39 | db 0x00 ; Base (high 8 bits) 40 | 41 | ; Protected mode 42 | 43 | .PmodeCode: 44 | 45 | dw 0xFFFF ; Limit 46 | dw 0x0000 ; Base (low 16 bits) 47 | db 0x00 ; Base (mid 8 bits) 48 | db 10011010b ; Access 49 | db 11001111b ; Granularity 50 | db 0x00 ; Base (high 8 bits) 51 | 52 | .PmodeData: 53 | 54 | dw 0xFFFF ; Limit 55 | dw 0x0000 ; Base (low 16 bits) 56 | db 0x00 ; Base (mid 8 bits) 57 | db 10010010b ; Access 58 | db 11001111b ; Granularity 59 | db 0x00 ; Base (high 8 bits) 60 | 61 | .GDTEnd: 62 | -------------------------------------------------------------------------------- /kernel/include/cio.h: -------------------------------------------------------------------------------- 1 | #ifndef __CIO_H__ 2 | #define __CIO_H__ 3 | 4 | #include 5 | 6 | #define port_out_b(port, value) ({ \ 7 | asm volatile ( "out %1, al" \ 8 | : \ 9 | : "a" ((uint8_t)value), "Nd" ((uint16_t)port) \ 10 | : "memory"); \ 11 | }) 12 | 13 | #define port_out_w(port, value) ({ \ 14 | asm volatile ( "out %1, ax" \ 15 | : \ 16 | : "a" ((uint16_t)value), "Nd" ((uint16_t)port) \ 17 | : "memory"); \ 18 | }) 19 | 20 | #define port_out_d(port, value) ({ \ 21 | asm volatile ( "out %1, eax" \ 22 | : \ 23 | : "a" ((uint32_t)value), "Nd" ((uint16_t)port) \ 24 | : "memory"); \ 25 | }) 26 | 27 | #define port_in_b(port) ({ \ 28 | uint8_t value; \ 29 | asm volatile ( "in al, %1" \ 30 | : "=a" (value) \ 31 | : "Nd" ((uint16_t)port) \ 32 | : "memory"); \ 33 | value; \ 34 | }) 35 | 36 | #define port_in_w(port) ({ \ 37 | uint16_t value; \ 38 | asm volatile ( "in ax, %1" \ 39 | : "=a" (value) \ 40 | : "Nd" ((uint16_t)port) \ 41 | : "memory"); \ 42 | value; \ 43 | }) 44 | 45 | #define port_in_d(port) ({ \ 46 | uint32_t value; \ 47 | asm volatile ( "in eax, %1" \ 48 | : "=a" (value) \ 49 | : "Nd" ((uint16_t)port) \ 50 | : "memory"); \ 51 | value; \ 52 | }) 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /kernel/src/drivers/e820.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | void get_e820(void *); 7 | 8 | uint64_t memory_size = 0; 9 | 10 | e820_entry_t e820_map[256]; 11 | 12 | static const char *e820_type(uint32_t type) { 13 | switch (type) { 14 | case 1: 15 | return "Usable RAM"; 16 | case 2: 17 | return "Reserved"; 18 | case 3: 19 | return "ACPI reclaimable"; 20 | case 4: 21 | return "ACPI NVS"; 22 | case 5: 23 | return "Bad memory"; 24 | default: 25 | return "???"; 26 | } 27 | } 28 | 29 | void init_e820(void) { 30 | /* Get e820 memory map. */ 31 | get_e820(e820_map); 32 | 33 | /* Print out memory map and find total usable memory. */ 34 | for (size_t i = 0; e820_map[i].type; i++) { 35 | kprint(KPRN_INFO, "e820: [%X -> %X] : %X <%s>", e820_map[i].base, 36 | e820_map[i].base + e820_map[i].length, 37 | e820_map[i].length, 38 | e820_type(e820_map[i].type)); 39 | if (e820_map[i].type == 1) { 40 | memory_size += e820_map[i].length; 41 | } 42 | } 43 | 44 | kprint(KPRN_INFO, "e820: Total usable memory: %U MiB", memory_size / 1024 / 1024); 45 | 46 | return; 47 | } 48 | -------------------------------------------------------------------------------- /kernel/src/drivers/pm.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | void pm_sleep(void) { 8 | kprint(KPRN_WARN, "PM: sleep is not implemented."); 9 | } 10 | 11 | void shutdown(void) { 12 | asm volatile ("cli" ::: "memory"); 13 | 14 | kprint(KPRN_INFO, "PM: shutdown request"); 15 | 16 | port_out_w((uint16_t)facp->PM1a_CNT_BLK, SLP_TYPa | (1 << 13)); 17 | if (facp->PM1b_CNT_BLK) 18 | port_out_w((uint16_t)facp->PM1b_CNT_BLK, SLP_TYPb | (1 << 13)); 19 | 20 | for (int i = 0; i < 100; i++) 21 | port_in_b(0x80); 22 | 23 | kprint(KPRN_WARN, "PM: Unable to shutdown."); 24 | 25 | asm volatile ("sti" ::: "memory"); 26 | } 27 | 28 | void reboot(void) { 29 | asm volatile ("cli" ::: "memory"); 30 | 31 | kprint(KPRN_INFO, "PM: reboot request"); 32 | 33 | kprint(KPRN_INFO, "PM: attempting PS/2 reset"); 34 | 35 | while (port_in_b(0x64) & 0x02); 36 | 37 | port_out_b(0x64, 0xfe); 38 | 39 | for (int i = 0; i < 100; i++) 40 | port_in_b(0x80); 41 | 42 | kprint(KPRN_INFO, "PM: PS/2 reset failed, triple faulting"); 43 | 44 | uint64_t dummy_idt_ptr[2] = {0,0}; 45 | 46 | asm volatile ( 47 | "lidt [%0];" 48 | "nop;" 49 | "nop;" 50 | "int 0x80;" 51 | "nop;" 52 | "nop;" 53 | : 54 | : "r" (dummy_idt_ptr) 55 | : "memory" 56 | ); 57 | 58 | for (;;) { asm volatile ("hlt" ::: "memory"); } 59 | } 60 | -------------------------------------------------------------------------------- /kernel/include/graphics.h: -------------------------------------------------------------------------------- 1 | #ifndef __GRAPHICS_H__ 2 | #define __GRAPHICS_H__ 3 | 4 | #include 5 | 6 | typedef struct { 7 | uint8_t version_min; 8 | uint8_t version_maj; 9 | uint32_t oem; // is a 32 bit pointer to char 10 | uint32_t capabilities; 11 | uint32_t vid_modes; // is a 32 bit pointer to uint16_t 12 | uint16_t vid_mem_blocks; 13 | uint16_t software_rev; 14 | uint32_t vendor; // is a 32 bit pointer to char 15 | uint32_t prod_name; // is a 32 bit pointer to char 16 | uint32_t prod_rev; // is a 32 bit pointer to char 17 | } __attribute__((packed)) vbe_info_struct_t; 18 | 19 | typedef struct { 20 | uint8_t pad0[16]; 21 | uint16_t pitch; 22 | uint16_t res_x; 23 | uint16_t res_y; 24 | uint8_t pad1[3]; 25 | uint8_t bpp; 26 | uint8_t pad2[14]; 27 | uint32_t framebuffer; 28 | uint8_t pad3[212]; 29 | } __attribute__((packed)) vbe_mode_info_t; 30 | 31 | typedef struct { 32 | uint32_t vbe_mode_info; // is a 32 bit pointer to vbe_mode_info_t 33 | uint16_t mode; 34 | } get_vbe_t; 35 | 36 | void init_graphics(void); 37 | 38 | void swap_vbufs(void); 39 | void plot_px(int x, int y, uint32_t hex); 40 | uint32_t get_ab0_px(int x, int y); 41 | void plot_ab0_px(int x, int y, uint32_t hex); 42 | extern volatile uint32_t *framebuffer; 43 | extern volatile uint32_t *antibuffer0; 44 | extern volatile uint32_t *antibuffer1; 45 | extern uint8_t vga_font[4096]; 46 | extern int vbe_width; 47 | extern int vbe_height; 48 | extern int vbe_pitch; 49 | 50 | extern int modeset_done; 51 | 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /kernel/src/time.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | volatile uint64_t uptime_raw = 0; 14 | volatile uint64_t uptime_sec = 0; 15 | 16 | void timer_interrupt(void) { 17 | 18 | if (!(++uptime_raw % KRNL_PIT_FREQ)) 19 | uptime_sec++; 20 | 21 | if (subleq_ready) { 22 | 23 | /* raise vector 0x80 for all APs */ 24 | for (int i = 1; i < cpu_count; i++) { 25 | lapic_write(APICREG_ICR1, ((uint32_t)cpu_locals[i].lapic_id) << 24); 26 | lapic_write(APICREG_ICR0, 0x80); 27 | } 28 | 29 | _writeram(335544304, _readram(335544304) + (0x100000000 / KRNL_PIT_FREQ)); 30 | 31 | if (cpu_count == 1) { 32 | subleq_io_flush(); 33 | 34 | if (!(uptime_raw % (KRNL_PIT_FREQ / MOUSE_UPDATE_FREQ))) 35 | mouse_update(); 36 | 37 | if (!(uptime_raw % (KRNL_PIT_FREQ / SCREEN_REFRESH_FREQ))) 38 | subleq_redraw_screen(); 39 | } 40 | 41 | } 42 | 43 | return; 44 | } 45 | 46 | void timer_interrupt_ap(void) { 47 | if (get_cpu_number() == cpu_count - 1) { 48 | subleq_io_flush(); 49 | 50 | if (!(uptime_raw % (KRNL_PIT_FREQ / MOUSE_UPDATE_FREQ))) 51 | mouse_update(); 52 | 53 | if (!(uptime_raw % (KRNL_PIT_FREQ / SCREEN_REFRESH_FREQ))) 54 | subleq_redraw_screen(); 55 | } 56 | 57 | return; 58 | } 59 | -------------------------------------------------------------------------------- /kernel/Makefile: -------------------------------------------------------------------------------- 1 | DEBUG = off 2 | 3 | SYSTEM_CC_TARGET := $(shell gcc -dumpmachine | head -c 6) 4 | ifeq ($(SYSTEM_CC_TARGET), x86_64) 5 | CC = gcc 6 | else 7 | SYSTEM_CC_TARGET := $(shell x86_64-elf-gcc -dumpmachine | head -c 6) 8 | ifeq ($(SYSTEM_CC_TARGET), x86_64) 9 | CC = x86_64-elf-gcc 10 | else 11 | $(error No suitable x86_64 GCC compiler found, please install an x86_64-elf-gcc toolchain) 12 | endif 13 | endif 14 | 15 | C_FILES = $(shell find src -type f -name '*.c') 16 | H_FILES = $(shell find . -type f -name '*.h') 17 | ASM_FILES = $(shell find asm -type f -name '*.asm') $(shell find startup -type f -name '*.asm') 18 | REAL_FILES = $(shell find blobs -type f -name '*.real') 19 | OBJ = $(C_FILES:.c=.o) $(ASM_FILES:.asm=.o) 20 | BINS = $(REAL_FILES:.real=.bin) 21 | 22 | CHARDFLAGS := \ 23 | -std=gnu99 \ 24 | -masm=intel \ 25 | -fno-pic \ 26 | -mno-80387 \ 27 | -mno-sse \ 28 | -mno-sse2 \ 29 | -mno-red-zone \ 30 | -mcmodel=kernel \ 31 | -ffreestanding \ 32 | -fno-stack-protector \ 33 | -I./include/ 34 | 35 | ifeq ($(DEBUG), qemu) 36 | CHARDFLAGS := $(CHARDFLAGS) -D_KERNEL_QEMU_OUTPUT_ 37 | else ifeq ($(DEBUG), vga) 38 | CHARDFLAGS := $(CHARDFLAGS) -D_KERNEL_VGA_OUTPUT_ 39 | endif 40 | 41 | CLINKFLAGS := \ 42 | -nostdlib \ 43 | -no-pie \ 44 | -T ./linker.ld 45 | 46 | CFLAGS = -Wall -Wextra -O2 47 | 48 | subleq.bin: subleq.elf 49 | objcopy -O binary subleq.elf $@ 50 | 51 | subleq.elf: $(BINS) $(OBJ) $(H_FILES) 52 | $(CC) $(OBJ) $(CLINKFLAGS) -o $@ 53 | 54 | %.o: %.c 55 | $(CC) $(CFLAGS) $(CHARDFLAGS) -c $< -o $@ 56 | 57 | %.bin: %.real 58 | nasm $< -f bin -o $@ 59 | 60 | %.o: %.asm 61 | nasm $< -f elf64 -o $@ 62 | 63 | clean: 64 | rm -f $(OBJ) $(BINS) subleq.bin 65 | -------------------------------------------------------------------------------- /kernel/asm/smp.asm: -------------------------------------------------------------------------------- 1 | global prepare_smp_trampoline 2 | global init_cpu0_local 3 | global check_ap_flag 4 | global get_cpu_number 5 | global get_cpu_kernel_stack 6 | 7 | extern load_tss 8 | 9 | section .data 10 | 11 | %define smp_trampoline_size smp_trampoline_end - smp_trampoline 12 | smp_trampoline: incbin "blobs/smp_trampoline.bin" 13 | smp_trampoline_end: 14 | 15 | section .text 16 | 17 | bits 64 18 | 19 | %define TRAMPOLINE_ADDR 0x1000 20 | %define PAGE_SIZE 4096 21 | 22 | prepare_smp_trampoline: 23 | ; entry point in rdi, page table in rsi 24 | ; stack pointer in rdx, cpu number in rcx 25 | push rdi 26 | push rsi 27 | push rcx 28 | 29 | ; prepare variables 30 | mov byte [0x510], 0 31 | mov qword [0x520], rdi 32 | mov qword [0x540], rsi 33 | mov qword [0x550], rdx 34 | mov qword [0x560], rcx 35 | sgdt [0x580] 36 | sidt [0x590] 37 | 38 | ; Copy trampoline blob to 0x1000 39 | mov rsi, smp_trampoline 40 | mov rdi, TRAMPOLINE_ADDR 41 | mov rcx, smp_trampoline_size 42 | rep movsb 43 | 44 | mov rdi, r8 45 | call load_tss 46 | 47 | pop rcx 48 | pop rsi 49 | pop rdi 50 | mov rax, TRAMPOLINE_ADDR / PAGE_SIZE 51 | ret 52 | 53 | check_ap_flag: 54 | xor rax, rax 55 | mov al, byte [0x510] 56 | ret 57 | 58 | init_cpu0_local: 59 | ; Load FS with the CPU local struct base address 60 | mov rcx, 0xc0000100 61 | mov eax, edi 62 | shr rdi, 32 63 | mov edx, edi 64 | wrmsr 65 | 66 | mov rdi, rsi 67 | call load_tss 68 | 69 | mov ax, 0x28 70 | ltr ax 71 | 72 | ret 73 | 74 | get_cpu_number: 75 | mov rax, qword [fs:0000] 76 | ret 77 | 78 | get_cpu_kernel_stack: 79 | mov rax, qword [fs:0008] 80 | ret 81 | -------------------------------------------------------------------------------- /kernel/blobs/smp_trampoline.real: -------------------------------------------------------------------------------- 1 | org 0x1000 2 | bits 16 3 | 4 | cli 5 | cld 6 | 7 | xor ax, ax 8 | mov ds, ax 9 | 10 | ; set the flag 11 | mov byte [0x510], 1 12 | 13 | jmp 0x0:fix_cs 14 | fix_cs: 15 | mov es, ax 16 | mov fs, ax 17 | mov gs, ax 18 | mov ss, ax 19 | 20 | lgdt [gdt_ptr] 21 | 22 | mov edx, dword [0x540] 23 | mov cr3, edx 24 | 25 | mov eax, cr4 26 | or eax, 1 << 5 27 | mov cr4, eax 28 | 29 | mov ecx, 0xc0000080 30 | rdmsr 31 | 32 | or eax, 0x00000100 33 | wrmsr 34 | 35 | mov eax, cr0 36 | or eax, 0x80000001 37 | and eax, ~(0x60000000) 38 | mov cr0, eax 39 | 40 | jmp 0x08:.mode64 41 | .mode64: 42 | bits 64 43 | mov ax, 0x10 44 | mov ds, ax 45 | mov es, ax 46 | mov ss, ax 47 | mov fs, ax 48 | mov gs, ax 49 | 50 | mov rsp, qword [0x550] 51 | 52 | lgdt [0x580] 53 | lidt [0x590] 54 | 55 | ; Load FS with the CPU local struct base address 56 | mov rcx, 0xc0000100 57 | mov eax, dword [0x560] 58 | mov edx, dword [0x560+4] 59 | wrmsr 60 | 61 | ; Load TSS 62 | mov ax, 0x28 63 | ltr ax 64 | 65 | ; jump to entry point 66 | mov rbx, qword [0x520] 67 | call rbx 68 | 69 | align 16 70 | 71 | gdt_ptr: 72 | dw .gdt_end - .gdt_start - 1 ; GDT size 73 | dq .gdt_start ; GDT start 74 | 75 | align 16 76 | .gdt_start: 77 | 78 | ; Null descriptor (required) 79 | .null_descriptor: 80 | dw 0x0000 ; Limit 81 | dw 0x0000 ; Base (low 16 bits) 82 | db 0x00 ; Base (mid 8 bits) 83 | db 00000000b ; Access 84 | db 00000000b ; Granularity 85 | db 0x00 ; Base (high 8 bits) 86 | 87 | ; 64 bit mode kernel 88 | .kernel_code_64: 89 | dw 0x0000 ; Limit 90 | dw 0x0000 ; Base (low 16 bits) 91 | db 0x00 ; Base (mid 8 bits) 92 | db 10011010b ; Access 93 | db 00100000b ; Granularity 94 | db 0x00 ; Base (high 8 bits) 95 | 96 | .kernel_data: 97 | dw 0x0000 ; Limit 98 | dw 0x0000 ; Base (low 16 bits) 99 | db 0x00 ; Base (mid 8 bits) 100 | db 10010010b ; Access 101 | db 00000000b ; Granularity 102 | db 0x00 ; Base (high 8 bits) 103 | 104 | .gdt_end: 105 | -------------------------------------------------------------------------------- /kernel/blobs/get_vbe_info.real: -------------------------------------------------------------------------------- 1 | org 0x8000 2 | bits 16 3 | 4 | ; DS:EBX --> Return struct 5 | 6 | push ebx 7 | mov ax, 0x4f00 8 | mov di, vbe_info_struct 9 | int 0x10 10 | pop ebx 11 | 12 | mov al, byte [vbe_info_struct.version_min] 13 | mov byte [ebx], al 14 | 15 | mov al, byte [vbe_info_struct.version_maj] 16 | mov byte [ebx+1], al 17 | 18 | xor eax, eax 19 | mov ax, word [vbe_info_struct.oem_seg] 20 | shl eax, 4 21 | xor ecx, ecx 22 | mov cx, word [vbe_info_struct.oem_off] 23 | add eax, ecx 24 | mov dword [ebx+2], eax 25 | 26 | mov eax, dword [vbe_info_struct.capabilities] 27 | mov dword [ebx+6], eax 28 | 29 | xor eax, eax 30 | mov ax, word [vbe_info_struct.vid_modes_seg] 31 | shl eax, 4 32 | xor ecx, ecx 33 | mov cx, word [vbe_info_struct.vid_modes_off] 34 | add eax, ecx 35 | mov dword [ebx+10], eax 36 | 37 | mov ax, word [vbe_info_struct.vid_mem_blocks] 38 | mov word [ebx+14], ax 39 | 40 | mov ax, word [vbe_info_struct.software_rev] 41 | mov word [ebx+16], ax 42 | 43 | xor eax, eax 44 | mov ax, word [vbe_info_struct.vendor_seg] 45 | shl eax, 4 46 | xor ecx, ecx 47 | mov cx, word [vbe_info_struct.vendor_off] 48 | add eax, ecx 49 | mov dword [ebx+18], eax 50 | 51 | xor eax, eax 52 | mov ax, word [vbe_info_struct.prod_name_seg] 53 | shl eax, 4 54 | xor ecx, ecx 55 | mov cx, word [vbe_info_struct.prod_name_off] 56 | add eax, ecx 57 | mov dword [ebx+22], eax 58 | 59 | xor eax, eax 60 | mov ax, word [vbe_info_struct.prod_rev_seg] 61 | shl eax, 4 62 | xor ecx, ecx 63 | mov cx, word [vbe_info_struct.prod_rev_off] 64 | add eax, ecx 65 | mov dword [ebx+26], eax 66 | 67 | ret 68 | 69 | align 4 70 | 71 | vbe_info_struct: 72 | .signature db 'VBE2' 73 | .version_min db 0 74 | .version_maj db 0 75 | .oem_off dw 0 76 | .oem_seg dw 0 77 | .capabilities dd 0 78 | .vid_modes_off dw 0 79 | .vid_modes_seg dw 0 80 | .vid_mem_blocks dw 0 81 | .software_rev dw 0 82 | .vendor_off dw 0 83 | .vendor_seg dw 0 84 | .prod_name_off dw 0 85 | .prod_name_seg dw 0 86 | .prod_rev_off dw 0 87 | .prod_rev_seg dw 0 88 | .reserved times 222 db 0 89 | .oem_data times 256 db 0 90 | -------------------------------------------------------------------------------- /bootloader/includes/disk.inc: -------------------------------------------------------------------------------- 1 | read_sector: 2 | 3 | ; *********************************************** 4 | ; Reads a disk sector with an LBA address 5 | ; *********************************************** 6 | 7 | ; IN: 8 | ; EAX = LBA sector to load 9 | ; DL = Drive number 10 | ; BP = Buffer segment 11 | ; BX = Buffer offset 12 | ; CX = Count 13 | 14 | ; OUT: 15 | ; Carry if error 16 | 17 | push eax 18 | push ebx 19 | push ecx 20 | push edx 21 | push esi 22 | push edi 23 | push ebp 24 | 25 | mov word [.target_segment], bp 26 | mov word [.target_offset], bx 27 | mov dword [.lba_address_low], eax 28 | mov word [.count], cx 29 | 30 | xor esi, esi 31 | mov si, .da_struct 32 | mov ah, 0x42 33 | 34 | clc ; Clear carry for int 0x13 because some BIOSes may not clear it on success 35 | 36 | int 0x13 ; Call int 0x13 37 | 38 | .done: 39 | 40 | pop ebp 41 | pop edi 42 | pop esi 43 | pop edx 44 | pop ecx 45 | pop ebx 46 | pop eax 47 | ret ; Exit routine 48 | 49 | align 4 50 | .da_struct: 51 | .packet_size db 16 52 | .unused db 0 53 | .count dw 0 54 | .target_offset dw 0 55 | .target_segment dw 0 56 | .lba_address_low dd 0 57 | .lba_address_high dd 0 58 | 59 | 60 | %define SECTORS_AT_ONCE 16 61 | 62 | read_sectors: 63 | 64 | ; ******************************************** 65 | ; Reads multiple LBA addressed sectors 66 | ; ******************************************** 67 | 68 | ; IN: 69 | ; EAX = LBA starting sector 70 | ; DL = Drive number 71 | ; ES = Buffer segment 72 | ; EBX = Buffer offset 73 | ; ECX = Sectors count 74 | 75 | ; OUT: 76 | ; Carry if error 77 | 78 | push eax ; Save GPRs 79 | push ebx 80 | push ecx 81 | push edx 82 | push esi 83 | push edi 84 | push ebp 85 | push fs 86 | 87 | push 0 88 | pop fs 89 | 90 | .loop: 91 | 92 | push ebx 93 | push ecx 94 | 95 | mov bp, 0x7000 ; Load in a temp buffer 96 | xor bx, bx 97 | mov cx, SECTORS_AT_ONCE 98 | 99 | call read_sector ; Read sector 100 | 101 | pop ecx 102 | pop ebx 103 | 104 | jc .done ; If carry exit with flag 105 | 106 | mov edi, (512*SECTORS_AT_ONCE)/4 107 | mov esi, 0x70000 108 | .copy_loop: 109 | mov ebp, dword [fs:esi] 110 | mov dword [es:ebx], ebp 111 | add esi, 4 112 | add ebx, 4 113 | dec edi 114 | jnz .copy_loop 115 | 116 | add eax, SECTORS_AT_ONCE ; Increment sector 117 | sub ecx, SECTORS_AT_ONCE 118 | jnz .loop ; Loop! 119 | 120 | .done: 121 | pop fs 122 | pop ebp 123 | pop edi 124 | pop esi 125 | pop edx 126 | pop ecx ; Restore GPRs 127 | pop ebx 128 | pop eax 129 | ret ; Exit routine 130 | -------------------------------------------------------------------------------- /kernel/asm/date.asm: -------------------------------------------------------------------------------- 1 | extern real_routine 2 | 3 | global get_time 4 | 5 | %define kernel_phys_offset 0xffffffffc0000000 6 | 7 | section .data 8 | 9 | %define get_time_size get_time_end - get_time_bin 10 | get_time_bin: incbin "blobs/get_time.bin" 11 | get_time_end: 12 | 13 | date_and_time: 14 | .seconds db 0 15 | .minutes db 0 16 | .hours db 0 17 | .days db 0 18 | .months db 0 19 | .years db 0 20 | .centuries db 0 21 | .error db 0 22 | 23 | section .text 24 | 25 | bcd_to_int: 26 | ; in: RBX = address of byte to convert 27 | push rax 28 | push rcx 29 | 30 | mov al, byte [rbx] ; seconds 31 | and al, 00001111b 32 | mov cl, al 33 | mov al, byte [rbx] 34 | and al, 11110000b 35 | shr al, 4 36 | mov ch, 10 37 | mul ch 38 | add cl, al 39 | 40 | mov byte [rbx], cl 41 | 42 | pop rcx 43 | pop rax 44 | ret 45 | 46 | get_time: 47 | ; void get_time(int *seconds, int *minutes, int *hours, 48 | ; int *days, int *months, int *years); 49 | push rbx 50 | push rbp 51 | push r12 52 | push r13 53 | push r14 54 | push r15 55 | 56 | push rdi 57 | push rsi 58 | push rdx 59 | push rcx 60 | push r8 61 | push r9 62 | 63 | mov rbx, date_and_time 64 | mov rdi, kernel_phys_offset 65 | sub rbx, rdi 66 | mov rsi, get_time_bin 67 | mov rcx, get_time_size 68 | call real_routine 69 | 70 | pop r9 71 | pop r8 72 | pop rcx 73 | pop rdx 74 | pop rsi 75 | pop rdi 76 | 77 | xor eax, eax 78 | mov r12, date_and_time 79 | 80 | cmp byte [r12+7], 0 81 | jne .err 82 | 83 | mov rbx, date_and_time.seconds 84 | call bcd_to_int 85 | mov al, byte [r12+0] 86 | mov dword [rdi], eax 87 | 88 | mov rbx, date_and_time.minutes 89 | call bcd_to_int 90 | mov al, byte [r12+1] 91 | mov dword [rsi], eax 92 | 93 | mov rbx, date_and_time.hours 94 | call bcd_to_int 95 | mov al, byte [r12+2] 96 | mov dword [rdx], eax 97 | 98 | mov rbx, date_and_time.days 99 | call bcd_to_int 100 | mov al, byte [r12+3] 101 | mov dword [rcx], eax 102 | 103 | mov rbx, date_and_time.months 104 | call bcd_to_int 105 | mov al, byte [r12+4] 106 | mov dword [r8], eax 107 | 108 | mov rbx, date_and_time.years 109 | call bcd_to_int 110 | mov al, byte [r12+5] 111 | mov dword [r9], eax 112 | 113 | mov rbx, date_and_time.centuries 114 | call bcd_to_int 115 | mov al, byte [r12+6] 116 | mov cx, 100 117 | mul cx 118 | add dword [r9], eax 119 | 120 | xor rax, rax 121 | jmp .done 122 | 123 | .err: 124 | mov rax, -1 125 | 126 | .done: 127 | pop r15 128 | pop r14 129 | pop r13 130 | pop r12 131 | pop rbp 132 | pop rbx 133 | ret 134 | -------------------------------------------------------------------------------- /bootloader/includes/a20_enabler.inc: -------------------------------------------------------------------------------- 1 | a20_check: 2 | 3 | ; ************************************************* 4 | ; Checks if the A20 address line is enabled 5 | ; ************************************************* 6 | 7 | ; OUT: 8 | ; Carry if disabled, cleared if enabled 9 | 10 | push ax ; Save registers 11 | push bx 12 | push es 13 | push fs 14 | 15 | xor ax, ax ; Set ES segment to zero 16 | mov es, ax 17 | not ax ; Set FS segment to 0xFFFF 18 | mov fs, ax 19 | 20 | mov ax, word [es:0x7DFE] ; Check using boot signature 21 | cmp word [fs:0x7E0E], ax ; If A20 is disabled, this should be the 22 | ; same address as the boot signature 23 | je .change_values ; If they are equal, check again with another value 24 | 25 | .enabled: 26 | 27 | clc ; A20 is enabled, clear carry flag 28 | jmp .done 29 | 30 | .change_values: 31 | 32 | mov word [es:0x7DFE], 0x1234 ; Change the value of 0000:7DFE to 0x1234 33 | cmp word [fs:0x7E0E], 0x1234 ; Is FFFF:7E0E changed as well? 34 | jne .enabled ; If it is, A20 is enabled 35 | 36 | stc ; Otherwise set carry 37 | 38 | .done: 39 | 40 | mov word [es:0x7DFE], ax ; Restore boot signature 41 | pop fs ; Restore registers 42 | pop es 43 | pop bx 44 | pop ax 45 | ret ; Exit routine 46 | 47 | 48 | 49 | 50 | enable_a20: 51 | 52 | ; ******************************************** 53 | ; Tries to enable the A20 address line 54 | ; ******************************************** 55 | 56 | ; OUT: 57 | ; Carry cleared if success, set if fail 58 | 59 | push eax ; Save registers 60 | 61 | call a20_check ; Check if a20 is already enabled 62 | jnc .done ; If it is, we are done 63 | 64 | mov ax, 0x2401 ; Use BIOS to try to enable a20 65 | int 0x15 66 | 67 | call a20_check ; Check again to see if BIOS succeeded 68 | jnc .done ; If it has, we are done 69 | 70 | .keyboard_method: 71 | 72 | cli ; Disable interrupts 73 | 74 | call .a20wait ; Use the keyboard controller to try and 75 | mov al, 0xAD ; open the A20 gate 76 | out 0x64, al 77 | 78 | call .a20wait 79 | mov al, 0xD0 80 | out 0x64, al 81 | 82 | call .a20wait2 83 | in al, 0x60 84 | push eax 85 | 86 | call .a20wait 87 | mov al, 0xD1 88 | out 0x64, al 89 | 90 | call .a20wait 91 | pop eax 92 | or al, 2 93 | out 0x60, al 94 | 95 | call .a20wait 96 | mov al, 0xAE 97 | out 0x64, al 98 | 99 | call .a20wait 100 | sti ; Enable interrupts back 101 | 102 | jmp .keyboard_done 103 | 104 | .a20wait: 105 | 106 | in al, 0x64 107 | test al, 2 108 | jnz .a20wait 109 | ret 110 | 111 | .a20wait2: 112 | 113 | in al, 0x64 114 | test al, 1 115 | jz .a20wait2 116 | ret 117 | 118 | .keyboard_done: 119 | 120 | call a20_check ; Check for success 121 | 122 | ; Now just quit the routine, forwarding the carry flag to the caller 123 | 124 | .done: 125 | pop eax 126 | ret 127 | -------------------------------------------------------------------------------- /kernel/asm/graphics.asm: -------------------------------------------------------------------------------- 1 | extern real_routine 2 | 3 | global get_vbe_info 4 | global get_vbe_mode_info 5 | global set_vbe_mode 6 | global dump_vga_font 7 | 8 | %define kernel_phys_offset 0xffffffffc0000000 9 | 10 | section .data 11 | 12 | %define get_vbe_info_size get_vbe_info_end - get_vbe_info_bin 13 | get_vbe_info_bin: incbin "blobs/get_vbe_info.bin" 14 | get_vbe_info_end: 15 | 16 | %define get_vbe_mode_info_size get_vbe_mode_info_end - get_vbe_mode_info_bin 17 | get_vbe_mode_info_bin: incbin "blobs/get_vbe_mode_info.bin" 18 | get_vbe_mode_info_end: 19 | 20 | %define set_vbe_mode_size set_vbe_mode_end - set_vbe_mode_bin 21 | set_vbe_mode_bin: incbin "blobs/set_vbe_mode.bin" 22 | set_vbe_mode_end: 23 | 24 | %define dump_vga_font_size dump_vga_font_end - dump_vga_font_bin 25 | dump_vga_font_bin: incbin "blobs/dump_vga_font.bin" 26 | dump_vga_font_end: 27 | 28 | section .text 29 | 30 | bits 64 31 | 32 | get_vbe_info: 33 | ; void get_vbe_info(vbe_info_struct_t* vbe_info_struct); 34 | push rbx 35 | push rbp 36 | push r12 37 | push r13 38 | push r14 39 | push r15 40 | 41 | mov rbx, rdi 42 | mov rdi, kernel_phys_offset 43 | sub rbx, rdi 44 | mov rsi, get_vbe_info_bin 45 | mov rcx, get_vbe_info_size 46 | call real_routine 47 | 48 | pop r15 49 | pop r14 50 | pop r13 51 | pop r12 52 | pop rbp 53 | pop rbx 54 | ret 55 | 56 | get_vbe_mode_info: 57 | ; void get_vbe_mode_info(get_vbe_t* get_vbe); 58 | push rbx 59 | push rbp 60 | push r12 61 | push r13 62 | push r14 63 | push r15 64 | 65 | mov rbx, rdi 66 | mov rdi, kernel_phys_offset 67 | sub rbx, rdi 68 | mov rsi, get_vbe_mode_info_bin 69 | mov rcx, get_vbe_mode_info_size 70 | call real_routine 71 | 72 | pop r15 73 | pop r14 74 | pop r13 75 | pop r12 76 | pop rbp 77 | pop rbx 78 | ret 79 | 80 | set_vbe_mode: 81 | ; void set_vbe_mode(uint16_t mode); 82 | push rbx 83 | push rbp 84 | push r12 85 | push r13 86 | push r14 87 | push r15 88 | 89 | mov rbx, rdi 90 | mov rsi, set_vbe_mode_bin 91 | mov rcx, set_vbe_mode_size 92 | call real_routine 93 | 94 | pop r15 95 | pop r14 96 | pop r13 97 | pop r12 98 | pop rbp 99 | pop rbx 100 | ret 101 | 102 | dump_vga_font: 103 | ; void dump_vga_font(uint8_t *bitmap); 104 | push rbx 105 | push rbp 106 | push r12 107 | push r13 108 | push r14 109 | push r15 110 | 111 | mov rbx, rdi 112 | mov rdi, kernel_phys_offset 113 | sub rbx, rdi 114 | mov rsi, dump_vga_font_bin 115 | mov rcx, dump_vga_font_size 116 | call real_routine 117 | 118 | pop r15 119 | pop r14 120 | pop r13 121 | pop r12 122 | pop rbp 123 | pop rbx 124 | ret 125 | -------------------------------------------------------------------------------- /kernel/include/acpi.h: -------------------------------------------------------------------------------- 1 | #ifndef __ACPI_H__ 2 | #define __ACPI_H__ 3 | 4 | #include 5 | #include 6 | 7 | typedef struct { 8 | char signature[8]; 9 | uint8_t checksum; 10 | char oem_id[6]; 11 | uint8_t rev; 12 | uint32_t rsdt_addr; 13 | /* ver 2.0 only */ 14 | uint32_t length; 15 | uint64_t xsdt_addr; 16 | uint8_t ext_checksum; 17 | uint8_t reserved[3]; 18 | } __attribute__((packed)) rsdp_t; 19 | 20 | typedef struct { 21 | char signature[4]; 22 | uint32_t length; 23 | uint8_t rev; 24 | uint8_t checksum; 25 | char oem_id[6]; 26 | char oem_table_id[8]; 27 | uint32_t oem_rev; 28 | uint32_t creator_id; 29 | uint32_t creator_rev; 30 | } __attribute__((packed)) acpi_sdt_t; 31 | 32 | typedef struct { 33 | acpi_sdt_t sdt; 34 | uint32_t sdt_ptr[]; 35 | } __attribute__((packed)) rsdt_t; 36 | 37 | typedef struct { 38 | acpi_sdt_t sdt; 39 | uint64_t sdt_ptr[]; 40 | } __attribute__((packed)) xsdt_t; 41 | 42 | typedef struct { 43 | acpi_sdt_t sdt; 44 | uint32_t local_controller_addr; 45 | uint32_t flags; 46 | uint8_t madt_entries_begin; 47 | } __attribute__((packed)) madt_t; 48 | 49 | typedef struct { 50 | char signature[4]; 51 | uint32_t length; 52 | uint8_t unneeded1[40 - 8]; 53 | uint32_t dsdt; 54 | uint8_t unneeded2[48 - 44]; 55 | uint32_t SMI_CMD; 56 | uint8_t ACPI_ENABLE; 57 | uint8_t ACPI_DISABLE; 58 | uint8_t unneeded3[64 - 54]; 59 | uint32_t PM1a_CNT_BLK; 60 | uint32_t PM1b_CNT_BLK; 61 | uint8_t unneeded4[89 - 72]; 62 | uint8_t PM1_CNT_LEN; 63 | } __attribute__((packed)) facp_t; 64 | 65 | 66 | typedef struct { 67 | uint8_t type; 68 | uint8_t length; 69 | } __attribute__((packed)) madt_header_t; 70 | 71 | typedef struct { 72 | madt_header_t madt_header; 73 | uint8_t processor_id; 74 | uint8_t apic_id; 75 | uint32_t flags; 76 | } __attribute__((packed)) local_apic_t; 77 | 78 | typedef struct { 79 | madt_header_t madt_header; 80 | uint8_t apic_id; 81 | uint8_t reserved; 82 | uint32_t addr; 83 | uint32_t gsib; 84 | } __attribute__((packed)) io_apic_t; 85 | 86 | typedef struct { 87 | madt_header_t madt_header; 88 | uint8_t bus_source; 89 | uint8_t irq_source; 90 | uint32_t gsi; 91 | uint16_t flags; 92 | } __attribute__((packed)) iso_t; 93 | 94 | typedef struct { 95 | madt_header_t madt_header; 96 | uint8_t processor; 97 | uint16_t flags; 98 | uint8_t lint; 99 | } __attribute__((packed)) nmi_t; 100 | 101 | 102 | extern rsdp_t *rsdp; 103 | extern rsdt_t *rsdt; 104 | extern xsdt_t *xsdt; 105 | extern madt_t *madt; 106 | extern facp_t *facp; 107 | 108 | extern local_apic_t *local_apics[]; 109 | extern size_t local_apic_ptr; 110 | 111 | extern io_apic_t *io_apics[]; 112 | extern size_t io_apic_ptr; 113 | 114 | extern iso_t *isos[]; 115 | extern size_t iso_ptr; 116 | 117 | extern nmi_t *nmis[]; 118 | extern size_t nmi_ptr; 119 | 120 | extern uint16_t SLP_TYPa; 121 | extern uint16_t SLP_TYPb; 122 | 123 | 124 | void init_acpi(void); 125 | void *acpi_find_sdt(const char *); 126 | 127 | #endif 128 | -------------------------------------------------------------------------------- /bootloader/bootloader.asm: -------------------------------------------------------------------------------- 1 | org 0x7C00 ; BIOS loads us here (0000:7C00) 2 | bits 16 ; 16-bit real mode code 3 | 4 | cli 5 | jmp 0x0000:initialise_cs ; Initialise CS to 0x0000 with a long jump 6 | initialise_cs: 7 | xor ax, ax 8 | mov ds, ax 9 | mov es, ax 10 | mov fs, ax 11 | mov gs, ax 12 | mov ss, ax 13 | mov sp, 0x7BF0 14 | sti 15 | 16 | mov si, LoadingMsg ; Print loading message using simple print (BIOS) 17 | call simple_print 18 | 19 | ; ****************** Load stage 2 ****************** 20 | 21 | mov si, Stage2Msg ; Print loading stage 2 message 22 | call simple_print 23 | 24 | mov si, 128 25 | mov bp, 0x1000 26 | mov bx, 0x0 ; Load to offset 0x1000:0x0000 27 | mov eax, 0 ; Start from LBA sector 0 28 | mov cx, 16 ; Load 128 sectors (64k) 29 | load_stage2: 30 | call read_sector 31 | jc err ; Catch any error 32 | add bx, 16*512 33 | add eax, 16 34 | sub si, 16 35 | jnz load_stage2 36 | 37 | mov si, DoneMsg 38 | call simple_print ; Display done message 39 | 40 | jmp 0x1000:0x0200 ; Jump to stage 2 41 | 42 | err: 43 | mov si, ErrMsg 44 | call simple_print 45 | 46 | halt: 47 | hlt 48 | jmp halt 49 | 50 | ;Data 51 | 52 | LoadingMsg db 0x0D, 0x0A, 'Loading subleq-emu...', 0x0D, 0x0A, 0x0A, 0x00 53 | Stage2Msg db 'Loading emulator...', 0x00 54 | ErrMsg db 0x0D, 0x0A, 'Error, system halted.', 0x00 55 | DoneMsg db ' DONE', 0x0D, 0x0A, 0x00 56 | 57 | ;Includes 58 | 59 | %include 'includes/simple_print.inc' 60 | %include 'includes/disk.inc' 61 | 62 | ; Add a fake MBR because some motherboards won't boot otherwise 63 | 64 | times 0x1b8-($-$$) db 0 65 | mbr: 66 | .signature: dd 0xdeadbeef 67 | times 2 db 0 68 | .p1: 69 | db 0x80 ; status (active) 70 | db 0x20, 0x21, 0x00 ; CHS start 71 | db 0x83 ; partition type (Linux) 72 | db 0xb6, 0x25, 0x51 ; CHS end 73 | dd disk_start/512 ; LBA start 74 | dd disk_size/512 ; size in sectors 75 | .p2: 76 | db 0x00 ; status (invalid) 77 | times 3 db 0 ; CHS start 78 | db 0x00 ; partition type 79 | times 3 db 0 ; CHS end 80 | dd 00 ; LBA start 81 | dd 00 ; size in sectors 82 | .p3: 83 | db 0x00 ; status (invalid) 84 | times 3 db 0 ; CHS start 85 | db 0x00 ; partition type 86 | times 3 db 0 ; CHS end 87 | dd 00 ; LBA start 88 | dd 00 ; size in sectors 89 | .p4: 90 | db 0x00 ; status (invalid) 91 | times 3 db 0 ; CHS start 92 | db 0x00 ; partition type 93 | times 3 db 0 ; CHS end 94 | dd 00 ; LBA start 95 | dd 00 ; size in sectors 96 | 97 | 98 | times 510-($-$$) db 0x00 ; Fill rest with 0x00 99 | bios_signature dw 0xAA55 ; BIOS signature 100 | 101 | incbin 'stage2.bin' 102 | 103 | ; bootloader is 64kb / 128 sectors 104 | times (128*512)-($-$$) db 0x00 ; Padding 105 | 106 | ; padding for partition alignment 107 | times (2048*512)-($-$$) db 0x00 ; Padding 108 | 109 | disk_start equ ($ - $$) 110 | disk_size equ (disk_end - disk_start) 111 | incbin '../Dawn/disk0.bin' 112 | disk_end equ ($ - $$) 113 | -------------------------------------------------------------------------------- /kernel/src/init.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | int get_time(int *seconds, int *minutes, int *hours, 19 | int *days, int *months, int *years); 20 | 21 | uint64_t get_jdn(int days, int months, int years) { 22 | return (1461 * (years + 4800 + (months - 14)/12))/4 + (367 * (months - 2 - 12 * ((months - 14)/12)))/12 - (3 * ((years + 4900 + (months - 14)/12)/100))/4 + days - 32075; 23 | } 24 | 25 | uint64_t get_dawn_epoch(int seconds, int minutes, int hours, 26 | int days, int months, int years) { 27 | 28 | uint64_t jdn_current = get_jdn(days, months, years); 29 | uint64_t jdn_2016 = get_jdn(1, 1, 2016); 30 | 31 | uint64_t jdn_diff = jdn_current - jdn_2016; 32 | 33 | return (jdn_diff * (60 * 60 * 24)) + hours*3600 + minutes*60 + seconds; 34 | } 35 | 36 | void flush_irqs(void); 37 | 38 | void kernel_init(uintptr_t ramdisk_loc) { 39 | /* interrupts disabled */ 40 | 41 | #ifdef _KERNEL_VGA_OUTPUT_ 42 | init_vga_textmode(); 43 | #endif 44 | 45 | /* build descriptor tables */ 46 | load_IDT(); 47 | 48 | /* detect memory */ 49 | init_e820(); 50 | 51 | /* initialise paging */ 52 | init_paging(ramdisk_loc); 53 | 54 | /* initialise graphics mode */ 55 | init_graphics(); 56 | 57 | #ifdef _KERNEL_VGA_OUTPUT_ 58 | init_vbe_tty(); 59 | #endif 60 | 61 | int hours, minutes, seconds, days, months, years; 62 | uint64_t dawn_epoch; 63 | if (get_time(&seconds, &minutes, &hours, &days, &months, &years)) { 64 | kprint(KPRN_ERR, "Error trying to retrieve current time"); 65 | dawn_epoch = 0; 66 | } else { 67 | kprint(KPRN_INFO, "Current time: %u/%u/%u %u:%u:%u", years, months, days, hours, minutes, seconds); 68 | if (years < 2016) { 69 | kprint(KPRN_ERR, "Year < 2016 is an invalid Dawn epoch"); 70 | dawn_epoch = 0; 71 | } else { 72 | dawn_epoch = get_dawn_epoch(seconds, minutes, hours, days, months, years); 73 | } 74 | } 75 | 76 | kprint(KPRN_INFO, "Dawn epoch: %U", dawn_epoch); 77 | 78 | /* remap PIC where it doesn't bother us */ 79 | kprint(KPRN_INFO, "PIC: Remapping and masking legacy PICs..."); 80 | flush_irqs(); 81 | map_PIC(0xa0, 0xa8); 82 | /* mask all PIC IRQs */ 83 | set_PIC0_mask(0b11111111); 84 | set_PIC1_mask(0b11111111); 85 | kprint(KPRN_INFO, "PIC: PIC 0 and 1 remapped and masked."); 86 | 87 | init_mouse(); 88 | 89 | /* set PIT frequency */ 90 | set_pit_freq(KRNL_PIT_FREQ); 91 | 92 | /* initialise ACPI */ 93 | init_acpi(); 94 | 95 | /* initialise APIC */ 96 | init_apic(); 97 | 98 | /****** END OF EARLY BOOTSTRAP ******/ 99 | 100 | init_subleq(ramdisk_loc); 101 | 102 | /* set the date to current time */ 103 | _writeram(335544304, (dawn_epoch + uptime_sec) * 0x100000000); 104 | 105 | /* pass control to the emulator */ 106 | subleq(); 107 | 108 | } 109 | -------------------------------------------------------------------------------- /kernel/blobs/real_init.real: -------------------------------------------------------------------------------- 1 | org 0x1000 2 | bits 64 3 | 4 | ; Save stack 5 | mov qword [saved_stack], rsp 6 | 7 | ; Save arg for later 8 | mov dword [arg], ebx 9 | 10 | ; Save lmode IDT 11 | sidt [lmode_idt] 12 | 13 | ; Save lmode GDT 14 | sgdt [lmode_gdt] 15 | 16 | ; Load real mode IDT 17 | lidt [real_idt] 18 | 19 | ; save cr3 20 | mov rax, cr3 21 | mov dword [cr3_reg], eax 22 | 23 | ; Load 16-bit segments 24 | jmp far dword [ptr16] 25 | 26 | ptr16: 27 | dd pmode16 28 | dw 0x18 29 | 30 | pmode16: 31 | bits 16 32 | mov ax, 0x20 33 | mov ds, ax 34 | mov es, ax 35 | mov ss, ax 36 | mov fs, ax 37 | mov gs, ax 38 | 39 | ; Leave compatibility mode 40 | mov eax, cr0 41 | and eax, 01111111111111111111111111111110b 42 | mov cr0, eax 43 | 44 | ; leave long mode 45 | mov ecx, 0xc0000080 46 | rdmsr 47 | 48 | and eax, 0xfffffeff 49 | wrmsr 50 | 51 | ; Load real mode segments 52 | jmp 0x0000:real_mode 53 | real_mode: 54 | xor ax, ax 55 | mov ds, ax 56 | mov es, ax 57 | mov fs, ax 58 | mov gs, ax 59 | mov ax, 0x1000 60 | mov ss, ax 61 | mov esp, 0xFFF0 62 | 63 | ; Retrieve arg 64 | mov ebx, dword [arg] 65 | 66 | ; Enable ints 67 | sti 68 | 69 | ; Call actual routine 70 | call 0x8000 71 | 72 | ; Disable ints 73 | cli 74 | 75 | ; Load intermediate bootstrap GDT 76 | lgdt [gdt_ptr] 77 | 78 | ; load cr3 79 | mov eax, dword [cr3_reg] 80 | mov cr3, eax 81 | 82 | mov ecx, 0xc0000080 83 | rdmsr 84 | 85 | or eax, 0x00000100 86 | wrmsr 87 | 88 | ; Enter long mode 89 | mov eax, cr0 90 | or eax, 0x80000001 91 | mov cr0, eax 92 | 93 | ; Load long mode segments 94 | jmp 0x08:.lmode 95 | .lmode: 96 | bits 64 97 | mov ax, 0x10 98 | mov ds, ax 99 | mov es, ax 100 | mov fs, ax 101 | mov gs, ax 102 | mov ss, ax 103 | 104 | ; Load lmode IDT 105 | lidt [lmode_idt] 106 | 107 | ; Load lmode GDT 108 | lgdt [lmode_gdt] 109 | 110 | ; Restore stack 111 | mov rsp, qword [saved_stack] 112 | 113 | ; Return 114 | ret 115 | 116 | data: 117 | 118 | align 4 119 | lmode_idt: 120 | dw 0 121 | dq 0 122 | 123 | align 4 124 | real_idt: 125 | dw 0x3FF 126 | dq 0 127 | 128 | align 4 129 | lmode_gdt: 130 | dw 0 131 | dq 0 132 | 133 | arg dd 0 134 | cr3_reg dd 0 135 | saved_stack dq 0 136 | 137 | align 16 138 | 139 | gdt_ptr: 140 | dw .gdt_end - .gdt_start - 1 ; GDT size 141 | dq .gdt_start ; GDT start 142 | 143 | align 16 144 | .gdt_start: 145 | 146 | ; Null descriptor (required) 147 | .null_descriptor: 148 | dw 0x0000 ; Limit 149 | dw 0x0000 ; Base (low 16 bits) 150 | db 0x00 ; Base (mid 8 bits) 151 | db 00000000b ; Access 152 | db 00000000b ; Granularity 153 | db 0x00 ; Base (high 8 bits) 154 | 155 | ; 64 bit mode kernel 156 | .kernel_code_64: 157 | dw 0x0000 ; Limit 158 | dw 0x0000 ; Base (low 16 bits) 159 | db 0x00 ; Base (mid 8 bits) 160 | db 10011010b ; Access 161 | db 00100000b ; Granularity 162 | db 0x00 ; Base (high 8 bits) 163 | 164 | .kernel_data: 165 | dw 0x0000 ; Limit 166 | dw 0x0000 ; Base (low 16 bits) 167 | db 0x00 ; Base (mid 8 bits) 168 | db 10010010b ; Access 169 | db 00000000b ; Granularity 170 | db 0x00 ; Base (high 8 bits) 171 | 172 | .gdt_end: 173 | -------------------------------------------------------------------------------- /bootloader/stage2.asm: -------------------------------------------------------------------------------- 1 | org 0x200 ; 1000:0200 2 | bits 16 3 | 4 | ; ************************* STAGE 2 ************************ 5 | stage2: 6 | 7 | mov ax, 0x1000 8 | mov ds, ax 9 | mov es, ax 10 | mov fs, ax 11 | mov gs, ax 12 | 13 | ; ***** Memory check ***** 14 | 15 | mem_check: 16 | 17 | push edx 18 | 19 | xor ebx, ebx 20 | .loop: 21 | mov eax, 0xe820 22 | mov ecx, 24 23 | mov edx, 0x534d4150 24 | mov edi, .e820_entry 25 | int 0x15 26 | jc .nomem 27 | test ebx, ebx 28 | jz .nomem 29 | cmp dword [.e820_entry + 16], 1 30 | jne .loop 31 | cmp dword [.e820_entry + 8], ((256+18)*1024*1024) 32 | jb .loop 33 | jmp .out 34 | 35 | align 16 36 | .e820_entry: 37 | times 32 db 0 38 | 39 | .nomem: 40 | mov si, NoMemMsg 41 | call simple_print 42 | jmp err 43 | 44 | .out: 45 | mov ebp, dword [.e820_entry] 46 | add ebp, 0x1200000 47 | and ebp, ~(0x200000-1) 48 | pop edx 49 | 50 | ; ***** A20 ***** 51 | 52 | mov si, A20Msg ; Display A20 message 53 | call simple_print 54 | 55 | call enable_a20 ; Enable the A20 address line to access the full memory 56 | jc err ; If it fails, print an error and halt 57 | 58 | mov si, DoneMsg 59 | call simple_print ; Display done message 60 | 61 | ; ***** Unreal Mode ***** 62 | 63 | mov si, UnrealMsg ; Display unreal message 64 | call simple_print 65 | 66 | lgdt [GDT] ; Load the GDT 67 | 68 | ; enter unreal mode 69 | 70 | cli ; Disable interrupts 71 | 72 | mov eax, cr0 ; Enable bit 0 of cr0 and enter protected mode 73 | or eax, 00000001b 74 | mov cr0, eax 75 | 76 | mov ax, 0x10 77 | mov ds, ax 78 | mov es, ax 79 | mov fs, ax 80 | mov gs, ax 81 | 82 | mov eax, cr0 ; Exit protected mode 83 | and eax, 11111110b 84 | mov cr0, eax 85 | 86 | mov ax, 0x1000 87 | mov ds, ax 88 | mov es, ax 89 | mov fs, ax 90 | mov gs, ax 91 | 92 | sti ; Enable interrupts 93 | 94 | mov si, DoneMsg 95 | call simple_print ; Display done message 96 | 97 | ; ***** Kernel ***** 98 | 99 | ; Load the kernel to 0x100000 (1 MiB) 100 | 101 | mov si, KernelMsg ; Show loading kernel message 102 | call simple_print 103 | 104 | mov ecx, kernel_size 105 | push 0 106 | pop es 107 | mov edi, 0x100000 108 | mov esi, kernel 109 | a32 o32 rep movsb 110 | 111 | mov si, DoneMsg 112 | call simple_print ; Display done message 113 | 114 | ; ****************** Load Dawn ****************** 115 | 116 | mov si, DawnMsg ; Print loading Dawn message 117 | call simple_print 118 | 119 | mov ax, 2048 ; Start from LBA sector 2048 120 | push 0x0 121 | pop es 122 | mov ebx, ebp 123 | mov ecx, ((256*1024*1024)/512) 124 | call read_sectors 125 | 126 | jc err ; Catch any error 127 | 128 | mov si, DoneMsg 129 | call simple_print ; Display done message 130 | 131 | ; enter pmode 132 | 133 | cli ; Disable interrupts 134 | 135 | push 0 136 | pop es 137 | mov esi, .trampoline 138 | mov ecx, .trampoline_end - .trampoline 139 | mov edi, 0x8000 140 | rep movsb 141 | 142 | mov eax, cr0 ; Enable bit 0 of cr0 and enter protected mode 143 | or eax, 00000001b 144 | mov cr0, eax 145 | 146 | jmp 0x18:0x8000 147 | 148 | bits 32 149 | 150 | .trampoline: 151 | 152 | mov ax, 0x20 153 | mov ds, ax 154 | mov es, ax 155 | mov fs, ax 156 | mov gs, ax 157 | mov ss, ax 158 | 159 | ; *** Setup registers *** 160 | 161 | mov esp, 0xEFFFF0 162 | 163 | xor eax, eax 164 | xor ebx, ebx 165 | xor ecx, ecx 166 | xor edx, edx 167 | xor esi, esi 168 | xor edi, edi 169 | 170 | jmp 0x18:0x100000 ; Jump to the newly loaded kernel 171 | 172 | .trampoline_end: 173 | 174 | bits 16 175 | err: 176 | mov si, ErrMsg 177 | call simple_print 178 | .halt: 179 | hlt 180 | jmp .halt 181 | 182 | ;Data 183 | 184 | A20Msg db 'Enabling A20 line...', 0x00 185 | UnrealMsg db 'Entering Unreal Mode...', 0x00 186 | KernelMsg db 'Loading kernel...', 0x00 187 | DawnMsg db 'Loading Dawn (please be patient)...', 0x00 188 | NoMemMsg db 0x0D, 0x0A, 'Not enough memory to run subleq-emu.', 0x0d, 0x0a, 0 189 | ErrMsg db 0x0D, 0x0A, 'Error, system halted.', 0x00 190 | DoneMsg db ' DONE', 0x0D, 0x0A, 0x00 191 | 192 | ;Includes 193 | 194 | bits 16 195 | %include 'includes/simple_print.inc' 196 | %include 'includes/disk.inc' 197 | %include 'includes/a20_enabler.inc' 198 | %include 'includes/gdt.inc' 199 | 200 | align 16 201 | kernel: 202 | incbin '../kernel/subleq.bin' 203 | .end: 204 | kernel_size equ (kernel.end - kernel) 205 | -------------------------------------------------------------------------------- /kernel/src/drivers/exceptions.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | static void generic_exception(size_t error_code, size_t fault_rip, size_t fault_cs, const char *fault_name, const char *extra) { 9 | 10 | kprint(KPRN_ERR, "CPU %U: %s occurred at: %X:%X", get_cpu_number(), fault_name, fault_cs, fault_rip); 11 | 12 | if (extra) 13 | kprint(KPRN_ERR, "%s", extra); 14 | 15 | panic("Emulation cannot continue.", error_code); 16 | 17 | } 18 | 19 | void except_div0(size_t fault_rip, size_t fault_cs) { 20 | 21 | generic_exception(0, fault_rip, fault_cs, "Division by zero", NULL); 22 | 23 | } 24 | 25 | void except_debug(size_t fault_rip, size_t fault_cs) { 26 | 27 | generic_exception(0, fault_rip, fault_cs, "Debug", NULL); 28 | 29 | } 30 | 31 | void except_nmi(size_t fault_rip, size_t fault_cs) { 32 | 33 | generic_exception(0, fault_rip, fault_cs, "NMI", NULL); 34 | 35 | } 36 | 37 | void except_breakpoint(size_t fault_rip, size_t fault_cs) { 38 | 39 | generic_exception(0, fault_rip, fault_cs, "Breakpoint", NULL); 40 | 41 | } 42 | 43 | void except_overflow(size_t fault_rip, size_t fault_cs) { 44 | 45 | generic_exception(0, fault_rip, fault_cs, "Overflow", NULL); 46 | 47 | } 48 | 49 | void except_bound_range_exceeded(size_t fault_rip, size_t fault_cs) { 50 | 51 | generic_exception(0, fault_rip, fault_cs, "Bound range exceeded", NULL); 52 | 53 | } 54 | 55 | void except_invalid_opcode(size_t fault_rip, size_t fault_cs) { 56 | 57 | generic_exception(0, fault_rip, fault_cs, "Invalid opcode", NULL); 58 | 59 | } 60 | 61 | void except_device_not_available(size_t fault_rip, size_t fault_cs) { 62 | 63 | generic_exception(0, fault_rip, fault_cs, "Device not available", NULL); 64 | 65 | } 66 | 67 | void except_double_fault(size_t error_code, size_t fault_rip, size_t fault_cs) { 68 | 69 | generic_exception(error_code, fault_rip, fault_cs, "Double fault", NULL); 70 | 71 | } 72 | 73 | void except_coprocessor_segment_overrun(size_t fault_rip, size_t fault_cs) { 74 | 75 | generic_exception(0, fault_rip, fault_cs, "Coprocessor segment overrun", NULL); 76 | 77 | } 78 | 79 | void except_invalid_tss(size_t error_code, size_t fault_rip, size_t fault_cs) { 80 | 81 | generic_exception(error_code, fault_rip, fault_cs, "Invalid TSS", NULL); 82 | 83 | } 84 | 85 | void except_segment_not_present(size_t error_code, size_t fault_rip, size_t fault_cs) { 86 | 87 | generic_exception(error_code, fault_rip, fault_cs, "Segment not present", NULL); 88 | 89 | } 90 | 91 | void except_stack_segment_fault(size_t error_code, size_t fault_rip, size_t fault_cs) { 92 | 93 | generic_exception(error_code, fault_rip, fault_cs, "Stack-segment fault", NULL); 94 | 95 | } 96 | 97 | void except_gen_prot_fault(size_t error_code, size_t fault_rip, size_t fault_cs) { 98 | 99 | generic_exception(error_code, fault_rip, fault_cs, "General protection fault", NULL); 100 | 101 | } 102 | 103 | void except_page_fault(size_t error_code, size_t fault_rip, size_t fault_cs) { 104 | 105 | kprint(KPRN_ERR, "cr2: %X", ({ 106 | size_t cr2; 107 | asm volatile ( 108 | "mov %0, cr2;" 109 | : "=r" (cr2) 110 | ); 111 | cr2; 112 | })); 113 | generic_exception(error_code, fault_rip, fault_cs, "Page fault", NULL); 114 | 115 | } 116 | 117 | void except_x87_exception(size_t fault_rip, size_t fault_cs) { 118 | 119 | generic_exception(0, fault_rip, fault_cs, "x87 exception", NULL); 120 | 121 | } 122 | 123 | void except_alignment_check(size_t error_code, size_t fault_rip, size_t fault_cs) { 124 | 125 | generic_exception(error_code, fault_rip, fault_cs, "Alignment check", NULL); 126 | 127 | } 128 | 129 | void except_machine_check(size_t fault_rip, size_t fault_cs) { 130 | 131 | generic_exception(0, fault_rip, fault_cs, "Machine check", NULL); 132 | 133 | } 134 | 135 | void except_simd_exception(size_t fault_rip, size_t fault_cs) { 136 | 137 | generic_exception(0, fault_rip, fault_cs, "SIMD exception", NULL); 138 | 139 | } 140 | 141 | void except_virtualisation_exception(size_t fault_rip, size_t fault_cs) { 142 | 143 | generic_exception(0, fault_rip, fault_cs, "Virtualisation exception", NULL); 144 | 145 | } 146 | 147 | void except_security_exception(size_t error_code, size_t fault_rip, size_t fault_cs) { 148 | 149 | generic_exception(error_code, fault_rip, fault_cs, "Security exception", NULL); 150 | 151 | } 152 | -------------------------------------------------------------------------------- /kernel/src/drivers/smp.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define MAX_CPUS 128 13 | #define CPU_STACK_SIZE 4096 14 | 15 | int cpu_count = 1; 16 | 17 | typedef struct { 18 | uint32_t unused0 __attribute__((aligned(16))); 19 | uint64_t rsp0; 20 | uint64_t rsp1; 21 | uint64_t rsp2; 22 | uint64_t unused1; 23 | uint64_t ist1; 24 | uint64_t ist2; 25 | uint64_t ist3; 26 | uint64_t ist4; 27 | uint64_t ist5; 28 | uint64_t ist6; 29 | uint64_t ist7; 30 | uint64_t unused2; 31 | uint32_t iopb_offset; 32 | } __attribute__((packed)) tss_t; 33 | 34 | typedef struct { 35 | uint8_t stack[CPU_STACK_SIZE] __attribute__((aligned(16))); 36 | } cpu_stack_t; 37 | 38 | static cpu_stack_t cpu_stacks[MAX_CPUS]; 39 | static cpu_stack_t cpu_int_stacks[MAX_CPUS]; 40 | cpu_local_t cpu_locals[MAX_CPUS]; 41 | static tss_t cpu_tss[MAX_CPUS] __attribute__((aligned(16))); 42 | 43 | void ap_kernel_entry(void) { 44 | /* APs jump here after initialisation */ 45 | 46 | kprint(KPRN_INFO, "SMP: Started up AP #%u", get_cpu_number()); 47 | kprint(KPRN_INFO, "SMP: AP #%u kernel stack top: %X", get_cpu_number(), get_cpu_kernel_stack()); 48 | 49 | lapic_enable(); 50 | 51 | asm volatile ( 52 | "mov cr3, %0;" 53 | "sti;" 54 | : 55 | : "r" ((size_t)subleq_pagemap - PHYS_MEM_OFFSET) 56 | : "memory" 57 | ); 58 | 59 | subleq(); 60 | 61 | return; 62 | } 63 | 64 | static int start_ap(uint8_t target_apic_id, int cpu_number) { 65 | if (cpu_number == MAX_CPUS) { 66 | panic("smp: CPU limit exceeded", cpu_count); 67 | } 68 | 69 | /* create CPU local struct */ 70 | cpu_local_t *cpu_local = &cpu_locals[cpu_number]; 71 | 72 | cpu_local->cpu_number = cpu_number; 73 | cpu_local->kernel_stack = (void *)&cpu_stacks[cpu_number]; 74 | cpu_local->lapic_id = target_apic_id; 75 | cpu_local->subleq_poke_vector = NULL; 76 | 77 | /* prepare TSS */ 78 | tss_t *tss = &cpu_tss[cpu_number]; 79 | 80 | tss->rsp0 = (uint64_t)(&cpu_stacks[cpu_number]); 81 | tss->ist1 = (uint64_t)(&cpu_int_stacks[cpu_number]); 82 | 83 | void *trampoline = prepare_smp_trampoline((void *)ap_kernel_entry, 84 | (void *)((size_t)kernel_pagemap - KERNEL_PHYS_OFFSET), 85 | &cpu_stacks[cpu_number], cpu_local, tss); 86 | 87 | /* Send the INIT IPI */ 88 | lapic_write(APICREG_ICR1, ((uint32_t)target_apic_id) << 24); 89 | lapic_write(APICREG_ICR0, 0x4500); 90 | /* wait 10ms */ 91 | sleep(10); 92 | /* Send the Startup IPI */ 93 | lapic_write(APICREG_ICR1, ((uint32_t)target_apic_id) << 24); 94 | lapic_write(APICREG_ICR0, 0x4600 | (uint32_t)(size_t)trampoline); 95 | /* wait 1ms */ 96 | sleep(1); 97 | 98 | if (check_ap_flag()) { 99 | goto success; 100 | } else { 101 | /* Send the Startup IPI again */ 102 | lapic_write(APICREG_ICR1, ((uint32_t)target_apic_id) << 24); 103 | lapic_write(APICREG_ICR0, 0x4600 | (uint32_t)(size_t)trampoline); 104 | /* wait 1s */ 105 | sleep(1000); 106 | if (check_ap_flag()) 107 | goto success; 108 | else 109 | return -1; 110 | } 111 | 112 | success: 113 | return 0; 114 | } 115 | 116 | void init_cpu0(void) { 117 | /* create CPU 0 local struct */ 118 | cpu_local_t *cpu_local = &cpu_locals[0]; 119 | 120 | cpu_local->cpu_number = 0; 121 | cpu_local->kernel_stack = (void *)&cpu_stacks[0]; 122 | cpu_local->lapic_id = 0; 123 | 124 | tss_t *tss = &cpu_tss[0]; 125 | 126 | tss->rsp0 = (uint64_t)(&cpu_stacks[0]); 127 | tss->ist1 = (uint64_t)(&cpu_int_stacks[0]); 128 | 129 | init_cpu0_local(cpu_local, tss); 130 | 131 | return; 132 | } 133 | 134 | void init_smp(void) { 135 | /* start up the APs and jump them into the kernel */ 136 | for (size_t i = 1; i < local_apic_ptr; i++) { 137 | if (!((local_apics[i]->flags & 1) ^ ((local_apics[i]->flags >> 1) & 1))) 138 | continue; 139 | kprint(KPRN_INFO, "smp: Starting up AP #%u", i); 140 | if (start_ap(local_apics[i]->apic_id, cpu_count)) { 141 | kprint(KPRN_ERR, "smp: Failed to start AP #%u", i); 142 | continue; 143 | } 144 | cpu_count++; 145 | /* wait a bit */ 146 | sleep(10); 147 | } 148 | 149 | kprint(KPRN_INFO, "smp: Total CPU count: %u", cpu_count); 150 | 151 | return; 152 | } 153 | -------------------------------------------------------------------------------- /kernel/src/drivers/graphics.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | vbe_info_struct_t vbe_info_struct; 9 | vbe_mode_info_t vbe_mode_info; 10 | get_vbe_t get_vbe; 11 | 12 | int modeset_done = 0; 13 | 14 | volatile uint32_t *framebuffer; 15 | volatile uint32_t *antibuffer0; 16 | volatile uint32_t *antibuffer1; 17 | 18 | int vbe_width = 1024; 19 | int vbe_height = 768; 20 | int vbe_pitch; 21 | 22 | uint16_t vid_modes[1024]; 23 | 24 | void get_vbe_info(vbe_info_struct_t *vbe_info_struct); 25 | void get_vbe_mode_info(get_vbe_t *get_vbe); 26 | void set_vbe_mode(uint16_t mode); 27 | void dump_vga_font(uint8_t *bitmap); 28 | 29 | uint8_t vga_font[4096]; 30 | 31 | void swap_vbufs(void) { 32 | volatile uint32_t *_ab0 = antibuffer0; 33 | volatile uint32_t *_ab1 = antibuffer1; 34 | volatile uint32_t *_fb = framebuffer; 35 | size_t _c = (vbe_pitch / sizeof(uint32_t)) * vbe_height; 36 | asm volatile ( 37 | "1: " 38 | "lodsd;" 39 | "cmp eax, dword ptr ds:[rbx];" 40 | "jne 2f;" 41 | "add rdi, 4;" 42 | "jmp 3f;" 43 | "2: " 44 | "stosd;" 45 | "3: " 46 | "add rbx, 4;" 47 | "dec rcx;" 48 | "jnz 1b;" 49 | : "+S" (_ab0), 50 | "+D" (_fb), 51 | "+b" (_ab1), 52 | "+c" (_c) 53 | : 54 | : "rax", "memory" 55 | ); 56 | } 57 | 58 | void plot_px(int x, int y, uint32_t hex) { 59 | if (x >= vbe_width || y >= vbe_height) 60 | return; 61 | 62 | size_t fb_i = x + (vbe_pitch / sizeof(uint32_t)) * y; 63 | 64 | framebuffer[fb_i] = hex; 65 | 66 | return; 67 | } 68 | 69 | uint32_t get_ab0_px(int x, int y) { 70 | if (x >= vbe_width || y >= vbe_height) 71 | return 0; 72 | 73 | size_t fb_i = x + (vbe_pitch / sizeof(uint32_t)) * y; 74 | 75 | return antibuffer0[fb_i]; 76 | } 77 | 78 | void plot_ab0_px(int x, int y, uint32_t hex) { 79 | if (x >= vbe_width || y >= vbe_height) 80 | return; 81 | 82 | size_t fb_i = x + (vbe_pitch / sizeof(uint32_t)) * y; 83 | 84 | antibuffer0[fb_i] = hex; 85 | 86 | return; 87 | } 88 | 89 | void init_graphics(void) { 90 | /* interrupts are supposed to be OFF */ 91 | 92 | kprint(KPRN_INFO, "Dumping VGA font..."); 93 | 94 | dump_vga_font(vga_font); 95 | 96 | kprint(KPRN_INFO, "Initialising VBE..."); 97 | 98 | get_vbe_info(&vbe_info_struct); 99 | /* copy the video mode array somewhere else because it might get overwritten */ 100 | for (size_t i = 0; ; i++) { 101 | vid_modes[i] = ((uint16_t *)(size_t)vbe_info_struct.vid_modes)[i]; 102 | if (((uint16_t *)(size_t)vbe_info_struct.vid_modes)[i+1] == 0xffff) { 103 | vid_modes[i+1] = 0xffff; 104 | break; 105 | } 106 | } 107 | 108 | kprint(KPRN_INFO, "Version: %u.%u", vbe_info_struct.version_maj, vbe_info_struct.version_min); 109 | kprint(KPRN_INFO, "OEM: %s", (char *)(size_t)vbe_info_struct.oem); 110 | kprint(KPRN_INFO, "Graphics vendor: %s", (char *)(size_t)vbe_info_struct.vendor); 111 | kprint(KPRN_INFO, "Product name: %s", (char *)(size_t)vbe_info_struct.prod_name); 112 | kprint(KPRN_INFO, "Product revision: %s", (char *)(size_t)vbe_info_struct.prod_rev); 113 | 114 | /* try to set the mode */ 115 | retry: 116 | get_vbe.vbe_mode_info = (uint32_t)(((size_t)&vbe_mode_info) - KERNEL_PHYS_OFFSET); 117 | for (size_t i = 0; vid_modes[i] != 0xffff; i++) { 118 | get_vbe.mode = vid_modes[i]; 119 | get_vbe_mode_info(&get_vbe); 120 | if (vbe_mode_info.res_x == vbe_width 121 | && vbe_mode_info.res_y == vbe_height 122 | && vbe_mode_info.bpp == 32) { 123 | /* mode found */ 124 | kprint(KPRN_INFO, "VBE found matching mode %x, attempting to set.", get_vbe.mode); 125 | vbe_pitch = (int)vbe_mode_info.pitch; 126 | framebuffer = (uint32_t *)((size_t)vbe_mode_info.framebuffer + PHYS_MEM_OFFSET); 127 | antibuffer0 = kalloc((vbe_pitch / sizeof(uint32_t)) * vbe_height * sizeof(uint32_t)); 128 | antibuffer1 = kalloc((vbe_pitch / sizeof(uint32_t)) * vbe_height * sizeof(uint32_t)); 129 | kprint(KPRN_INFO, "Framebuffer address: %X", framebuffer); 130 | set_vbe_mode(get_vbe.mode); 131 | goto success; 132 | } 133 | } 134 | 135 | if (vbe_width == 1024 && vbe_height == 768) { 136 | vbe_width = 800; 137 | vbe_height = 600; 138 | goto retry; 139 | } 140 | 141 | if (vbe_width == 800 && vbe_height == 600) { 142 | vbe_width = 640; 143 | vbe_height = 480; 144 | goto retry; 145 | } 146 | 147 | if (vbe_width == 640 && vbe_height == 480) { 148 | panic("VBE: can't set video mode.", 0); 149 | } 150 | 151 | vbe_width = 1024; 152 | vbe_height = 768; 153 | goto retry; 154 | 155 | success: 156 | modeset_done = 1; 157 | kprint(KPRN_INFO, "VBE init done."); 158 | return; 159 | } 160 | -------------------------------------------------------------------------------- /kernel/asm/subleq.asm: -------------------------------------------------------------------------------- 1 | global subleq.reentry 2 | 3 | section .text 4 | 5 | %macro loop_cycle 0 6 | pop rsi 7 | pop rbx 8 | bswap rsi 9 | bswap rbx 10 | mov rax, qword [rsi] 11 | mov rdx, qword [rbx] 12 | 13 | pop rdi 14 | 15 | cmp rdx, rax 16 | je %%eq 17 | 18 | bswap rax 19 | bswap rdx 20 | sub rdx, rax 21 | bswap rdx 22 | mov qword [rbx], rdx 23 | 24 | jg %%end 25 | jmp %%branch 26 | 27 | %%eq: 28 | mov qword [rbx], rcx 29 | 30 | %%branch: 31 | bswap rdi 32 | mov rsp, rdi 33 | 34 | %%end: 35 | %endmacro 36 | 37 | subleq_loop: 38 | mov qword [fs:18], 0 39 | 40 | xor rcx, rcx 41 | 42 | .start: 43 | loop_cycle 44 | loop_cycle 45 | loop_cycle 46 | 47 | cmp qword [fs:18], 0 48 | je .start 49 | jmp subleq.reentry 50 | 51 | %macro pusham 0 52 | push rax 53 | push rbx 54 | push rcx 55 | push rdx 56 | push rsi 57 | push rdi 58 | push rbp 59 | push r8 60 | push r9 61 | push r10 62 | push r11 63 | push r12 64 | push r13 65 | push r14 66 | push r15 67 | %endmacro 68 | 69 | %macro popam 0 70 | pop r15 71 | pop r14 72 | pop r13 73 | pop r12 74 | pop r11 75 | pop r10 76 | pop r9 77 | pop r8 78 | pop rbp 79 | pop rdi 80 | pop rsi 81 | pop rdx 82 | pop rcx 83 | pop rbx 84 | pop rax 85 | %endmacro 86 | 87 | extern shutdown 88 | extern reboot 89 | extern pm_sleep 90 | 91 | global _readram 92 | global _writeram 93 | 94 | section .text 95 | 96 | bits 64 97 | 98 | global subleq 99 | subleq: 100 | mov r11, qword [fs:0000] ; uint64_t cpu_number; 101 | 102 | xor rsp, rsp ; uint64_t eip = 0; 103 | mov r9, 1 ; int is_halted = 1; 104 | 105 | mov r10, 334364672 ; uint64_t cpu_bank; 106 | mov rax, r11 107 | shl rax, 4 108 | add r10, rax 109 | 110 | mov rax, 4 ; _writeram(cpu_bank + 0, 4); // status 111 | bswap rax 112 | mov qword [r10], rax 113 | 114 | mov qword [r10 + 8], rsp ; _writeram(cpu_bank + 8, 0); // EIP 115 | 116 | test r11, r11 117 | jz .loop_cpu0 118 | 119 | .loop_allcpu: 120 | ; check status 121 | mov rax, qword [r10] 122 | bswap rax 123 | 124 | mov rbx, .jump_table0 125 | jmp [rbx + rax * 8] 126 | align 16 127 | .jump_table0: 128 | dq .loop_allcpu 129 | dq .case1 130 | dq .case2 131 | dq .loop_allcpu 132 | dq .case4 133 | 134 | .loop_cpu0: 135 | ; check status 136 | mov rax, qword [r10] 137 | bswap rax 138 | 139 | mov rbx, .jump_table1 140 | jmp [rbx + rax * 8] 141 | align 16 142 | .jump_table1: 143 | times 8 dq .execute_cycle 144 | dq .shutdown 145 | times 7 dq .execute_cycle 146 | dq .reboot 147 | times 15 dq .execute_cycle 148 | dq .sleep 149 | 150 | .execute_cycle: 151 | ; eip = subleq_cycle(eip); 152 | 153 | jmp subleq_loop 154 | 155 | .reentry: 156 | test r11, r11 157 | jz .loop_cpu0 158 | 159 | mov r8, rsp 160 | bswap r8 161 | mov qword [r10 + 8], r8 ; _writeram(cpu_bank + 8, eip); 162 | jmp .loop_allcpu 163 | 164 | .case1: 165 | ; active 166 | test r9, r9 ; if (is_halted) { 167 | jz .execute_cycle 168 | xor r9, r9 ; is_halted = 0; 169 | mov rsp, qword [r10 + 8] ; eip = _readram(cpu_bank + 8); 170 | bswap rsp 171 | jmp .execute_cycle 172 | 173 | .case2: 174 | ; stop requested 175 | mov rax, 4 176 | bswap rax 177 | mov qword [r10], rax ; _writeram(cpu_bank + 0, 4); 178 | 179 | .case4: 180 | ; halted 181 | mov r9, 1 ; is_halted = 1; 182 | hlt ; halt 183 | jmp .loop_allcpu ; continue; 184 | 185 | .shutdown: 186 | cli 187 | mov rbp, rsp 188 | mov rsp, qword [fs:0008] 189 | sti 190 | mov rax, shutdown 191 | pusham 192 | call rax 193 | popam 194 | cli 195 | mov rsp, rbp 196 | sti 197 | jmp .execute_cycle 198 | 199 | .reboot: 200 | cli 201 | mov rbp, rsp 202 | mov rsp, qword [fs:0008] 203 | sti 204 | mov rax, reboot 205 | pusham 206 | call rax 207 | popam 208 | cli 209 | mov rsp, rbp 210 | sti 211 | jmp .execute_cycle 212 | 213 | .sleep: 214 | cli 215 | mov rbp, rsp 216 | mov rsp, qword [fs:0008] 217 | sti 218 | mov rax, pm_sleep 219 | pusham 220 | call rax 221 | popam 222 | cli 223 | mov rsp, rbp 224 | sti 225 | jmp .execute_cycle 226 | 227 | _readram: 228 | mov rax, qword [rdi] 229 | bswap rax 230 | ret 231 | 232 | _writeram: 233 | bswap rsi 234 | mov qword [rdi], rsi 235 | ret 236 | -------------------------------------------------------------------------------- /kernel/src/drivers/apic.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | /** contains pieces of code from https://nemez.net/osdev, credits to Nemes **/ 10 | 11 | uint32_t lapic_read(uint32_t reg) { 12 | size_t lapic_base = (size_t)madt->local_controller_addr + PHYS_MEM_OFFSET; 13 | return *((volatile uint32_t *)(lapic_base + reg)); 14 | } 15 | 16 | void lapic_write(uint32_t reg, uint32_t val) { 17 | size_t lapic_base = (size_t)madt->local_controller_addr + PHYS_MEM_OFFSET; 18 | *((volatile uint32_t *)(lapic_base + reg)) = val; 19 | return; 20 | } 21 | 22 | uint32_t ioapic_read(size_t ioapic_num, uint32_t reg) { 23 | volatile uint32_t *ioapic_base = (volatile uint32_t *)((size_t)io_apics[ioapic_num]->addr + PHYS_MEM_OFFSET); 24 | *ioapic_base = reg; 25 | return *(ioapic_base + 4); 26 | } 27 | 28 | void ioapic_write(size_t ioapic_num, uint32_t reg, uint32_t val) { 29 | volatile uint32_t *ioapic_base = (volatile uint32_t *)((size_t)io_apics[ioapic_num]->addr + PHYS_MEM_OFFSET); 30 | *ioapic_base = reg; 31 | *(ioapic_base + 4) = val; 32 | return; 33 | } 34 | 35 | uint32_t get_max_redir(size_t ioapic_num) { 36 | return (ioapic_read(ioapic_num, 1) & 0xff0000) >> 16; 37 | } 38 | 39 | size_t get_ioapic_from_gsi(uint32_t gsi) { 40 | for (size_t i = 0; i < io_apic_ptr; i++) { 41 | if (io_apics[i]->gsib <= gsi && io_apics[i]->gsib + get_max_redir(i) > gsi) 42 | return i; 43 | } 44 | return -1; 45 | } 46 | 47 | void ioapic_redirect(uint8_t irq, uint32_t gsi, uint16_t flags, uint8_t apic) { 48 | size_t ioapic = get_ioapic_from_gsi(gsi); 49 | 50 | /* offset the interrupt vector to start directly after exception handlers */ 51 | uint64_t redirection = irq + 32; 52 | /* active low */ 53 | if (flags & 2) { 54 | redirection |= 1 << 13; 55 | } 56 | /* level triggered */ 57 | if (flags & 8) { 58 | redirection |= 1 << 15; 59 | } 60 | /* put the APIC ID of the target APIC (the APIC that will handle this IRQ) */ 61 | redirection |= ((uint64_t)apic) << 56; 62 | 63 | /* IOREGTBL registers start at index 16 and GSI has to be offset by the I/O */ 64 | /* APIC's interrupt base */ 65 | uint32_t ioredtbl = (gsi - io_apics[ioapic]->gsib) * 2 + 16; 66 | 67 | /* write the IOREGTBL as two 32 bit writes */ 68 | ioapic_write(ioapic, ioredtbl + 0, (uint32_t)(redirection)); 69 | ioapic_write(ioapic, ioredtbl + 1, (uint32_t)(redirection >> 32)); 70 | } 71 | 72 | void lapic_set_nmi(uint8_t vec, uint16_t flags, uint8_t lint) { 73 | /* set as NMI and set the desired interrupt vector from the IDT */ 74 | uint32_t nmi = 800 | vec; 75 | /* active low */ 76 | if (flags & 2) { 77 | nmi |= 1 << 13; 78 | } 79 | /* level triggered */ 80 | if (flags & 8) { 81 | nmi |= 1 << 15; 82 | } 83 | if (lint == 1) { 84 | /* set APICREG_LINT1 */ 85 | lapic_write(0x360, nmi); 86 | } else if (lint == 0) { 87 | /* set APICREG_LINT0 */ 88 | lapic_write(0x350, nmi); 89 | } 90 | } 91 | 92 | void install_redirs(void) { 93 | /* install IRQ 0 ISO */ 94 | for (size_t i = 0; i < iso_ptr; i++) { 95 | if (isos[i]->irq_source == 0) { 96 | ioapic_redirect(isos[i]->irq_source, isos[i]->gsi, isos[i]->flags, local_apics[0]->apic_id); 97 | goto irq0_found; 98 | } 99 | } 100 | /* not found in the ISOs, force IRQ 0 */ 101 | ioapic_redirect(0, 0, 0, local_apics[0]->apic_id); 102 | irq0_found: 103 | /* install IRQ 1 ISO */ 104 | for (size_t i = 0; i < iso_ptr; i++) { 105 | if (isos[i]->irq_source == 1) { 106 | ioapic_redirect(isos[i]->irq_source, isos[i]->gsi, isos[i]->flags, local_apics[0]->apic_id); 107 | goto irq1_found; 108 | } 109 | } 110 | /* install keyboard redirect (IRQ 1) */ 111 | ioapic_redirect(1, 1, 0, local_apics[0]->apic_id); 112 | irq1_found: 113 | /* install IRQ 12 ISO */ 114 | for (size_t i = 0; i < iso_ptr; i++) { 115 | if (isos[i]->irq_source == 12) { 116 | ioapic_redirect(isos[i]->irq_source, isos[i]->gsi, isos[i]->flags, local_apics[0]->apic_id); 117 | goto irq12_found; 118 | } 119 | } 120 | /* install mouse redirect (IRQ 12) */ 121 | ioapic_redirect(12, 12, 0, local_apics[0]->apic_id); 122 | irq12_found: 123 | return; 124 | } 125 | 126 | void install_nmis(void) { 127 | for (size_t i = 0; i < nmi_ptr; i++) 128 | lapic_set_nmi(0x90 + i, nmis[i]->flags, nmis[i]->lint); 129 | return; 130 | } 131 | 132 | void lapic_enable(void) { 133 | lapic_write(0xf0, lapic_read(0xf0) | 0x1FF); 134 | } 135 | 136 | void init_apic(void) { 137 | kprint(KPRN_INFO, "APIC: Installing interrupt source overrides..."); 138 | install_redirs(); 139 | kprint(KPRN_INFO, "APIC: Installing NMIs..."); 140 | install_nmis(); 141 | /* enable lapic */ 142 | kprint(KPRN_INFO, "APIC: Enabling local APIC..."); 143 | lapic_enable(); 144 | kprint(KPRN_INFO, "APIC: Done."); 145 | return; 146 | } 147 | 148 | void eoi(void) { 149 | lapic_write(0xb0, 0); 150 | return; 151 | } 152 | -------------------------------------------------------------------------------- /kernel/src/subleq.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | int subleq_ready = 0; 14 | 15 | typedef struct { 16 | uint64_t io_loc; 17 | uint64_t value; 18 | int tries; 19 | } io_stack_t; 20 | 21 | #define IO_STACK_MAX 4096 22 | 23 | static io_stack_t io_stack[IO_STACK_MAX]; 24 | static size_t io_stack_ptr = 0; 25 | 26 | void subleq_io_write(uint64_t io_loc, uint64_t value) { 27 | if (io_stack_ptr == IO_STACK_MAX) 28 | panic("io_stack overflow", 0); 29 | 30 | io_stack[io_stack_ptr].io_loc = io_loc; 31 | io_stack[io_stack_ptr].value = value; 32 | io_stack[io_stack_ptr].tries = 0; 33 | io_stack_ptr++; 34 | 35 | return; 36 | } 37 | 38 | void subleq_io_flush(void) { 39 | 40 | while (io_stack_ptr) { 41 | if (!_readram(io_stack[0].io_loc)) { 42 | _writeram(io_stack[0].io_loc, io_stack[0].value); 43 | for (size_t j = 1; j < io_stack_ptr; j++) { 44 | io_stack[j - 1] = io_stack[j]; 45 | } 46 | io_stack_ptr--; 47 | } else { 48 | break; 49 | } 50 | } 51 | 52 | return; 53 | } 54 | 55 | static volatile uint64_t last_frame_counter = 0; 56 | 57 | static uint32_t *dawn_framebuffer; 58 | 59 | pt_entry_t *subleq_pagemap; 60 | 61 | static void subleq_acquire_mem(uintptr_t ramdisk_loc) { 62 | subleq_pagemap = kmalloc(1); 63 | if (!subleq_pagemap) 64 | for (;;); 65 | 66 | subleq_pagemap = (pt_entry_t *)((size_t)subleq_pagemap + PHYS_MEM_OFFSET); 67 | 68 | /* Map in Dawn */ 69 | for (size_t i = 0; i < (256*1024*1024) / PAGE_SIZE; i++) { 70 | map_page(subleq_pagemap, ramdisk_loc + i * PAGE_SIZE, i * PAGE_SIZE); 71 | } 72 | 73 | size_t pg; 74 | uint64_t *lastptr = 0; 75 | 76 | for (pg = 0; ; pg++) { 77 | uint64_t *ptr = kmalloc(1); 78 | if (!ptr) 79 | break; 80 | if (map_page(subleq_pagemap, (size_t)ptr, (size_t)(256*1024*1024) + pg * PAGE_SIZE)) 81 | break; 82 | lastptr = (pt_entry_t *)((size_t)ptr + PHYS_MEM_OFFSET); 83 | } 84 | 85 | /* Add 8 KiB of gibberish because Dawn is great */ 86 | for (size_t i = 0; i < 8192 / sizeof(uint64_t); i++) { 87 | size_t base = (PAGE_SIZE - 8192) / sizeof(uint64_t); 88 | lastptr[base + i] = 0xffffffffffffffff; 89 | } 90 | 91 | /* Map in kernel */ 92 | for (size_t i = 256; i < 512; i++) { 93 | subleq_pagemap[i] = kernel_pagemap[i]; 94 | } 95 | 96 | kprint(KPRN_INFO, "subleq: Acquired %U 2 MiB pages.", pg); 97 | 98 | return; 99 | } 100 | 101 | void subleq_redraw_screen(void) { 102 | if (last_frame_counter != _readram(335540096 + 32)) { 103 | last_frame_counter = _readram(335540096 + 32); 104 | volatile uint32_t *tmp = antibuffer0; 105 | antibuffer0 = antibuffer1; 106 | antibuffer1 = tmp; 107 | for (int x = 0; x < vbe_width; x++) { 108 | for (int y = 0; y < vbe_height; y++) { 109 | size_t fb_i = x + vbe_width * y; 110 | uint32_t val = dawn_framebuffer[fb_i]; 111 | asm volatile ( 112 | "rol eax, 8;" 113 | "bswap eax;" 114 | : "=a" (val) 115 | : "a" (val) 116 | ); 117 | plot_ab0_px(x, y, val); 118 | } 119 | } 120 | swap_vbufs(); 121 | put_mouse_cursor(1); 122 | } 123 | 124 | return; 125 | } 126 | 127 | static void get_cpu_name(char *str) { 128 | asm volatile ( 129 | "mov eax, 0x80000002;" 130 | "cpuid;" 131 | "stosd;" 132 | "mov eax, ebx;" 133 | "stosd;" 134 | "mov eax, ecx;" 135 | "stosd;" 136 | "mov eax, edx;" 137 | "stosd;" 138 | "mov eax, 0x80000003;" 139 | "cpuid;" 140 | "stosd;" 141 | "mov eax, ebx;" 142 | "stosd;" 143 | "mov eax, ecx;" 144 | "stosd;" 145 | "mov eax, edx;" 146 | "stosd;" 147 | "mov eax, 0x80000004;" 148 | "cpuid;" 149 | "stosd;" 150 | "mov eax, ebx;" 151 | "stosd;" 152 | : "+D" (str) 153 | : 154 | : "rax", "rbx", "rcx", "rdx", "memory" 155 | ); 156 | 157 | return; 158 | } 159 | 160 | void init_subleq(uintptr_t ramdisk_loc) { 161 | init_cpu0(); 162 | 163 | asm volatile ("sti" ::: "memory"); 164 | 165 | subleq_acquire_mem(ramdisk_loc); 166 | 167 | init_smp(); 168 | 169 | asm volatile ( 170 | "mov cr3, %0" 171 | : 172 | : "r" ((size_t)subleq_pagemap - PHYS_MEM_OFFSET) 173 | : "memory" 174 | ); 175 | 176 | subleq_ready = 1; 177 | 178 | dawn_framebuffer = (uint32_t *)(256*1024*1024); 179 | 180 | /* CPU name */ 181 | get_cpu_name((char *)335413288); 182 | 183 | /* display */ 184 | _writeram(335540096, (uint64_t)vbe_width); 185 | _writeram(335540096 + 8, (uint64_t)vbe_height); 186 | _writeram(335540096 + 16, (uint64_t)32); 187 | _writeram(335540096 + 24, (uint64_t)2); 188 | 189 | subleq_ready = 1; 190 | 191 | return; 192 | } 193 | -------------------------------------------------------------------------------- /kernel/src/drivers/acpi.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | rsdp_t *rsdp; 9 | rsdt_t *rsdt; 10 | xsdt_t *xsdt; 11 | madt_t *madt; 12 | facp_t *facp; 13 | 14 | static int use_xsdt = 0; 15 | 16 | local_apic_t *local_apics[MAX_MADT]; 17 | size_t local_apic_ptr = 0; 18 | 19 | io_apic_t *io_apics[MAX_MADT]; 20 | size_t io_apic_ptr = 0; 21 | 22 | iso_t *isos[MAX_MADT]; 23 | size_t iso_ptr = 0; 24 | 25 | nmi_t *nmis[MAX_MADT]; 26 | size_t nmi_ptr = 0; 27 | 28 | uint16_t SLP_TYPa; 29 | uint16_t SLP_TYPb; 30 | 31 | /* Find SDT by signature */ 32 | void *acpi_find_sdt(const char *signature) { 33 | acpi_sdt_t *ptr; 34 | 35 | if (use_xsdt) { 36 | for (size_t i = 0; i < xsdt->sdt.length; i++) { 37 | ptr = (acpi_sdt_t *)((size_t)xsdt->sdt_ptr[i] + PHYS_MEM_OFFSET); 38 | if (!kstrncmp(ptr->signature, signature, 4)) { 39 | kprint(KPRN_INFO, "acpi: Found \"%s\" at %X", signature, (size_t)ptr); 40 | return (void *)ptr; 41 | } 42 | } 43 | } else { 44 | for (size_t i = 0; i < rsdt->sdt.length; i++) { 45 | ptr = (acpi_sdt_t *)((size_t)rsdt->sdt_ptr[i] + PHYS_MEM_OFFSET); 46 | if (!kstrncmp(ptr->signature, signature, 4)) { 47 | kprint(KPRN_INFO, "acpi: Found \"%s\" at %X", signature, (size_t)ptr); 48 | return (void *)ptr; 49 | } 50 | } 51 | } 52 | 53 | kprint(KPRN_INFO, "acpi: \"%s\" not found", signature); 54 | return (void *)0; 55 | } 56 | 57 | void init_acpi(void) { 58 | kprint(KPRN_INFO, "ACPI: Initialising..."); 59 | 60 | /* look for the "RSD PTR " signature from 0x80000 to 0xa0000 */ 61 | /* 0xf0000 to 0x100000 */ 62 | for (size_t i = 0x80000 + PHYS_MEM_OFFSET; i < 0x100000 + PHYS_MEM_OFFSET; i += 16) { 63 | if (i == 0xa0000 + PHYS_MEM_OFFSET) { 64 | /* skip video mem and mapped hardware */ 65 | i = 0xe0000 + PHYS_MEM_OFFSET - 16; 66 | continue; 67 | } 68 | if (!kstrncmp((char *)i, "RSD PTR ", 8)) { 69 | kprint(KPRN_INFO, "ACPI: Found RSDP at %X", i); 70 | rsdp = (rsdp_t *)i; 71 | goto rsdp_found; 72 | } 73 | } 74 | panic("ACPI: RSDP table not found", 0); 75 | 76 | rsdp_found: 77 | if (rsdp->rev >= 2 && rsdp->xsdt_addr) { 78 | use_xsdt = 1; 79 | kprint(KPRN_INFO, "acpi: Found XSDT at %X", (uint32_t)rsdp->xsdt_addr + PHYS_MEM_OFFSET); 80 | xsdt = (xsdt_t *)(size_t)(rsdp->xsdt_addr + PHYS_MEM_OFFSET); 81 | } else { 82 | kprint(KPRN_INFO, "acpi: Found RSDT at %X", (uint32_t)rsdp->rsdt_addr + PHYS_MEM_OFFSET); 83 | rsdt = (rsdt_t *)(size_t)(rsdp->rsdt_addr + PHYS_MEM_OFFSET); 84 | } 85 | 86 | /* search for MADT table */ 87 | madt = acpi_find_sdt("APIC"); 88 | if (!madt) 89 | panic("ACPI: MADT table not found", 0); 90 | 91 | kprint(KPRN_INFO, "ACPI: Rev.: %u", madt->sdt.rev); 92 | kprint(KPRN_INFO, "ACPI: OEMID: %k", madt->sdt.oem_id, 6); 93 | kprint(KPRN_INFO, "ACPI: OEM table ID: %k", madt->sdt.oem_table_id, 8); 94 | kprint(KPRN_INFO, "ACPI: OEM rev.: %u", madt->sdt.oem_rev); 95 | 96 | /* parse the MADT entries */ 97 | for (uint8_t *madt_ptr = (uint8_t *)(&madt->madt_entries_begin); 98 | (size_t)madt_ptr < (size_t)madt + madt->sdt.length; 99 | madt_ptr += *(madt_ptr + 1)) { 100 | switch (*(madt_ptr)) { 101 | case 0: 102 | /* processor local APIC */ 103 | kprint(KPRN_INFO, "ACPI: Found local APIC #%u", local_apic_ptr); 104 | local_apics[local_apic_ptr++] = (local_apic_t *)madt_ptr; 105 | break; 106 | case 1: 107 | /* I/O APIC */ 108 | kprint(KPRN_INFO, "ACPI: Found I/O APIC #%u", io_apic_ptr); 109 | io_apics[io_apic_ptr++] = (io_apic_t *)madt_ptr; 110 | break; 111 | case 2: 112 | /* interrupt source override */ 113 | kprint(KPRN_INFO, "ACPI: Found ISO #%u", iso_ptr); 114 | isos[iso_ptr++] = (iso_t *)madt_ptr; 115 | break; 116 | case 4: 117 | /* NMI */ 118 | kprint(KPRN_INFO, "ACPI: Found NMI #%u", nmi_ptr); 119 | nmis[nmi_ptr++] = (nmi_t *)madt_ptr; 120 | break; 121 | default: 122 | break; 123 | } 124 | } 125 | 126 | facp = acpi_find_sdt("FACP"); 127 | 128 | char *dsdt_ptr = (char *)(size_t)facp->dsdt + 36 + PHYS_MEM_OFFSET; 129 | size_t dsdt_len = *((uint32_t *)((size_t)facp->dsdt + 4 + PHYS_MEM_OFFSET)) - 36; 130 | 131 | kprint(0, "DSDT_PTR = %X", dsdt_ptr); 132 | kprint(0, "DSDT_LEN = %X", dsdt_len); 133 | 134 | size_t s5_addr = 0; 135 | for (size_t i = 0; i < dsdt_len; i++) { 136 | if (!kstrncmp(&dsdt_ptr[i], "_S5_", 4)) { 137 | s5_addr = (size_t)&dsdt_ptr[i]; 138 | goto s5_found; 139 | } 140 | } 141 | panic("s5 not found", 0); 142 | 143 | s5_found: 144 | kprint(0, "s5_addr = %X", s5_addr); 145 | 146 | s5_addr += 5; 147 | s5_addr += ((*((uint8_t *)s5_addr) & 0xc0) >> 6) + 2; 148 | 149 | if (*(uint8_t *)s5_addr == 0x0a) 150 | s5_addr++; 151 | SLP_TYPa = (uint16_t)(*((uint8_t *)s5_addr)) << 10; 152 | s5_addr++; 153 | 154 | if (*(uint8_t *)s5_addr == 0x0a) 155 | s5_addr++; 156 | SLP_TYPb = (uint16_t)(*((uint8_t *)s5_addr)) << 10; 157 | s5_addr++; 158 | 159 | return; 160 | 161 | } 162 | -------------------------------------------------------------------------------- /kernel/asm/isr.asm: -------------------------------------------------------------------------------- 1 | %macro pusham 0 2 | push rax 3 | push rbx 4 | push rcx 5 | push rdx 6 | push rsi 7 | push rdi 8 | push rbp 9 | push r8 10 | push r9 11 | push r10 12 | push r11 13 | push r12 14 | push r13 15 | push r14 16 | push r15 17 | %endmacro 18 | 19 | %macro popam 0 20 | pop r15 21 | pop r14 22 | pop r13 23 | pop r12 24 | pop r11 25 | pop r10 26 | pop r9 27 | pop r8 28 | pop rbp 29 | pop rdi 30 | pop rsi 31 | pop rdx 32 | pop rcx 33 | pop rbx 34 | pop rax 35 | %endmacro 36 | 37 | ; IDT hooks 38 | ; ... CPU exceptions 39 | global handler_irq_apic 40 | global handler_irq_pic0 41 | global handler_irq_pic1 42 | global handler_div0 43 | global handler_debug 44 | global handler_nmi 45 | global handler_breakpoint 46 | global handler_overflow 47 | global handler_bound_range_exceeded 48 | global handler_invalid_opcode 49 | global handler_device_not_available 50 | global handler_double_fault 51 | global handler_coprocessor_segment_overrun 52 | global handler_invalid_tss 53 | global handler_segment_not_present 54 | global handler_stack_segment_fault 55 | global handler_gpf 56 | global handler_pf 57 | global handler_x87_exception 58 | global handler_alignment_check 59 | global handler_machine_check 60 | global handler_simd_exception 61 | global handler_virtualisation_exception 62 | global handler_security_exception 63 | ; ... misc 64 | global irq0_handler 65 | global keyboard_isr 66 | global mouse_isr 67 | 68 | global handler_wakeup 69 | 70 | ; CPU exception handlers 71 | extern except_div0 72 | extern except_debug 73 | extern except_nmi 74 | extern except_breakpoint 75 | extern except_overflow 76 | extern except_bound_range_exceeded 77 | extern except_invalid_opcode 78 | extern except_device_not_available 79 | extern except_double_fault 80 | extern except_coprocessor_segment_overrun 81 | extern except_invalid_tss 82 | extern except_segment_not_present 83 | extern except_stack_segment_fault 84 | extern except_gen_prot_fault 85 | extern except_page_fault 86 | extern except_x87_exception 87 | extern except_alignment_check 88 | extern except_machine_check 89 | extern except_simd_exception 90 | extern except_virtualisation_exception 91 | extern except_security_exception 92 | 93 | ; misc external references 94 | extern eoi 95 | extern timer_interrupt 96 | extern timer_interrupt_ap 97 | extern keyboard_handler 98 | extern mouse_handler 99 | 100 | section .text 101 | 102 | bits 64 103 | 104 | handler_irq_apic: 105 | pusham 106 | call eoi 107 | popam 108 | iretq 109 | 110 | handler_irq_pic0: 111 | push rax 112 | mov al, 0x20 ; acknowledge interrupt to PIC0 113 | out 0x20, al 114 | pop rax 115 | iretq 116 | 117 | handler_irq_pic1: 118 | push rax 119 | mov al, 0x20 ; acknowledge interrupt to both PICs 120 | out 0xA0, al 121 | out 0x20, al 122 | pop rax 123 | iretq 124 | 125 | handler_div0: 126 | pop rdi 127 | pop rsi 128 | call except_div0 129 | 130 | handler_debug: 131 | pop rdi 132 | pop rsi 133 | call except_debug 134 | 135 | handler_nmi: 136 | pop rdi 137 | pop rsi 138 | call except_nmi 139 | 140 | handler_breakpoint: 141 | pop rdi 142 | pop rsi 143 | call except_breakpoint 144 | 145 | handler_overflow: 146 | pop rdi 147 | pop rsi 148 | call except_overflow 149 | 150 | handler_bound_range_exceeded: 151 | pop rdi 152 | pop rsi 153 | call except_bound_range_exceeded 154 | 155 | handler_invalid_opcode: 156 | pop rdi 157 | pop rsi 158 | call except_invalid_opcode 159 | 160 | handler_device_not_available: 161 | pop rdi 162 | pop rsi 163 | call except_device_not_available 164 | 165 | handler_double_fault: 166 | pop rdi 167 | pop rsi 168 | pop rdx 169 | call except_double_fault 170 | 171 | handler_coprocessor_segment_overrun: 172 | pop rdi 173 | pop rsi 174 | call except_coprocessor_segment_overrun 175 | 176 | handler_invalid_tss: 177 | pop rdi 178 | pop rsi 179 | pop rdx 180 | call except_invalid_tss 181 | 182 | handler_segment_not_present: 183 | pop rdi 184 | pop rsi 185 | pop rdx 186 | call except_segment_not_present 187 | 188 | handler_stack_segment_fault: 189 | pop rdi 190 | pop rsi 191 | pop rdx 192 | call except_stack_segment_fault 193 | 194 | handler_gpf: 195 | pop rdi 196 | pop rsi 197 | pop rdx 198 | call except_gen_prot_fault 199 | 200 | handler_pf: 201 | pop rdi 202 | pop rsi 203 | pop rdx 204 | call except_page_fault 205 | 206 | handler_x87_exception: 207 | pop rdi 208 | pop rsi 209 | call except_x87_exception 210 | 211 | handler_alignment_check: 212 | pop rdi 213 | pop rsi 214 | pop rdx 215 | call except_alignment_check 216 | 217 | handler_machine_check: 218 | pop rdi 219 | pop rsi 220 | call except_machine_check 221 | 222 | handler_simd_exception: 223 | pop rdi 224 | pop rsi 225 | call except_simd_exception 226 | 227 | handler_virtualisation_exception: 228 | pop rdi 229 | pop rsi 230 | call except_virtualisation_exception 231 | 232 | handler_security_exception: 233 | pop rdi 234 | pop rsi 235 | call except_security_exception 236 | 237 | extern subleq.reentry 238 | 239 | handler_wakeup: 240 | pusham 241 | call timer_interrupt_ap 242 | call eoi 243 | 244 | mov rax, subleq.reentry 245 | lock xchg qword [fs:18], rax 246 | 247 | popam 248 | 249 | 250 | iretq 251 | 252 | irq0_handler: 253 | pusham 254 | call timer_interrupt 255 | call eoi 256 | 257 | mov rax, subleq.reentry 258 | lock xchg qword [fs:18], rax 259 | 260 | popam 261 | 262 | iretq 263 | 264 | keyboard_isr: 265 | pusham 266 | xor rax, rax 267 | in al, 0x60 ; read from keyboard 268 | mov rdi, rax 269 | call keyboard_handler 270 | call eoi 271 | popam 272 | iretq 273 | 274 | mouse_isr: 275 | pusham 276 | call mouse_handler 277 | call eoi 278 | popam 279 | iretq 280 | -------------------------------------------------------------------------------- /kernel/src/klib.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | size_t memcpy(char *dest, const char *source, size_t count) { 12 | return kmemcpy(dest, source, count); 13 | } 14 | 15 | size_t kmemcpy(char *dest, const char *source, size_t count) { 16 | size_t i; 17 | 18 | for (i = 0; i < count; i++) 19 | dest[i] = source[i]; 20 | 21 | return i; 22 | } 23 | 24 | size_t kstrcpy(char *dest, const char *source) { 25 | size_t i; 26 | 27 | for (i = 0; source[i]; i++) 28 | dest[i] = source[i]; 29 | 30 | dest[i] = 0; 31 | 32 | return i; 33 | } 34 | 35 | int kstrcmp(const char *dest, const char *source) { 36 | size_t i; 37 | 38 | for (i = 0; dest[i] == source[i]; i++) 39 | if ((!dest[i]) && (!source[i])) return 0; 40 | 41 | return 1; 42 | } 43 | 44 | int kstrncmp(const char *dest, const char *source, size_t len) { 45 | size_t i; 46 | 47 | for (i = 0; i < len; i++) 48 | if (dest[i] != source[i]) return 1; 49 | 50 | return 0; 51 | } 52 | 53 | size_t kstrlen(const char *str) { 54 | size_t len; 55 | 56 | for (len = 0; str[len]; len++); 57 | 58 | return len; 59 | } 60 | 61 | typedef struct { 62 | size_t pages; 63 | size_t size; 64 | } kalloc_metadata_t; 65 | 66 | void *kalloc(size_t size) { 67 | size_t pages = size / PAGE_SIZE; 68 | if (size % PAGE_SIZE) pages++; 69 | 70 | // allocate the size in page + allocate an additional page for metadata 71 | char *ptr = kmalloc(pages + 1); 72 | if (!ptr) 73 | return (void*)0; 74 | 75 | ptr += PHYS_MEM_OFFSET; 76 | 77 | kalloc_metadata_t* metadata = (kalloc_metadata_t*)ptr; 78 | ptr += PAGE_SIZE; 79 | 80 | metadata->pages = pages; 81 | metadata->size = size; 82 | 83 | return (void *)ptr; 84 | } 85 | 86 | void kfree(void *addr) { 87 | kalloc_metadata_t *metadata = (kalloc_metadata_t *)((size_t)addr - PAGE_SIZE); 88 | 89 | kmfree((void *)(metadata - PHYS_MEM_OFFSET), metadata->pages + 1); 90 | 91 | return; 92 | } 93 | 94 | void *krealloc(void *addr, size_t new_size) { 95 | if (!addr) return kalloc(new_size); 96 | if (!new_size) { 97 | kfree(addr); 98 | return (void *)0; 99 | } 100 | 101 | kalloc_metadata_t *metadata = (kalloc_metadata_t *)((size_t)addr - PAGE_SIZE); 102 | 103 | char *new_ptr; 104 | if ((new_ptr = kalloc(new_size)) == 0) 105 | return (void*)0; 106 | 107 | if (metadata->size > new_size) 108 | kmemcpy(new_ptr, (char *)addr, new_size); 109 | else 110 | kmemcpy(new_ptr, (char *)addr, metadata->size); 111 | 112 | kfree(addr); 113 | 114 | return new_ptr; 115 | } 116 | 117 | void kputs(const char *string) { 118 | 119 | for (size_t i = 0; string[i]; i++) { 120 | #ifdef _KERNEL_QEMU_OUTPUT_ 121 | port_out_b(0xe9, string[i]); 122 | #endif 123 | #ifdef _KERNEL_VGA_OUTPUT_ 124 | tty_putchar(string[i]); 125 | #endif 126 | } 127 | 128 | return; 129 | } 130 | 131 | void knputs(const char *string, size_t len) { 132 | 133 | for (size_t i = 0; i < len; i++) { 134 | #ifdef _KERNEL_QEMU_OUTPUT_ 135 | port_out_b(0xe9, string[i]); 136 | #endif 137 | #ifdef _KERNEL_VGA_OUTPUT_ 138 | tty_putchar(string[i]); 139 | #endif 140 | } 141 | 142 | return; 143 | } 144 | 145 | void kprn_ui(uint64_t x) { 146 | int i; 147 | char buf[21] = {0}; 148 | 149 | if (!x) { 150 | kputs("0"); 151 | return; 152 | } 153 | 154 | for (i = 19; x; i--) { 155 | buf[i] = (x % 10) + 0x30; 156 | x = x / 10; 157 | } 158 | 159 | i++; 160 | kputs(buf + i); 161 | 162 | return; 163 | } 164 | 165 | static const char hex_to_ascii_tab[] = { 166 | '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' 167 | }; 168 | 169 | void kprn_x(uint64_t x) { 170 | int i; 171 | char buf[17] = {0}; 172 | 173 | if (!x) { 174 | kputs("0x0"); 175 | return; 176 | } 177 | 178 | for (i = 15; x; i--) { 179 | buf[i] = hex_to_ascii_tab[(x % 16)]; 180 | x = x / 16; 181 | } 182 | 183 | i++; 184 | kputs("0x"); 185 | kputs(buf + i); 186 | 187 | return; 188 | } 189 | 190 | void kprint(int type, const char *fmt, ...) { 191 | va_list args; 192 | 193 | va_start(args, fmt); 194 | 195 | /* print timestamp */ 196 | kputs("["); kprn_ui(uptime_sec); kputs("."); 197 | kprn_ui(uptime_raw); kputs("] "); 198 | 199 | switch (type) { 200 | case KPRN_INFO: 201 | kputs("\e[36minfo\e[37m: "); 202 | break; 203 | case KPRN_WARN: 204 | kputs("\e[33mwarning\e[37m: "); 205 | break; 206 | case KPRN_ERR: 207 | kputs("\e[31mERROR\e[37m: "); 208 | break; 209 | case KPRN_DBG: 210 | kputs("\e[36mDEBUG\e[37m: "); 211 | break; 212 | default: 213 | return; 214 | } 215 | 216 | char *str; 217 | 218 | for (;;) { 219 | char c; 220 | size_t len; 221 | while (*fmt && *fmt != '%') knputs(fmt++, 1); 222 | if (!*fmt++) { 223 | va_end(args); 224 | kputs("\n"); 225 | return; 226 | } 227 | switch (*fmt++) { 228 | case 's': 229 | str = (char *)va_arg(args, const char *); 230 | if (!str) 231 | kputs("(null)"); 232 | else 233 | kputs(str); 234 | break; 235 | case 'k': 236 | str = (char *)va_arg(args, const char *); 237 | len = va_arg(args, size_t); 238 | knputs(str, len); 239 | break; 240 | case 'u': 241 | kprn_ui((uint64_t)va_arg(args, unsigned int)); 242 | break; 243 | case 'U': 244 | kprn_ui((uint64_t)va_arg(args, uint64_t)); 245 | break; 246 | case 'x': 247 | kprn_x((uint64_t)va_arg(args, unsigned int)); 248 | break; 249 | case 'X': 250 | kprn_x((uint64_t)va_arg(args, uint64_t)); 251 | break; 252 | case 'c': 253 | c = (char)va_arg(args, int); 254 | knputs(&c, 1); 255 | break; 256 | default: 257 | kputs("?"); 258 | break; 259 | } 260 | } 261 | } 262 | -------------------------------------------------------------------------------- /kernel/src/paging.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define MEMORY_BASE 0x1000000 10 | #define BITMAP_BASE (MEMORY_BASE / PAGE_SIZE) 11 | 12 | static volatile uint32_t *mem_bitmap; 13 | static volatile uint32_t initial_bitmap[] = { 0xfffffffe }; 14 | static volatile uint32_t *tmp_bitmap; 15 | 16 | static inline int rd_bitmap(size_t i) { 17 | i -= BITMAP_BASE; 18 | 19 | size_t entry = i / 32; 20 | size_t offset = i % 32; 21 | 22 | return (int)((mem_bitmap[entry] >> offset) & 1); 23 | } 24 | 25 | static inline void wr_bitmap(size_t i, int val) { 26 | i -= BITMAP_BASE; 27 | 28 | size_t entry = i / 32; 29 | size_t offset = i % 32; 30 | 31 | if (val) 32 | mem_bitmap[entry] |= (1 << offset); 33 | else 34 | mem_bitmap[entry] &= ~(1 << offset); 35 | 36 | return; 37 | } 38 | 39 | void *kmalloc(size_t pages) { 40 | /* allocate memory pages using a bitmap to track free and used pages */ 41 | 42 | /* find contiguous free pages */ 43 | size_t pg_counter = 0; 44 | size_t i; 45 | size_t strt_page; 46 | for (i = BITMAP_BASE; i < BITMAP_BASE + ((PAGE_SIZE / sizeof(uint32_t)) * 32); i++) { 47 | if (!rd_bitmap(i)) 48 | pg_counter++; 49 | else 50 | pg_counter = 0; 51 | if (pg_counter == pages) 52 | goto found; 53 | } 54 | 55 | return (void *)0; 56 | 57 | found: 58 | strt_page = i - (pages - 1); 59 | 60 | for (i = strt_page; i < (strt_page + pages); i++) 61 | wr_bitmap(i, 1); 62 | 63 | /* zero out the pages */ 64 | uint64_t *phys_pages = (uint64_t *)((strt_page * PAGE_SIZE) + PHYS_MEM_OFFSET); 65 | for (size_t i = 0; i < (pages * PAGE_SIZE) / sizeof(uint64_t); i++) 66 | phys_pages[i] = 0; 67 | 68 | return (void *)(strt_page * PAGE_SIZE); 69 | 70 | } 71 | 72 | void kmfree(void *ptr, size_t pages) { 73 | 74 | size_t strt_page = (size_t)ptr / PAGE_SIZE; 75 | 76 | for (size_t i = strt_page; i < (strt_page + pages); i++) 77 | wr_bitmap(i, 0); 78 | 79 | return; 80 | 81 | } 82 | 83 | /* Populate bitmap using e820 data. */ 84 | static void init_pmm(uintptr_t ramdisk_loc) { 85 | mem_bitmap = initial_bitmap; 86 | if (!(tmp_bitmap = kmalloc(1))) { 87 | kprint(KPRN_ERR, "kalloc failure in init_pmm(). Halted."); 88 | for (;;); 89 | } 90 | 91 | tmp_bitmap = (uint32_t *)((size_t)tmp_bitmap + PHYS_MEM_OFFSET); 92 | 93 | for (size_t i = 0; i < PAGE_SIZE / sizeof(uint32_t); i++) 94 | tmp_bitmap[i] = 0xffffffff; 95 | 96 | mem_bitmap = tmp_bitmap; 97 | 98 | kprint(KPRN_INFO, "pmm: Mapping memory as specified by the e820..."); 99 | 100 | /* For each region specified by the e820, iterate over each page which 101 | fits in that region and if the region type indicates the area itself 102 | is usable, write that page as free in the bitmap. Otherwise, mark the page as used. */ 103 | for (size_t i = 0; e820_map[i].type; i++) { 104 | size_t aligned_base; 105 | if (e820_map[i].base % PAGE_SIZE) 106 | aligned_base = e820_map[i].base + (PAGE_SIZE - (e820_map[i].base % PAGE_SIZE)); 107 | else 108 | aligned_base = e820_map[i].base; 109 | size_t aligned_length = (e820_map[i].length / PAGE_SIZE) * PAGE_SIZE; 110 | if ((e820_map[i].base % PAGE_SIZE) && aligned_length) aligned_length -= PAGE_SIZE; 111 | 112 | for (size_t j = 0; j * PAGE_SIZE < aligned_length; j++) { 113 | size_t addr = aligned_base + j * PAGE_SIZE; 114 | 115 | size_t page = addr / PAGE_SIZE; 116 | 117 | if (addr < (MEMORY_BASE + PAGE_SIZE /* bitmap */)) 118 | continue; 119 | 120 | // skip ramdisk 121 | if (addr >= ramdisk_loc && addr < ramdisk_loc + (256*1024*1024)) { 122 | wr_bitmap(page, 1); 123 | continue; 124 | } 125 | 126 | if (e820_map[i].type == 1) 127 | wr_bitmap(page, 0); 128 | else 129 | wr_bitmap(page, 1); 130 | } 131 | } 132 | 133 | return; 134 | } 135 | 136 | static void init_vmm(void) { 137 | kprint(KPRN_INFO, "vmm: Identity mapping memory as specified by the e820..."); 138 | 139 | for (size_t i = 0; e820_map[i].type; i++) { 140 | size_t aligned_base = e820_map[i].base - (e820_map[i].base % PAGE_SIZE); 141 | size_t aligned_length = (e820_map[i].length / PAGE_SIZE) * PAGE_SIZE; 142 | if (e820_map[i].length % PAGE_SIZE) aligned_length += PAGE_SIZE; 143 | if (e820_map[i].base % PAGE_SIZE) aligned_length += PAGE_SIZE; 144 | 145 | for (size_t j = 0; j * PAGE_SIZE < aligned_length; j++) { 146 | size_t addr = aligned_base + j * PAGE_SIZE; 147 | 148 | if (addr < 0x100000000) 149 | continue; 150 | 151 | map_page(kernel_pagemap, addr, addr + PHYS_MEM_OFFSET); 152 | } 153 | } 154 | 155 | return; 156 | } 157 | 158 | int map_page(pt_entry_t *pml4, size_t phys_addr, size_t virt_addr) { 159 | /* Calculate the indices in the various tables using the virtual address */ 160 | size_t pml4_entry = (virt_addr & ((size_t)0x1ff << 39)) >> 39; 161 | size_t pdpt_entry = (virt_addr & ((size_t)0x1ff << 30)) >> 30; 162 | size_t pd_entry = (virt_addr & ((size_t)0x1ff << 21)) >> 21; 163 | 164 | pt_entry_t *pdpt, *pd; 165 | 166 | /* Check present flag */ 167 | if (pml4[pml4_entry] & 0x1) { 168 | /* Reference pdpt */ 169 | pdpt = (pt_entry_t *)((pml4[pml4_entry] & 0xfffffffffffff000) + PHYS_MEM_OFFSET); 170 | } else { 171 | /* Allocate a page for the pdpt. */ 172 | pdpt = kmalloc(1); 173 | if (!pdpt) 174 | return -1; 175 | 176 | /* Present + writable + user (0b111) */ 177 | pml4[pml4_entry] = (pt_entry_t)pdpt | 0x03; 178 | 179 | pdpt = (pt_entry_t *)((size_t)pdpt + PHYS_MEM_OFFSET); 180 | } 181 | 182 | /* Rinse and repeat */ 183 | if (pdpt[pdpt_entry] & 0x1) { 184 | pd = (pt_entry_t *)((pdpt[pdpt_entry] & 0xfffffffffffff000) + PHYS_MEM_OFFSET); 185 | } else { 186 | /* Allocate a page for the pd. */ 187 | pd = kmalloc(1); 188 | if (!pd) 189 | return -1; 190 | 191 | /* Present + writable + user (0b111) */ 192 | pdpt[pdpt_entry] = (pt_entry_t)pd | 0x03; 193 | 194 | pd = (pt_entry_t *)((size_t)pd + PHYS_MEM_OFFSET); 195 | } 196 | 197 | /* Set the entry as present and point it to the passed physical address */ 198 | /* Also set the specified flags */ 199 | pd[pd_entry] = (pt_entry_t)(phys_addr | (0x03 | (1 << 7))); 200 | return 0; 201 | } 202 | 203 | void init_paging(uintptr_t ramdisk_loc) { 204 | init_pmm(ramdisk_loc); 205 | init_vmm(); 206 | 207 | return; 208 | } 209 | -------------------------------------------------------------------------------- /kernel/asm/idt.asm: -------------------------------------------------------------------------------- 1 | global load_IDT 2 | 3 | extern handler_simple 4 | extern handler_code 5 | extern handler_irq_apic 6 | extern handler_irq_pic0 7 | extern handler_irq_pic1 8 | extern handler_div0 9 | extern handler_debug 10 | extern handler_nmi 11 | extern handler_breakpoint 12 | extern handler_overflow 13 | extern handler_bound_range_exceeded 14 | extern handler_invalid_opcode 15 | extern handler_device_not_available 16 | extern handler_double_fault 17 | extern handler_coprocessor_segment_overrun 18 | extern handler_invalid_tss 19 | extern handler_segment_not_present 20 | extern handler_stack_segment_fault 21 | extern handler_gpf 22 | extern handler_pf 23 | extern handler_x87_exception 24 | extern handler_alignment_check 25 | extern handler_machine_check 26 | extern handler_simd_exception 27 | extern handler_virtualisation_exception 28 | extern handler_security_exception 29 | extern irq0_handler 30 | extern keyboard_isr 31 | extern mouse_isr 32 | 33 | extern handler_wakeup 34 | 35 | section .data 36 | 37 | align 4 38 | IDT: 39 | dw .IDTEnd - .IDTStart - 1 ; IDT size 40 | dq .IDTStart ; IDT start 41 | 42 | align 4 43 | .IDTStart: 44 | times 0x100 dq 0,0 ; 64 bit IDT entries are 128 bit 45 | .IDTEnd: 46 | 47 | section .text 48 | 49 | bits 64 50 | 51 | make_entry: 52 | ; RBX = address 53 | ; CX = selector 54 | ; DL = type 55 | ; DH = IST 56 | ; DI = vector 57 | 58 | push rax 59 | push rbx 60 | push rcx 61 | push rdx 62 | push rdi 63 | push r8 64 | 65 | push rdx 66 | 67 | mov rax, 16 68 | and rdi, 0x0000FFFF 69 | mul rdi 70 | mov r8, IDT.IDTStart 71 | add rax, r8 72 | mov rdi, rax 73 | 74 | mov ax, bx 75 | stosw 76 | mov ax, cx 77 | stosw 78 | pop rdx 79 | mov al, dh 80 | stosb 81 | mov al, dl 82 | stosb 83 | shr rbx, 16 84 | mov ax, bx 85 | stosw 86 | shr rbx, 16 87 | mov eax, ebx 88 | stosd 89 | xor eax, eax 90 | stosd 91 | 92 | pop r8 93 | pop rdi 94 | pop rdx 95 | pop rcx 96 | pop rbx 97 | pop rax 98 | ret 99 | 100 | load_IDT: 101 | push rbx 102 | push rcx 103 | push rdx 104 | push rdi 105 | 106 | xor di, di 107 | mov dl, 10001110b 108 | mov dh, 0 109 | mov cx, 0x08 110 | mov rbx, handler_div0 111 | call make_entry ; int 0x00, divide by 0 112 | 113 | inc di 114 | mov rbx, handler_debug 115 | call make_entry ; int 0x01, debug 116 | 117 | inc di 118 | mov rbx, handler_nmi 119 | call make_entry ; int 0x02, NMI 120 | 121 | inc di 122 | mov rbx, handler_breakpoint 123 | call make_entry ; int 0x03, breakpoint 124 | 125 | inc di 126 | mov rbx, handler_overflow 127 | call make_entry ; int 0x04, overflow 128 | 129 | inc di 130 | mov rbx, handler_bound_range_exceeded 131 | call make_entry ; int 0x05, bound range exceeded 132 | 133 | inc di 134 | mov rbx, handler_invalid_opcode 135 | call make_entry ; int 0x06, invalid opcode 136 | 137 | inc di 138 | mov rbx, handler_device_not_available 139 | call make_entry ; int 0x07, device not available 140 | 141 | inc di 142 | mov rbx, handler_double_fault 143 | call make_entry ; int 0x08, double fault 144 | 145 | inc di 146 | mov rbx, handler_coprocessor_segment_overrun 147 | call make_entry ; int 0x09, coprocessor segment overrun 148 | 149 | inc di 150 | mov rbx, handler_invalid_tss 151 | call make_entry ; int 0x0A, invalid TSS 152 | 153 | inc di 154 | mov rbx, handler_segment_not_present 155 | call make_entry ; int 0x0B, segment not present 156 | 157 | inc di 158 | mov rbx, handler_stack_segment_fault 159 | call make_entry ; int 0x0C, stack-segment fault 160 | 161 | inc di 162 | mov rbx, handler_gpf 163 | call make_entry ; int 0x0D, general protection fault 164 | 165 | inc di 166 | mov rbx, handler_pf 167 | call make_entry ; int 0x0E, page fault 168 | 169 | add di, 2 170 | mov rbx, handler_x87_exception 171 | call make_entry ; int 0x10, x87 floating point exception 172 | 173 | inc di 174 | mov rbx, handler_alignment_check 175 | call make_entry ; int 0x11, alignment check 176 | 177 | inc di 178 | mov rbx, handler_machine_check 179 | call make_entry ; int 0x12, machine check 180 | 181 | inc di 182 | mov rbx, handler_simd_exception 183 | call make_entry ; int 0x13, SIMD floating point exception 184 | 185 | mov di, 0x1d 186 | mov rbx, handler_virtualisation_exception 187 | call make_entry ; int 0x14, virtualisation exception 188 | 189 | inc di 190 | mov rbx, handler_security_exception 191 | call make_entry ; int 0x1E, security exception 192 | 193 | mov dh, 1 194 | add di, 2 195 | mov rbx, irq0_handler 196 | call make_entry 197 | 198 | inc di 199 | mov rbx, keyboard_isr 200 | call make_entry 201 | 202 | inc di 203 | mov rbx, handler_irq_apic 204 | call make_entry 205 | 206 | inc di 207 | call make_entry 208 | 209 | inc di 210 | call make_entry 211 | 212 | inc di 213 | call make_entry 214 | 215 | inc di 216 | call make_entry 217 | 218 | inc di 219 | call make_entry 220 | 221 | inc di 222 | call make_entry 223 | 224 | inc di 225 | call make_entry 226 | 227 | inc di 228 | call make_entry 229 | 230 | inc di 231 | call make_entry 232 | 233 | inc di 234 | mov rbx, mouse_isr 235 | call make_entry 236 | 237 | inc di 238 | call make_entry 239 | 240 | inc di 241 | call make_entry 242 | 243 | inc di 244 | call make_entry 245 | 246 | mov di, 0x80 247 | mov rbx, handler_wakeup 248 | call make_entry 249 | 250 | mov di, 0x81 251 | mov rbx, handler_abort 252 | call make_entry 253 | 254 | mov di, 0xa0 255 | mov rbx, handler_irq_pic0 256 | call make_entry 257 | 258 | inc di 259 | call make_entry 260 | 261 | inc di 262 | call make_entry 263 | 264 | inc di 265 | call make_entry 266 | 267 | inc di 268 | call make_entry 269 | 270 | inc di 271 | call make_entry 272 | 273 | inc di 274 | call make_entry 275 | 276 | inc di 277 | call make_entry 278 | 279 | inc di 280 | mov rbx, handler_irq_pic1 281 | call make_entry 282 | 283 | inc di 284 | call make_entry 285 | 286 | inc di 287 | call make_entry 288 | 289 | inc di 290 | call make_entry 291 | 292 | inc di 293 | call make_entry 294 | 295 | inc di 296 | call make_entry 297 | 298 | inc di 299 | call make_entry 300 | 301 | inc di 302 | call make_entry 303 | 304 | mov di, 0x90 305 | mov rbx, handler_irq_apic 306 | call make_entry 307 | 308 | inc di 309 | call make_entry 310 | 311 | inc di 312 | call make_entry 313 | 314 | inc di 315 | call make_entry 316 | 317 | inc di 318 | call make_entry 319 | 320 | inc di 321 | call make_entry 322 | 323 | inc di 324 | call make_entry 325 | 326 | inc di 327 | call make_entry 328 | 329 | mov di, 0xff 330 | call make_entry 331 | 332 | mov rbx, IDT 333 | lidt [rbx] 334 | 335 | pop rdi 336 | pop rdx 337 | pop rcx 338 | pop rbx 339 | ret 340 | 341 | handler_abort: 342 | cli 343 | hlt 344 | jmp handler_abort 345 | -------------------------------------------------------------------------------- /kernel/src/drivers/keyboard.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define MAX_CODE 0x57 9 | #define CAPSLOCK 0x3A 10 | #define RIGHT_SHIFT 0x36 11 | #define LEFT_SHIFT 0x2A 12 | #define RIGHT_SHIFT_REL 0xB6 13 | #define LEFT_SHIFT_REL 0xAA 14 | #define CTRL 0x1D 15 | #define CTRL_REL 0x9D 16 | 17 | static int capslock_active = 0; 18 | static int shift_active = 0; 19 | static int ctrl_active = 0; 20 | 21 | static const uint8_t ascii_capslock[] = { 22 | '\0', '\e', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b', '\t', 23 | 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '[', ']', '\n', '\0', 'A', 'S', 24 | 'D', 'F', 'G', 'H', 'J', 'K', 'L', ';', '\'', '`', '\0', '\\', 'Z', 'X', 'C', 'V', 25 | 'B', 'N', 'M', ',', '.', '/', '\0', '\0', '\0', ' ' 26 | }; 27 | 28 | static const uint8_t ascii_shift[] = { 29 | '\0', '\e', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '\b', '\t', 30 | 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n', '\0', 'A', 'S', 31 | 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~', '\0', '|', 'Z', 'X', 'C', 'V', 32 | 'B', 'N', 'M', '<', '>', '?', '\0', '\0', '\0', ' ' 33 | }; 34 | 35 | static const uint8_t ascii_shift_capslock[] = { 36 | '\0', '\e', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '\b', '\t', 37 | 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '{', '}', '\n', '\0', 'a', 's', 38 | 'd', 'f', 'g', 'h', 'j', 'k', 'l', ':', '"', '~', '\0', '|', 'z', 'x', 'c', 'v', 39 | 'b', 'n', 'm', '<', '>', '?', '\0', '\0', '\0', ' ' 40 | }; 41 | 42 | static const uint8_t ascii_nomod[] = { 43 | '\0', '\e', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b', '\t', 44 | 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', '\0', 'a', 's', 45 | 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', '\0', '\\', 'z', 'x', 'c', 'v', 46 | 'b', 'n', 'm', ',', '.', '/', '\0', '\0', '\0', ' ' 47 | }; 48 | 49 | static int extra_scancodes = 0; 50 | 51 | void keyboard_handler(uint8_t input_byte) { 52 | uint8_t c; 53 | 54 | if (input_byte == 0xe0) { 55 | extra_scancodes = 1; 56 | return; 57 | } 58 | 59 | if (extra_scancodes) { 60 | /* extra scancodes */ 61 | extra_scancodes = 0; 62 | switch (input_byte) { 63 | case 0x48: 64 | /* cursor up */ 65 | if (shift_active) 66 | subleq_io_write(335542256, 18); 67 | else 68 | subleq_io_write(335542256, 14); 69 | break; 70 | case 0x4B: 71 | /* cursor left */ 72 | if (shift_active) 73 | subleq_io_write(335542256, 19); 74 | else if (ctrl_active) 75 | subleq_io_write(335542256, 4); 76 | else 77 | subleq_io_write(335542256, 15); 78 | break; 79 | case 0x50: 80 | /* cursor down */ 81 | if (shift_active) 82 | subleq_io_write(335542256, 20); 83 | else 84 | subleq_io_write(335542256, 16); 85 | break; 86 | case 0x4D: 87 | /* cursor right */ 88 | if (shift_active) 89 | subleq_io_write(335542256, 21); 90 | else if (ctrl_active) 91 | subleq_io_write(335542256, 7); 92 | else 93 | subleq_io_write(335542256, 17); 94 | break; 95 | case 0x49: 96 | /* pgup */ 97 | subleq_io_write(335542256, 9); 98 | break; 99 | case 0x51: 100 | /* pgdown */ 101 | subleq_io_write(335542256, 10); 102 | break; 103 | case 0x53: 104 | /* delete */ 105 | subleq_io_write(335542256, 29); 106 | break; 107 | case CTRL: 108 | ctrl_active = 1; 109 | break; 110 | case CTRL_REL: 111 | ctrl_active = 0; 112 | break; 113 | } 114 | return; 115 | } 116 | 117 | switch (input_byte) { 118 | case 0x4b: 119 | /* keypad 4 */ 120 | hw_mouse_enabled = 0; 121 | subleq_io_write(335542176 + 3 * 8, -0x3000000); 122 | return; 123 | case 0x4d: 124 | /* keypad 6 */ 125 | hw_mouse_enabled = 0; 126 | subleq_io_write(335542176 + 3 * 8, 0x3000000); 127 | return; 128 | case 0x48: 129 | /* keypad 8 */ 130 | hw_mouse_enabled = 0; 131 | subleq_io_write(335542176 + 4 * 8, -0x3000000); 132 | return; 133 | case 0x50: 134 | /* keypad 2 */ 135 | hw_mouse_enabled = 0; 136 | subleq_io_write(335542176 + 4 * 8, 0x3000000); 137 | return; 138 | case 0x47: 139 | /* keypad 7 */ 140 | hw_mouse_enabled = 0; 141 | _writeram(335542176 + 0 * 8, 0x100000000); 142 | return; 143 | case 0xc7: 144 | /* keypad 7 rel */ 145 | hw_mouse_enabled = 0; 146 | _writeram(335542176 + 0 * 8, 0); 147 | return; 148 | case 0x49: 149 | /* keypad 9 */ 150 | hw_mouse_enabled = 0; 151 | _writeram(335542176 + 1 * 8, 0x100000000); 152 | return; 153 | case 0xc9: 154 | /* keypad 9 rel */ 155 | hw_mouse_enabled = 0; 156 | _writeram(335542176 + 1 * 8, 0); 157 | return; 158 | case 0x4c: 159 | /* keypad 5 */ 160 | hw_mouse_enabled = 0; 161 | _writeram(335542176 + 2 * 8, 0x100000000); 162 | return; 163 | case 0xcc: 164 | /* keypad 5 rel */ 165 | hw_mouse_enabled = 0; 166 | _writeram(335542176 + 2 * 8, 0); 167 | return; 168 | default: 169 | break; 170 | } 171 | 172 | switch (input_byte) { 173 | case LEFT_SHIFT: 174 | case RIGHT_SHIFT: 175 | shift_active = 1; 176 | return; 177 | case LEFT_SHIFT_REL: 178 | case RIGHT_SHIFT_REL: 179 | shift_active = 0; 180 | return; 181 | case CTRL: 182 | ctrl_active = 1; 183 | return; 184 | case CTRL_REL: 185 | ctrl_active = 0; 186 | return; 187 | case CAPSLOCK: 188 | capslock_active = !capslock_active; 189 | return; 190 | default: 191 | break; 192 | } 193 | 194 | if (input_byte < MAX_CODE) { 195 | 196 | if (!capslock_active && !shift_active) 197 | c = ascii_nomod[input_byte]; 198 | 199 | else if (!capslock_active && shift_active) 200 | c = ascii_shift[input_byte]; 201 | 202 | else if (capslock_active && shift_active) 203 | c = ascii_shift_capslock[input_byte]; 204 | 205 | else 206 | c = ascii_capslock[input_byte]; 207 | 208 | /* ctrl v */ 209 | if ((c == 'v' || c == 'V') && ctrl_active) { 210 | subleq_io_write(335542256, 22); 211 | return; 212 | } 213 | /* ctrl x */ 214 | if ((c == 'x' || c == 'X') && ctrl_active) { 215 | subleq_io_write(335542256, 23); 216 | return; 217 | } 218 | /* ctrl c */ 219 | if ((c == 'c' || c == 'C') && ctrl_active) { 220 | subleq_io_write(335542256, 25); 221 | return; 222 | } 223 | 224 | switch (c) { 225 | case '\n': 226 | subleq_io_write(335542256, 13); 227 | break; 228 | case '\e': 229 | subleq_io_write(335542256, 27); 230 | break; 231 | default: 232 | subleq_io_write(335542256, (uint64_t)c); 233 | break; 234 | } 235 | 236 | } 237 | 238 | return; 239 | } 240 | -------------------------------------------------------------------------------- /kernel/src/drivers/vga_textmode.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define VIDEO_BOTTOM ((VD_ROWS * VD_COLS) - 1) 8 | #define VD_COLS (80 * 2) 9 | #define VD_ROWS 25 10 | 11 | static void escape_parse(char c); 12 | 13 | static char *video_mem = (char *)(0xb8000 + PHYS_MEM_OFFSET); 14 | static size_t cursor_offset = 0; 15 | static int cursor_status = 1; 16 | static uint8_t text_palette = 0x07; 17 | static uint8_t cursor_palette = 0x70; 18 | static int escape = 0; 19 | static int esc_value0 = 0; 20 | static int esc_value1 = 0; 21 | static int *esc_value = &esc_value0; 22 | static int esc_default0 = 1; 23 | static int esc_default1 = 1; 24 | static int *esc_default = &esc_default0; 25 | 26 | void init_vga_textmode(void) { 27 | port_out_b(0x3d4, 0x0a); 28 | port_out_b(0x3d5, 0x20); 29 | text_clear(); 30 | return; 31 | } 32 | 33 | void text_putstring(const char *str) { 34 | for (size_t i = 0; str[i]; i++) 35 | text_putchar(str[i]); 36 | return; 37 | } 38 | 39 | static void clear_cursor(void) { 40 | video_mem[cursor_offset + 1] = text_palette; 41 | return; 42 | } 43 | 44 | static void draw_cursor(void) { 45 | if (cursor_status) { 46 | video_mem[cursor_offset + 1] = cursor_palette; 47 | } 48 | return; 49 | } 50 | 51 | static void scroll(void) { 52 | // move the text up by one row 53 | for (size_t i = 0; i <= VIDEO_BOTTOM - VD_COLS; i++) 54 | video_mem[i] = video_mem[i + VD_COLS]; 55 | // clear the last line of the screen 56 | for (size_t i = VIDEO_BOTTOM; i > VIDEO_BOTTOM - VD_COLS; i -= 2) { 57 | video_mem[i] = text_palette; 58 | video_mem[i - 1] = ' '; 59 | } 60 | return; 61 | } 62 | 63 | void text_clear(void) { 64 | clear_cursor(); 65 | for (size_t i = 0; i < VIDEO_BOTTOM; i += 2) { 66 | video_mem[i] = ' '; 67 | video_mem[i + 1] = text_palette; 68 | } 69 | cursor_offset = 0; 70 | draw_cursor(); 71 | return; 72 | } 73 | 74 | static void text_clear_no_move(void) { 75 | clear_cursor(); 76 | for (size_t i = 0; i < VIDEO_BOTTOM; i += 2) { 77 | video_mem[i] = ' '; 78 | video_mem[i + 1] = text_palette; 79 | } 80 | draw_cursor(); 81 | return; 82 | } 83 | 84 | void text_enable_cursor(void) { 85 | cursor_status = 1; 86 | draw_cursor(); 87 | return; 88 | } 89 | 90 | void text_disable_cursor(void) { 91 | cursor_status = 0; 92 | clear_cursor(); 93 | return; 94 | } 95 | 96 | void text_putchar(char c) { 97 | if (escape) { 98 | escape_parse(c); 99 | return; 100 | } 101 | switch (c) { 102 | case 0x00: 103 | break; 104 | case 0x1B: 105 | escape = 1; 106 | return; 107 | case 0x0A: 108 | if (text_get_cursor_pos_y() == (VD_ROWS - 1)) { 109 | clear_cursor(); 110 | scroll(); 111 | text_set_cursor_pos(0, (VD_ROWS - 1)); 112 | } else { 113 | text_set_cursor_pos(0, (text_get_cursor_pos_y() + 1)); 114 | } 115 | break; 116 | case 0x08: 117 | if (cursor_offset) { 118 | clear_cursor(); 119 | cursor_offset -= 2; 120 | video_mem[cursor_offset] = ' '; 121 | draw_cursor(); 122 | } 123 | break; 124 | default: 125 | clear_cursor(); 126 | video_mem[cursor_offset] = c; 127 | if (cursor_offset >= (VIDEO_BOTTOM - 1)) { 128 | scroll(); 129 | cursor_offset = VIDEO_BOTTOM - (VD_COLS - 1); 130 | } else 131 | cursor_offset += 2; 132 | draw_cursor(); 133 | } 134 | return; 135 | } 136 | 137 | static uint8_t ansi_colours[] = { 0, 4, 2, 6, 1, 5, 3, 7 }; 138 | 139 | static void sgr(void) { 140 | 141 | if (esc_value0 >= 30 && esc_value0 <= 37) { 142 | uint8_t pal = text_get_text_palette(); 143 | pal = (pal & 0xf0) + ansi_colours[esc_value0 - 30]; 144 | text_set_text_palette(pal); 145 | return; 146 | } 147 | 148 | if (esc_value0 >= 40 && esc_value0 <= 47) { 149 | uint8_t pal = text_get_text_palette(); 150 | pal = (pal & 0x0f) + ansi_colours[esc_value0 - 40] * 0x10; 151 | text_set_text_palette(pal); 152 | return; 153 | } 154 | 155 | return; 156 | } 157 | 158 | static void escape_parse(char c) { 159 | 160 | if (c >= '0' && c <= '9') { 161 | *esc_value *= 10; 162 | *esc_value += c - '0'; 163 | *esc_default = 0; 164 | return; 165 | } 166 | 167 | switch (c) { 168 | case '[': 169 | return; 170 | case ';': 171 | esc_value = &esc_value1; 172 | esc_default = &esc_default1; 173 | return; 174 | case 'A': 175 | if (esc_default0) 176 | esc_value0 = 1; 177 | if (esc_value0 > text_get_cursor_pos_y()) 178 | esc_value0 = text_get_cursor_pos_y(); 179 | text_set_cursor_pos(text_get_cursor_pos_x(), 180 | text_get_cursor_pos_y() - esc_value0); 181 | break; 182 | case 'B': 183 | if (esc_default0) 184 | esc_value0 = 1; 185 | if ((text_get_cursor_pos_y() + esc_value0) > (VD_ROWS - 1)) 186 | esc_value0 = (VD_ROWS - 1) - text_get_cursor_pos_y(); 187 | text_set_cursor_pos(text_get_cursor_pos_x(), 188 | text_get_cursor_pos_y() + esc_value0); 189 | break; 190 | case 'C': 191 | if (esc_default0) 192 | esc_value0 = 1; 193 | if ((text_get_cursor_pos_x() + esc_value0) > (VD_COLS / 2 - 1)) 194 | esc_value0 = (VD_COLS / 2 - 1) - text_get_cursor_pos_x(); 195 | text_set_cursor_pos(text_get_cursor_pos_x() + esc_value0, 196 | text_get_cursor_pos_y()); 197 | break; 198 | case 'D': 199 | if (esc_default0) 200 | esc_value0 = 1; 201 | if (esc_value0 > text_get_cursor_pos_x()) 202 | esc_value0 = text_get_cursor_pos_x(); 203 | text_set_cursor_pos(text_get_cursor_pos_x() - esc_value0, 204 | text_get_cursor_pos_y()); 205 | break; 206 | case 'H': 207 | esc_value0--; 208 | esc_value1--; 209 | if (esc_default0) 210 | esc_value0 = 0; 211 | if (esc_default1) 212 | esc_value1 = 0; 213 | if (esc_value1 >= (VD_COLS / 2)) 214 | esc_value1 = (VD_COLS / 2) - 1; 215 | if (esc_value0 >= VD_ROWS) 216 | esc_value0 = VD_ROWS - 1; 217 | text_set_cursor_pos(esc_value1, esc_value0); 218 | break; 219 | case 'm': 220 | sgr(); 221 | break; 222 | case 'J': 223 | switch (esc_value0) { 224 | case 2: 225 | text_clear_no_move(); 226 | break; 227 | default: 228 | break; 229 | } 230 | break; 231 | default: 232 | escape = 0; 233 | text_putchar('?'); 234 | break; 235 | } 236 | 237 | esc_value = &esc_value0; 238 | esc_value0 = 0; 239 | esc_value1 = 0; 240 | esc_default = &esc_default0; 241 | esc_default0 = 1; 242 | esc_default1 = 1; 243 | escape = 0; 244 | 245 | return; 246 | } 247 | 248 | void text_set_cursor_palette(uint8_t c) { 249 | cursor_palette = c; 250 | draw_cursor(); 251 | return; 252 | } 253 | 254 | uint8_t text_get_cursor_palette(void) { 255 | return cursor_palette; 256 | } 257 | 258 | void text_set_text_palette(uint8_t c) { 259 | text_palette = c; 260 | return; 261 | } 262 | 263 | uint8_t text_get_text_palette(void) { 264 | return text_palette; 265 | } 266 | 267 | int text_get_cursor_pos_x(void) { 268 | return (cursor_offset % VD_COLS) / 2; 269 | } 270 | 271 | int text_get_cursor_pos_y(void) { 272 | return cursor_offset / VD_COLS; 273 | } 274 | 275 | void text_set_cursor_pos(int x, int y) { 276 | clear_cursor(); 277 | cursor_offset = y * VD_COLS + x * 2; 278 | draw_cursor(); 279 | return; 280 | } 281 | -------------------------------------------------------------------------------- /kernel/startup/startup.asm: -------------------------------------------------------------------------------- 1 | ; This file contains the code that is gonna be linked at the beginning of 2 | ; the kernel binary. 3 | ; It should contain core CPU initialisation routines such as entering 4 | ; long mode, then it should call 'kernel_init'. 5 | 6 | extern kernel_init 7 | global startup 8 | global kernel_pagemap 9 | global load_tss 10 | 11 | %define kernel_phys_offset 0xffffffffc0000000 12 | 13 | section .bss 14 | 15 | align 16 16 | kstack: 17 | resb 0x10000 18 | .top: 19 | 20 | align 4096 21 | 22 | kernel_pagemap equ kernel_pagemap_t 23 | kernel_pagemap_t: 24 | .pml4: 25 | resq 512 26 | 27 | .pdpt_phys: 28 | resq 512 29 | 30 | .pd_phys: 31 | .pd_phys1: 32 | resq 512 33 | .pd_phys2: 34 | resq 512 35 | .pd_phys3: 36 | resq 512 37 | .pd_phys4: 38 | resq 512 39 | 40 | .pdpt_low: 41 | resq 512 42 | 43 | .pd_low: 44 | .pd_low1: 45 | resq 512 46 | .pd_low2: 47 | resq 512 48 | .pd_low3: 49 | resq 512 50 | .pd_low4: 51 | resq 512 52 | 53 | .pdpt_kern: 54 | resq 512 55 | 56 | .pd_kern: 57 | resq 512 58 | 59 | section .data 60 | 61 | align 16 62 | GDT: 63 | 64 | dw .GDTEnd - .GDTStart - 1 ; GDT size 65 | dq .GDTStart ; GDT start 66 | 67 | align 16 68 | .GDT_ptrlow: 69 | 70 | dw .GDTEnd - .GDTStart - 1 ; GDT size 71 | dd .GDTStart - kernel_phys_offset ; GDT start 72 | 73 | align 16 74 | .GDTStart: 75 | 76 | ; Null descriptor (required) 77 | 78 | .NullDescriptor: 79 | 80 | dw 0x0000 ; Limit 81 | dw 0x0000 ; Base (low 16 bits) 82 | db 0x00 ; Base (mid 8 bits) 83 | db 00000000b ; Access 84 | db 00000000b ; Granularity 85 | db 0x00 ; Base (high 8 bits) 86 | 87 | ; 64 bit mode 88 | 89 | .KernelCode64: 90 | 91 | dw 0x0000 ; Limit 92 | dw 0x0000 ; Base (low 16 bits) 93 | db 0x00 ; Base (mid 8 bits) 94 | db 10011010b ; Access 95 | db 00100000b ; Granularity 96 | db 0x00 ; Base (high 8 bits) 97 | 98 | .KernelData64: 99 | 100 | dw 0x0000 ; Limit 101 | dw 0x0000 ; Base (low 16 bits) 102 | db 0x00 ; Base (mid 8 bits) 103 | db 10010010b ; Access 104 | db 00000000b ; Granularity 105 | db 0x00 ; Base (high 8 bits) 106 | 107 | ; Unreal mode 108 | 109 | .UnrealCode: 110 | 111 | dw 0xFFFF ; Limit 112 | dw 0x0000 ; Base (low 16 bits) 113 | db 0x00 ; Base (mid 8 bits) 114 | db 10011010b ; Access 115 | db 10001111b ; Granularity 116 | db 0x00 ; Base (high 8 bits) 117 | 118 | .UnrealData: 119 | 120 | dw 0xFFFF ; Limit 121 | dw 0x0000 ; Base (low 16 bits) 122 | db 0x00 ; Base (mid 8 bits) 123 | db 10010010b ; Access 124 | db 10001111b ; Granularity 125 | db 0x00 ; Base (high 8 bits) 126 | 127 | ; tss 128 | .tss: 129 | dw 104 ; tss length 130 | .tss_low: 131 | dw 0 132 | .tss_mid: 133 | db 0 134 | .tss_flags1: 135 | db 10001001b 136 | .tss_flags2: 137 | db 00000000b 138 | .tss_high: 139 | db 0 140 | .tss_upper32: 141 | dd 0 142 | .tss_reserved: 143 | dd 0 144 | 145 | .GDTEnd: 146 | 147 | section .text 148 | 149 | bits 64 150 | 151 | load_tss: 152 | ; addr in RDI 153 | push rbx 154 | mov eax, edi 155 | mov rbx, GDT.tss_low 156 | mov word [rbx], ax 157 | mov eax, edi 158 | and eax, 0xff0000 159 | shr eax, 16 160 | mov rbx, GDT.tss_mid 161 | mov byte [rbx], al 162 | mov eax, edi 163 | and eax, 0xff000000 164 | shr eax, 24 165 | mov rbx, GDT.tss_high 166 | mov byte [rbx], al 167 | mov rax, rdi 168 | shr rax, 32 169 | mov rbx, GDT.tss_upper32 170 | mov dword [rbx], eax 171 | mov rbx, GDT.tss_flags1 172 | mov byte [rbx], 10001001b 173 | mov rbx, GDT.tss_flags2 174 | mov byte [rbx], 0 175 | pop rbx 176 | ret 177 | 178 | bits 32 179 | 180 | nolongmode: 181 | call clearscreen 182 | mov esi, .msg - kernel_phys_offset 183 | call textmodeprint 184 | .halt: 185 | cli 186 | hlt 187 | jmp .halt 188 | 189 | section .data 190 | 191 | .msg db "This CPU does not support long mode.", 0 192 | 193 | section .text 194 | 195 | textmodeprint: 196 | pusha 197 | mov edi, 0xb8000 198 | .loop: 199 | lodsb 200 | test al, al 201 | jz .out 202 | stosb 203 | inc edi 204 | jmp .loop 205 | .out: 206 | popa 207 | ret 208 | 209 | clearscreen: 210 | ; clear screen 211 | pusha 212 | mov edi, 0xb8000 213 | mov ecx, 80*25 214 | mov al, ' ' 215 | mov ah, 0x17 216 | rep stosw 217 | popa 218 | ret 219 | 220 | startup: 221 | mov esp, kstack.top - kernel_phys_offset 222 | 223 | ; check if long mode is present 224 | mov eax, 0x80000001 225 | xor edx, edx 226 | cpuid 227 | and edx, 1 << 29 228 | test edx, edx 229 | jz nolongmode 230 | 231 | ; load the GDT 232 | mov ebx, GDT.GDT_ptrlow - kernel_phys_offset 233 | lgdt [ebx] 234 | 235 | mov edi, kernel_pagemap_t.pd_low - kernel_phys_offset 236 | mov eax, 0x03 | (1 << 7) 237 | mov ecx, 512 * 4 238 | .loop1: 239 | stosd 240 | add eax, 0x200000 241 | mov dword [edi], 0 242 | add edi, 4 243 | loop .loop1 244 | 245 | mov edi, kernel_pagemap_t.pdpt_low - kernel_phys_offset 246 | mov eax, kernel_pagemap_t.pd_low1 - kernel_phys_offset 247 | or eax, 0x03 248 | stosd 249 | xor eax, eax 250 | stosd 251 | mov eax, kernel_pagemap_t.pd_low2 - kernel_phys_offset 252 | or eax, 0x03 253 | stosd 254 | xor eax, eax 255 | stosd 256 | mov eax, kernel_pagemap_t.pd_low3 - kernel_phys_offset 257 | or eax, 0x03 258 | stosd 259 | xor eax, eax 260 | stosd 261 | mov eax, kernel_pagemap_t.pd_low4 - kernel_phys_offset 262 | or eax, 0x03 263 | stosd 264 | xor eax, eax 265 | stosd 266 | 267 | mov edi, kernel_pagemap_t.pml4 - kernel_phys_offset 268 | mov eax, kernel_pagemap_t.pdpt_low - kernel_phys_offset 269 | or eax, 0x03 270 | stosd 271 | xor eax, eax 272 | stosd 273 | 274 | mov edi, kernel_pagemap_t.pd_kern - kernel_phys_offset 275 | mov eax, 0x03 | (1 << 7) 276 | mov ecx, 512 277 | .loop2: 278 | stosd 279 | add eax, 0x200000 280 | mov dword [edi], 0 281 | add edi, 4 282 | loop .loop2 283 | 284 | mov edi, kernel_pagemap_t.pdpt_kern+(511*8) - kernel_phys_offset 285 | mov eax, kernel_pagemap_t.pd_kern - kernel_phys_offset 286 | or eax, 0x03 287 | stosd 288 | xor eax, eax 289 | stosd 290 | 291 | mov edi, kernel_pagemap_t.pml4+(511*8) - kernel_phys_offset 292 | mov eax, kernel_pagemap_t.pdpt_kern - kernel_phys_offset 293 | or eax, 0x03 294 | stosd 295 | xor eax, eax 296 | stosd 297 | 298 | mov edi, kernel_pagemap_t.pd_phys - kernel_phys_offset 299 | mov eax, 0x03 | (1 << 7) 300 | mov ecx, 512 * 4 301 | .loop3: 302 | stosd 303 | add eax, 0x200000 304 | mov dword [edi], 0 305 | add edi, 4 306 | loop .loop3 307 | 308 | mov edi, kernel_pagemap_t.pdpt_phys - kernel_phys_offset 309 | mov eax, kernel_pagemap_t.pd_phys1 - kernel_phys_offset 310 | or eax, 0x03 311 | stosd 312 | xor eax, eax 313 | stosd 314 | mov eax, kernel_pagemap_t.pd_phys2 - kernel_phys_offset 315 | or eax, 0x03 316 | stosd 317 | xor eax, eax 318 | stosd 319 | mov eax, kernel_pagemap_t.pd_phys3 - kernel_phys_offset 320 | or eax, 0x03 321 | stosd 322 | xor eax, eax 323 | stosd 324 | mov eax, kernel_pagemap_t.pd_phys4 - kernel_phys_offset 325 | or eax, 0x03 326 | stosd 327 | xor eax, eax 328 | stosd 329 | 330 | mov edi, kernel_pagemap_t.pml4+(256*8) - kernel_phys_offset 331 | mov eax, kernel_pagemap_t.pdpt_phys - kernel_phys_offset 332 | or eax, 0x03 333 | stosd 334 | xor eax, eax 335 | stosd 336 | 337 | mov edx, kernel_pagemap_t - kernel_phys_offset 338 | mov cr3, edx 339 | 340 | mov eax, cr4 341 | or eax, 1 << 5 342 | mov cr4, eax 343 | 344 | mov ecx, 0xc0000080 345 | rdmsr 346 | 347 | or eax, 0x00000100 348 | wrmsr 349 | 350 | mov eax, cr0 351 | or eax, 0x80000000 352 | mov cr0, eax 353 | 354 | jmp 0x08:.mode64 - kernel_phys_offset 355 | .mode64: 356 | bits 64 357 | mov ax, 0x10 358 | mov ds, ax 359 | mov es, ax 360 | mov fs, ax 361 | mov gs, ax 362 | mov ss, ax 363 | 364 | mov rax, .higher_half 365 | jmp rax 366 | .higher_half: 367 | mov rsp, kstack.top 368 | 369 | mov rbx, GDT 370 | lgdt [rbx] 371 | 372 | mov rdi, rbp 373 | mov rax, kernel_init 374 | call rax 375 | -------------------------------------------------------------------------------- /kernel/src/drivers/vbe_tty.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int vbe_tty_available = 0; 8 | 9 | static int cursor_x = 0; 10 | static int cursor_y = 0; 11 | static int cursor_status = 1; 12 | static uint32_t cursor_bg_col = 0x00ffffff; 13 | static uint32_t cursor_fg_col = 0x00000000; 14 | static uint32_t text_bg_col = 0x00000000; 15 | static uint32_t text_fg_col = 0x00aaaaaa; 16 | static char *grid; 17 | static uint32_t *gridbg; 18 | static uint32_t *gridfg; 19 | static int escape = 0; 20 | static int esc_value0 = 0; 21 | static int esc_value1 = 0; 22 | static int *esc_value = &esc_value0; 23 | static int esc_default0 = 1; 24 | static int esc_default1 = 1; 25 | static int *esc_default = &esc_default0; 26 | static int raw = 0; 27 | static int noblock = 0; 28 | static int noscroll = 0; 29 | 30 | static int rows; 31 | static int cols; 32 | 33 | static void plot_char(char c, int x, int y, uint32_t hex_fg, uint32_t hex_bg) { 34 | int orig_x = x; 35 | 36 | for (int i = 0; i < 16; i++) { 37 | for (int j = 0; j < 8; j++) { 38 | if ((vga_font[c * 16 + i] >> (7 - j)) & 1) 39 | plot_px(x++, y, hex_fg); 40 | else 41 | plot_px(x++, y, hex_bg); 42 | } 43 | y++; 44 | x = orig_x; 45 | } 46 | 47 | return; 48 | } 49 | 50 | static void plot_char_grid(char c, int x, int y, uint32_t hex_fg, uint32_t hex_bg) { 51 | plot_char(c, x * 8, y * 16, hex_fg, hex_bg); 52 | grid[x + y * cols] = c; 53 | gridfg[x + y * cols] = hex_fg; 54 | gridbg[x + y * cols] = hex_bg; 55 | return; 56 | } 57 | 58 | static void clear_cursor(void) { 59 | plot_char(grid[cursor_x + cursor_y * cols], 60 | cursor_x * 8, cursor_y * 16, 61 | text_fg_col, text_bg_col); 62 | return; 63 | } 64 | 65 | static void draw_cursor(void) { 66 | if (cursor_status) 67 | plot_char(grid[cursor_x + cursor_y * cols], 68 | cursor_x * 8, cursor_y * 16, 69 | cursor_fg_col, cursor_bg_col); 70 | return; 71 | } 72 | 73 | void vbe_tty_refresh(void) { 74 | /* interpret the grid and print the chars */ 75 | for (size_t i = 0; i < (size_t)(rows * cols); i++) { 76 | plot_char_grid(grid[i], i % cols, i / cols, gridfg[i], gridbg[i]); 77 | } 78 | draw_cursor(); 79 | 80 | return; 81 | } 82 | 83 | static void scroll(void) { 84 | /* notify grid */ 85 | for (size_t i = cols; i < (size_t)(rows * cols); i++) { 86 | grid[i - cols] = grid[i]; 87 | gridbg[i - cols] = gridbg[i]; 88 | gridfg[i - cols] = gridfg[i]; 89 | } 90 | /* clear the last line of the screen */ 91 | for (size_t i = rows * cols - cols; i < (size_t)(rows * cols); i++) { 92 | grid[i] = ' '; 93 | gridbg[i] = text_bg_col; 94 | gridfg[i] = text_fg_col; 95 | } 96 | 97 | vbe_tty_refresh(); 98 | return; 99 | } 100 | 101 | void vbe_tty_clear(void) { 102 | for (size_t i = 0; i < (size_t)(rows * cols); i++) { 103 | grid[i] = ' '; 104 | gridbg[i] = text_bg_col; 105 | gridfg[i] = text_fg_col; 106 | } 107 | 108 | cursor_x = 0; 109 | cursor_y = 0; 110 | 111 | vbe_tty_refresh(); 112 | 113 | return; 114 | } 115 | 116 | static void vbe_tty_clear_no_move(void) { 117 | for (size_t i = 0; i < (size_t)(rows * cols); i++) { 118 | grid[i] = ' '; 119 | gridbg[i] = text_bg_col; 120 | gridfg[i] = text_fg_col; 121 | } 122 | 123 | vbe_tty_refresh(); 124 | return; 125 | } 126 | 127 | void vbe_tty_enable_cursor(void) { 128 | cursor_status = 1; 129 | draw_cursor(); 130 | return; 131 | } 132 | 133 | void vbe_tty_disable_cursor(void) { 134 | cursor_status = 0; 135 | clear_cursor(); 136 | return; 137 | } 138 | 139 | static uint32_t ansi_colours[] = { 140 | 0x00000000, /* black */ 141 | 0x00aa0000, /* red */ 142 | 0x0000aa00, /* green */ 143 | 0x00aa5500, /* brown */ 144 | 0x000000aa, /* blue */ 145 | 0x00aa00aa, /* magenta */ 146 | 0x0000aaaa, /* cyan */ 147 | 0x00aaaaaa, /* grey */ 148 | }; 149 | 150 | static void sgr(void) { 151 | 152 | if (esc_value0 >= 30 && esc_value0 <= 37) { 153 | text_fg_col = ansi_colours[esc_value0 - 30]; 154 | return; 155 | } 156 | 157 | if (esc_value0 >= 40 && esc_value0 <= 47) { 158 | text_bg_col = ansi_colours[esc_value0 - 40]; 159 | return; 160 | } 161 | 162 | return; 163 | } 164 | 165 | static void escape_parse(char c) { 166 | 167 | if (c >= '0' && c <= '9') { 168 | *esc_value *= 10; 169 | *esc_value += c - '0'; 170 | *esc_default = 0; 171 | return; 172 | } 173 | 174 | switch (c) { 175 | case '[': 176 | return; 177 | case ';': 178 | esc_value = &esc_value1; 179 | esc_default = &esc_default1; 180 | return; 181 | case 'A': 182 | if (esc_default0) 183 | esc_value0 = 1; 184 | if (esc_value0 > cursor_y) 185 | esc_value0 = cursor_y; 186 | vbe_tty_set_cursor_pos(cursor_x, cursor_y - esc_value0); 187 | break; 188 | case 'B': 189 | if (esc_default0) 190 | esc_value0 = 1; 191 | if ((cursor_y + esc_value0) > (rows - 1)) 192 | esc_value0 = (rows - 1) - cursor_y; 193 | vbe_tty_set_cursor_pos(cursor_x, cursor_y + esc_value0); 194 | break; 195 | case 'C': 196 | if (esc_default0) 197 | esc_value0 = 1; 198 | if ((cursor_x + esc_value0) > (cols - 1)) 199 | esc_value0 = (cols - 1) - cursor_x; 200 | vbe_tty_set_cursor_pos(cursor_x + esc_value0, cursor_y); 201 | break; 202 | case 'D': 203 | if (esc_default0) 204 | esc_value0 = 1; 205 | if (esc_value0 > cursor_x) 206 | esc_value0 = cursor_x; 207 | vbe_tty_set_cursor_pos(cursor_x - esc_value0, cursor_y); 208 | break; 209 | case 'H': 210 | esc_value0 -= 1; 211 | esc_value1 -= 1; 212 | if (esc_default0) 213 | esc_value0 = 0; 214 | if (esc_default1) 215 | esc_value1 = 0; 216 | if (esc_value1 >= cols) 217 | esc_value1 = cols - 1; 218 | if (esc_value0 >= rows) 219 | esc_value0 = rows - 1; 220 | vbe_tty_set_cursor_pos(esc_value1, esc_value0); 221 | break; 222 | case 'm': 223 | sgr(); 224 | break; 225 | case 'J': 226 | switch (esc_value0) { 227 | case 2: 228 | vbe_tty_clear_no_move(); 229 | break; 230 | default: 231 | break; 232 | } 233 | break; 234 | /* non-standard sequences */ 235 | case 'r': /* enter/exit raw mode */ 236 | raw = !raw; 237 | break; 238 | case 'b': /* enter/exit non-blocking mode */ 239 | noblock = !noblock; 240 | break; 241 | case 's': /* enter/exit non-scrolling mode */ 242 | noscroll = !noscroll; 243 | break; 244 | /* end non-standard sequences */ 245 | default: 246 | escape = 0; 247 | vbe_tty_putchar('?'); 248 | break; 249 | } 250 | 251 | esc_value = &esc_value0; 252 | esc_value0 = 0; 253 | esc_value1 = 0; 254 | esc_default = &esc_default0; 255 | esc_default0 = 1; 256 | esc_default1 = 1; 257 | escape = 0; 258 | 259 | return; 260 | } 261 | 262 | void vbe_tty_putchar(char c) { 263 | if (!vbe_tty_available) 264 | return; 265 | 266 | if (escape) { 267 | escape_parse(c); 268 | return; 269 | } 270 | switch (c) { 271 | case 0x00: 272 | break; 273 | case 0x1B: 274 | escape = 1; 275 | break; 276 | case 0x0A: 277 | if (cursor_y == (rows - 1)) { 278 | vbe_tty_set_cursor_pos(0, (rows - 1)); 279 | scroll(); 280 | } else { 281 | vbe_tty_set_cursor_pos(0, (cursor_y + 1)); 282 | } 283 | break; 284 | case 0x08: 285 | if (cursor_x || cursor_y) { 286 | clear_cursor(); 287 | if (cursor_x) { 288 | cursor_x--; 289 | } else { 290 | cursor_y--; 291 | cursor_x = cols - 1; 292 | } 293 | draw_cursor(); 294 | } 295 | break; 296 | default: 297 | plot_char_grid(c, cursor_x++, cursor_y, text_fg_col, text_bg_col); 298 | if (cursor_x == cols) { 299 | cursor_x = 0; 300 | cursor_y++; 301 | } 302 | if (cursor_y == rows) { 303 | cursor_y--; 304 | if (!noscroll) 305 | scroll(); 306 | } 307 | draw_cursor(); 308 | } 309 | 310 | return; 311 | } 312 | 313 | void vbe_tty_set_cursor_pos(int x, int y) { 314 | clear_cursor(); 315 | cursor_x = x; 316 | cursor_y = y; 317 | draw_cursor(); 318 | return; 319 | } 320 | 321 | void init_vbe_tty(void) { 322 | kprint(KPRN_INFO, "vbe_tty: Initialising..."); 323 | 324 | cols = vbe_width / 8; 325 | rows = vbe_height / 16; 326 | 327 | grid = kalloc(rows * cols); 328 | gridbg = kalloc(rows * cols * sizeof(uint32_t)); 329 | gridfg = kalloc(rows * cols * sizeof(uint32_t)); 330 | if (!grid || !gridbg || !gridfg) 331 | panic("Out of memory in init_vbe_tty()", 0); 332 | 333 | for (size_t i = 0; i < (size_t)(rows * cols); i++) { 334 | grid[i] = ' '; 335 | gridbg[i] = text_bg_col; 336 | gridfg[i] = text_fg_col; 337 | } 338 | 339 | vbe_tty_available = 1; 340 | 341 | vbe_tty_refresh(); 342 | kprint(KPRN_INFO, "vbe_tty: Ready!"); 343 | return; 344 | } 345 | -------------------------------------------------------------------------------- /kernel/src/drivers/mouse.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int hw_mouse_enabled = 0; 10 | 11 | typedef struct { 12 | uint8_t flags; 13 | uint8_t x_mov; 14 | uint8_t y_mov; 15 | } mouse_packet_t; 16 | 17 | static int mouse_x = 0; 18 | static int mouse_y = 0; 19 | 20 | typedef struct { 21 | int64_t bitmap[16 * 16]; 22 | } cursor_t; 23 | 24 | #define X 0x00ffffff 25 | #define B 0x00000000 26 | #define o (-1) 27 | 28 | cursor_t cursor = { 29 | { 30 | X, X, X, X, X, X, X, X, X, X, X, X, o, o, o, o, 31 | X, B, B, B, B, B, B, B, B, B, X, o, o, o, o, o, 32 | X, B, B, B, B, B, B, B, B, X, o, o, o, o, o, o, 33 | X, B, B, B, B, B, B, B, X, o, o, o, o, o, o, o, 34 | X, B, B, B, B, B, B, X, o, o, o, o, o, o, o, o, 35 | X, B, B, B, B, B, B, B, X, o, o, o, o, o, o, o, 36 | X, B, B, B, B, B, B, B, B, X, o, o, o, o, o, o, 37 | X, B, B, B, X, B, B, B, B, B, X, o, o, o, o, o, 38 | X, B, B, X, o, X, B, B, B, B, B, X, o, o, o, o, 39 | X, B, X, o, o, o, X, B, B, B, B, B, X, o, o, o, 40 | X, X, o, o, o, o, o, X, B, B, B, B, B, X, o, o, 41 | X, o, o, o, o, o, o, o, X, B, B, B, B, B, X, o, 42 | o, o, o, o, o, o, o, o, o, X, B, B, B, B, B, X, 43 | o, o, o, o, o, o, o, o, o, o, X, B, B, B, X, o, 44 | o, o, o, o, o, o, o, o, o, o, o, X, B, X, o, o, 45 | o, o, o, o, o, o, o, o, o, o, o, o, X, o, o, o, 46 | } 47 | }; 48 | 49 | #undef X 50 | #undef B 51 | #undef o 52 | 53 | static inline void mouse_wait(uint8_t a_type) { 54 | uint32_t _time_out=100000; //unsigned int 55 | if (a_type==0) { 56 | while (_time_out--) { 57 | if ((port_in_b(0x64) & 1)==1) { 58 | return; 59 | } 60 | } 61 | return; 62 | } else { 63 | while (_time_out--) { 64 | if ((port_in_b(0x64) & 2)==0) { 65 | return; 66 | } 67 | } 68 | return; 69 | } 70 | } 71 | 72 | static inline void mouse_write(uint8_t a_write) { 73 | //Wait to be able to send a command 74 | mouse_wait(1); 75 | //Tell the mouse we are sending a command 76 | port_out_b(0x64, 0xD4); 77 | //Wait for the final part 78 | mouse_wait(1); 79 | //Finally write 80 | port_out_b(0x60, a_write); 81 | } 82 | 83 | static inline uint8_t mouse_read(void) { 84 | //Get's response from mouse 85 | mouse_wait(0); 86 | return port_in_b(0x60); 87 | } 88 | 89 | static inline uint64_t scale_position(uint64_t min, uint64_t max, 90 | uint64_t oldmin, uint64_t oldmax, 91 | uint64_t val) { 92 | return (oldmax - oldmin) * (val - min) / (max - min) + oldmin; 93 | } 94 | 95 | static int last_plotted_mouse_x = 0; 96 | static int last_plotted_mouse_y = 0; 97 | 98 | void put_mouse_cursor(int refresh) { 99 | if (!hw_mouse_enabled) { 100 | for (size_t x = 0; x < 16; x++) { 101 | for (size_t y = 0; y < 16; y++) { 102 | plot_px(last_plotted_mouse_x + x, last_plotted_mouse_y + y, 103 | get_ab0_px(last_plotted_mouse_x + x, last_plotted_mouse_y + y)); 104 | } 105 | } 106 | return; 107 | } 108 | 109 | if (!refresh) { 110 | for (size_t x = 0; x < 16; x++) { 111 | for (size_t y = 0; y < 16; y++) { 112 | plot_px(last_plotted_mouse_x + x, last_plotted_mouse_y + y, 113 | get_ab0_px(last_plotted_mouse_x + x, last_plotted_mouse_y + y)); 114 | } 115 | } 116 | } 117 | 118 | for (size_t x = 0; x < 16; x++) { 119 | for (size_t y = 0; y < 16; y++) { 120 | if (cursor.bitmap[x * 16 + y] != -1) 121 | plot_px(mouse_x + x, mouse_y + y, cursor.bitmap[x * 16 + y]); 122 | } 123 | } 124 | 125 | last_plotted_mouse_x = mouse_x; 126 | last_plotted_mouse_y = mouse_y; 127 | 128 | return; 129 | } 130 | 131 | static uint64_t dawn_mouse_x = 0; 132 | static uint64_t dawn_mouse_y = 0; 133 | static uint64_t dawn_mouse_click_l = 0; 134 | static uint64_t dawn_mouse_click_r = 0; 135 | static uint64_t dawn_mouse_click_m = 0; 136 | 137 | typedef struct { 138 | uint64_t mouse_x; 139 | uint64_t mouse_y; 140 | uint64_t mouse_click_l; 141 | uint64_t mouse_click_r; 142 | uint64_t mouse_click_m; 143 | } dmouse_packet_t; 144 | 145 | #define MAX_PACKETS 1024 146 | 147 | dmouse_packet_t packets[MAX_PACKETS]; 148 | size_t packet_i = 0; 149 | 150 | static dmouse_packet_t process_packet(mouse_packet_t *p) { 151 | dmouse_packet_t dp; 152 | 153 | int64_t x_mov; 154 | int64_t y_mov; 155 | 156 | if (p->flags & (1 << 0)) { 157 | dp.mouse_click_l = 0x100000000; 158 | } else { 159 | dp.mouse_click_l = 0; 160 | } 161 | 162 | if (p->flags & (1 << 1)) { 163 | dp.mouse_click_r = 0x100000000; 164 | } else { 165 | dp.mouse_click_r = 0; 166 | } 167 | 168 | if (p->flags & (1 << 2)) { 169 | dp.mouse_click_m = 0x100000000; 170 | } else { 171 | dp.mouse_click_m = 0; 172 | } 173 | 174 | if (p->flags & (1 << 4)) 175 | x_mov = (int8_t)p->x_mov; 176 | else 177 | x_mov = p->x_mov; 178 | 179 | if (p->flags & (1 << 5)) 180 | y_mov = (int8_t)p->y_mov; 181 | else 182 | y_mov = p->y_mov; 183 | 184 | if (mouse_x + x_mov < 0) { 185 | mouse_x = 0; 186 | } else if (mouse_x + x_mov >= vbe_width) { 187 | mouse_x = vbe_width - 1; 188 | } else { 189 | mouse_x += x_mov; 190 | } 191 | 192 | if (mouse_y - y_mov < 0) { 193 | mouse_y = 0; 194 | } else if (mouse_y - y_mov >= vbe_height) { 195 | mouse_y = vbe_height - 1; 196 | } else { 197 | mouse_y -= y_mov; 198 | } 199 | 200 | dp.mouse_x = scale_position(0, vbe_width, 0, 0x100000000, mouse_x); 201 | dp.mouse_y = scale_position(0, vbe_height, 0, 0x100000000, mouse_y); 202 | 203 | return dp; 204 | } 205 | 206 | void mouse_update(void) { 207 | /* 208 | 335542176 209 | +0 = left click 210 | +1 = right click 211 | +2 = middle click 212 | +3 = relative x 213 | +4 = relative y 214 | +5 = reserved 215 | +6 = absolute x 216 | +7 = absolute y 217 | +8 = touch 218 | +9 = scroll wheel 219 | */ 220 | 221 | if (!hw_mouse_enabled) 222 | return; 223 | 224 | /* wait for Dawn to clear mouse registers 3 through 9 */ 225 | if ( 226 | _readram(335542176 + 3 * 8) || 227 | _readram(335542176 + 4 * 8) || 228 | _readram(335542176 + 6 * 8) || 229 | _readram(335542176 + 7 * 8) || 230 | _readram(335542176 + 8 * 8) || 231 | _readram(335542176 + 9 * 8) 232 | ) return; 233 | 234 | if (packet_i) { 235 | dawn_mouse_click_l = packets[0].mouse_click_l; 236 | dawn_mouse_click_r = packets[0].mouse_click_r; 237 | dawn_mouse_click_m = packets[0].mouse_click_m; 238 | dawn_mouse_x = packets[0].mouse_x; 239 | dawn_mouse_y = packets[0].mouse_y; 240 | for (size_t i = 1; i < packet_i; i++) { 241 | packets[i - 1] = packets[i]; 242 | } 243 | packet_i--; 244 | } 245 | 246 | _writeram(335542176 + 0 * 8, dawn_mouse_click_l); 247 | _writeram(335542176 + 1 * 8, dawn_mouse_click_r); 248 | _writeram(335542176 + 2 * 8, dawn_mouse_click_m); 249 | _writeram(335542176 + 6 * 8, dawn_mouse_x); 250 | _writeram(335542176 + 7 * 8, dawn_mouse_y); 251 | 252 | return; 253 | } 254 | 255 | static int is_location_info(mouse_packet_t *p) { 256 | if (packet_i) { 257 | if (p->flags & (1 << 0)) { 258 | if (!packets[packet_i - 1].mouse_click_l) 259 | return 0; 260 | } else { 261 | if (packets[packet_i - 1].mouse_click_l) 262 | return 0; 263 | } 264 | 265 | if (p->flags & (1 << 1)) { 266 | if (!packets[packet_i - 1].mouse_click_r) 267 | return 0; 268 | } else { 269 | if (packets[packet_i - 1].mouse_click_r) 270 | return 0; 271 | } 272 | 273 | if (p->flags & (1 << 2)) { 274 | if (!packets[packet_i - 1].mouse_click_m) 275 | return 0; 276 | } else { 277 | if (packets[packet_i - 1].mouse_click_m) 278 | return 0; 279 | } 280 | } else { 281 | if (p->flags & (1 << 0)) { 282 | if (!dawn_mouse_click_l) 283 | return 0; 284 | } else { 285 | if (dawn_mouse_click_l) 286 | return 0; 287 | } 288 | 289 | if (p->flags & (1 << 1)) { 290 | if (!dawn_mouse_click_r) 291 | return 0; 292 | } else { 293 | if (dawn_mouse_click_r) 294 | return 0; 295 | } 296 | 297 | if (p->flags & (1 << 2)) { 298 | if (!dawn_mouse_click_m) 299 | return 0; 300 | } else { 301 | if (dawn_mouse_click_m) 302 | return 0; 303 | } 304 | } 305 | 306 | return 1; 307 | } 308 | 309 | static int handler_cycle = 0; 310 | static mouse_packet_t current_packet; 311 | static int discard_packet = 0; 312 | 313 | void mouse_handler(void) { 314 | switch (handler_cycle) { 315 | case 0: 316 | current_packet.flags = mouse_read(); 317 | handler_cycle++; 318 | if (current_packet.flags & (1 << 6) || current_packet.flags & (1 << 7)) 319 | discard_packet = 1; // discard rest of packet 320 | if (!(current_packet.flags & (1 << 3))) 321 | discard_packet = 1; // discard rest of packet 322 | break; 323 | case 1: 324 | current_packet.x_mov = mouse_read(); 325 | handler_cycle++; 326 | break; 327 | case 2: 328 | current_packet.y_mov = mouse_read(); 329 | handler_cycle = 0; 330 | 331 | if (discard_packet) { 332 | discard_packet = 0; 333 | break; 334 | } 335 | 336 | hw_mouse_enabled = 1; 337 | 338 | dmouse_packet_t dp = process_packet(¤t_packet); 339 | put_mouse_cursor(0); 340 | 341 | if (is_location_info(¤t_packet)) { 342 | dawn_mouse_click_l = dp.mouse_click_l; 343 | dawn_mouse_click_r = dp.mouse_click_r; 344 | dawn_mouse_click_m = dp.mouse_click_m; 345 | dawn_mouse_x = dp.mouse_x; 346 | dawn_mouse_y = dp.mouse_y; 347 | } else { 348 | if (packet_i == MAX_PACKETS) 349 | panic("mouse packets overflow", 0); 350 | packets[packet_i++] = dp; 351 | } 352 | } 353 | 354 | return; 355 | } 356 | 357 | void init_mouse(void) { 358 | mouse_x = vbe_width / 2; 359 | mouse_y = vbe_height / 2; 360 | 361 | dawn_mouse_x = scale_position(0, vbe_width, 0, 0x100000000, mouse_x); 362 | dawn_mouse_y = scale_position(0, vbe_height, 0, 0x100000000, mouse_y); 363 | 364 | mouse_wait(1); 365 | port_out_b(0x64, 0xA8); 366 | 367 | mouse_wait(1); 368 | port_out_b(0x64, 0x20); 369 | uint8_t status = mouse_read(); 370 | mouse_read(); 371 | status |= (1 << 1); 372 | status &= ~(1 << 5); 373 | mouse_wait(1); 374 | port_out_b(0x64, 0x60); 375 | mouse_wait(1); 376 | port_out_b(0x60, status); 377 | mouse_read(); 378 | 379 | mouse_write(0xF6); 380 | mouse_read(); 381 | 382 | mouse_write(0xF4); 383 | mouse_read(); 384 | } 385 | -------------------------------------------------------------------------------- /hardware.txt: -------------------------------------------------------------------------------- 1 | Dawn hardware platform overview 2 | 3 | 4 | The goal of this platform was to offer a system that is simple enough to be manufactured by any corporation or 5 | individual person in any nation. The platform uses a SUBLEQ cpu that have no instruction set, only a fix operation 6 | (substract and jump if result is less or equal to 0). The CPU is 64 bit, the hardwares should be placed beetwhen 7 | the 256 mbyte and 320 mbyte locations. The hardware supports almost unlimit number of CPU cores, 2^63 RAM, 2^63 disks. 8 | Platform supports a 8 channel sound system, up to 4 joysticks. The hardware not implements MMU, IRQ-s, DMA, or any 9 | system controller hardware to keep the things extremely simple, small and cheap. 10 | 11 | 12 | 13 | 14 | 15 | The CPU: 16 | ----------------- 17 | 18 | 19 | 64 bit big-endian SUBLEQ CPU. The opcodes are stored in ABC format, and they operate in the folowing way (pseudocode): 20 | 21 | long long A=GET_64_BIT_DATA(eip); 22 | long long B=GET_64_BIT_DATA(eip+8); 23 | long long C=GET_64_BIT_DATA(eip+16); 24 | long long value_of_b=GET_64_BIT_DATA(B)-GET_64_BIT_DATA(A); 25 | STORE_64_BIT_DATA(value_of_b, B); 26 | if(value_of_b<=0){ 27 | eip=C; 28 | }else{ 29 | eip+=24; 30 | } 31 | 32 | The instruction uses fixed memory addresses. 33 | On multicore systems, EIP should be stored and CPU controlling methods are used too: 34 | CPU control area begin from memory address 334364672 to address 335413248. 35 | Each CPU core have a 16 byte (2 long long) control bank starting from CPU 0. First 8 byte means the CPU state 36 | (0: no cpu, 1: runs, 2: stop requested, 4: stopped). If a stop request is being writed, the hardware should write 4 after it succesfully 37 | stopped the core. Second bank store the EIP for each core. 38 | The CPU state changes can be requested even approx a million times per cycle. 39 | When the CPU is being stopped or started, the cache memory should be 40 | synced, and the EIP should be saved to the second 8 byte. On system start, only the 0. CPU starts 41 | the rest will have status 4. 42 | CPU-s usually being handled in the same time. If the 0. CPU is disabled (8 being written to the control memory) 43 | then the system shuts down. If 16 is being written, the system reboots. 44 | 45 | Control bank and eip only will be written by the CPU cores itself, and the kernel from the CPU0. 46 | 47 | Hardware access is only manditory on the 0. CPU. 48 | 49 | Memory address 334364664 (long long) can specify to the system, how much clock it takes to stop/start 50 | the CPU-s. If not specified, kernel will assume ~1000 clock cycle. 51 | 52 | Memory address 335413288 stores the CPU name, maximum 40 byte. This should be prescisely filled with the 53 | manufacturer name and the model/type, for example: \"YourCorp YourCPU3 /8 Ghz/64 Core\" 54 | In emulators, it must be filled with the host hardware CPU name and model, and NOT just only with the emulator name! 55 | 56 | Creating Dawn optimized CPU-s (for speed): 57 | -If you want to add cache to your CPU, add 2 kbyte cache at least, becouse the temporary-value calculation in the compiler is optimized for more than half kbyte of level 1 cache. 58 | -A thread typically will run for a few tousand of cycles, the minimum ideal l2 cache size is 8 kbyte * core number. 59 | -In-order superscalar designs will scale efficiently up to 2 or 3 pipeline. Out of order design scalability limits is not yet known, the theocretical maximum is 20 pipeline. 60 | -In practice, you should chase high ghz-s. Since the cores are built from few and simple transistors, you can do this. 61 | -Strict cache coherency beethwen the CPU cores are not mandatory, it can be delayed, but disabling/enabling the cores always must properly sync it. 62 | -Disabling and enabling a CPU core must be very fast, it could be done millions of times per seconds, as fast as the kernel can work. 63 | -BUT: Usually, all cores are enabled/disabled in the same time almost simultanously and in asynchron mode. They dont need to be disabled immediately, you can sync them for a few hundred cycle if you want. The kernel will wait a bit, but after a while, they will mark the core as inactive, and you really should avoid this! 64 | -The first core will be allocated to the kernel. Add at least 8 cores for efficient operation. Of course one-core implementations will work too. 65 | -Core0 can be a bit stronger than the others. Virtual and weaker CPU cores should be at the end of the cpu list, stronger cores should be come first. 66 | 67 | Dawn supports hot-pluging for cpus with the folowing limitations: 68 | -If cpu from Socket0 is removed, the kernel will stall until you place the cpu back. 69 | -You must place back the cpus to sockets, becouse the sheduler will operate incorrectly in these cases, causing stall in random threads and processes. 70 | -You can use cpus from any manufacturers and any speed (if - of course - your hardware implementation allows this) - but the kernel will always display the primary system CPU name. 71 | 72 | How many CPU cores Dawn can handle? 73 | -262144*2^63. Dawn can handle 262144 cpus by default, and if that is not enough, then starts to use pages to adress more of them. This behavior was not yet tested - no hardware to do it - so probably will not work yet. 74 | If more cpu is needed, There is a banking address at memory 335413256. The operating system will write the number of the CPU bank here to access processors in the next bank, the hardware 75 | should write the same value to 335413262 when its succesfully mapped the new cpu bank to the addresses beginning from 334364672 again. 76 | 77 | 78 | 79 | 80 | 81 | Time: 82 | --------- 83 | Timer is placed on memory address 335544304 (unsigned long long). Installing timer is not manditory to run the operating system, but it is stronly recommended to have. 84 | Without timer, the sound and input handling will not be proper. Ideally, the timer have a precisity at least 2-3 microsecond. 2^32 means one second. 0 means 2016 january 1. 85 | Memory address 335544300 (uint32) is also assigned for the timer, in the case of the timer overflows, so the timer is basically a 80-bit number. 86 | 87 | 88 | Sound: 89 | ------ 90 | The sound card begins on memory address 335544116, signed 64 bit integer data for each output channels (8*8 byte total). The next 8*8 byte is the sound input (microphones, line in, etc). 91 | 92 | 93 | Keyboard: 94 | --------- 95 | Keyboard data accepted at memory address 335542256 (long long). Unicode characters are accepted here directly. There are special keycodes, those are the folowing: 96 | 1 = Main Button 97 | 2 = Home 98 | 3 = End 99 | 4 = crtl+left 100 | 5 = Quit (AltF4) 101 | 6 = Shutdown 102 | 7 = crtl+right 103 | 8 = Backspace 104 | 9: PgUp 105 | 10: PgDown 106 | 11: Shift+Home 107 | 12: Shift+End 108 | 13 = Enter key 109 | 14 = Up 110 | 15 = Left 111 | 16 = Down 112 | 17 = Right 113 | 18: Shift+Up 114 | 19: Shift+Left 115 | 20 = Shift+Down 116 | 21 = Shift+Right 117 | 22 = Paste 118 | 23 = Cut 119 | 24 = crtl+alt+del / alt-tab 120 | 25 = Copy 121 | 26 = Shift+Crtl+Home 122 | 27 = Escape key 123 | 28 = Shift+Crtl+End 124 | 29 = Del 125 | 30 = Off button (software) 126 | 31 = Everything to taskbar 127 | 191 = Find 128 | 192 = Printscreen 129 | The OS deletes the memory address, after it copyed out the character value. No dedicated keyboard controller chip is required, typematic and release functions handled by the OS. 130 | 131 | Mouse: 132 | ------ 133 | Mouse data starts from memory location 335542176, where first is the left click (long long, 2^32 means one kilograms), right click (long long, 2^32 means one kilograms), 134 | middle click (long long, 2^32 means one kilograms), relative movement x (long long, 2^32 means one pixel) relative movement y (long long, 2^32 means one pixel), 135 | touchscreen or absolute mouse movement x and y (two long long data, 0,0 means left upper corner, 2^32,2^32 means right lower corner), power of the touch (long long, 136 | 2^32 means one kilogram, left click still should be signaled separately on regular mouse data location), and finally a long long variable for the up/down wheel (-1: up, 1: down). 137 | All value is erased by the kernel once it reads them. Multitouch is supported, but the softwares must also support it by being able to rely on pressure packets. 138 | No dedicated touch hardware or DSP is needed, touched locations can loaded randomly or in order each after each after the previous has been readed out. 139 | 140 | 141 | Joystick: 142 | --------- 143 | Joyistkc memory address is at 335538080, where it having 5 xy direction (5*2*64 bit signed number each, where 2^32 means ONE), and 20 buttons (64-bit numbers, where 2^32 144 | means ONE). After this, the next joystick memory location begins, the data order is the same. Maximum 4 joystick is supported. 145 | Joystick force feedback memory location begins from 335539040, where it can have the same 5 xy direction (5*2*64 bit signed number each, where 2^32 means ONE), and 20 146 | buttons. This first 960 byte specifies the locations, the next 960 byte specifies the force, 2^32 means one kilogram. 147 | 148 | 149 | 150 | 151 | Display: 152 | ------- 153 | Video memory starts from the memory location 256 mbyte. It can have up maximum 33554448 byte, and can be RGB or RGBA (transparent displays are supported). 154 | Memory address 335540096 specify the resolution (8 byte for width, 8 byte for height, 8 byte for color depth (24 or 32)). 155 | Then 8 byte that indicates if the frame buffer not need to be refreshed in every cycle (1). If this indicator is 2, and the 156 | depth was 32 bit, it will signal the OS that it can write directly to frame buffer without flickering or access issues. 157 | Then, a 8 byte frame number counter, which is incrased by the operating system 158 | after a frame is rendered for proper sync. Then the display refresh hz is coming (8 byte). Resolution x and y, and display hz can set by the hardware any time. 159 | It can be set by the operating system too, but this is not manditory. If all of these parameters are 0, kernel will assume 1024x512 display with 24 bit. 160 | Last 8 byte indicates the screen off state. If value is 1, the screen is turned off, if its 0, the screen is on. 161 | If the fix 32 mbyte of RAM is too few, the video memory can be paged at a 8 byte long long memory address: 335413272. The operating system will write the number of 162 | the VGA bank here to access the next 33554448 byte of video memory in the next bank, the hardware should write the same value to 335413280when its succesfully mapped 163 | the new video memory bank sized 32 mbyte again. 164 | 165 | Network send: 166 | ------------- 167 | Antenna sending address is 335413336, begining with an one-byte indicator that specifies if something is one the buffer to be sent (1), or not (0). 168 | After the hardware sends the data, must clear this location with 0. After this, the data package is folowing: 169 | A 8 bit integer as sum of the whole package bytes prepared to send: data, sender, receiver coordinates (every byte). 170 | Then 24 bit data for sending location X, 24 bit for sending location Y, 24 bit for target location X, 24 bit for target location Y, and finally the actual data (64 bit). 171 | 172 | The same order applies for receiving data packets, those begin from the address 335413400, and being cleared by the OS after the packet is processed. 173 | On memory addres 335413592 (long long) there is the signal distance of the antenna in meters. This should be contain the real maximum, and not the theocretical. 174 | 175 | Location system: 176 | --------------- 177 | Compass is at memory address 335413664 (3 long long value) contains the x, y, and z angle of the device. 178 | Satelite receiver and barometer is at 335413632 (3 long long value) contains the x, y surface locations, the format is what the system is internally using for 179 | networking. The last long long value is the height in meters. 180 | Accelerometer is at 335413600, (3 long long value) 181 | 182 | 183 | 184 | Webcamera: 185 | ---------- 186 | Webcamera datas begin from the memory address 334313440. 16 separate webcameras can exist in the system, the data is the folowing for each one (one after one). 187 | Data format is the folowing: 64 bit width, 64 bit height, 64 bit is for the selected memory bank of the webcam, which must be copyed to the next 64 bit location if the bank 188 | switch is being complete. After this, there is a 2 kbyte of data bank, which is the actual pixel data (rgb). 189 | 190 | 191 | Free ports: 192 | ----------- 193 | From memory address 334309344 there is a 4 kbyte data range for your own hardware devices. This is the area where you can connect your own hardware and hardwares. 194 | This area will never be touched by the operating system. 195 | 196 | 197 | Hardware boot sequences and BIOS: 198 | ---------------------------------- 199 | A 256 kbyte memory area begining from the address 334047200 is reserved for the hardware manufacturer. This can contain the boot sequence of the motherboard if needed, 200 | or any other things the hardware developer wants here. Please beware that in the case of a malfunctioning software overwrites this area, it should not cause the 201 | damage of the hardware itself. 202 | 203 | 204 | Battery: 205 | -------- 206 | A 64 bit number at 334047192 memory address indicates the battery charge level. Only the last 8 byte is used, however: 0 means no charge, 255 means full charge. 207 | The charge level will not affect the operating system behaviour, it only displays it on the screen. Do not update this more than once per minute. 208 | 209 | 210 | 211 | Disks: 212 | --------------------- 213 | At the memory location 334361440 the disk devices are located. The system supports up to 100 disk drives. 214 | Each disk drive has 3 x 8 byte control location: the first 8 byte indicates the readed data (generally, disks returns 215 | only one byte, and the first 7 byte is zero, but high performance disks can return up to 7 bytes in reverse order), 216 | the second 8 byte indicates the location. The last 8 byte indicates the disk command:(0=no disk, 1=initial value, 2=read disk, 4=write to disk, 3= finished reading, 5=finished writing). 217 | On error, the readed data should be -1. 218 | "; 219 | 220 | --------------------------------------------------------------------------------