diff --git a/Makefile b/Makefile index c6d91ed..b2499c8 100644 --- a/Makefile +++ b/Makefile @@ -12,13 +12,13 @@ CC_PROBLEMATIC_FLAGS=-Wno-unused-parameter -Wno-unused-variable LD := x86_64-elf-ld $(ELFFILE): $(BUILDDIR) $(OBJFILES) - nasm -f elf64 src/idt/idt.S -o $(BUILDDIR)/idt_stub.o + nasm -f elf64 src/arch/x86/idt.S -o $(BUILDDIR)/idt_stub.o $(LD) -o $(ELFFILE) -T linker.ld $(OBJFILES) $(BUILDDIR)/idt_stub.o # Get the symbols for debugging nm -n $(ELFFILE) | awk '$$2 ~ /[TtDdBbRr]/ {print $$1, $$3}' > symbols.map python3 symbols.py nasm -f elf64 symbols.S -o $(BUILDDIR)/symbols.o - $(LD) -o $(ELFFILE) -T linker.ld $(OBJFILES) $(BUILDDIR)/idt_stub.o + $(LD) -o $(ELFFILE) -T linker.ld $(OBJFILES) $(BUILDDIR)/idt_stub.o $(BUILDDIR)/symbols.o $(BUILDDIR): @mkdir -p $(BUILDDIR) diff --git a/docs/MANUAL.md b/docs/MANUAL.md index 34195e4..35ac2c5 100644 --- a/docs/MANUAL.md +++ b/docs/MANUAL.md @@ -2,9 +2,30 @@ # Table of Contents -- nothing (yet). +- [Overview](#i-overview) + - [Supported Hardware](#a-supported-hardware) + - [Features](#b-features) +- [Kernel architecture](#ii-kernel-architecture) + - [Boot process](#a-boot-process) + - [Memory management](#b-memory-management) + - [Scheduling](#c-scheduling) + - [Input/output](#d-inputoutput) +- [Syscall table](#iii-syscall-table) -## I. Kernel architecture +## I. Overview + +## a. Supported Hardware + +The recommended hardware to run PepperOS is the following: + +- UEFI/BIOS +- Any x86 processor, 64-bits only +- PS/2 Keyboard +- Minimum 128MB of memory + +## b. Features + +## II. Kernel architecture ### a. Boot process @@ -14,6 +35,6 @@ ### d. Input/Output -## II. Syscall table +## III. Syscall table Not yet implemented. \ No newline at end of file diff --git a/include/idt/idt.h b/include/arch/x86.h similarity index 78% rename from include/idt/idt.h rename to include/arch/x86.h index b74fb56..1c677d8 100644 --- a/include/idt/idt.h +++ b/include/arch/x86.h @@ -1,14 +1,17 @@ -/* - * @author xamidev - * @brief Interrupt Descriptor Table setup and dispatching - * @license GPL-3.0-only - */ - -#ifndef IDT_H -#define IDT_H +#ifndef X86_H +#define X86_H +#include #include +uint64_t rdmsr(uint32_t msr); +void cpuid(uint32_t leaf, uint32_t* eax, uint32_t* ebx, uint32_t* ecx, uint32_t* edx); +void wrmsr(uint32_t msr, uint64_t value); +bool x86_has_msr(); +void x86_arch_init(); + +/* Interrupt Descriptor Table */ + void idt_init(void); struct interrupt_descriptor { diff --git a/include/config.h b/include/config.h index 8cab072..3a1e9e3 100644 --- a/include/config.h +++ b/include/config.h @@ -11,7 +11,14 @@ #define PEPPEROS_VERSION_MAJOR "0" #define PEPPEROS_VERSION_MINOR "0" #define PEPPEROS_VERSION_PATCH "58" -#define PEPPEROS_SPLASH "\x1b[38;5;196mPepperOS\x1b[0m version \x1b[38;5;220m"PEPPEROS_VERSION_MAJOR"."PEPPEROS_VERSION_MINOR"."PEPPEROS_VERSION_PATCH"\x1b[0m built on \x1b[38;5;40m"__DATE__" "__TIME__"\x1b[0m\n" +#define PEPPEROS_SPLASH \ +"\x1b[38;5;196m \x1b[38;5;231m____ _____\r\n\x1b[0m"\ +"\x1b[38;5;196m ____ ___ ____ ____ ___ _____\x1b[38;5;231m/ __ \\/ ___/\r\n\x1b[0m"\ +"\x1b[38;5;196m / __ \\/ _ \\/ __ \\/ __ \\/ _ \\/ ___\x1b[38;5;231m/ / / /\\__ \\ \r\n\x1b[0m"\ +"\x1b[38;5;196m / /_/ / __/ /_/ / /_/ / __/ / \x1b[38;5;231m/ /_/ /___/ / \r\n\x1b[0m"\ +"\x1b[38;5;196m / .___/\\___/ .___/ .___/\\___/_/ \x1b[38;5;231m\\____//____/ \r\n\x1b[0m"\ +"\x1b[38;5;196m/_/ /_/ /_/ \r\n\x1b[0m"\ +" --- version \x1b[38;5;220m"PEPPEROS_VERSION_MAJOR"."PEPPEROS_VERSION_MINOR"."PEPPEROS_VERSION_PATCH"\x1b[0m built on \x1b[38;5;40m"__DATE__" "__TIME__"\x1b[0m\r\n" /* process */ #define PROCESS_NAME_MAX 64 @@ -31,7 +38,7 @@ #define KERNEL_IDT_ENTRIES 33 /* paging */ -#define PAGING_MAX_PHYS 0x100000000 +#define PAGING_MAX_PHYS 0x200000000 /* heap */ #define KHEAP_SIZE (32*1024*1024) @@ -39,6 +46,9 @@ /* term */ #define TERM_HISTORY_MAX_LINES 256 +/* kbd */ +#define KBD_BUFFER_MAX 256 + /* time */ #define TIMER_FREQUENCY 1000 diff --git a/include/io/kbd/ps2.h b/include/io/kbd/ps2.h index c9aed30..55c12b5 100644 --- a/include/io/kbd/ps2.h +++ b/include/io/kbd/ps2.h @@ -7,7 +7,12 @@ #ifndef PS2_H #define PS2_H +#include + void keyboard_handler(void); +char keyboard_getchar(); +int keyboard_putchar(char c); +int keyboard_getline(char* output, size_t size); #define SHIFT_PRESSED_BIT 0b00000001 #define ALT_PRESSED_BIT 0b00000010 diff --git a/include/io/term/term.h b/include/io/term/term.h index 3ce0722..4ce1a32 100644 --- a/include/io/term/term.h +++ b/include/io/term/term.h @@ -8,8 +8,8 @@ #define TERM_H void kputs(const char* str); -void _putchar(char character); void term_init(void); int printf(const char* fmt, ...); +void internal_putc(int c, void *_); #endif diff --git a/include/kernel.h b/include/kernel.h index 58784aa..98b43ac 100644 --- a/include/kernel.h +++ b/include/kernel.h @@ -17,7 +17,7 @@ enum ErrorCodes { #include #include -#include +#include #include extern volatile uint64_t ticks; diff --git a/src/arch/x86/cpuid.c b/src/arch/x86/cpuid.c new file mode 100644 index 0000000..b4a9a55 --- /dev/null +++ b/src/arch/x86/cpuid.c @@ -0,0 +1,21 @@ +/* + * @author xamidev + * @brief x86 CPU identification + * @license GPL-3.0-only + */ + +#include +#include + +/* + * cpuid - Wrapper for CPUID instruction + * @leaf: Requested leaf (input EAX) + * @eax: EAX register value (output) + * @ebx: EBX register value (output) + * @ecx: ECX register value (output) + * @edx: EDX register value (output) +*/ +void cpuid(uint32_t leaf, uint32_t* eax, uint32_t* ebx, uint32_t* ecx, uint32_t* edx) +{ + __asm__ volatile("cpuid" : "=a"(*eax), "=b"(*ebx), "=c"(*ecx), "=d"(*edx) : "a"(leaf)); +} \ No newline at end of file diff --git a/src/idt/idt.S b/src/arch/x86/idt.S similarity index 100% rename from src/idt/idt.S rename to src/arch/x86/idt.S diff --git a/src/idt/idt.c b/src/arch/x86/idt.c similarity index 99% rename from src/idt/idt.c rename to src/arch/x86/idt.c index 51b0eca..822033c 100644 --- a/src/idt/idt.c +++ b/src/arch/x86/idt.c @@ -4,7 +4,7 @@ * @license GPL-3.0-only */ -#include +#include #include #include #include diff --git a/src/arch/x86/init.c b/src/arch/x86/init.c new file mode 100644 index 0000000..9d74333 --- /dev/null +++ b/src/arch/x86/init.c @@ -0,0 +1,46 @@ +/* + * @author xamidev + * @brief x86 architecture-dependant initialization + * @license GPL-3.0-only + */ + +#include +#include +#include +#include + +/* + * x86_overwrite_pat - Set PAT to WC + * + * This function overwrites the 1st Page Attribute + * Table entry, to enable the Write-Combining property + * when we map memory regions later on. + * The framebuffer will be mapped with WC, which makes + * memory access significantly faster by using burst + * operations. +*/ + +static void x86_overwrite_pat() +{ + uint64_t pat = rdmsr(0x277); + pat &= ~(0xFFULL << 8); // Clear PAT1 + pat |= (0x01ULL << 8); // PAT1 = 0x01 (WC) + wrmsr(0x277, pat); +} + +/* + * x86_arch_init - Initialize x86 CPU structures + * + * This function is responsible for overriding a PAT entry + * (to put the framebuffer area in WC mode) only. + * + * Later, all architecture-dependant init (GDT, IDT, TSS, ...) + * should be initialized here, and separate function pointers + * should be set up for each arch. + */ +void x86_arch_init() +{ + x86_overwrite_pat(); + idt_init(); + gdt_init(); +} \ No newline at end of file diff --git a/src/arch/x86/msr.c b/src/arch/x86/msr.c new file mode 100644 index 0000000..276239c --- /dev/null +++ b/src/arch/x86/msr.c @@ -0,0 +1,66 @@ +/* + * @author xamidev + * @brief x86 MSR C wrappers + * @description + * Wrapper functions to access Model Specific Registers + * + * @license GPL-3.0-only + */ + +#include +#include +#include + +/* + * rdmsr - Read from MSR + * @msr: model specific register number + * + * Read a 64-bit word from a Model Specific Register. + * Wrapper for the "rdmsr" instruction. It originally + * outputs to two 32-bit registers (EDX:EAX), so the + * function does the job of uniting them as a 64-bit + * value for us. + * + * Return: + * - value read from MSR + */ +uint64_t rdmsr(uint32_t msr) +{ + uint32_t low; + uint32_t high; + + __asm__ volatile("rdmsr" : "=a"(low), "=d"(high) : "c"(msr)); + + return ((uint64_t)high << 32) | low; +} + +/* + * wrmsr - Write to MSR + * @msr: model specific register number + * + * Write a 64-bit value to a Model Specific Register. + */ +void wrmsr(uint32_t msr, uint64_t value) +{ + uint32_t low = (uint32_t)(value & 0xFFFFFFFF); + uint32_t high = (uint32_t)(value >> 32); + + __asm__ volatile("wrmsr" : : "c"(msr), "a"(low), "d"(high) : "memory"); +} + +/* + * x86_has_msr - Test for MSR support + * + * Checks if CPU supports Model Specific Registers + * using CPUID.01h:EDX[bit 5]. + * + * Return: + * true - MSR are supported + * false - MSR are not supported + */ +bool x86_has_msr() +{ + uint32_t eax, ebx, ecx, edx; + cpuid(1, &eax, &ebx, &ecx, &edx); + return (edx & (1 << 5)) != 0; +} \ No newline at end of file diff --git a/src/debug/panic.c b/src/debug/panic.c index 5fc2069..22ff590 100644 --- a/src/debug/panic.c +++ b/src/debug/panic.c @@ -5,7 +5,7 @@ */ #include -#include +#include #include #include @@ -36,27 +36,6 @@ void read_rflags(uint64_t rflags) CHECK_BIT(rflags, 19) ? "VIF " : "", /*virtual interrupt flag*/ CHECK_BIT(rflags, 20) ? "VIP " : "", /*virtual interrupt pending*/ CHECK_BIT(rflags, 21) ? "ID " : ""); /*id flag*/ - - if (init.terminal) { - printf("\x1b[38;5;226m%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\x1b[38;5;231m\r\n", - CHECK_BIT(rflags, 0) ? "CF " : "", - CHECK_BIT(rflags, 2) ? "PF " : "", - CHECK_BIT(rflags, 4) ? "AF " : "", - CHECK_BIT(rflags, 6) ? "ZF " : "", - CHECK_BIT(rflags, 7) ? "SF " : "", - CHECK_BIT(rflags, 8) ? "TF " : "", - CHECK_BIT(rflags, 9) ? "IF " : "", - CHECK_BIT(rflags, 10) ? "DF " : "", - CHECK_BIT(rflags, 11) ? "OF " : "", - (CHECK_BIT(rflags, 12) && CHECK_BIT(rflags, 13)) ? "IOPL3 " : "IOPL0 ", - CHECK_BIT(rflags, 14) ? "NT " : "", - CHECK_BIT(rflags, 16) ? "RF " : "", - CHECK_BIT(rflags, 17) ? "VM " : "", - CHECK_BIT(rflags, 18) ? "AC " : "", - CHECK_BIT(rflags, 19) ? "VIF " : "", - CHECK_BIT(rflags, 20) ? "VIP " : "", - CHECK_BIT(rflags, 21) ? "ID " : ""); - } } /* diff --git a/src/io/kbd/ps2.c b/src/io/kbd/ps2.c index e47d8a8..aea8c13 100644 --- a/src/io/kbd/ps2.c +++ b/src/io/kbd/ps2.c @@ -4,6 +4,7 @@ * @license GPL-3.0-only */ +#include "config.h" #include #include #include @@ -18,6 +19,11 @@ uint8_t key_status = 0b00000000; unsigned char* keymap; unsigned char* keymap_shifted; +// Keyboard buffer +char keyboard_buffer[KBD_BUFFER_MAX] = {0}; +int write_index = 0; +int read_index = 0; + extern struct init_status init; unsigned char kbdus[128] = @@ -210,10 +216,11 @@ void keyboard_handler() if (c) { if (c == '\n') { - _putchar('\r'); + internal_putc('\r', NULL); } - // Should probably have a keyboard buffer here... instead of this - _putchar(c); + + internal_putc(c, NULL); + keyboard_putchar(c); } } } @@ -221,6 +228,79 @@ void keyboard_handler() } } +/* + * keyboard_getchar - Get a character from keyboard + * + * This function reads one character from the keyboard buffer. + * If the keyboard buffer is empty, it will block until a key + * is pressed. + * + * Return: + * - character from keyboard buffer + */ +char keyboard_getchar() +{ + while (read_index == write_index); // Empty buffer + + char c = keyboard_buffer[read_index]; + read_index = (read_index+1) % KBD_BUFFER_MAX; + return c; +} + +/* + * keyboard_putchar - Puts a character in the keyboard buffer + * @c: character to add + * + * This function is used in the keyboard handler to add new + * characters to the keyboard buffer. + * + * Return: + * %-1 - keyboard buffer is full + * %0 - operation completed successfully + */ +int keyboard_putchar(char c) +{ + if ((write_index+1) % KBD_BUFFER_MAX == read_index) { + // Full buffer + return -1; + } + + keyboard_buffer[write_index] = c; + write_index = (write_index+1) % KBD_BUFFER_MAX; + return 0; +} + +/* + * keyboard_getline - Gets a line of input from keyboard + * @output: Output string + * @size: Size of output string + * + * Read a line of characters from the keyboard, until the + * buffer fills or a newline character is read. + * The output string is NULL-terminated. + * + * Return: + * - the number of characters read + */ +int keyboard_getline(char* output, size_t size) +{ + char c; + size_t index = 0; + + // Read until Enter is pressed + while ((c = keyboard_getchar()) != 0x0A) { + if (index == size-1) { + output[index] = c; + output[index+1] = '\0'; + return index; + } + output[index] = c; + index++; + } + output[index+1] = '\0'; + return index; +} + /* * keyboard_init - Keyboard initialization * @layout: Desired layout diff --git a/src/io/serial/serial.c b/src/io/serial/serial.c index 95ea78f..f36a450 100644 --- a/src/io/serial/serial.c +++ b/src/io/serial/serial.c @@ -6,9 +6,13 @@ #include #include +#include extern struct init_status init; +extern int panic_count; +struct spinlock_t serial_lock = {0}; + /* * outb - Writes a byte to a CPU port * @port: CPU port to write to @@ -85,9 +89,15 @@ static int is_transmit_empty() */ void skputc(char c) { - // TODO: Spinlock here (serial access) - while (!is_transmit_empty()); // wait for free spot - outb(PORT, c); + if (panic_count == 0) { + spinlock_acquire(&serial_lock); + while (!is_transmit_empty()); // wait for free spot + outb(PORT, c); + spinlock_release(&serial_lock); + } else { + while (!is_transmit_empty()); + outb(PORT, c); + } } /* diff --git a/src/io/term/term.c b/src/io/term/term.c index 785151d..65b11a1 100644 --- a/src/io/term/term.c +++ b/src/io/term/term.c @@ -30,19 +30,10 @@ extern struct flanterm_context* ft_ctx; extern struct init_status init; struct spinlock_t term_lock = {0}; +struct spinlock_t printf_lock = {0}; extern int panic_count; -/* - * _putchar - Writes a character to terminal (DEPRECATED) - * @character: character to write - */ -void _putchar(char character) -{ - // TODO: Spinlock here (terminal access) - flanterm_write(ft_ctx, &character, 1); -} - /* * internal_putc - Internal putchar function * @c: char to print @@ -83,14 +74,26 @@ void internal_putc(int c, void *_) * * Return: * - number of characters sent to the callback + * %-1 - error */ int printf(const char* fmt, ...) { - va_list args; - va_start(args, fmt); - int ret = npf_vpprintf(internal_putc, NULL, fmt, args); - va_end(args); - return ret; + if (panic_count == 0) { + spinlock_acquire(&printf_lock); + va_list args; + va_start(args, fmt); + int ret = npf_vpprintf(internal_putc, NULL, fmt, args); + va_end(args); + spinlock_release(&printf_lock); + return ret; + } else { + va_list args; + va_start(args, fmt); + int ret = npf_vpprintf(internal_putc, NULL, fmt, args); + va_end(args); + return ret; + } + return -1; } /* @@ -103,30 +106,14 @@ void kputs(const char* str) { size_t i=0; while (str[i] != 0) { - _putchar(str[i]); + internal_putc(str[i], NULL); i++; } - _putchar('\r'); } extern struct flanterm_context* ft_ctx; extern struct boot_context boot_ctx; -/* - * flanterm_free_wrapper - free() wrapper for Flanterm - * @ptr: pointer to free - * @size: amount of bytes to free - * - * This function exists solely because the Flanterm initialization - * function only accepts a free() function with a size parameter, - * and the default one doesn't have it. - */ -void flanterm_free_wrapper(void* ptr, size_t size) -{ - (void)size; - kfree(ptr); -} - /* * term_init - Video output/terminal initialization * diff --git a/src/kmain.c b/src/kmain.c index 37daa7f..1a83b8f 100644 --- a/src/kmain.c +++ b/src/kmain.c @@ -4,6 +4,7 @@ * @license GPL-3.0-only */ +#include "arch/x86.h" #include #include #include @@ -11,7 +12,6 @@ #include #include #include -#include #include #include