26 Commits

Author SHA1 Message Date
xamidev e8a0a36889 Enable FPU 2026-03-31 21:04:44 +02:00
xamidev 1fc5225fd2 kheap info 2026-03-31 17:48:11 +02:00
xamidev 2f1eef9e15 UBSan conditional compilation 2026-03-29 09:38:24 +02:00
xamidev 65371077d9 more UBsan 2026-03-28 21:50:19 +01:00
xamidev 3cd38f654c Undefined Behavior Sanitization 2026-03-28 21:09:08 +01:00
xamidev 89259ec9b2 Stack Smashing Protection 2026-03-26 20:14:56 +01:00
xamidev 0fbaf6d26e Date functions (get current time) 2026-03-26 17:59:02 +01:00
xamidev 532953da4d CPU Name identification 2026-03-26 16:53:39 +01:00
xamidev ac788c55d3 Upgrade VMM for processes 2026-03-22 09:03:43 +01:00
xamidev 3ae56bbad5 Kernel debug shell 2026-03-21 11:34:46 +01:00
xamidev db36899152 Add kprintf for DEBUG(); differentiated from printf() 2026-03-21 10:36:54 +01:00
xamidev 03f87723d1 Splash 2026-03-20 10:04:16 +01:00
xamidev 3607a7179c printf spinlock + remove DEPRECATED stuff + begin separating x86 stuff 2026-03-20 09:01:57 +01:00
xamidev 424b4c4632 Use MSR to map framebuffer as WC (write-combining) = huge speed diff on real HW 2026-03-19 19:34:31 +01:00
xamidev 6a82d581fb Fix PMM for real HW + serial lock 2026-03-19 16:54:23 +01:00
xamidev b77c53ae99 Keyboard buffer + getline 2026-03-18 13:07:26 +01:00
xamidev f7735eb3a4 Move headers to include/ 2026-03-18 11:48:33 +01:00
xamidev a1e8aacd01 improve README.md 2026-03-17 10:33:10 +01:00
xamidev ccc8985d4c Merge pull request 'Improve Makefile' (#15) from furtest/pepperOS:makefile into main
Reviewed-on: xamidev/pepperOS#15
2026-03-15 21:17:44 +01:00
xamidev 0482f594ef Flanterm back to bump alloc (allows earlier use for real hw debugging) 2026-03-15 21:11:47 +01:00
furtest b02a4b5284 Fix build-iso prerequisites 2026-03-15 18:05:24 +01:00
furtest 32f3889565 Move PHONY tags and fix clean
Move the PHONY tags to make them clearer to read.
Fix the clean rule so it deletes the build directory.
2026-03-15 18:01:35 +01:00
furtest 803ac0879b Auto find source files check for changes
Previously the build process removed everything and did all the build
again on each make invocation.
This fixes this behaviour with two changes.
First dynamically find the list of files to build using find instead of
a manually written list.
Then use implicit rules to only build files that need to be built again
instead of recompiling everything.
2026-03-15 17:56:26 +01:00
furtest 9fc55f98d8 Use variables for build and pepperk and rename build target.
Instead of hardcoding the names set them using a variable.
Also rename the target build to the name of the file it builds which is
in the ELFFILE variable.
2026-03-15 16:58:04 +01:00
furtest 11bd628821 Extract CC and LD to variables.
This allows to change the name of the compiler or linker when calling
make.
2026-03-15 16:57:29 +01:00
xamidev 80d8b49560 Merge pull request 'spinlock' (#14) from spinlock into main
Reviewed-on: xamidev/pepperOS#14
2026-03-15 09:55:45 +01:00
64 changed files with 1784 additions and 430 deletions
+42 -19
View File
@@ -1,31 +1,50 @@
SOURCES = src/sched/spinlock.c src/debug/misc.c src/io/term/flanterm_backends/fb.c src/io/term/flanterm.c src/debug/panic.c src/debug/stacktrace.c src/boot/boot.c src/sched/scheduler.c src/sched/process.c src/mem/heap/kheap.c src/mem/paging/vmm.c src/mem/paging/paging.c src/mem/paging/pmm.c src/string/string.c src/io/kbd/ps2.c src/io/serial/serial.c src/io/term/term.c src/idt/idt.c src/mem/gdt/gdt.c src/mem/misc/utils.c src/time/timer.c src/kmain.c
CC_FLAGS=-Wall -Wextra -std=gnu99 -nostdlib -ffreestanding -fno-stack-protector -fno-omit-frame-pointer -fno-stack-check -fno-PIC -ffunction-sections -fdata-sections -mcmodel=kernel BUILDDIR := build
CC_PROBLEMATIC_FLAGS=-Wno-unused-parameter -Wno-unused-variable ELFFILE := pepperk
SRC := src
.PHONY: build build-iso debug debug2 run clean CC_PROBLEMATIC_FLAGS:=-Wno-unused-parameter -Wno-unused-variable
build: ifeq ($(UBSAN),true)
mkdir -p build SOURCES := $(shell find src -name '*.c')
rm -f *.o build/*.o CC_PROBLEMATIC_FLAGS:= -fsanitize=undefined
x86_64-elf-gcc -g -c -Isrc $(SOURCES) $(CC_PROBLEMATIC_FLAGS) $(CC_FLAGS) else
mv *.o build/ SOURCES := $(shell find src -name '*.c')
nasm -f elf64 src/idt/idt.S -o build/idt_stub.o SOURCES := $(filter-out src/security/ubsan.c, $(SOURCES))
x86_64-elf-ld -o pepperk -T linker.ld build/*.o endif
nm -n pepperk | awk '$$2 ~ /[TtDdBbRr]/ {print $$1, $$3}' > symbols.map
OBJFILES := $(patsubst $(SRC)/%.c, $(BUILDDIR)/%.o, $(SOURCES))
CC := x86_64-elf-gcc
CC_FLAGS=-Wall -Wextra -std=gnu99 -nostdlib -ffreestanding -fstack-protector -fno-omit-frame-pointer -fno-stack-check -fno-PIC -ffunction-sections -fdata-sections -mcmodel=kernel
LD := x86_64-elf-ld
$(ELFFILE): $(BUILDDIR) $(OBJFILES)
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 python3 symbols.py
nasm -f elf64 symbols.S -o build/symbols.o nasm -f elf64 symbols.S -o $(BUILDDIR)/symbols.o
x86_64-elf-ld -o pepperk -T linker.ld build/*.o $(LD) -o $(ELFFILE) -T linker.ld $(OBJFILES) $(BUILDDIR)/idt_stub.o $(BUILDDIR)/symbols.o
$(BUILDDIR):
@mkdir -p $(BUILDDIR)
$(BUILDDIR)/%.o: $(SRC)/%.c
mkdir -p $(dir $@)
$(CC) -g -c -Iinclude $< $(CC_PROBLEMATIC_FLAGS) $(CC_FLAGS) -o $@
limine/limine: limine/limine:
rm -rf limine rm -rf limine
git clone https://github.com/limine-bootloader/limine.git --branch=v9.x-binary --depth=1 git clone https://github.com/limine-bootloader/limine.git --branch=v9.x-binary --depth=1
$(MAKE) -C limine $(MAKE) -C limine
build-iso: limine/limine build build-iso: limine/limine $(ELFFILE)
rm -rf iso_root rm -rf iso_root
mkdir -p iso_root/boot mkdir -p iso_root/boot
cp -v pepperk iso_root/boot cp -v $(ELFFILE) iso_root/boot
mkdir -p iso_root/boot/limine mkdir -p iso_root/boot/limine
cp -v limine.conf iso_root/boot/limine cp -v limine.conf iso_root/boot/limine
mkdir -p iso_root/EFI/BOOT mkdir -p iso_root/EFI/BOOT
@@ -39,16 +58,20 @@ build-iso: limine/limine build
iso_root -o pepper.iso iso_root -o pepper.iso
./limine/limine bios-install pepper.iso ./limine/limine bios-install pepper.iso
.PHONY: debug
debug: debug:
/usr/bin/qemu-system-x86_64 -drive file=pepper.iso -s -S -d int -D qemu.log -no-reboot -no-shutdown & /usr/bin/qemu-system-x86_64 -drive file=pepper.iso -s -S -d int -D qemu.log -no-reboot -no-shutdown &
gdb pepperk --command=debug.gdb gdb $(ELFFILE) --command=debug.gdb
.PHONY: debug2
debug2: debug2:
/usr/bin/qemu-system-x86_64 -drive file=pepper.iso -s -S -d int -no-reboot -no-shutdown & /usr/bin/qemu-system-x86_64 -drive file=pepper.iso -s -S -d int -no-reboot -no-shutdown &
pwndbg pepperk --command=debug.gdb pwndbg $(ELFFILE) --command=debug.gdb
.PHONY: run
run: build-iso run: build-iso
/usr/bin/qemu-system-x86_64 -cdrom pepper.iso -serial stdio /usr/bin/qemu-system-x86_64 -cdrom pepper.iso -serial stdio
.PHONY: clean
clean: clean:
rm -rf *.o symbols.map symbols.S pepperk iso_root pepper.iso limine build/*.o rm -rf $(BUILDDIR) symbols.map symbols.S $(ELFFILE) iso_root pepper.iso limine
+44 -6
View File
@@ -1,17 +1,52 @@
# <img width="40" height="40" alt="red-pepper" src="https://i.ibb.co/mrHH6d1m/pixil-frame-0-4.png" /> pepperOS: "will never be done" # <img width="40" height="40" alt="red-pepper" src="https://i.ibb.co/mrHH6d1m/pixil-frame-0-4.png" /> pepperOS: "will never be done"
## Trying the kernel ## Description
First install the dependencies: `sudo apt install python3 xorriso make qemu-system` PepperOS is a 64-bit freely-licensed monolithic kernel for x86 processors, with round-robin preemptive scheduling and 4-level paging. See the [manual](docs/MANUAL.md) for more.
Also, you have to get an x86_64 toolchain for compilation. The easiest way to do that on most systems is to install it from Homebrew: ## Trying the kernel in QEMU
### Debian-based distributions
First, install the dependencies: `sudo apt install nasm python3 xorriso make qemu-system`
Then, you can get an x86_64 toolchain for compilation. The easiest way to do that on most systems is to install it from Homebrew:
``` ```
brew install x86_64-elf-gcc brew install x86_64-elf-gcc
``` ```
Then, to compile the kernel and make an ISO image file: `make build-iso` If you're already on a 64-bit machine (which you probably are), and don't want to install a cross-compiler, you can just override `CC` and `LD` variables in the Makefile, like so:
To run it with QEMU, `make run`
```
CC := gcc
LD := ld
```
Then, to compile the kernel and make an ISO image file, run: `make build-iso`
To run it with QEMU, do: `make run`
## Trying the kernel on real hardware
Compile the kernel and generate an ISO image like described above, then burn the image to a USB stick, `/dev/sdX` being the device name (you can get it using `lsblk`):
```
sudo dd if=pepper.iso of=/dev/sdX
```
## Compilation options
By default, PepperOS is compiled without the following features:
```
UBSAN - undefined behavior sanitization
```
These features can be activated by setting them to "true" at the end of the make command, for example:
```
make UBSAN=true
```
## TODO ## TODO
@@ -44,7 +79,7 @@ In the future, maybe?
PepperOS wouldn't be possible without the following freely-licensed software: PepperOS wouldn't be possible without the following freely-licensed software:
- the [Limine](https://codeberg.org/Limine/Limine) portable bootloader - the [Limine](https://codeberg.org/Limine/Limine) portable bootloader
- Marco Paland's freestanding [printf implementation](https://github.com/mpaland) - Charles Nicholson's [nanoprintf](https://github.com/charlesnicholson/nanoprintf)
- Mintuski's [Flanterm](https://codeberg.org/Mintsuki/Flanterm) terminal emulator - Mintuski's [Flanterm](https://codeberg.org/Mintsuki/Flanterm) terminal emulator
...and without these amazing resources: ...and without these amazing resources:
@@ -52,3 +87,6 @@ PepperOS wouldn't be possible without the following freely-licensed software:
- the [OSDev](https://osdev.org) wiki & forums - the [OSDev](https://osdev.org) wiki & forums
- Intel 64 and IA-32 Architectures Software Developer's Manual - Intel 64 and IA-32 Architectures Software Developer's Manual
- Documentation for the [GNU Compiler Collection](https://gcc.gnu.org/onlinedocs/gcc/) - Documentation for the [GNU Compiler Collection](https://gcc.gnu.org/onlinedocs/gcc/)
- dreamos82's [OSDev Notes](https://github.com/dreamportdev/Osdev-Notes/tree/master)
- the [Sortix UBsan hook implementations](https://gitlab.com/sortix/sortix/-/blob/main/libc/ubsan/ubsan.c)
- the [CSC 395](https://curtsinger.cs.grinnell.edu/teaching/2022S/CSC395/kernel/) Kernel Development course from Grinnell College
+40
View File
@@ -0,0 +1,40 @@
# PepperOS Manual
# Table of Contents
- [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. 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
### b. Memory management
### c. Scheduling
### d. Input/Output
## III. Syscall table
Not yet implemented.
+1 -1
View File
@@ -1,6 +1,6 @@
/* /*
* @author xamidev <xamidev@riseup.net> * @author xamidev <xamidev@riseup.net>
* @brief Global Descriptor Table (for legacy reasons) * @brief Global Descriptor Table
* @license GPL-3.0-only * @license GPL-3.0-only
*/ */
+17 -8
View File
@@ -1,14 +1,21 @@
/* #ifndef X86_H
* @author xamidev <xamidev@riseup.net> #define X86_H
* @brief Interrupt Descriptor Table setup and dispatching
* @license GPL-3.0-only
*/
#ifndef IDT_H
#define IDT_H
#include <stdbool.h>
#include <stdint.h> #include <stdint.h>
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();
void x86_cpu_identification();
int cpuid_get_vendor_string(char* str);
/* Interrupt Descriptor Table */
void idt_init(void); void idt_init(void);
struct interrupt_descriptor { struct interrupt_descriptor {
@@ -56,4 +63,6 @@ struct cpu_status_t {
uint64_t iret_ss; uint64_t iret_ss;
}; };
struct cpu_status_t* syscall_handler(struct cpu_status_t* regs);
#endif #endif
+14
View File
@@ -0,0 +1,14 @@
/*
* @author xamidev <xamidev@riseup.net>
* @brief Boot routines
* @license GPL-3.0-only
*/
#ifndef BOOT_H
#define BOOT_H
#include <kernel.h>
void populate_boot_context(struct boot_context* boot_ctx);
#endif
+61
View File
@@ -0,0 +1,61 @@
/*
* @author xamidev <xamidev@riseup.net>
* @brief PepperOS configuration file
* @license GPL-3.0-only
*/
#ifndef CONFIG_H
#define CONFIG_H
/* version */
#define PEPPEROS_VERSION_MAJOR "0"
#define PEPPEROS_VERSION_MINOR "0"
#define PEPPEROS_VERSION_PATCH "109"
#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"
/* pedicel */
#define PEDICEL_PROMPT "pedicel$ "
#define PEDICEL_INPUT_SIZE 128
/* process */
#define PROCESS_NAME_MAX 64
#define PROCESS_STACK_SIZE 0x10000 // 64kb
#define PROCESS_STACK_TOP 0x80000000
/* sched */
// 1 tick = 1 ms => quantum = 10ms
#define SCHEDULER_QUANTUM 10
/* kernel */
#define KERNEL_BASE 0xFFFFFFFF80000000ULL
// 2 MB should be enough (as of now, the whole kernel ELF is around 75kb)
#define KERNEL_SIZE 0x200000
#define KERNEL_STACK_SIZE 65536
#define KERNEL_IDT_ENTRIES 33
/* paging */
#define PAGING_MAX_PHYS 0x200000000
/* heap */
#define KHEAP_SIZE (32*1024*1024)
/* term */
#define TERM_HISTORY_MAX_LINES 256
/* kbd */
#define KBD_BUFFER_MAX 256
/* time */
#define TIMER_FREQUENCY 1000
/* ssp */
#define STACK_CHK_GUARD 0x7ABA5C007ABA5C00
#endif
@@ -7,7 +7,12 @@
#ifndef PS2_H #ifndef PS2_H
#define PS2_H #define PS2_H
#include <stddef.h>
void keyboard_handler(void); 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 SHIFT_PRESSED_BIT 0b00000001
#define ALT_PRESSED_BIT 0b00000010 #define ALT_PRESSED_BIT 0b00000010
@@ -8,8 +8,9 @@
#define TERM_H #define TERM_H
void kputs(const char* str); void kputs(const char* str);
void _putchar(char character);
void term_init(void); void term_init(void);
int printf(const char* fmt, ...); int printf(const char* fmt, ...);
void internal_putc(int c, void *_);
int kprintf(const char* fmt, ...);
#endif #endif
+9 -4
View File
@@ -7,6 +7,7 @@
#ifndef KERNEL_H #ifndef KERNEL_H
#define KERNEL_H #define KERNEL_H
#include "limine.h"
enum ErrorCodes { enum ErrorCodes {
ENOMEM, ENOMEM,
EIO EIO
@@ -15,13 +16,13 @@ enum ErrorCodes {
#define CLEAR_INTERRUPTS __asm__ volatile("cli") #define CLEAR_INTERRUPTS __asm__ volatile("cli")
#define SET_INTERRUPTS __asm__ volatile("sti") #define SET_INTERRUPTS __asm__ volatile("sti")
#include "io/serial/serial.h" #include <io/serial/serial.h>
#include "io/term/term.h" #include <io/term/term.h>
#include "idt/idt.h" #include <arch/x86.h>
#include <stdbool.h> #include <stdbool.h>
extern volatile uint64_t ticks; extern volatile uint64_t ticks;
#define DEBUG(log, ...) printf("[%8u] debug: <%s>: " log "\r\n", ticks, __func__, ##__VA_ARGS__) #define DEBUG(log, ...) kprintf("[%8u] debug: <%s>: " log "\r\n", ticks, __func__, ##__VA_ARGS__)
/* #define DEBUG(log, ...) \ /* #define DEBUG(log, ...) \
printf("debug: [%s]: " log "\r\n", __FILE__, ##__VA_ARGS__); \ printf("debug: [%s]: " log "\r\n", __FILE__, ##__VA_ARGS__); \
@@ -38,6 +39,8 @@ void panic(struct cpu_status_t* ctx, const char* str);
void hcf(void); void hcf(void);
void idle(void); void idle(void);
void pedicel_main(void* arg);
/* debug */ /* debug */
void debug_stack_trace(unsigned int max_frames); void debug_stack_trace(unsigned int max_frames);
const char* debug_find_symbol(uintptr_t rip, uintptr_t* offset); const char* debug_find_symbol(uintptr_t rip, uintptr_t* offset);
@@ -50,6 +53,7 @@ struct boot_context {
struct limine_memmap_response* mmap; struct limine_memmap_response* mmap;
struct limine_hhdm_response* hhdm; struct limine_hhdm_response* hhdm;
struct limine_kernel_address_response* kaddr; struct limine_kernel_address_response* kaddr;
struct limine_boot_time_response* bootdate;
}; };
// Are these modules initialized yet? // Are these modules initialized yet?
@@ -58,6 +62,7 @@ struct init_status {
bool serial; bool serial;
bool keyboard; bool keyboard;
bool timer; bool timer;
bool all;
}; };
#endif #endif
View File
@@ -28,5 +28,6 @@ void* kmalloc(size_t size);
void kfree(void* ptr); void kfree(void* ptr);
void* kalloc_stack(void); void* kalloc_stack(void);
void kheap_map_page(void); void kheap_map_page(void);
void kheap_info();
#endif #endif
@@ -11,14 +11,16 @@
#include <stdint.h> #include <stdint.h>
#include <limine.h> #include <limine.h>
#include "mem/heap/kheap.h" #include <mem/kheap.h>
#include <kernel.h> #include <kernel.h>
void paging_init(struct boot_context boot_ctx); void paging_init(struct boot_context boot_ctx);
void paging_map_page(uint64_t* root_table, uint64_t virt, uint64_t phys, uint64_t flags); void paging_map_page(uint64_t* root_table, uint64_t virt, uint64_t phys, uint64_t flags);
uint64_t* alloc_page_table();
// To swap root page tables // To swap root page tables
void load_cr3(uint64_t value); void load_cr3(uint64_t value);
void invlpg(void *addr);
extern uint64_t hhdm_off; extern uint64_t hhdm_off;
@@ -8,6 +8,7 @@
#define MEM_UTILS_H #define MEM_UTILS_H
#include <stddef.h> #include <stddef.h>
#include <limine.h>
void* memcpy(void* restrict dest, const void* restrict src, size_t n); void* memcpy(void* restrict dest, const void* restrict src, size_t n);
void* memset(void* s, int c, size_t n); void* memset(void* s, int c, size_t n);
+29
View File
@@ -0,0 +1,29 @@
/*
* @author xamidev <xamidev@riseup.net>
* @brief Virtual memory manager
* @license GPL-3.0-only
*/
#ifndef VMM_H
#define VMM_H
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
struct vmm_context {
uint64_t* pml4;
};
void vmm_init(void);
void* vmm_alloc_region(uint64_t* pml4, size_t pages, uint64_t flags);
bool vmm_is_mapped(uint64_t* pml4, uint64_t virt);
void vmm_unmap(uint64_t* pml4, uint64_t virt);
void* vmm_map(uint64_t* pml4, uint64_t virt, uint64_t flags);
uint64_t* vmm_create_address_space();
uint64_t vmm_virt_to_phys(uint64_t* pml4, uint64_t virt);
#define VMM_USER_SPACE_START 0x0000000000001000
#define VMM_USER_SPACE_END 0x00007FFFFFFFF000
#endif
@@ -8,7 +8,7 @@
#define PROCESS_H #define PROCESS_H
#include <stddef.h> #include <stddef.h>
#include "config.h" #include <config.h>
#include <stdint.h> #include <stdint.h>
typedef enum { typedef enum {
+65
View File
@@ -0,0 +1,65 @@
/*
* @author xamidev <xamidev@riseup.net>
* @brief Undefined behavior sanitization hooks
* @license GPL-3.0-only
*/
#ifndef UBSAN_H
#define UBSAN_H
#include <stdint.h>
struct ubsan_source_location
{
const char* filename;
uint32_t line;
uint32_t column;
};
struct ubsan_type_descriptor
{
uint16_t type_kind;
uint16_t type_info;
char type_name[];
};
struct ubsan_type_mismatch_v1_data
{
struct ubsan_source_location location;
struct ubsan_type_descriptor* type;
unsigned char log_alignment;
unsigned char type_check_kind;
};
struct ubsan_pointer_overflow_data
{
struct ubsan_source_location location;
};
struct ubsan_shift_out_of_bounds_data
{
struct ubsan_source_location location;
struct ubsan_type_descriptor* lhs_type;
struct ubsan_type_descriptor* rhs_type;
};
struct ubsan_invalid_value_data
{
struct ubsan_source_location location;
struct ubsan_type_descriptor* type;
};
struct ubsan_out_of_bounds_data
{
struct ubsan_source_location location;
struct ubsan_type_descriptor* array_type;
struct ubsan_type_descriptor* index_type;
};
struct ubsan_overflow_data
{
struct ubsan_source_location location;
struct ubsan_type_descriptor* type;
};
#endif
@@ -12,5 +12,6 @@
char *strcpy(char *dest, const char *src); char *strcpy(char *dest, const char *src);
char *strcat(char *dest, const char *src); char *strcat(char *dest, const char *src);
void strncpy(char* dst, const char* src, size_t n); void strncpy(char* dst, const char* src, size_t n);
int strncmp(const char* s1, const char* s2, size_t n);
#endif #endif
+25
View File
@@ -0,0 +1,25 @@
/*
* @author xamidev <xamidev@riseup.net>
* @brief Date helper functions
* @license GPL-3.0-only
*/
#ifndef DATE_H
#define DATE_H
#include <stdint.h>
struct date {
uint64_t year;
uint8_t month;
uint8_t day;
uint8_t hour;
uint8_t minute;
uint8_t second;
};
struct date date_timestamp_to_date(uint64_t timestamp);
struct date date_now();
#endif
+2
View File
@@ -1,6 +1,8 @@
timeout: 3 timeout: 3
interface_branding: Welcome to the PepperOS disk!
/PepperOS /PepperOS
protocol: limine protocol: limine
comment: Default configuration (warning: spicy)
path: boot():/boot/pepperk path: boot():/boot/pepperk
+48
View File
@@ -0,0 +1,48 @@
/*
* @author xamidev <xamidev@riseup.net>
* @brief x86 CPU identification
* @license GPL-3.0-only
*/
#include <stdint.h>
#include <stddef.h>
#include <kernel.h>
#include <string/string.h>
/*
* 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));
}
/*
* cpuid_get_vendor_string - Get the CPU vendor string
* @str: String at least 13 bytes long (for output)
*
* Return:
* %0 - on success
*/
int cpuid_get_vendor_string(char* str)
{
uint32_t eax, ebx, ecx, edx;
cpuid(0, &eax, &ebx, &ecx, &edx);
char output[13] = {0};
uint32_t regs[3] = {ebx, edx, ecx};
for (unsigned int j=0; j<3; j++) {
for (unsigned int i=0; i<4; i++) {
output[4*j+i] = (char)((regs[j] >> 8*i) & 0xff);
}
}
strncpy(str, output, 13);
return 0;
}
+2 -2
View File
@@ -4,9 +4,9 @@
* @license GPL-3.0-only * @license GPL-3.0-only
*/ */
#include "gdt.h" #include <arch/gdt.h>
#include <stdint.h> #include <stdint.h>
#include "io/serial/serial.h" #include <io/serial/serial.h>
#include <kernel.h> #include <kernel.h>
// Descriptors are 8-byte wide (64bits) // Descriptors are 8-byte wide (64bits)
+9
View File
@@ -32,6 +32,8 @@ global vector_19_handler
global vector_20_handler global vector_20_handler
global vector_21_handler global vector_21_handler
global vector_128_handler
interrupt_stub: interrupt_stub:
; We'll push all general-purpose registers to the stack, ; We'll push all general-purpose registers to the stack,
; so they're intact and don't bother the code that was ; so they're intact and don't bother the code that was
@@ -313,3 +315,10 @@ vector_33_handler:
push qword 0 push qword 0
push qword 33 push qword 33
jmp interrupt_stub jmp interrupt_stub
; Syscall Interrupt (0x80)
align 16
vector_128_handler:
push qword 0
push qword 128
jmp interrupt_stub
+31 -13
View File
@@ -4,16 +4,16 @@
* @license GPL-3.0-only * @license GPL-3.0-only
*/ */
#include "idt.h" #include <arch/x86.h>
#include <stdint.h> #include <stdint.h>
#include <stddef.h> #include <stddef.h>
#include "io/serial/serial.h" #include <io/serial/serial.h>
#include "io/kbd/ps2.h" #include <io/kbd/ps2.h>
#include <kernel.h> #include <kernel.h>
#include <stdbool.h> #include <stdbool.h>
#include "sched/scheduler.h" #include <sched/scheduler.h>
#include "config.h" #include <config.h>
#include "sched/process.h" #include <sched/process.h>
struct interrupt_descriptor idt[256]; struct interrupt_descriptor idt[256];
struct idtr idt_reg; struct idtr idt_reg;
@@ -21,9 +21,13 @@ struct idtr idt_reg;
// Address to our first interrupt handler // Address to our first interrupt handler
extern char vector_0_handler[]; extern char vector_0_handler[];
extern char vector_128_handler[];
// Timer ticks // Timer ticks
extern volatile uint64_t ticks; extern volatile uint64_t ticks;
extern struct init_status init;
/* /*
* idt_set_entry - Sets an Interrupt Descriptor Table entry * idt_set_entry - Sets an Interrupt Descriptor Table entry
* @vector: Vector number in the IDT * @vector: Vector number in the IDT
@@ -72,6 +76,9 @@ void idt_init()
// Each vector handler is 16-byte aligned, so <vector_no>*16 = address of that handler // Each vector handler is 16-byte aligned, so <vector_no>*16 = address of that handler
idt_set_entry(i, vector_0_handler + (i*16), 0); idt_set_entry(i, vector_0_handler + (i*16), 0);
} }
idt_set_entry(0x80, vector_128_handler, 0);
idt_load(&idt); idt_load(&idt);
DEBUG("IDT initialized"); DEBUG("IDT initialized");
} }
@@ -119,6 +126,19 @@ static void page_fault_handler(struct cpu_status_t* ctx)
CHECK_BIT(ctx->error_code, 7) ? " SGX_VIOLATION" : "", CHECK_BIT(ctx->error_code, 7) ? " SGX_VIOLATION" : "",
cr2); cr2);
if (init.all) {
printf("\x1b[38;5;231mPage Fault at rip=0x%p, err=%u (%s%s%s%s%s%s%s%s) when accessing addr=0x%p\x1b[0m", ctx->iret_rip, ctx->error_code,
CHECK_BIT(ctx->error_code, 0) ? "PAGE_PROTECTION_VIOLATION " : "PAGE_NOT_PRESENT ",
CHECK_BIT(ctx->error_code, 1) ? "ON_WRITE " : "ON_READ ",
CHECK_BIT(ctx->error_code, 2) ? "IN_USER_MODE" : "IN_KERNEL_MODE",
CHECK_BIT(ctx->error_code, 3) ? " WAS_RESERVED" : "",
CHECK_BIT(ctx->error_code, 4) ? " ON_INSTRUCTION_FETCH" : "",
CHECK_BIT(ctx->error_code, 5) ? " PK_VIOLATION" : "",
CHECK_BIT(ctx->error_code, 6) ? " ON_SHADOWSTACK_ACCESS" : "",
CHECK_BIT(ctx->error_code, 7) ? " SGX_VIOLATION" : "",
cr2);
}
panic(ctx, "page fault"); panic(ctx, "page fault");
} }
@@ -154,12 +174,6 @@ static void gp_fault_handler(struct cpu_status_t* ctx)
panic(ctx, "gp fault"); panic(ctx, "gp fault");
} }
// DEBUG
void kbdproc_main(void* arg)
{
printf("Key pressed/released.\r\n");
}
/* /*
* interrupt_dispatch - Interrupt dispatcher * interrupt_dispatch - Interrupt dispatcher
* @context: CPU context * @context: CPU context
@@ -258,10 +272,14 @@ struct cpu_status_t* interrupt_dispatch(struct cpu_status_t* context)
case 33: // Keyboard Interrupt case 33: // Keyboard Interrupt
keyboard_handler(); keyboard_handler();
process_create("keyboard-initiated", kbdproc_main, NULL); // DEBUG //process_create("keyboard-initiated", kbdproc_main, NULL); // DEBUG
outb(0x20, 0x20); outb(0x20, 0x20);
break; break;
case 128: // Syscall Interrupt (0x80)
syscall_handler(context);
break;
default: default:
DEBUG("Unexpected Interrupt"); DEBUG("Unexpected Interrupt");
break; break;
+114
View File
@@ -0,0 +1,114 @@
/*
* @author xamidev <xamidev@riseup.net>
* @brief x86 architecture-dependant initialization
* @license GPL-3.0-only
*/
#include <arch/gdt.h>
#include <stdint.h>
#include <arch/x86.h>
#include <kernel.h>
#include <mem/utils.h>
/*
* 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_enable_fpu - Enable Floating Point Unit
*
* This function enables the Floating Point Unit,
* which allows the CPU to do floating point
* operations.
*
* Here we do not check for FPU support but we
* should. However most processors support it.
*/
static void x86_enable_fpu()
{
size_t cr4;
__asm__ volatile("mov %%cr4, %0" : "=r"(cr4));
cr4 |= 0x200;
__asm__ volatile("mov %0, %%cr4" :: "r"(cr4));
uint16_t cw = 0x37F;
asm volatile("fldcw %0" :: "m"(cw));
}
/*
* 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();
x86_enable_fpu();
x86_cpu_identification();
idt_init();
gdt_init();
}
/*
* cpu_supports_brandstring - Does the CPU support brand strings?
*
* Return:
* true - if it does
* false - if it doesn't
*/
bool cpu_supports_brandstring() {
uint32_t eax, ebx, ecx, edx;
cpuid(0x80000000, &eax, &ebx, &ecx, &edx);
if (eax < 0x80000004) {
return false;
} else {
return true;
}
}
/*
* x86_cpu_idenfitication - get info about the CPU
*
* This function displays the CPU vendor name or the
* extended "brand string" if it's supported, on
* debug output.
*/
void x86_cpu_identification()
{
if (cpu_supports_brandstring()) {
uint32_t regs[12];
// Some CPUs don't return null-terminated values so we do it as a failsafe default
char str[sizeof(regs)+1] = {0};
cpuid(0x80000002, &regs[0], &regs[1], &regs[2], &regs[3]);
cpuid(0x80000003, &regs[4], &regs[5], &regs[6], &regs[7]);
cpuid(0x80000004, &regs[8], &regs[9], &regs[10], &regs[11]);
memcpy(str, regs, sizeof(regs));
str[sizeof(regs)] = '\0';
DEBUG("CPU: %s", str);
} else {
char vendor_string[13] = {0};
cpuid_get_vendor_string(vendor_string);
DEBUG("CPU vendor is: %s", vendor_string);
}
}
+66
View File
@@ -0,0 +1,66 @@
/*
* @author xamidev <xamidev@riseup.net>
* @brief x86 MSR C wrappers
* @description
* Wrapper functions to access Model Specific Registers
*
* @license GPL-3.0-only
*/
#include <stdint.h>
#include <stdbool.h>
#include <arch/x86.h>
/*
* 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> - 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;
}
+26
View File
@@ -0,0 +1,26 @@
/*
* @author xamidev <xamidev@riseup.net>
* @brief System call handling
* @license GPL-3.0-only
*/
#include <arch/x86.h>
#include <kernel.h>
struct cpu_status_t* syscall_handler(struct cpu_status_t* regs)
{
DEBUG("Syscall %lx with argument %lx", regs->rdi, regs->rsi);
switch (regs->rdi)
{
case 0:
break;
case 1:
break;
default:
regs->rsi = 0xdeadbeef;
break;
}
return regs;
}
+19
View File
@@ -9,7 +9,9 @@
* @license GPL-3.0-only * @license GPL-3.0-only
*/ */
#include <kernel.h>
#include <limine.h> #include <limine.h>
#include <stddef.h>
__attribute__((used, section(".limine_requests"))) __attribute__((used, section(".limine_requests")))
volatile struct limine_framebuffer_request framebuffer_request = { volatile struct limine_framebuffer_request framebuffer_request = {
@@ -35,8 +37,25 @@ volatile struct limine_kernel_address_request kerneladdr_request = {
.revision = 0 .revision = 0
}; };
__attribute__((used, section(".limine_requests")))
volatile struct limine_boot_time_request date_request = {
.id = LIMINE_BOOT_TIME_REQUEST,
.revision = 0
};
__attribute__((used, section(".limine_requests_start"))) __attribute__((used, section(".limine_requests_start")))
volatile LIMINE_REQUESTS_START_MARKER; volatile LIMINE_REQUESTS_START_MARKER;
__attribute__((used, section(".limine_requests_end"))) __attribute__((used, section(".limine_requests_end")))
volatile LIMINE_REQUESTS_END_MARKER; volatile LIMINE_REQUESTS_END_MARKER;
void populate_boot_context(struct boot_context* ctx)
{
// Populate boot context
// This stays valid only if the BOOTLOADER_RECLAIMABLE regions are preserved
ctx->fb = framebuffer_request.response ? framebuffer_request.response->framebuffers[0] : NULL;
ctx->mmap = memmap_request.response ? memmap_request.response : NULL;
ctx->hhdm = hhdm_request.response ? hhdm_request.response : NULL;
ctx->kaddr = kerneladdr_request.response ? kerneladdr_request.response : NULL;
ctx->bootdate = date_request.response ? date_request.response : NULL;
}
-45
View File
@@ -1,45 +0,0 @@
/*
* @author xamidev <xamidev@riseup.net>
* @brief PepperOS configuration file
* @license GPL-3.0-only
*/
#ifndef CONFIG_H
#define CONFIG_H
/* version */
#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 "PEPPEROS_VERSION_MAJOR"."PEPPEROS_VERSION_MINOR"."PEPPEROS_VERSION_PATCH"\n"
/* process */
#define PROCESS_NAME_MAX 64
#define PROCESS_STACK_SIZE 0x10000 // 64kb
#define PROCESS_BASE 0x400000
#define PROCESS_STACK_BASE 0x1000000
/* sched */
// 1 tick = 1 ms => quantum = 10ms
#define SCHEDULER_QUANTUM 10
/* kernel */
#define KERNEL_BASE 0xFFFFFFFF80000000ULL
// 2 MB should be enough (as of now, the whole kernel ELF is around 75kb)
#define KERNEL_SIZE 0x200000
#define KERNEL_STACK_SIZE 65536
#define KERNEL_IDT_ENTRIES 33
/* paging */
#define PAGING_MAX_PHYS 0x100000000
/* heap */
#define KHEAP_SIZE (32*1024*1024)
/* term */
#define TERM_HISTORY_MAX_LINES 256
/* time */
#define TIMER_FREQUENCY 1000
#endif
+2 -2
View File
@@ -5,8 +5,8 @@
*/ */
#include <kernel.h> #include <kernel.h>
#include "limine.h" #include <limine.h>
#include "string/string.h" #include <string/string.h>
#include <stddef.h> #include <stddef.h>
extern struct boot_context boot_ctx; extern struct boot_context boot_ctx;
+3 -24
View File
@@ -5,9 +5,9 @@
*/ */
#include <stddef.h> #include <stddef.h>
#include "idt/idt.h" #include <arch/x86.h>
#include "io/serial/serial.h" #include <io/serial/serial.h>
#include "kernel.h" #include <kernel.h>
extern struct init_status init; extern struct init_status init;
extern int panic_count; extern int panic_count;
@@ -36,27 +36,6 @@ void read_rflags(uint64_t rflags)
CHECK_BIT(rflags, 19) ? "VIF " : "", /*virtual interrupt flag*/ CHECK_BIT(rflags, 19) ? "VIF " : "", /*virtual interrupt flag*/
CHECK_BIT(rflags, 20) ? "VIP " : "", /*virtual interrupt pending*/ CHECK_BIT(rflags, 20) ? "VIP " : "", /*virtual interrupt pending*/
CHECK_BIT(rflags, 21) ? "ID " : ""); /*id flag*/ 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 " : "");
}
} }
/* /*
+1 -1
View File
@@ -5,7 +5,7 @@
*/ */
#include <stdint.h> #include <stdint.h>
#include "kernel.h" #include <kernel.h>
#include <stddef.h> #include <stddef.h>
extern struct init_status init; extern struct init_status init;
+92 -6
View File
@@ -4,10 +4,11 @@
* @license GPL-3.0-only * @license GPL-3.0-only
*/ */
#include "io/serial/serial.h" #include "config.h"
#include "ps2.h" #include <io/serial/serial.h>
#include <io/kbd/ps2.h>
#include <stdint.h> #include <stdint.h>
#include "io/term/term.h" #include <io/term/term.h>
#include <kernel.h> #include <kernel.h>
#include <stddef.h> #include <stddef.h>
@@ -18,6 +19,11 @@ uint8_t key_status = 0b00000000;
unsigned char* keymap; unsigned char* keymap;
unsigned char* keymap_shifted; 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; extern struct init_status init;
unsigned char kbdus[128] = unsigned char kbdus[128] =
@@ -210,10 +216,11 @@ void keyboard_handler()
if (c) { if (c) {
if (c == '\n') { 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,85 @@ 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:
* <char> - 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:
* <num> - 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 (c == '\b') {
if (index > 0) {
index--;
output[index] = '\0';
printf(" \b");
}
continue;
}
if (index >= size-1) {
continue;
}
output[index++] = c;
}
output[index] = '\0';
return index;
}
/* /*
* keyboard_init - Keyboard initialization * keyboard_init - Keyboard initialization
* @layout: Desired layout * @layout: Desired layout
+13 -3
View File
@@ -5,10 +5,14 @@
*/ */
#include <kernel.h> #include <kernel.h>
#include "serial.h" #include <io/serial/serial.h>
#include <sched/spinlock.h>
extern struct init_status init; extern struct init_status init;
extern int panic_count;
struct spinlock_t serial_lock = {0};
/* /*
* outb - Writes a byte to a CPU port * outb - Writes a byte to a CPU port
* @port: CPU port to write to * @port: CPU port to write to
@@ -61,8 +65,8 @@ int serial_init()
// Set normal operation mode // Set normal operation mode
outb(PORT + 4, 0x0F); outb(PORT + 4, 0x0F);
DEBUG("*** Welcome to PepperOS! ***");
init.serial = true; init.serial = true;
DEBUG("*** Welcome to PepperOS! (built @ %s %s) ***", __DATE__, __TIME__);
return 0; return 0;
} }
@@ -85,9 +89,15 @@ static int is_transmit_empty()
*/ */
void skputc(char c) void skputc(char c)
{ {
// TODO: Spinlock here (serial access) if (panic_count == 0) {
spinlock_acquire(&serial_lock);
while (!is_transmit_empty()); // wait for free spot while (!is_transmit_empty()); // wait for free spot
outb(PORT, c); outb(PORT, c);
spinlock_release(&serial_lock);
} else {
while (!is_transmit_empty());
outb(PORT, c);
}
} }
/* /*
+1 -1
View File
@@ -41,7 +41,7 @@
#define FLANTERM_IN_FLANTERM #define FLANTERM_IN_FLANTERM
#endif #endif
#include "flanterm.h" #include <io/term/flanterm.h>
// Tries to implement this standard for terminfo // Tries to implement this standard for terminfo
// https://man7.org/linux/man-pages/man4/console_codes.4.html // https://man7.org/linux/man-pages/man4/console_codes.4.html
+2 -2
View File
@@ -51,8 +51,8 @@
#define FLANTERM_IN_FLANTERM #define FLANTERM_IN_FLANTERM
#endif #endif
#include "../flanterm.h" #include <io/term/flanterm.h>
#include "fb.h" #include <io/term/flanterm_backends/fb.h>
void *memset(void *, int, size_t); void *memset(void *, int, size_t);
void *memcpy(void *, const void *, size_t); void *memcpy(void *, const void *, size_t);
+89 -38
View File
@@ -13,36 +13,27 @@ because this shitty implementation will be replaced one day by Flanterm
#include <stddef.h> #include <stddef.h>
#include <kernel.h> #include <kernel.h>
#include "term.h" #include <io/term/term.h>
#include "config.h" #include <config.h>
#include "flanterm.h" #include <io/term/flanterm.h>
#include "flanterm_backends/fb.h" #include <io/term/flanterm_backends/fb.h>
#include "mem/heap/kheap.h" #include <mem/kheap.h>
#include "limine.h" #include <limine.h>
#include <stdarg.h> #include <stdarg.h>
#include "sched/spinlock.h" #include <sched/spinlock.h>
#include "io/serial/serial.h" #include <io/serial/serial.h>
#define NANOPRINTF_IMPLEMENTATION #define NANOPRINTF_IMPLEMENTATION
#include "nanoprintf.h" #include <io/term/nanoprintf.h>
extern struct flanterm_context* ft_ctx; extern struct flanterm_context* ft_ctx;
extern struct init_status init; extern struct init_status init;
struct spinlock_t term_lock = {0}; struct spinlock_t term_lock = {0};
struct spinlock_t printf_lock = {0};
extern int panic_count; 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 * internal_putc - Internal putchar function
* @c: char to print * @c: char to print
@@ -74,6 +65,38 @@ void internal_putc(int c, void *_)
} }
} }
/*
* debug_putc - Internal DEBUG putchar function
* @c: char to print
* @_: (unused, for nanoprintf)
*
* Prints a character to the terminal if it's ready and if
* the kernel is still initializing, and also always to the
* serial interface if it's ready.
*/
void debug_putc(int c, void *_)
{
(void)_;
char ch = (char)c;
if (init.terminal && (!init.all || panic_count > 0)) {
if (panic_count == 0) {
spinlock_acquire(&term_lock);
flanterm_write(ft_ctx, &ch, 1);
spinlock_release(&term_lock);
} else {
flanterm_write(ft_ctx, &ch, 1);
}
}
if (init.serial) {
if (ch == '\n') {
skputc('\r');
}
skputc(ch);
}
}
/* /*
* printf - Fromatted printing * printf - Fromatted printing
* @fmt: format string * @fmt: format string
@@ -83,15 +106,59 @@ void internal_putc(int c, void *_)
* *
* Return: * Return:
* <ret> - number of characters sent to the callback * <ret> - number of characters sent to the callback
* %-1 - error
*/ */
int printf(const char* fmt, ...) int printf(const char* fmt, ...)
{ {
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_list args;
va_start(args, fmt); va_start(args, fmt);
int ret = npf_vpprintf(internal_putc, NULL, fmt, args); int ret = npf_vpprintf(internal_putc, NULL, fmt, args);
va_end(args); va_end(args);
return ret; return ret;
} }
return -1;
}
/*
* kprintf - Fromatted DEBUG printing
* @fmt: format string
* @...: variadic arguments
*
* Wrapper for nanoprintf; to be used only for
* kernel/debug messages.
*
* Return:
* <ret> - number of characters sent to the callback
* %-1 - error
*/
int kprintf(const char* fmt, ...)
{
if (panic_count == 0) {
spinlock_acquire(&printf_lock);
va_list args;
va_start(args, fmt);
int ret = npf_vpprintf(debug_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(debug_putc, NULL, fmt, args);
va_end(args);
return ret;
}
return -1;
}
/* /*
* kputs - Kernel puts * kputs - Kernel puts
@@ -103,30 +170,14 @@ void kputs(const char* str)
{ {
size_t i=0; size_t i=0;
while (str[i] != 0) { while (str[i] != 0) {
_putchar(str[i]); internal_putc(str[i], NULL);
i++; i++;
} }
_putchar('\r');
} }
extern struct flanterm_context* ft_ctx; extern struct flanterm_context* ft_ctx;
extern struct boot_context boot_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 * term_init - Video output/terminal initialization
* *
@@ -136,8 +187,8 @@ void term_init()
{ {
uint32_t bgColor = 0x252525; uint32_t bgColor = 0x252525;
ft_ctx = flanterm_fb_init( ft_ctx = flanterm_fb_init(
kmalloc, NULL,
flanterm_free_wrapper, NULL,
boot_ctx.fb->address, boot_ctx.fb->width, boot_ctx.fb->height, boot_ctx.fb->pitch, boot_ctx.fb->address, boot_ctx.fb->width, boot_ctx.fb->height, boot_ctx.fb->pitch,
boot_ctx.fb->red_mask_size, boot_ctx.fb->red_mask_shift, boot_ctx.fb->red_mask_size, boot_ctx.fb->red_mask_shift,
boot_ctx.fb->green_mask_size, boot_ctx.fb->green_mask_shift, boot_ctx.fb->green_mask_size, boot_ctx.fb->green_mask_shift,
+101
View File
@@ -0,0 +1,101 @@
/*
* @author xamidev <xamidev@riseup.net>
* @brief PepperOS kernel shell
* @license GPL-3.0-only
*/
#include <io/term/term.h>
#include <config.h>
#include <io/kbd/ps2.h>
#include <string/string.h>
#include <stdint.h>
#include <kernel.h>
#include <time/date.h>
#include <mem/kheap.h>
__attribute__((noinline))
void smash_it()
{
char buf[16]; (void)buf;
for (size_t i=0; i<256; i++) {
buf[i] = (char)i;
}
}
/*
* pedicel_main - Kernel shell main function
* @arg: argument (optional)
*
* This is the entry point for the kernel shell process.
* It is used to start programs and to test different things
* on different real hardware easily.
*
* Named after the root part of the pepper.
*/
void pedicel_main(void* arg)
{
printf("Welcome to the kernel shell!\r\nType 'help' for a list of commands.\r\n");
for (;;) {
char input_buf[PEDICEL_INPUT_SIZE] = {0};
printf(PEDICEL_PROMPT);
keyboard_getline(input_buf, PEDICEL_INPUT_SIZE);
if (strncmp(input_buf, "help", 4) == 0) {
printf("\r\nYou are currently running the test kernel shell. This is not\r\n"
"a fully-fledged shell like you'd find in a complete operating system,\r\n"
"but rather a toy to play around in the meantime.\r\n\r\n"
"clear - clear the screen\r\n"
"panic - trigger a test panic\r\n"
"syscall - trigger int 0x80\r\n"
"pf - trigger a page fault\r\n"
"now - get current date\r\n"
"smash - smash the stack\r\n"
"mem - get used heap info\r\n");
continue;
}
if (strncmp(input_buf, "", 1) == 0) {
continue;
}
if (strncmp(input_buf, "clear", 5) == 0) {
printf("\x1b[2J\x1b[H");
continue;
}
if (strncmp(input_buf, "panic", 5) == 0) {
panic(NULL, "test panic");
}
if (strncmp(input_buf, "syscall", 7) == 0) {
__asm__ volatile("mov $0x00, %rdi");
__asm__ volatile("int $0x80");
continue;
}
if (strncmp(input_buf, "pf", 2) == 0) {
volatile uint64_t* fault = (uint64_t*)0xdeadbeef;
fault[0] = 1;
}
if (strncmp(input_buf, "now", 3) == 0) {
struct date now = date_now();
printf("Now is %02u:%02u:%02u on %u/%u/%u\r\n", now.hour, now.minute,
now.second, now.day, now.month, now.year);
continue;
}
if (strncmp(input_buf, "smash", 5) == 0) {
smash_it();
continue;
}
if (strncmp(input_buf, "mem", 3) == 0) {
kheap_info();
continue;
}
printf("%s: command not found\r\n", input_buf);
}
}
+35 -39
View File
@@ -7,24 +7,24 @@
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#include <limine.h> #include <limine.h>
#include "io/term/term.h" #include <io/term/term.h>
#include "io/term/term.h" #include <io/serial/serial.h>
#include "io/serial/serial.h" #include <arch/gdt.h>
#include "mem/gdt/gdt.h" #include <mem/utils.h>
#include "mem/misc/utils.h" #include <kernel.h>
#include "idt/idt.h" #include <time/timer.h>
#include "kernel.h" #include <io/kbd/ps2.h>
#include "time/timer.h" #include <mem/pmm.h>
#include "io/kbd/ps2.h" #include <mem/paging.h>
#include "mem/paging/pmm.h" #include <mem/vmm.h>
#include "mem/paging/paging.h" #include <mem/kheap.h>
#include "mem/paging/vmm.h" #include <sched/process.h>
#include "mem/heap/kheap.h" #include <sched/scheduler.h>
#include "sched/process.h" #include <config.h>
#include "sched/scheduler.h" #include <io/term/flanterm.h>
#include "config.h" #include <io/term/flanterm_backends/fb.h>
#include "io/term/flanterm.h" #include <arch/x86.h>
#include "io/term/flanterm_backends/fb.h" #include <boot/boot.h>
// Limine version used // Limine version used
__attribute__((used, section(".limine_requests"))) __attribute__((used, section(".limine_requests")))
@@ -61,17 +61,12 @@ extern volatile struct limine_framebuffer_request framebuffer_request;
extern volatile struct limine_memmap_request memmap_request; extern volatile struct limine_memmap_request memmap_request;
extern volatile struct limine_hhdm_request hhdm_request; extern volatile struct limine_hhdm_request hhdm_request;
extern volatile struct limine_kernel_address_request kerneladdr_request; extern volatile struct limine_kernel_address_request kerneladdr_request;
extern volatile struct limine_boot_time_request date_request;
extern struct process_t* processes_list; extern struct process_t* processes_list;
extern struct process_t* current_process; extern struct process_t* current_process;
struct process_t* idle_proc; struct process_t* idle_proc;
// Never gets executed although pedicel is scheduled?
void pedicel_main(void* arg)
{
printf("\n\nWelcome to PepperOS! Pedicel speaking.\r\nNothing left to do, let's go idle!");
}
void idle_main(void* arg) void idle_main(void* arg)
{ {
for (;;) { for (;;) {
@@ -79,6 +74,14 @@ void idle_main(void* arg)
} }
} }
void thing_main(void* arg)
{
printf("What's your name, pal? ");
char name[10];
keyboard_getline(name, 10);
printf("\r\n{%s} is such a nice name!\r\n", name);
}
extern uintptr_t kheap_start; extern uintptr_t kheap_start;
/* /*
@@ -94,37 +97,30 @@ void kmain()
CLEAR_INTERRUPTS; CLEAR_INTERRUPTS;
if (!LIMINE_BASE_REVISION_SUPPORTED) hcf(); if (!LIMINE_BASE_REVISION_SUPPORTED) hcf();
populate_boot_context(&boot_ctx);
term_init();
serial_init(); serial_init();
timer_init(); timer_init();
// Populate boot context x86_arch_init();
boot_ctx.fb = framebuffer_request.response ? framebuffer_request.response->framebuffers[0] : NULL;
boot_ctx.mmap = memmap_request.response ? memmap_request.response : NULL;
boot_ctx.hhdm = hhdm_request.response ? hhdm_request.response : NULL;
boot_ctx.kaddr = kerneladdr_request.response ? kerneladdr_request.response : NULL;
boot_mem_display(); boot_mem_display();
pmm_init(boot_ctx); pmm_init(boot_ctx);
// Remap kernel , HHDM and framebuffer
paging_init(boot_ctx); paging_init(boot_ctx);
kheap_init(); kheap_init();
keyboard_init(FR); keyboard_init(FR);
term_init();
gdt_init();
idt_init();
process_init(); process_init();
idle_proc = process_create("idle", (void*)idle_main, 0); idle_proc = process_create("idle", (void*)idle_main, 0);
struct process_t* pedicel = process_create("pedicel", (void*)pedicel_main, 0); process_create("pedicel", (void*)pedicel_main, 0);
process_display_list(processes_list);
scheduler_init(); scheduler_init();
kputs(PEPPEROS_SPLASH); printf(PEPPEROS_SPLASH);
init.all = true;
idle(); idle();
} }
+34 -5
View File
@@ -4,13 +4,13 @@
* @license GPL-3.0-only * @license GPL-3.0-only
*/ */
#include "kheap.h" #include <mem/kheap.h>
#include "mem/paging/paging.h" #include <mem/paging.h>
#include "mem/paging/pmm.h" #include <mem/pmm.h>
#include <stddef.h> #include <stddef.h>
#include <kernel.h> #include <kernel.h>
#include "sched/process.h" #include <sched/process.h>
#include "config.h" #include <config.h>
extern uint64_t kernel_phys_base; extern uint64_t kernel_phys_base;
extern uint64_t kernel_virt_base; extern uint64_t kernel_virt_base;
@@ -158,3 +158,32 @@ void* kalloc_stack()
uint8_t* ptr = kmalloc(PROCESS_STACK_SIZE); // As it's out of kmalloc, stack is already mapped into kernel space uint8_t* ptr = kmalloc(PROCESS_STACK_SIZE); // As it's out of kmalloc, stack is already mapped into kernel space
return ptr ? ptr+PROCESS_STACK_SIZE : NULL; return ptr ? ptr+PROCESS_STACK_SIZE : NULL;
} }
/*
* kheap_info - Display heap info
*
* This function writes the size of the heap (total),
* the number of allocated bytes, and the number of
* free bytes to the standard output.
*/
void kheap_info()
{
uint64_t free_bytes = 0;
struct heap_block_t* curr = (struct heap_block_t*)kheap_start;
while (curr) {
if (curr->free == true) {
free_bytes += curr->size;
}
curr = curr->next;
}
uint64_t total = end-kheap_start;
printf("total=% 8u bytes (%u kB)\r\n"
"alloc=% 8u bytes (%u kB)\r\n"
" free=% 8u bytes (%u kB)\r\n",
total, (total)/1000,
total-free_bytes, (total-free_bytes)/1000,
free_bytes, free_bytes/1000);
}
+9 -9
View File
@@ -4,12 +4,12 @@
* @license GPL-3.0-only * @license GPL-3.0-only
*/ */
#include "paging.h" #include <mem/paging.h>
#include "pmm.h" #include <mem/pmm.h>
#include <kernel.h> #include <kernel.h>
#include <stddef.h> #include <stddef.h>
#include <limine.h> #include <limine.h>
#include "config.h" #include <config.h>
/* /*
Paging on x86 uses four different page table levels: Paging on x86 uses four different page table levels:
@@ -43,7 +43,7 @@ void load_cr3(uint64_t value) {
* This function is used to flush at least the TLB entrie(s) * This function is used to flush at least the TLB entrie(s)
* for the page that contains the <addr> address. * for the page that contains the <addr> address.
*/ */
static inline void invlpg(void *addr) void invlpg(void *addr)
{ {
asm volatile("invlpg (%0)" :: "r"(addr) : "memory"); asm volatile("invlpg (%0)" :: "r"(addr) : "memory");
} }
@@ -59,7 +59,7 @@ static inline void invlpg(void *addr)
* Return: * Return:
* <virt> - Pointer to allocated page table * <virt> - Pointer to allocated page table
*/ */
static uint64_t* alloc_page_table() uint64_t* alloc_page_table()
{ {
uint64_t* virt = (uint64_t*)PHYS_TO_VIRT(pmm_alloc()); uint64_t* virt = (uint64_t*)PHYS_TO_VIRT(pmm_alloc());
@@ -173,9 +173,9 @@ void paging_init(struct boot_context boot_ctx)
} }
} }
// 4GB // 8GB
if (max_phys > PAGING_MAX_PHYS) { if (max_phys > PAGING_MAX_PHYS) {
DEBUG("WARNING: max_phys capped to 4GB (%x) (from max_phys=%p)", PAGING_MAX_PHYS, max_phys); DEBUG("WARNING: max_phys capped to PAGING_MAX_PHYS (from max_phys=%p)", max_phys);
max_phys = PAGING_MAX_PHYS; max_phys = PAGING_MAX_PHYS;
} }
@@ -202,9 +202,9 @@ void paging_init(struct boot_context boot_ctx)
uint64_t fb_size = fb->pitch * fb->height; uint64_t fb_size = fb->pitch * fb->height;
uint64_t fb_pages = (fb_size + PAGE_SIZE-1)/PAGE_SIZE; uint64_t fb_pages = (fb_size + PAGE_SIZE-1)/PAGE_SIZE;
// Map the framebuffer (with cache-disable & write-through) // Map the framebuffer (PWT set, and no PCD means PAT1 [Write-Combining] for this region)
for (uint64_t i=0; i<fb_pages; i++) { for (uint64_t i=0; i<fb_pages; i++) {
paging_map_page(kernel_pml4, fb_virt+i*PAGE_SIZE, fb_phys+i*PAGE_SIZE, PTE_WRITABLE | PTE_PCD | PTE_PWT); paging_map_page(kernel_pml4, fb_virt+i*PAGE_SIZE, fb_phys+i*PAGE_SIZE, PTE_WRITABLE | PTE_PWT);
page_count++; page_count++;
} }
DEBUG("Mapped %u pages for framebuffer", page_count); DEBUG("Mapped %u pages for framebuffer", page_count);
-81
View File
@@ -1,81 +0,0 @@
/*
* @author xamidev <xamidev@riseup.net>
* @brief Virtual memory manager
* @license GPL-3.0-only
*/
/*
The VMM (virtual memory manager) will have two roles:
- mapping pages
- unmapping pages
in a specified virtual space
compared to the PMM which allocs/frees 4kb frames ("physical pages").
*/
#include "vmm.h"
#include "paging.h"
#include <stddef.h>
#include "pmm.h"
#include <kernel.h>
void* vmm_pt_root = 0;
// Linked list head for virtual memory objects
struct vm_object* vm_objs = NULL;
/*
* Will have to be rewritten and expanded,
* to prepare for userspace.
* The platform-agnostic flags will be removed
* because as long as the kernel is x86 only,
* we don't need over complication.
* Plus I don't plan to port to other architectures
*/
uint64_t convert_x86_vm_flags(size_t flags)
{
uint64_t value = 0;
if (flags & VM_FLAG_WRITE)
{
value |= PTE_WRITABLE;
}
if (flags & VM_FLAG_USER)
{
value |= PTE_USER;
}
if ((flags & VM_FLAG_EXEC) == 0)
{
value |= PTE_NOEXEC;
}
return value;
}
extern uint64_t *kernel_pml4;
void vmm_setup_pt_root()
{
// We alloc a physical page (frame) for the pointer, then map it
// to virt (pointer)
uintptr_t phys = pmm_alloc();
vmm_pt_root = (void*)kernel_pml4;
paging_map_page(kernel_pml4, (uint64_t)vmm_pt_root, phys, convert_x86_vm_flags(VM_FLAG_WRITE | VM_FLAG_EXEC));
DEBUG("VMM setup: vmm_pt_root=0x%p (phys=0x%p)", vmm_pt_root, phys);
}
/* void* vmm_alloc(size_t length, size_t flags)
{
// We will try to allocate at least length bytes, which have to be rounded UP to
// the next page so its coherent with the PMM
size_t len = ALIGN_UP(length, PAGE_SIZE);
// Need to implement this (as linked list)
// but for now kernel heap is sufficient
// The VMM will prob be more useful when we have userspace
} */
void vmm_init()
{
// NO U
//vmm_setup_pt_root();
}
-34
View File
@@ -1,34 +0,0 @@
/*
* @author xamidev <xamidev@riseup.net>
* @brief Virtual memory manager
* @license GPL-3.0-only
*/
#ifndef VMM_H
#define VMM_H
#include <stdint.h>
#include <stddef.h>
/*
This will be our linked list of virtual memory objects.
Flags here aren't x86 flags, they are platform-agnostic
kernel-defined flags.
*/
struct vm_object {
uintptr_t base;
size_t length;
size_t flags;
struct vm_object* next;
};
// Flags bitfield
#define VM_FLAG_NONE 0
#define VM_FLAG_WRITE (1 << 0)
#define VM_FLAG_EXEC (1 << 1)
#define VM_FLAG_USER (1 << 2)
void vmm_init(void);
#endif
+27 -49
View File
@@ -11,55 +11,20 @@ it will probably need to get some info from Limine,
to see which pages are used by kernel/bootloader/mmio/fb etc. to see which pages are used by kernel/bootloader/mmio/fb etc.
*/ */
#include "paging.h" #include "config.h"
#include <mem/paging.h>
#include <limine.h> #include <limine.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <kernel.h> #include <kernel.h>
#include "mem/misc/utils.h" #include <mem/utils.h>
#include "pmm.h" #include <mem/pmm.h>
/* /*
First we'll have to discover the physical memory layout, First we'll have to discover the physical memory layout,
and for that we can use a Limine request. and for that we can use a Limine request.
*/ */
struct limine_memmap_entry* biggest_entry;
/*
* pmm_find_biggest_usable_region - Finding the biggest free memory region
* @memmap: Limine memory map
* @hhdm: Limine HHDM offset
*
* This function uses the memory map provided by the bootloader
* to find the single biggest free memory region we can use.
*/
static void pmm_find_biggest_usable_region(struct limine_memmap_response* memmap, struct limine_hhdm_response* hhdm)
{
// Max length of a usable memory region
uint64_t length_max = 0;
uint64_t offset = hhdm->offset;
DEBUG("Usable Memory:");
for (size_t i=0; i<memmap->entry_count; i++) {
struct limine_memmap_entry* entry = memmap->entries[i];
if (entry->type == LIMINE_MEMMAP_USABLE) {
DEBUG("0x%p-0x%p mapped at 0x%p-0x%p", entry->base, entry->base+entry->length,
entry->base+offset, entry->base+entry->length+offset);
if (entry->length > length_max)
{
length_max = entry->length;
biggest_entry = entry;
}
}
}
DEBUG("Biggest usable memory region:");
DEBUG("0x%p-0x%p mapped at 0x%p-0x%p", biggest_entry->base, biggest_entry->base + biggest_entry->length,
biggest_entry->base+offset, biggest_entry->base+biggest_entry->length+offset);
}
// Offset from Higher Half Direct Map // Offset from Higher Half Direct Map
uint64_t hhdm_off; uint64_t hhdm_off;
@@ -99,19 +64,32 @@ void pmm_free(uintptr_t addr)
* This function marks the biggest memory region as * This function marks the biggest memory region as
* free, so we can use it in pmm_alloc. * free, so we can use it in pmm_alloc.
*/ */
static void pmm_init_freelist() static void pmm_init_freelist(struct limine_memmap_response* memmap)
{ {
// We simply call pmm_free() on each page that is marked USABLE uint64_t total_pages = 0;
// in our big memory region.
uint64_t base = ALIGN_UP(biggest_entry->base, PAGE_SIZE); for (size_t i=0; i<memmap->entry_count; i++) {
uint64_t end = ALIGN_DOWN(biggest_entry->base + biggest_entry->length, PAGE_SIZE); struct limine_memmap_entry* entry = memmap->entries[i];
if (entry->type == LIMINE_MEMMAP_USABLE) {
uint64_t base = ALIGN_UP(entry->base, PAGE_SIZE);
uint64_t end = ALIGN_DOWN(entry->base + entry->length, PAGE_SIZE);
if (end > PAGING_MAX_PHYS) {
end = PAGING_MAX_PHYS;
}
// Region above PAGING_MAX_PHYS
if (base >= end) continue;
uint64_t page_count=0;
for (uint64_t addr = base; addr < end; addr += PAGE_SIZE) { for (uint64_t addr = base; addr < end; addr += PAGE_SIZE) {
pmm_free(addr); pmm_free(addr);
page_count++; total_pages++;
} }
DEBUG("%u frames in freelist, available for use (%u bytes)", page_count, page_count*PAGE_SIZE); }
}
DEBUG("%u frames in freelist, %u bytes available (%u MB)", total_pages, total_pages*PAGE_SIZE, total_pages*PAGE_SIZE/1000000);
} }
/* /*
@@ -124,9 +102,9 @@ static void pmm_init_freelist()
void pmm_init(struct boot_context boot_ctx) void pmm_init(struct boot_context boot_ctx)
{ {
hhdm_off = boot_ctx.hhdm->offset; hhdm_off = boot_ctx.hhdm->offset;
pmm_find_biggest_usable_region(boot_ctx.mmap, boot_ctx.hhdm); //pmm_find_biggest_usable_region(boot_ctx.mmap, boot_ctx.hhdm);
// Now we have biggest USABLE region, // Now we have biggest USABLE region,
// so to populate the free list we just iterate through it // so to populate the free list we just iterate through it
pmm_init_freelist(); pmm_init_freelist(boot_ctx.mmap);
} }
+2 -2
View File
@@ -7,8 +7,8 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <limine.h> #include <limine.h>
#include "kernel.h" #include <kernel.h>
#include "string/string.h" #include <string/string.h>
// We won't be linked to standard library, but still need the basic mem* functions // We won't be linked to standard library, but still need the basic mem* functions
// so everything goes allright with the compiler // so everything goes allright with the compiler
+232
View File
@@ -0,0 +1,232 @@
/*
* @author xamidev <xamidev@riseup.net>
* @brief Virtual memory manager
* @license GPL-3.0-only
*/
/*
The VMM (virtual memory manager) will have two roles:
- mapping pages
- unmapping pages
in a specified virtual space
compared to the PMM which allocs/frees 4kb frames ("physical pages").
*/
#include <mem/vmm.h>
#include <mem/paging.h>
#include <stddef.h>
#include <mem/pmm.h>
#include <kernel.h>
extern uint64_t *kernel_pml4;
/*
* vmm_switch_to - Switch to a different VMM context
* @ctx: VMM context to switch to
*
* This function makes the CPU switch to another
* virtual memory context, by using the PML4 address
* specified in the VMM context pointed to by @ctx.
*/
void vmm_switch_to(struct vmm_context* ctx)
{
if (!ctx || !ctx->pml4) {
panic(NULL, "Attempted to switch to bad PML4!");
}
uint64_t pml4 = VIRT_TO_PHYS(ctx->pml4);
asm volatile ("mov %0, %%cr3" :: "r"(pml4) : "memory");
}
/*
* vmm_virt_to_phys - Translate from virtual to physical address
* @pml4: virtual address of the Page Map Level 4 (root page table)
* @virt: virtual address to translate
*
* This function goes through page table structures, beginning at
* the root page table which lives at @pml4, and translates @virt
* to a physical address, if it's found in the tables.
*
* Return:
* <phys> - physical address
* %-1 - address is not present in page tables pointed to by @pml4
*/
uint64_t vmm_virt_to_phys(uint64_t* pml4, uint64_t virt)
{
uint64_t pml4_i = PML4_INDEX(virt);
uint64_t pdpt_i = PDPT_INDEX(virt);
uint64_t pd_i = PD_INDEX(virt);
uint64_t pt_i = PT_INDEX(virt);
if (!(pml4[pml4_i] & PTE_PRESENT)) return -1;
uint64_t* pdpt = (uint64_t*)PHYS_TO_VIRT(pml4[pml4_i] & PTE_ADDR_MASK);
if (!(pdpt[pdpt_i] & PTE_PRESENT)) return -1;
uint64_t* pd = (uint64_t*)PHYS_TO_VIRT(pdpt[pdpt_i] & PTE_ADDR_MASK);
if (!(pd[pd_i] & PTE_PRESENT)) return -1;
uint64_t* pt = (uint64_t*)PHYS_TO_VIRT(pd[pd_i] & PTE_ADDR_MASK);
if (!(pt[pt_i] & PTE_PRESENT)) return -1;
uint64_t phys = (pt[pt_i] & PTE_ADDR_MASK) + (virt & 0xFFF);
return phys;
}
/*
* vmm_create_address_space - Create a new address space
*
* This function allocates a PML4, and then copies the kernel
* page tables into it.
*
* Return:
* <pml4> - address of the new PML4
* NULL - on error (couldn't allocate a page table)
*/
uint64_t* vmm_create_address_space()
{
uint64_t* pml4 = alloc_page_table();
if (!pml4) return NULL;
for (size_t i=256; i<512; i++) {
pml4[i] = kernel_pml4[i];
}
return pml4;
}
/*
* vmm_map - Map & allocate a page
* @pml4: Page Map Level 4 (root table)
* @virt: Virtual address to map
* @flags: Flags to apply on page
*
* This function allocates a page frame with the PMM,
* and maps this page to the provided @virt address,
* with the corresponding @flags.
*
* Return:
* <virt> - virtual address
*/
void* vmm_map(uint64_t* pml4, uint64_t virt, uint64_t flags)
{
uint64_t phys = pmm_alloc();
if (!phys) {
panic(NULL, "VMM/PMM out of memory!");
}
paging_map_page(pml4, virt, phys, flags | PTE_PRESENT);
return (void*)virt;
}
/*
* vmm_unmap - Unmap & free a page
* @pml4: Page Map Level 4 (root table)
* @virt: Virtual address to unmap
*
* This function frees a page frame with the PMM,
* and unmaps the virtual page at @virt.
*/
void vmm_unmap(uint64_t* pml4, uint64_t virt)
{
uint64_t pml4_i = PML4_INDEX(virt);
uint64_t pdpt_i = PDPT_INDEX(virt);
uint64_t pd_i = PD_INDEX(virt);
uint64_t pt_i = PT_INDEX(virt);
if (!(pml4[pml4_i] & PTE_PRESENT)) return;
uint64_t* pdpt = (uint64_t*)PHYS_TO_VIRT(pml4[pml4_i] & PTE_ADDR_MASK);
if (!(pdpt[pdpt_i] & PTE_PRESENT)) return;
uint64_t* pd = (uint64_t*)PHYS_TO_VIRT(pdpt[pdpt_i] & PTE_ADDR_MASK);
if (!(pd[pd_i] & PTE_PRESENT)) return;
uint64_t* pt = (uint64_t*)PHYS_TO_VIRT(pd[pd_i] & PTE_ADDR_MASK);
if (!(pt[pt_i] & PTE_PRESENT)) return;
uint64_t phys = pt[pt_i] & PTE_ADDR_MASK;
pmm_free(phys);
pt[pt_i] = 0;
invlpg((void*)virt);
}
/*
* vmm_is_mapped - Check if an address is mapped
* @pml4: Page Map Level 4 (root table)
* @virt: Virtual address to check
*
* This function checks if the @virt address is
* mapped in the tables pointed to by @pml4.
*
* Return:
* true - @virt is mapped in tables of @pml4
* false - @virt is not mapped there
*/
bool vmm_is_mapped(uint64_t* pml4, uint64_t virt)
{
uint64_t pml4_i = PML4_INDEX(virt);
uint64_t pdpt_i = PDPT_INDEX(virt);
uint64_t pd_i = PD_INDEX(virt);
uint64_t pt_i = PT_INDEX(virt);
if (!(pml4[pml4_i] & PTE_PRESENT)) return false;
uint64_t* pdpt = (uint64_t*)PHYS_TO_VIRT(pml4[pml4_i] & PTE_ADDR_MASK);
if (!(pdpt[pdpt_i] & PTE_PRESENT)) return false;
uint64_t* pd = (uint64_t*)PHYS_TO_VIRT(pdpt[pdpt_i] & PTE_ADDR_MASK);
if (!(pd[pd_i] & PTE_PRESENT)) return false;
uint64_t* pt = (uint64_t*)PHYS_TO_VIRT(pd[pd_i] & PTE_ADDR_MASK);
return (pt[pt_i] & PTE_PRESENT);
}
/*
* vmm_alloc_range - Map and allocate a memory range
* @pml4: Page Map Level 4 (root table)
* @pages: Amount of pages to allocate/map
* @flags: Flags to put on mapped pages
*
* This function looks for enough space in page tables
* to map @pages pages, then maps them into the provided
* @pml4 with the provided @flags and allocates them.
*
* Return:
* <start_virt> - the starting virtual address for the mapped range
*/
void* vmm_alloc_region(uint64_t* pml4, size_t pages, uint64_t flags)
{
uint64_t found_pages = 0;
uint64_t start_virt = VMM_USER_SPACE_START;
for (uint64_t curr = VMM_USER_SPACE_START; curr < VMM_USER_SPACE_END; curr += PAGE_SIZE) {
if (!vmm_is_mapped(pml4, curr)) {
if (found_pages == 0) start_virt = curr;
found_pages++;
} else {
found_pages = 0;
}
if (found_pages == pages) {
for (size_t i = 0; i < pages; i++) {
uint64_t addr_to_map = start_virt + (i * PAGE_SIZE);
if (!vmm_map(pml4, addr_to_map, flags)) {
panic(NULL, "VMM out of memory!");
}
}
return (void*)start_virt;
}
}
panic(NULL, "VMM out of memory!");
return NULL;
}
void vmm_init()
{
// NO U
//vmm_setup_pt_root();
}
+8 -8
View File
@@ -5,15 +5,15 @@
*/ */
#include <stddef.h> #include <stddef.h>
#include "process.h" #include <sched/process.h>
#include "mem/heap/kheap.h" #include <mem/kheap.h>
#include "kernel.h" #include <kernel.h>
#include "string/string.h" #include <string/string.h>
#include "mem/gdt/gdt.h" #include <arch/gdt.h>
#include "config.h" #include <config.h>
#include "io/serial/serial.h" #include <io/serial/serial.h>
#include <io/term/flanterm.h>
#include "io/term/flanterm.h"
extern struct flanterm_context* ft_ctx; extern struct flanterm_context* ft_ctx;
struct process_t* processes_list; struct process_t* processes_list;
+9 -7
View File
@@ -4,11 +4,11 @@
* @license GPL-3.0-only * @license GPL-3.0-only
*/ */
#include "kernel.h" #include <kernel.h>
#include "process.h" #include <sched/process.h>
#include "mem/paging/paging.h" #include <mem/paging.h>
#include <stdint.h> #include <stdint.h>
#include "io/serial/serial.h" #include <io/serial/serial.h>
extern struct process_t* processes_list; extern struct process_t* processes_list;
extern struct process_t* current_process; extern struct process_t* current_process;
@@ -49,7 +49,6 @@ struct cpu_status_t* scheduler_schedule(struct cpu_status_t* context)
} }
current_process->context = context; current_process->context = context;
//current_process->status = READY;
for (;;) { for (;;) {
struct process_t* prev_process = current_process; struct process_t* prev_process = current_process;
@@ -65,14 +64,17 @@ struct cpu_status_t* scheduler_schedule(struct cpu_status_t* context)
return idle_proc->context; return idle_proc->context;
} else { } else {
current_process->status = RUNNING; current_process->status = RUNNING;
/* if (prev_process != current_process) {
DEBUG("Changed from {pid=%u, name=%s} to {pid=%u, name=%s}", prev_process->pid, prev_process->name, current_process->pid, current_process->name);
} */
break; break;
} }
} }
DEBUG("current_process={pid=%u, name='%s', root_page_table[virt]=%p}", current_process->pid, current_process->name, current_process->root_page_table); //DEBUG("current_process={pid=%u, name='%s', root_page_table[virt]=%p}", current_process->pid, current_process->name, current_process->root_page_table);
load_cr3(VIRT_TO_PHYS((uint64_t)current_process->root_page_table)); load_cr3(VIRT_TO_PHYS((uint64_t)current_process->root_page_table));
DEBUG("Loaded process PML4 into CR3"); //DEBUG("Loaded process PML4 into CR3");
return current_process->context; return current_process->context;
} }
+2 -2
View File
@@ -6,8 +6,8 @@
#include <stdatomic.h> #include <stdatomic.h>
#include <stdbool.h> #include <stdbool.h>
#include "kernel.h" #include <kernel.h>
#include "spinlock.h" #include <sched/spinlock.h>
/* /*
* spinlock_acquire - Lock a lock * spinlock_acquire - Lock a lock
+17
View File
@@ -0,0 +1,17 @@
/*
* @author xamidev <xamidev@riseup.net>
* @brief Stack Smashing Protection feature
* @license GPL-3.0-only
*/
#include <config.h>
#include <stdint.h>
#include <kernel.h>
#include <stddef.h>
uint64_t __stack_chk_guard = STACK_CHK_GUARD;
void __stack_chk_fail(void)
{
panic(NULL, "SSP: Stask Smashing Detected!!! (very spicy)");
}
+293
View File
@@ -0,0 +1,293 @@
/*
* @author xamidev <xamidev@riseup.net>
* @brief Undefined behavior sanitization hooks
* @license GPL-3.0-only
*/
#include <stdint.h>
#include <security/ubsan.h>
#include <kernel.h>
#include <stddef.h>
/*
* Hooks were inspired from the Sortix implementation:
* https://gitlab.com/sortix/sortix/-/blob/main/libc/ubsan/ubsan.c
*
* Not all hooks are implemented here.
*/
extern struct init_status init;
/*
* __ubsan_handle_type_mismatch_v1 - Hook for UBSan
* @data_raw: pointer to error data
* @pointer_raw: faulty pointer
*
* This function is executed when the UBSan library detects
* following undefined behavior: type mismatch, null pointer
* access, and unaligned access. It halts the system and
* gives the location of the code that triggered it.
*/
void __ubsan_handle_type_mismatch_v1(void* data_raw, void* pointer_raw)
{
struct ubsan_type_mismatch_v1_data* data = (struct ubsan_type_mismatch_v1_data*) data_raw;
uintptr_t pointer = (uintptr_t)pointer_raw;
uintptr_t alignment = (uintptr_t)1UL << data->log_alignment;
const char* violation = "type mismatch";
if ( !pointer ) {
violation = "null pointer access";
}
else if ( alignment && (pointer & (alignment - 1)) ) {
violation = "unaligned access";
}
struct ubsan_source_location* loc = &data->location;
DEBUG("\x1b[38;5;231mUBSan: %s (ptr=%p) at %s:%u:%u\x1b[0m", violation, pointer, loc->filename, loc->line, loc->column);
if (init.all) {
printf("\x1b[38;5;231mUBSan: %s (ptr=%p) at %s:%u:%u\x1b[0m\r\n", violation, pointer, loc->filename, loc->line, loc->column);
}
panic(NULL, "Undefined Behavior Sanitization error");
}
/*
* __ubsan_handle_pointer_overflow - Hook for UBSan
* @data_raw: pointer to error data
* @base_raw: base pointer
* @result_raw: pointer after faulty operation
*
* This function is executed when the UBSan library detects
* following undefined behavior: pointer overflow.
* It halts the system and gives the location of the code
* that triggered it.
*/
void __ubsan_handle_pointer_overflow(void* data_raw, void* base_raw, void* result_raw)
{
struct ubsan_pointer_overflow_data* data = (struct ubsan_pointer_overflow_data*) data_raw;
uintptr_t base = (uintptr_t)base_raw;
uintptr_t result = (uintptr_t)result_raw;
struct ubsan_source_location* loc = &data->location;
DEBUG("\x1b[38;5;231mUBSan: pointer overflow (base=%p, result=%p) at %s:%u:%u\x1b[0m", base, result, loc->filename, loc->line, loc->column);
if (init.all) {
printf("\x1b[38;5;231mUBSan: pointer overflow (base=%p, result=%p) at %s:%u:%u\x1b[0m", base, result, loc->filename, loc->line, loc->column);
}
panic(NULL, "Undefined Behavior Sanitization error: pointer overflow");
}
/*
* __ubsan_handle_shift_out_of_bounds - Hook for UBSan
* @data_raw: pointer to error data
* @lhs_raw: left hand side (value being shifted)
* @rhs_raw: right hand side (shift amount)
*
* This function is executed when the UBSan library detects
* following undefined behavior: shift out of bounds.
* It halts the system and gives the location of the code
* that triggered it.
*/
void __ubsan_handle_shift_out_of_bounds(void* data_raw, void* lhs_raw, void* rhs_raw)
{
struct ubsan_shift_out_of_bounds_data* data = (struct ubsan_shift_out_of_bounds_data*) data_raw;
uintptr_t lhs = (uintptr_t) lhs_raw;
uintptr_t rhs = (uintptr_t) rhs_raw;
struct ubsan_source_location* loc = &data->location;
DEBUG("\x1b[38;5;231mUBSan: shift out of bounds (lhs=%p, rhs=%p) at %s:%u:%u\x1b[0m", lhs, rhs, loc->filename, loc->line, loc->column);
if (init.all) {
printf("\x1b[38;5;231mUBSan: shift out of bounds (lhs=%p, rhs=%p) at %s:%u:%u\x1b[0m", lhs, rhs, loc->filename, loc->line, loc->column);
}
panic(NULL, "Undefined Behavior Sanitization error: shift out of bounds");
}
/*
* __ubsan_handle_load_invalid_value - Hook for UBSan
* @data_raw: pointer to error data
* @value_raw: value loaded
*
* This function is executed when the UBSan library detects
* following undefined behavior: invalid value load.
* It halts the system and gives the location of the code
* that triggered it.
*/
void __ubsan_handle_load_invalid_value(void* data_raw, void* value_raw)
{
struct ubsan_invalid_value_data* data = (struct ubsan_invalid_value_data*) data_raw;
uintptr_t value = (uintptr_t) value_raw;
struct ubsan_source_location* loc = &data->location;
DEBUG("\x1b[38;5;231mUBSan: invalid value load (value=%p) at %s:%u:%u\x1b[0m", value, loc->filename, loc->line, loc->column);
if (init.all) {
printf("\x1b[38;5;231mUBSan: invalid value load (value=%p) at %s:%u:%u\x1b[0m", value, loc->filename, loc->line, loc->column);
}
panic(NULL, "Undefined Behavior Sanitization error: invalid value load");
}
/*
* __ubsan_handle_out_of_bounds - Hook for UBSan
* @data_raw: pointer to error data
* @index_raw: out-of-bounds index in array
*
* This function is executed when the UBSan library detects
* following undefined behavior: access out of bounds.
* It halts the system and gives the location of the code
* that triggered it.
*/
void __ubsan_handle_out_of_bounds(void* data_raw, void* index_raw)
{
struct ubsan_out_of_bounds_data* data = (struct ubsan_out_of_bounds_data*) data_raw;
uintptr_t index = (uintptr_t) index_raw;
struct ubsan_source_location* loc = &data->location;
DEBUG("\x1b[38;5;231mUBSan: out of bounds (index=%p) at %s:%u:%u\x1b[0m", index, loc->filename, loc->line, loc->column);
if (init.all) {
printf("\x1b[38;5;231mUBSan: out of bounds (index=%p) at %s:%u:%u\x1b[0m", index, loc->filename, loc->line, loc->column);
}
panic(NULL, "Undefined Behavior Sanitization error: out of bounds");
}
/*
* __ubsan_handle_divrem_overflow - Hook for UBSan
* @data_raw: pointer to error data
* @lhs_raw: left hand side operator
* @rhs_raw: right hand side operator
*
* This function is executed when the UBSan library detects
* following undefined behavior: division remainder overflow.
* It halts the system and gives the location of the code
* that triggered it.
*/
void __ubsan_handle_divrem_overflow(void* data_raw, void* lhs_raw, void* rhs_raw)
{
struct ubsan_overflow_data* data = (struct ubsan_overflow_data*) data_raw;
uintptr_t lhs = (uintptr_t) lhs_raw;
uintptr_t rhs = (uintptr_t) rhs_raw;
struct ubsan_source_location* loc = &data->location;
DEBUG("\x1b[38;5;231mUBSan: division remainder overflow (lhs=%p, rhs=%p) at %s:%u:%u\x1b[0m", lhs, rhs, loc->filename, loc->line, loc->column);
if (init.all) {
printf("\x1b[38;5;231mUBSan: division remainder overflow (lhs=%p, rhs=%p) at %s:%u:%u\x1b[0m", lhs, rhs, loc->filename, loc->line, loc->column);
}
panic(NULL, "Undefined Behavior Sanitization error: division remainder overflow");
}
/*
* __ubsan_handle_sub_overflow - Hook for UBSan
* @data_raw: pointer to error data
* @lhs_raw: left hand side operator
* @rhs_raw: right hand side operator
*
* This function is executed when the UBSan library detects
* following undefined behavior: subtraction overflow.
* It halts the system and gives the location of the code
* that triggered it.
*/
void __ubsan_handle_sub_overflow(void* data_raw, void* lhs_raw, void* rhs_raw)
{
struct ubsan_overflow_data* data = (struct ubsan_overflow_data*) data_raw;
uintptr_t lhs = (uintptr_t) lhs_raw;
uintptr_t rhs = (uintptr_t) rhs_raw;
struct ubsan_source_location* loc = &data->location;
DEBUG("\x1b[38;5;231mUBSan: subtraction overflow (lhs=%p, rhs=%p) at %s:%u:%u\x1b[0m", lhs, rhs, loc->filename, loc->line, loc->column);
if (init.all) {
printf("\x1b[38;5;231mUBSan: subtraction overflow (lhs=%p, rhs=%p) at %s:%u:%u\x1b[0m", lhs, rhs, loc->filename, loc->line, loc->column);
}
panic(NULL, "Undefined Behavior Sanitization error: subtraction overflow");
}
/*
* __ubsan_handle_add_overflow - Hook for UBSan
* @data_raw: pointer to error data
* @lhs_raw: left hand side operator
* @rhs_raw: right hand side operator
*
* This function is executed when the UBSan library detects
* following undefined behavior: addition overflow.
* It halts the system and gives the location of the code
* that triggered it.
*/
void __ubsan_handle_add_overflow(void* data_raw, void* lhs_raw, void* rhs_raw)
{
struct ubsan_overflow_data* data = (struct ubsan_overflow_data*) data_raw;
uintptr_t lhs = (uintptr_t) lhs_raw;
uintptr_t rhs = (uintptr_t) rhs_raw;
struct ubsan_source_location* loc = &data->location;
DEBUG("\x1b[38;5;231mUBSan: addition overflow (lhs=%p, rhs=%p) at %s:%u:%u\x1b[0m", lhs, rhs, loc->filename, loc->line, loc->column);
if (init.all) {
printf("\x1b[38;5;231mUBSan: addition overflow (lhs=%p, rhs=%p) at %s:%u:%u\x1b[0m", lhs, rhs, loc->filename, loc->line, loc->column);
}
panic(NULL, "Undefined Behavior Sanitization error: addition overflow");
}
/*
* __ubsan_handle_mul_overflow - Hook for UBSan
* @data_raw: pointer to error data
* @lhs_raw: left hand side operator
* @rhs_raw: right hand side operator
*
* This function is executed when the UBSan library detects
* following undefined behavior: multiplication overflow.
* It halts the system and gives the location of the code
* that triggered it.
*/
void __ubsan_handle_mul_overflow(void* data_raw, void* lhs_raw, void* rhs_raw)
{
struct ubsan_overflow_data* data = (struct ubsan_overflow_data*) data_raw;
uintptr_t lhs = (uintptr_t) lhs_raw;
uintptr_t rhs = (uintptr_t) rhs_raw;
struct ubsan_source_location* loc = &data->location;
DEBUG("\x1b[38;5;231mUBSan: multiplication overflow (lhs=%p, rhs=%p) at %s:%u:%u\x1b[0m", lhs, rhs, loc->filename, loc->line, loc->column);
if (init.all) {
printf("\x1b[38;5;231mUBSan: multiplication overflow (lhs=%p, rhs=%p) at %s:%u:%u\x1b[0m", lhs, rhs, loc->filename, loc->line, loc->column);
}
panic(NULL, "Undefined Behavior Sanitization error: multiplication overflow");
}
/*
* __ubsan_handle_negate_overflow - Hook for UBSan
* @data_raw: pointer to error data
* @old_value_raw: value before overflow
*
* This function is executed when the UBSan library detects
* following undefined behavior: negation overflow.
* It halts the system and gives the location of the code
* that triggered it.
*/
void __ubsan_handle_negate_overflow(void* data_raw, void* old_value_raw)
{
struct ubsan_overflow_data* data = (struct ubsan_overflow_data*) data_raw;
uintptr_t old_value = (uintptr_t) old_value_raw;
struct ubsan_source_location* loc = &data->location;
DEBUG("\x1b[38;5;231mUBSan: negation overflow (old_value=%p) at %s:%u:%u\x1b[0m", old_value, loc->filename, loc->line, loc->column);
if (init.all) {
printf("\x1b[38;5;231mUBSan: negation overflow (old_value=%p) at %s:%u:%u\x1b[0m", old_value, loc->filename, loc->line, loc->column);
}
panic(NULL, "Undefined Behavior Sanitization error: negation overflow");
}
+29
View File
@@ -70,3 +70,32 @@ void strncpy(char* dst, const char* src, size_t n)
size_t i = 0; size_t i = 0;
while(i++ != n && (*dst++ = *src++)); while(i++ != n && (*dst++ = *src++));
} }
/*
* strncmp - compare two strings up to n characters
* @s1: first string
* @s2: second string
* @n: number of bytes to compare
*
* Taken from: https://github.com/DevSolar/pdclib/blob/master/functions/string/strncmp.c
*
* Return:
* $0 - @s1 and @s2 are equal
* $<0 - @s1 is less than @s2
* $>0 - @s1 is greater than @s2
*/
int strncmp(const char* s1, const char* s2, size_t n)
{
while ( n && *s1 && ( *s1 == *s2 ) ) {
++s1;
++s2;
--n;
}
if ( n == 0 ) {
return 0;
}
else {
return ( *(unsigned char *)s1 - *(unsigned char *)s2 );
}
}
+89
View File
@@ -0,0 +1,89 @@
/*
* @author xamidev <xamidev@riseup.net>
* @brief Date helper functions
* @license GPL-3.0-only
*/
#include <stdint.h>
#include <time/date.h>
#include <mem/utils.h>
#include <kernel.h>
extern struct boot_context boot_ctx;
// Unix epoch used as reference: Jan 1st 1970, 00:00:00 UTC
struct date epoch = {
.year = 1970,
.month = 1,
.day = 1,
.hour = 0,
.minute = 0,
.second = 0
};
/*
* date_timestamp_to_date - Convert UNIX timestamp to a date structure
* @timestamp: UNIX timestamp
*
* Return:
* <date> - date structure
*/
struct date date_timestamp_to_date(uint64_t timestamp)
{
struct date result;
memcpy(&result, &epoch, sizeof(struct date));
uint64_t nr_days = timestamp / 86400;
while (nr_days > 0) {
unsigned int nr_month = 0;
int leap_year = 0;
if (result.year % 4 == 0 && (result.year % 100 != 0 || result.year % 400 == 0)) {
leap_year = 1;
} else {
leap_year = 0;
}
if (result.month == 2) {
if (leap_year != 0) {
nr_month = 29;
} else {
nr_month = 28;
}
} else {
nr_month = 31 - ((result.month -1) % 7 % 2);
}
if (nr_days >= nr_month) {
nr_days -= nr_month;
result.month++;
if (result.month > 12) {
result.month = 1;
result.year++;
}
} else {
result.day += nr_days;
nr_days = 0;
}
}
result.second = timestamp % 60;
timestamp /= 60;
result.minute = timestamp % 60;
timestamp /= 60;
result.hour = timestamp % 24;
return result;
}
/*
* date_now - Get the current date (time at boot + timer ticks)
*
* Return:
* <date> - date structure
*/
struct date date_now()
{
uint64_t timestamp_now = boot_ctx.bootdate->boot_time + (ticks/1000);
return date_timestamp_to_date(timestamp_now);
}
+2 -2
View File
@@ -5,9 +5,9 @@
*/ */
#include <stdint.h> #include <stdint.h>
#include "io/serial/serial.h" #include <io/serial/serial.h>
#include <kernel.h> #include <kernel.h>
#include "config.h" #include <config.h>
/* /*
For now, the timer module will be using the PIC. For now, the timer module will be using the PIC.