Compare commits
23 Commits
be1be41a64
...
flanterm
| Author | SHA1 | Date | |
|---|---|---|---|
|
9df33b49d8
|
|||
|
1f055ab31c
|
|||
|
70f19ab299
|
|||
|
9470dedb61
|
|||
|
4cf4fb0dda
|
|||
|
ac7216d84a
|
|||
|
458ba375f3
|
|||
| b920c87bab | |||
|
4fbd9b3987
|
|||
|
8aad1235c3
|
|||
|
38710653be
|
|||
|
7f997f6611
|
|||
|
7bb542d901
|
|||
|
4a90de9521
|
|||
|
c46157fad0
|
|||
| 6e633b44b7 | |||
|
b8a155fada
|
|||
|
091f94f89e
|
|||
|
b469952d91
|
|||
|
9cbecc1689
|
|||
|
12ab12f1b2
|
|||
|
0f72987bc1
|
|||
|
d9dfd4c749
|
3
.gitignore
vendored
3
.gitignore
vendored
@@ -7,3 +7,6 @@ iso_root
|
|||||||
*.gch
|
*.gch
|
||||||
*/*.gch
|
*/*.gch
|
||||||
*/*/*.gch
|
*/*/*.gch
|
||||||
|
.gdb_history
|
||||||
|
symbols.map
|
||||||
|
symbols.S
|
||||||
24
DOOM.txt
Normal file
24
DOOM.txt
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
up to doom:
|
||||||
|
|
||||||
|
- Return from pedicel_main() normally (to idle)
|
||||||
|
|
||||||
|
** Checkpoint: ring0 process working
|
||||||
|
|
||||||
|
- VFS layer (open/read/write/...) with USTar filesystem (for initrd)
|
||||||
|
|
||||||
|
** Checkpoint: files not linked to but accessible by the kernel
|
||||||
|
|
||||||
|
- Ring3 memory mappings
|
||||||
|
- Ring3 privilege switch
|
||||||
|
|
||||||
|
** Checkpoint: welcome to userland
|
||||||
|
|
||||||
|
- Syscall interface
|
||||||
|
- Implement syscalls needed for doom
|
||||||
|
|
||||||
|
** Checkpoint: can run simple programs, ring 3, loaded from filesystem
|
||||||
|
|
||||||
|
- Properly handle the keyboard interrupt (keyboard buffer)
|
||||||
|
- Port DOOMgeneric (few functions with Framebuffer/ticks/etc.)
|
||||||
|
|
||||||
|
** Achievement: It runs doom!
|
||||||
21
Makefile
21
Makefile
@@ -1,10 +1,17 @@
|
|||||||
SOURCES = 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/printf.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
|
SOURCES = 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/printf.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
|
||||||
|
|
||||||
|
PROBLEMATIC_FLAGS=-Wno-unused-parameter -Wno-unused-variable
|
||||||
|
|
||||||
build:
|
build:
|
||||||
rm -f *.o
|
rm -f *.o
|
||||||
x86_64-elf-gcc -g -c -Isrc $(SOURCES) -Wall -Wextra -std=gnu99 -nostdlib -ffreestanding -fno-stack-protector -fno-stack-check -fno-PIC -ffunction-sections -fdata-sections -mcmodel=kernel
|
x86_64-elf-gcc -g -c -Isrc $(SOURCES) $(PROBLEMATIC_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
|
||||||
objcopy -O elf64-x86-64 -B i386 -I binary zap-light16.psf zap-light16.o
|
objcopy -O elf64-x86-64 -B i386 -I binary zap-light16.psf zap-light16.o
|
||||||
nasm -f elf64 src/idt/idt.S -o idt_stub.o
|
nasm -f elf64 src/idt/idt.S -o idt_stub.o
|
||||||
|
nasm -f elf64 src/entry.S -o entry.o
|
||||||
|
x86_64-elf-ld -o pepperk -T linker.ld *.o
|
||||||
|
nm -n pepperk | awk '$$2 ~ /[TtDdBbRr]/ {print $$1, $$3}' > symbols.map
|
||||||
|
python3 symbols.py
|
||||||
|
nasm -f elf64 symbols.S -o symbols.o
|
||||||
x86_64-elf-ld -o pepperk -T linker.ld *.o
|
x86_64-elf-ld -o pepperk -T linker.ld *.o
|
||||||
|
|
||||||
limine/limine:
|
limine/limine:
|
||||||
@@ -30,11 +37,15 @@ build-iso: limine/limine build
|
|||||||
./limine/limine bios-install pepper.iso
|
./limine/limine bios-install pepper.iso
|
||||||
|
|
||||||
debug:
|
debug:
|
||||||
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 &
|
||||||
gdb pepperk --command=debug.gdb
|
gdb pepperk --command=debug.gdb
|
||||||
|
|
||||||
|
debug2:
|
||||||
|
/usr/bin/qemu-system-x86_64 -drive file=pepper.iso -s -S -d int -no-reboot -no-shutdown &
|
||||||
|
pwndbg pepperk --command=debug.gdb
|
||||||
|
|
||||||
run: build-iso
|
run: build-iso
|
||||||
qemu-system-x86_64 -cdrom pepper.iso -serial stdio
|
/usr/bin/qemu-system-x86_64 -cdrom pepper.iso -serial stdio
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf *.o pepperk iso_root pepper.iso limine
|
rm -rf *.o symbols.map symbols.S pepperk iso_root pepper.iso limine
|
||||||
|
|||||||
23
README.md
23
README.md
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
## Trying the kernel
|
## Trying the kernel
|
||||||
|
|
||||||
First install the dependencies: `sudo apt install xorriso make qemu-system`
|
First install the dependencies: `sudo apt install python3 xorriso make qemu-system`
|
||||||
|
|
||||||
Then, to compile the kernel and make an ISO image file: `make build-iso`
|
Then, to compile the kernel and make an ISO image file: `make build-iso`
|
||||||
To run it with QEMU, `make run`
|
To run it with QEMU, `make run`
|
||||||
@@ -11,18 +11,27 @@ To run it with QEMU, `make run`
|
|||||||
|
|
||||||
The basics that I'm targeting are:
|
The basics that I'm targeting are:
|
||||||
|
|
||||||
|
### Basic utility of what we call a "kernel"
|
||||||
|
|
||||||
- Fix terminal driver (backspace issues, scrolling) OR add Flanterm or equivalent
|
- Fix terminal driver (backspace issues, scrolling) OR add Flanterm or equivalent
|
||||||
- Implement paging / see what Limine does at boot with memory management
|
- Implement tasks, and task switching + context switching and spinlock acquire/release
|
||||||
- Implement tasks, and task switching
|
|
||||||
- Load an executable
|
- Load an executable
|
||||||
- Scheduler (round-robin using the PIT timer interrupt)
|
- Filesystem (TAR for read-only initfs, then maybe read-write using FAT12/16/32 or easier fs) w/ VFS layer
|
||||||
- Filesystem (TAR for read-only initfs, then maybe read-write using FAT12/16/32
|
|
||||||
- Getting to userspace (syscalls)
|
- Getting to userspace (syscalls)
|
||||||
- Porting musl libc or equivalent
|
- Porting musl libc or equivalent
|
||||||
|
|
||||||
In the future, maybe?
|
### Scalability/maintenance/expansion features
|
||||||
|
|
||||||
- SMP support
|
- Documentation
|
||||||
|
- SOME error handling in functions
|
||||||
|
- Unit tests
|
||||||
|
- Good error codes (like Linux kernel: ENOMEM, ENOENT, ...)
|
||||||
|
- Make the panic function work within itself without dependencies + error message (and still get cpu context?)
|
||||||
|
|
||||||
|
### Optional features
|
||||||
|
|
||||||
|
In the future, maybe?
|
||||||
|
- SMP support (Limine provides functionality to make this easier)
|
||||||
- Parsing the ACPI tables and using them for something
|
- Parsing the ACPI tables and using them for something
|
||||||
- Replacing the PIT timer with APIC
|
- Replacing the PIT timer with APIC
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
target remote localhost:1234
|
target remote localhost:1234
|
||||||
set disassembly-flavor intel
|
set disassembly-flavor intel
|
||||||
display/8i $rip
|
display/4i $rip
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
OUTPUT_FORMAT(elf64-x86-64)
|
OUTPUT_FORMAT(elf64-x86-64)
|
||||||
|
|
||||||
ENTRY(kmain)
|
ENTRY(_start)
|
||||||
|
|
||||||
PHDRS
|
PHDRS
|
||||||
{
|
{
|
||||||
|
|||||||
41
src/boot/boot.c
Normal file
41
src/boot/boot.c
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* @author xamidev <xamidev@riseup.net>
|
||||||
|
* @brief Limine requests for boot
|
||||||
|
* @license GPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <limine.h>
|
||||||
|
|
||||||
|
// Framebuffer request
|
||||||
|
__attribute__((used, section(".limine_requests")))
|
||||||
|
volatile struct limine_framebuffer_request framebuffer_request = {
|
||||||
|
.id = LIMINE_FRAMEBUFFER_REQUEST,
|
||||||
|
.revision = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
// Memory map request
|
||||||
|
__attribute__((used, section(".limine_requests")))
|
||||||
|
volatile struct limine_memmap_request memmap_request = {
|
||||||
|
.id = LIMINE_MEMMAP_REQUEST,
|
||||||
|
.revision = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
// Higher Half Direct Map
|
||||||
|
__attribute__((used, section(".limine_requests")))
|
||||||
|
volatile struct limine_hhdm_request hhdm_request = {
|
||||||
|
.id = LIMINE_HHDM_REQUEST,
|
||||||
|
.revision = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
// Executable Address/Kernel Address (find base phys/virt address of kernel)
|
||||||
|
__attribute__((used, section(".limine_requests")))
|
||||||
|
volatile struct limine_kernel_address_request kerneladdr_request = {
|
||||||
|
.id = LIMINE_KERNEL_ADDRESS_REQUEST,
|
||||||
|
.revision = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
__attribute__((used, section(".limine_requests_start")))
|
||||||
|
volatile LIMINE_REQUESTS_START_MARKER;
|
||||||
|
|
||||||
|
__attribute__((used, section(".limine_requests_end")))
|
||||||
|
volatile LIMINE_REQUESTS_END_MARKER;
|
||||||
38
src/config.h
Normal file
38
src/config.h
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* @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 "pepperOS 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
|
||||||
|
|
||||||
|
/* heap */
|
||||||
|
#define KHEAP_SIZE (16*1024*1024)
|
||||||
|
|
||||||
|
/* term */
|
||||||
|
#define TERM_HISTORY_MAX_LINES 256
|
||||||
|
|
||||||
|
#endif
|
||||||
25
src/debug/panic.c
Normal file
25
src/debug/panic.c
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#include <stddef.h>
|
||||||
|
#include "idt/idt.h"
|
||||||
|
#include "io/serial/serial.h"
|
||||||
|
#include "kernel.h"
|
||||||
|
|
||||||
|
void panic(struct cpu_status_t* ctx, const char* str)
|
||||||
|
{
|
||||||
|
CLEAR_INTERRUPTS;
|
||||||
|
if (ctx == NULL)
|
||||||
|
{
|
||||||
|
DEBUG("\x1b[38;5;231m\x1b[48;5;196mKernel panic!!!\x1b[0m Something went horribly wrong! (no cpu ctx)");
|
||||||
|
DIE_DEBUG(str);
|
||||||
|
skputc('\r');
|
||||||
|
skputc('\n');
|
||||||
|
DEBUG("\x1b[38;5;231m\x1b[48;5;196mend Kernel panic - halting...\x1b[0m");
|
||||||
|
hcf();
|
||||||
|
}
|
||||||
|
DEBUG("\x1b[38;5;231m\x1b[48;5;196mKernel panic!!!\x1b[0m at rip=%p\r\nSomething went horribly wrong! (%s) vect=0x%.2x errcode=0x%x\n\rrax=%p rbx=%p rcx=%p rdx=%p\n\rrsi=%p rdi=%p r8=%p r9=%p\n\rr10=%p r11=%p r12=%p r13=%p\n\rr14=%p r15=%p\n\n\rflags=%p\n\rHalting...",
|
||||||
|
ctx->iret_rip,
|
||||||
|
str,
|
||||||
|
ctx->vector_number, ctx->error_code, ctx->rax, ctx->rbx, ctx->rcx, ctx->rdx, ctx->rsi, ctx->rdi,
|
||||||
|
ctx->r8, ctx->r9, ctx->r10, ctx->r11, ctx->r12, ctx->r13, ctx->r14, ctx->r15, ctx->iret_flags);
|
||||||
|
debug_stack_trace(100);
|
||||||
|
hcf();
|
||||||
|
}
|
||||||
75
src/debug/stacktrace.c
Normal file
75
src/debug/stacktrace.c
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include "kernel.h"
|
||||||
|
|
||||||
|
void debug_stack_trace(unsigned int max_frames)
|
||||||
|
{
|
||||||
|
DEBUG("*** begin stack trace ***");
|
||||||
|
// Thanks GCC :)
|
||||||
|
uintptr_t* rbp = (uintptr_t*)__builtin_frame_address(0);
|
||||||
|
|
||||||
|
for (unsigned int frame=0; frame<max_frames && rbp != NULL; frame++)
|
||||||
|
{
|
||||||
|
// Return address, 1 word above saved rbp
|
||||||
|
uintptr_t rip = rbp[1];
|
||||||
|
uintptr_t offset = 0;
|
||||||
|
const char* name = debug_find_symbol(rip, &offset);
|
||||||
|
DEBUG("[%u] <0x%p> (%s+0x%x)", frame, (void*)rip, name, offset);
|
||||||
|
|
||||||
|
uintptr_t* next_rbp = (uintptr_t*)rbp[0];
|
||||||
|
|
||||||
|
// invalid rbp or we're at the end
|
||||||
|
if (next_rbp <= rbp || next_rbp == NULL)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
rbp = next_rbp;
|
||||||
|
}
|
||||||
|
DEBUG("*** end stack trace ***");
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint64_t addr;
|
||||||
|
const char *name;
|
||||||
|
} __attribute__((packed)) kernel_symbol_t;
|
||||||
|
|
||||||
|
__attribute__((weak)) extern kernel_symbol_t symbol_table[];
|
||||||
|
__attribute__((weak)) extern uint64_t symbol_count;
|
||||||
|
|
||||||
|
// binary search
|
||||||
|
const char* debug_find_symbol(uintptr_t rip, uintptr_t* offset)
|
||||||
|
{
|
||||||
|
if (!symbol_table || symbol_count == 0)
|
||||||
|
{
|
||||||
|
if (offset) *offset = 0;
|
||||||
|
return "???";
|
||||||
|
}
|
||||||
|
|
||||||
|
int low = 0, high = (int)symbol_count - 1;
|
||||||
|
int best = -1;
|
||||||
|
|
||||||
|
while (low <= high)
|
||||||
|
{
|
||||||
|
int mid = (low + high) / 2;
|
||||||
|
if (symbol_table[mid].addr <= rip)
|
||||||
|
{
|
||||||
|
best = mid;
|
||||||
|
low = mid + 1;
|
||||||
|
} else {
|
||||||
|
high = mid - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (best != -1)
|
||||||
|
{
|
||||||
|
if (offset)
|
||||||
|
{
|
||||||
|
*offset = rip - symbol_table[best].addr;
|
||||||
|
}
|
||||||
|
return symbol_table[best].name;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offset) *offset = 0;
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
23
src/entry.S
Normal file
23
src/entry.S
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
bits 64
|
||||||
|
global _start
|
||||||
|
|
||||||
|
extern kmain
|
||||||
|
extern kernel_stack
|
||||||
|
|
||||||
|
KERNEL_STACK_SIZE equ 65536
|
||||||
|
|
||||||
|
section .text
|
||||||
|
|
||||||
|
_start:
|
||||||
|
cli
|
||||||
|
|
||||||
|
; load kernel stack
|
||||||
|
lea rsp, [kernel_stack+KERNEL_STACK_SIZE]
|
||||||
|
|
||||||
|
; rbp=0 so last frame in stack trace
|
||||||
|
xor rbp, rbp
|
||||||
|
|
||||||
|
; 16 byte align
|
||||||
|
and rsp, -16
|
||||||
|
|
||||||
|
call kmain
|
||||||
@@ -1,4 +1,8 @@
|
|||||||
; Assembly stub for the IDT
|
;
|
||||||
|
; @author xamidev <xamidev@riseup.net>
|
||||||
|
; @brief Stub for Interrupt Descriptor Table handlers
|
||||||
|
; @license GPL-3.0-only
|
||||||
|
;
|
||||||
|
|
||||||
bits 64
|
bits 64
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* @author xamidev <xamidev@riseup.net>
|
||||||
|
* @brief Interrupt Descriptor Table setup and dispatching
|
||||||
|
* @license GPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
#include "idt.h"
|
#include "idt.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 "sched/scheduler.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "sched/process.h"
|
||||||
|
|
||||||
struct interrupt_descriptor idt[256];
|
struct interrupt_descriptor idt[256];
|
||||||
struct idtr idt_reg;
|
struct idtr idt_reg;
|
||||||
@@ -53,8 +63,67 @@ void idt_init()
|
|||||||
DEBUG("IDT initialized");
|
DEBUG("IDT initialized");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline uint64_t read_cr2(void)
|
||||||
|
{
|
||||||
|
uint64_t val;
|
||||||
|
asm volatile ("mov %%cr2, %0" : "=r"(val));
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void page_fault_handler(struct cpu_status_t* ctx)
|
||||||
|
{
|
||||||
|
// It could be used to remap pages etc. to fix the fault, but right now what I'm more
|
||||||
|
// interested in is getting more info out of those numbers cause i'm lost each time i have
|
||||||
|
// to read all this mess
|
||||||
|
uint64_t cr2 = read_cr2();
|
||||||
|
|
||||||
|
DEBUG("\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");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gp_fault_handler(struct cpu_status_t* ctx)
|
||||||
|
{
|
||||||
|
DEBUG("\x1b[38;5;231mGeneral Protection Fault at rip=0x%p, err=%u (%s)\x1b[0m",
|
||||||
|
ctx->iret_rip,
|
||||||
|
ctx->error_code,
|
||||||
|
(ctx->error_code == 0) ? "NOT_SEGMENT_RELATED" : "SEGMENT_RELATED");
|
||||||
|
|
||||||
|
// Segment-related
|
||||||
|
if (ctx->error_code != 0)
|
||||||
|
{
|
||||||
|
bool is_external = CHECK_BIT(ctx->error_code, 0);
|
||||||
|
// is it IDT, GDT, LDT?
|
||||||
|
uint8_t table = ctx->error_code & 0x6; // 0b110 (isolate table)
|
||||||
|
uint16_t index = ctx->error_code & 0xFFF8; // 13*1 1111111111111 + 000 = 1111111111111000
|
||||||
|
|
||||||
|
char* table_names[4] = {"GDT", "IDT", "LDT", "IDT"};
|
||||||
|
|
||||||
|
DEBUG("\x1b[38;5;231m%s in %s index %u\x1b[0m",
|
||||||
|
is_external ? "EXTERNAL" : "INTERNAL",
|
||||||
|
table_names[table],
|
||||||
|
index);
|
||||||
|
}
|
||||||
|
|
||||||
|
panic(ctx, "gp fault");
|
||||||
|
}
|
||||||
|
|
||||||
struct cpu_status_t* interrupt_dispatch(struct cpu_status_t* context)
|
struct cpu_status_t* interrupt_dispatch(struct cpu_status_t* context)
|
||||||
{
|
{
|
||||||
|
if (context == NULL)
|
||||||
|
{
|
||||||
|
panic(NULL, "Interrupt dispatch recieved NULL context!");
|
||||||
|
}
|
||||||
|
|
||||||
switch(context->vector_number)
|
switch(context->vector_number)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
@@ -77,6 +146,7 @@ struct cpu_status_t* interrupt_dispatch(struct cpu_status_t* context)
|
|||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
DEBUG("Invalid Opcode!");
|
DEBUG("Invalid Opcode!");
|
||||||
|
panic(context, "Invalid Opcode!");
|
||||||
break;
|
break;
|
||||||
case 7:
|
case 7:
|
||||||
DEBUG("Device Not Available!");
|
DEBUG("Device Not Available!");
|
||||||
@@ -97,10 +167,11 @@ struct cpu_status_t* interrupt_dispatch(struct cpu_status_t* context)
|
|||||||
DEBUG("Stack-Segment Fault!");
|
DEBUG("Stack-Segment Fault!");
|
||||||
break;
|
break;
|
||||||
case 13:
|
case 13:
|
||||||
DEBUG("General Protection Fault!");
|
gp_fault_handler(context);
|
||||||
break;
|
break;
|
||||||
case 14:
|
case 14:
|
||||||
DEBUG("Page Fault!");
|
// Better debugging for page faults...
|
||||||
|
page_fault_handler(context);
|
||||||
break;
|
break;
|
||||||
case 15:
|
case 15:
|
||||||
DEBUG("Intel Reserved Interrupt! (Achievement unlocked: How Did We Get Here?)");
|
DEBUG("Intel Reserved Interrupt! (Achievement unlocked: How Did We Get Here?)");
|
||||||
@@ -124,14 +195,23 @@ struct cpu_status_t* interrupt_dispatch(struct cpu_status_t* context)
|
|||||||
DEBUG("Control Protection Exception!");
|
DEBUG("Control Protection Exception!");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 32:
|
case 32: // Timer Interrupt
|
||||||
//DEBUG("Tick!");
|
|
||||||
ticks++;
|
ticks++;
|
||||||
// Send an EOI so that we can continue having interrupts
|
// Send an EOI so that we can continue having interrupts
|
||||||
outb(0x20, 0x20);
|
outb(0x20, 0x20);
|
||||||
|
|
||||||
|
if (ticks % SCHEDULER_QUANTUM == 0)
|
||||||
|
{
|
||||||
|
return scheduler_schedule(context);
|
||||||
|
//struct cpu_status_t* current_ctx = scheduler_schedule(context);
|
||||||
|
//process_switch(current_ctx->iret_rsp, current_ctx->iret_rip);
|
||||||
|
//SET_INTERRUPTS;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 33:
|
case 33:
|
||||||
|
DEBUG("Keyboard Interrupt");
|
||||||
keyboard_handler();
|
keyboard_handler();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
/*
|
||||||
|
* @author xamidev <xamidev@riseup.net>
|
||||||
|
* @brief Interrupt Descriptor Table setup and dispatching
|
||||||
|
* @license GPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef IDT_H
|
#ifndef IDT_H
|
||||||
#define IDT_H
|
#define IDT_H
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
// PS/2 Keyboard support
|
/*
|
||||||
|
* @author xamidev <xamidev@riseup.net>
|
||||||
|
* @brief PS/2 Keyboard driver
|
||||||
|
* @license GPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
#include "io/serial/serial.h"
|
#include "io/serial/serial.h"
|
||||||
#include "ps2.h"
|
#include "ps2.h"
|
||||||
@@ -201,12 +205,11 @@ void keyboard_handler()
|
|||||||
|
|
||||||
if (c)
|
if (c)
|
||||||
{
|
{
|
||||||
putchar(c);
|
// Should probably have a keyboard buffer here... instead of this
|
||||||
|
_putchar(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
skputs("key pressed!\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// End of Interrupt (to master PIC)
|
// End of Interrupt (to master PIC)
|
||||||
@@ -233,5 +236,11 @@ void keyboard_init(unsigned char layout)
|
|||||||
skputs("Unsupported layout.");
|
skputs("Unsupported layout.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unmask IRQ1
|
||||||
|
uint8_t mask = inb(0x21);
|
||||||
|
mask &= ~(1 << 1);
|
||||||
|
outb(0x21, mask);
|
||||||
|
|
||||||
DEBUG("PS/2 Keyboard initialized");
|
DEBUG("PS/2 Keyboard initialized");
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,9 @@
|
|||||||
|
/*
|
||||||
|
* @author xamidev <xamidev@riseup.net>
|
||||||
|
* @brief PS/2 Keyboard driver
|
||||||
|
* @license GPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef PS2_H
|
#ifndef PS2_H
|
||||||
#define PS2_H
|
#define PS2_H
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
/*
|
||||||
|
* @author xamidev <xamidev@riseup.net>
|
||||||
|
* @brief Debug serial driver
|
||||||
|
* @license GPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
#include <kernel.h>
|
#include <kernel.h>
|
||||||
#include "serial.h"
|
#include "serial.h"
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
/*
|
||||||
|
* @author xamidev <xamidev@riseup.net>
|
||||||
|
* @brief Debug serial driver
|
||||||
|
* @license GPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef SERIAL_H
|
#ifndef SERIAL_H
|
||||||
#define SERIAL_H
|
#define SERIAL_H
|
||||||
|
|
||||||
|
|||||||
2129
src/io/term/flanterm.c
Normal file
2129
src/io/term/flanterm.c
Normal file
File diff suppressed because it is too large
Load Diff
72
src/io/term/flanterm.h
Normal file
72
src/io/term/flanterm.h
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||||
|
|
||||||
|
/* Copyright (C) 2022-2026 Mintsuki and contributors.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FLANTERM_H
|
||||||
|
#define FLANTERM_H 1
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define FLANTERM_CB_DEC 10
|
||||||
|
#define FLANTERM_CB_BELL 20
|
||||||
|
#define FLANTERM_CB_PRIVATE_ID 30
|
||||||
|
#define FLANTERM_CB_STATUS_REPORT 40
|
||||||
|
#define FLANTERM_CB_POS_REPORT 50
|
||||||
|
#define FLANTERM_CB_KBD_LEDS 60
|
||||||
|
#define FLANTERM_CB_MODE 70
|
||||||
|
#define FLANTERM_CB_LINUX 80
|
||||||
|
#define FLANTERM_CB_OSC 90
|
||||||
|
|
||||||
|
#ifdef FLANTERM_IN_FLANTERM
|
||||||
|
|
||||||
|
#include "flanterm_private.h"
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
struct flanterm_context;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void flanterm_write(struct flanterm_context *ctx, const char *buf, size_t count);
|
||||||
|
void flanterm_flush(struct flanterm_context *ctx);
|
||||||
|
void flanterm_full_refresh(struct flanterm_context *ctx);
|
||||||
|
void flanterm_deinit(struct flanterm_context *ctx, void (*_free)(void *ptr, size_t size));
|
||||||
|
|
||||||
|
void flanterm_get_dimensions(struct flanterm_context *ctx, size_t *cols, size_t *rows);
|
||||||
|
void flanterm_set_autoflush(struct flanterm_context *ctx, bool state);
|
||||||
|
void flanterm_set_callback(struct flanterm_context *ctx, void (*callback)(struct flanterm_context *, uint64_t, uint64_t, uint64_t, uint64_t));
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
1441
src/io/term/flanterm_backends/fb.c
Normal file
1441
src/io/term/flanterm_backends/fb.c
Normal file
File diff suppressed because it is too large
Load Diff
79
src/io/term/flanterm_backends/fb.h
Normal file
79
src/io/term/flanterm_backends/fb.h
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||||
|
|
||||||
|
/* Copyright (C) 2022-2026 Mintsuki and contributors.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FLANTERM_FB_H
|
||||||
|
#define FLANTERM_FB_H 1
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "../flanterm.h"
|
||||||
|
|
||||||
|
#ifdef FLANTERM_IN_FLANTERM
|
||||||
|
|
||||||
|
#include "fb_private.h"
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define FLANTERM_FB_ROTATE_0 0
|
||||||
|
#define FLANTERM_FB_ROTATE_90 1
|
||||||
|
#define FLANTERM_FB_ROTATE_180 2
|
||||||
|
#define FLANTERM_FB_ROTATE_270 3
|
||||||
|
|
||||||
|
struct flanterm_context *flanterm_fb_init(
|
||||||
|
/* If _malloc and _free are nulled, use the bump allocated instance (1 use only). */
|
||||||
|
void *(*_malloc)(size_t size),
|
||||||
|
void (*_free)(void *ptr, size_t size),
|
||||||
|
uint32_t *framebuffer, size_t width, size_t height, size_t pitch,
|
||||||
|
uint8_t red_mask_size, uint8_t red_mask_shift,
|
||||||
|
uint8_t green_mask_size, uint8_t green_mask_shift,
|
||||||
|
uint8_t blue_mask_size, uint8_t blue_mask_shift,
|
||||||
|
uint32_t *canvas, /* If nulled, no canvas. */
|
||||||
|
uint32_t *ansi_colours, uint32_t *ansi_bright_colours, /* If nulled, default. */
|
||||||
|
uint32_t *default_bg, uint32_t *default_fg, /* If nulled, default. */
|
||||||
|
uint32_t *default_bg_bright, uint32_t *default_fg_bright, /* If nulled, default. */
|
||||||
|
/* If font is null, use default font and font_width and font_height ignored. */
|
||||||
|
void *font, size_t font_width, size_t font_height, size_t font_spacing,
|
||||||
|
/* If scale_x and scale_y are 0, automatically scale font based on resolution. */
|
||||||
|
size_t font_scale_x, size_t font_scale_y,
|
||||||
|
size_t margin,
|
||||||
|
/* One of FLANTERM_FB_ROTATE_* values. */
|
||||||
|
int rotation
|
||||||
|
);
|
||||||
|
|
||||||
|
void flanterm_fb_set_flush_callback(struct flanterm_context *ctx, void (*flush_callback)(volatile void *address, size_t length));
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
127
src/io/term/flanterm_backends/fb_private.h
Normal file
127
src/io/term/flanterm_backends/fb_private.h
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||||
|
|
||||||
|
/* Copyright (C) 2022-2026 Mintsuki and contributors.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FLANTERM_FB_PRIVATE_H
|
||||||
|
#define FLANTERM_FB_PRIVATE_H 1
|
||||||
|
|
||||||
|
#ifndef FLANTERM_IN_FLANTERM
|
||||||
|
#error "Do not use fb_private.h. Use interfaces defined in fb.h only."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define FLANTERM_FB_FONT_GLYPHS 256
|
||||||
|
|
||||||
|
struct flanterm_fb_char {
|
||||||
|
uint32_t c;
|
||||||
|
uint32_t fg;
|
||||||
|
uint32_t bg;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct flanterm_fb_queue_item {
|
||||||
|
size_t x, y;
|
||||||
|
struct flanterm_fb_char c;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct flanterm_fb_context {
|
||||||
|
struct flanterm_context term;
|
||||||
|
|
||||||
|
void (*plot_char)(struct flanterm_context *ctx, struct flanterm_fb_char *c, size_t x, size_t y);
|
||||||
|
void (*flush_callback)(volatile void *address, size_t length);
|
||||||
|
|
||||||
|
size_t font_width;
|
||||||
|
size_t font_height;
|
||||||
|
size_t glyph_width;
|
||||||
|
size_t glyph_height;
|
||||||
|
|
||||||
|
size_t font_scale_x;
|
||||||
|
size_t font_scale_y;
|
||||||
|
|
||||||
|
size_t offset_x, offset_y;
|
||||||
|
|
||||||
|
volatile uint32_t *framebuffer;
|
||||||
|
size_t pitch;
|
||||||
|
size_t width;
|
||||||
|
size_t height;
|
||||||
|
size_t phys_height;
|
||||||
|
size_t bpp;
|
||||||
|
|
||||||
|
uint8_t red_mask_size, red_mask_shift;
|
||||||
|
uint8_t green_mask_size, green_mask_shift;
|
||||||
|
uint8_t blue_mask_size, blue_mask_shift;
|
||||||
|
|
||||||
|
int rotation;
|
||||||
|
|
||||||
|
size_t font_bits_size;
|
||||||
|
uint8_t *font_bits;
|
||||||
|
size_t font_bool_size;
|
||||||
|
bool *font_bool;
|
||||||
|
|
||||||
|
uint32_t ansi_colours[8];
|
||||||
|
uint32_t ansi_bright_colours[8];
|
||||||
|
uint32_t default_fg, default_bg;
|
||||||
|
uint32_t default_fg_bright, default_bg_bright;
|
||||||
|
|
||||||
|
size_t canvas_size;
|
||||||
|
uint32_t *canvas;
|
||||||
|
|
||||||
|
size_t grid_size;
|
||||||
|
size_t queue_size;
|
||||||
|
size_t map_size;
|
||||||
|
|
||||||
|
struct flanterm_fb_char *grid;
|
||||||
|
|
||||||
|
struct flanterm_fb_queue_item *queue;
|
||||||
|
size_t queue_i;
|
||||||
|
|
||||||
|
struct flanterm_fb_queue_item **map;
|
||||||
|
|
||||||
|
uint32_t text_fg;
|
||||||
|
uint32_t text_bg;
|
||||||
|
size_t cursor_x;
|
||||||
|
size_t cursor_y;
|
||||||
|
|
||||||
|
uint32_t saved_state_text_fg;
|
||||||
|
uint32_t saved_state_text_bg;
|
||||||
|
size_t saved_state_cursor_x;
|
||||||
|
size_t saved_state_cursor_y;
|
||||||
|
|
||||||
|
size_t old_cursor_x;
|
||||||
|
size_t old_cursor_y;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
133
src/io/term/flanterm_private.h
Normal file
133
src/io/term/flanterm_private.h
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||||
|
|
||||||
|
/* Copyright (C) 2022-2026 Mintsuki and contributors.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FLANTERM_PRIVATE_H
|
||||||
|
#define FLANTERM_PRIVATE_H 1
|
||||||
|
|
||||||
|
#ifndef FLANTERM_IN_FLANTERM
|
||||||
|
#error "Do not use flanterm_private.h. Use interfaces defined in flanterm.h only."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define FLANTERM_MAX_ESC_VALUES 16
|
||||||
|
|
||||||
|
struct flanterm_context {
|
||||||
|
/* internal use */
|
||||||
|
|
||||||
|
size_t tab_size;
|
||||||
|
bool autoflush;
|
||||||
|
bool cursor_enabled;
|
||||||
|
bool scroll_enabled;
|
||||||
|
bool wrap_enabled;
|
||||||
|
bool origin_mode;
|
||||||
|
bool control_sequence;
|
||||||
|
bool escape;
|
||||||
|
bool osc;
|
||||||
|
bool osc_escape;
|
||||||
|
size_t osc_buf_i;
|
||||||
|
uint8_t osc_buf[256];
|
||||||
|
bool rrr;
|
||||||
|
bool discard_next;
|
||||||
|
bool bold;
|
||||||
|
bool bg_bold;
|
||||||
|
bool reverse_video;
|
||||||
|
bool dec_private;
|
||||||
|
bool insert_mode;
|
||||||
|
bool csi_unhandled;
|
||||||
|
uint64_t code_point;
|
||||||
|
size_t unicode_remaining;
|
||||||
|
uint8_t g_select;
|
||||||
|
uint8_t charsets[2];
|
||||||
|
size_t current_charset;
|
||||||
|
size_t escape_offset;
|
||||||
|
size_t esc_values_i;
|
||||||
|
size_t saved_cursor_x;
|
||||||
|
size_t saved_cursor_y;
|
||||||
|
size_t current_primary;
|
||||||
|
size_t current_bg;
|
||||||
|
size_t scroll_top_margin;
|
||||||
|
size_t scroll_bottom_margin;
|
||||||
|
uint32_t esc_values[FLANTERM_MAX_ESC_VALUES];
|
||||||
|
uint8_t last_printed_char;
|
||||||
|
bool last_was_graphic;
|
||||||
|
bool saved_state_bold;
|
||||||
|
bool saved_state_bg_bold;
|
||||||
|
bool saved_state_reverse_video;
|
||||||
|
bool saved_state_origin_mode;
|
||||||
|
bool saved_state_wrap_enabled;
|
||||||
|
size_t saved_state_current_charset;
|
||||||
|
uint8_t saved_state_charsets[2];
|
||||||
|
size_t saved_state_current_primary;
|
||||||
|
size_t saved_state_current_bg;
|
||||||
|
|
||||||
|
/* to be set by backend */
|
||||||
|
|
||||||
|
size_t rows, cols;
|
||||||
|
|
||||||
|
void (*raw_putchar)(struct flanterm_context *, uint8_t c);
|
||||||
|
void (*clear)(struct flanterm_context *, bool move);
|
||||||
|
void (*set_cursor_pos)(struct flanterm_context *, size_t x, size_t y);
|
||||||
|
void (*get_cursor_pos)(struct flanterm_context *, size_t *x, size_t *y);
|
||||||
|
void (*set_text_fg)(struct flanterm_context *, size_t fg);
|
||||||
|
void (*set_text_bg)(struct flanterm_context *, size_t bg);
|
||||||
|
void (*set_text_fg_bright)(struct flanterm_context *, size_t fg);
|
||||||
|
void (*set_text_bg_bright)(struct flanterm_context *, size_t bg);
|
||||||
|
void (*set_text_fg_rgb)(struct flanterm_context *, uint32_t fg);
|
||||||
|
void (*set_text_bg_rgb)(struct flanterm_context *, uint32_t bg);
|
||||||
|
void (*set_text_fg_default)(struct flanterm_context *);
|
||||||
|
void (*set_text_bg_default)(struct flanterm_context *);
|
||||||
|
void (*set_text_fg_default_bright)(struct flanterm_context *);
|
||||||
|
void (*set_text_bg_default_bright)(struct flanterm_context *);
|
||||||
|
void (*move_character)(struct flanterm_context *, size_t new_x, size_t new_y, size_t old_x, size_t old_y);
|
||||||
|
void (*scroll)(struct flanterm_context *);
|
||||||
|
void (*revscroll)(struct flanterm_context *);
|
||||||
|
void (*swap_palette)(struct flanterm_context *);
|
||||||
|
void (*save_state)(struct flanterm_context *);
|
||||||
|
void (*restore_state)(struct flanterm_context *);
|
||||||
|
void (*double_buffer_flush)(struct flanterm_context *);
|
||||||
|
void (*full_refresh)(struct flanterm_context *);
|
||||||
|
void (*deinit)(struct flanterm_context *, void (*)(void *, size_t));
|
||||||
|
|
||||||
|
/* to be set by client */
|
||||||
|
|
||||||
|
void (*callback)(struct flanterm_context *, uint64_t, uint64_t, uint64_t, uint64_t);
|
||||||
|
};
|
||||||
|
|
||||||
|
void flanterm_context_reinit(struct flanterm_context *ctx);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,3 +1,9 @@
|
|||||||
|
/*
|
||||||
|
* @author xamidev <xamidev@riseup.net>
|
||||||
|
* @brief Framebuffer-based terminal driver
|
||||||
|
* @license GPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
// Terminal output
|
// Terminal output
|
||||||
/*
|
/*
|
||||||
There are a couple of bugs here and there but for now I don't care too much
|
There are a couple of bugs here and there but for now I don't care too much
|
||||||
@@ -9,8 +15,11 @@ 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 "term.h"
|
||||||
|
#include "mem/misc/utils.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "flanterm.h"
|
||||||
|
|
||||||
extern struct limine_framebuffer* framebuffer;
|
extern struct boot_context boot_ctx;
|
||||||
|
|
||||||
// Importing the PSF object file
|
// Importing the PSF object file
|
||||||
extern unsigned char _binary_zap_light16_psf_start[];
|
extern unsigned char _binary_zap_light16_psf_start[];
|
||||||
@@ -22,128 +31,97 @@ uint8_t* glyphs = _binary_zap_light16_psf_start + sizeof(PSF1_Header);
|
|||||||
#define FONT_WIDTH 8
|
#define FONT_WIDTH 8
|
||||||
#define FONT_HEIGHT font->characterSize
|
#define FONT_HEIGHT font->characterSize
|
||||||
|
|
||||||
|
extern struct flanterm_context* ft_ctx;
|
||||||
|
|
||||||
// Character cursor
|
// Character cursor
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
unsigned int x;
|
size_t x;
|
||||||
unsigned int y;
|
size_t y;
|
||||||
} Cursor;
|
} Cursor;
|
||||||
|
|
||||||
Cursor cursor = {0};
|
static Cursor cursor = {0, 0};
|
||||||
|
|
||||||
unsigned char* fb;
|
static uint8_t* fb;
|
||||||
|
static struct limine_framebuffer* framebuffer;
|
||||||
|
|
||||||
|
uint8_t lines_length[TERM_HISTORY_MAX_LINES];
|
||||||
|
|
||||||
|
static inline size_t term_max_cols(void)
|
||||||
|
{
|
||||||
|
return framebuffer->width / FONT_WIDTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline size_t term_max_lines(void)
|
||||||
|
{
|
||||||
|
return framebuffer->height / FONT_HEIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
int term_init()
|
int term_init()
|
||||||
{
|
{
|
||||||
// Get framebuffer address from Limine struct
|
// Get framebuffer address from Limine struct
|
||||||
|
|
||||||
if (framebuffer)
|
if (!boot_ctx.fb)
|
||||||
{
|
{
|
||||||
fb = framebuffer->address;
|
|
||||||
DEBUG("terminal initialized");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
framebuffer = boot_ctx.fb;
|
||||||
|
fb = (uint8_t*)framebuffer->address;
|
||||||
|
|
||||||
|
memset(lines_length, 0, sizeof(lines_length));
|
||||||
|
|
||||||
|
DEBUG("terminal initialized, fb=0x%p (width=%u height=%u pitch=%u bpp=%u)", fb, framebuffer->width, framebuffer->height, framebuffer->pitch, framebuffer->bpp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// These are marked "static" because we don't wanna expose them all around
|
// These are marked "static" because we don't wanna expose them all around
|
||||||
// AKA they should just be seen here (kind of like private functions in cpp)
|
// AKA they should just be seen here (kind of like private functions in cpp)
|
||||||
static void putpixel(int x, int y, int color)
|
static inline void putpixel(size_t x, size_t y, uint32_t color)
|
||||||
{
|
{
|
||||||
|
// Guard so we don't write past fb boundaries
|
||||||
|
if (x >= framebuffer->width || y >= framebuffer->height) return;
|
||||||
// Depth isn't part of limine_framebuffer attributes so it will be 4
|
// Depth isn't part of limine_framebuffer attributes so it will be 4
|
||||||
unsigned pos = x*4 + y*framebuffer->pitch;
|
size_t pos = x*4 + y*framebuffer->pitch;
|
||||||
fb[pos] = color & 255; // blue channel
|
fb[pos] = color & 255; // blue channel
|
||||||
fb[pos+1] = (color >> 8) & 255; // green
|
fb[pos+1] = (color >> 8) & 255; // green
|
||||||
fb[pos+2] = (color >> 16) & 255; // blue
|
fb[pos+2] = (color >> 16) & 255; // blue
|
||||||
}
|
}
|
||||||
|
|
||||||
static void draw_char(char c, int px, int py, int fg, int bg)
|
void term_scroll()
|
||||||
{
|
{
|
||||||
uint8_t* glyph = glyphs + ((unsigned char)c * FONT_HEIGHT);
|
// Erase first text line
|
||||||
|
memset(fb, 255, FONT_HEIGHT*framebuffer->pitch);
|
||||||
|
|
||||||
for (size_t y=0; y<FONT_HEIGHT; y++)
|
// Move whole framebuffer up by one text line
|
||||||
{
|
memmove(fb, fb+(FONT_HEIGHT*framebuffer->pitch), (framebuffer->height-FONT_HEIGHT)*framebuffer->pitch);
|
||||||
uint8_t row = glyph[y];
|
|
||||||
for (size_t x=0; x<8; x++)
|
|
||||||
{
|
|
||||||
int color = (row & (0x80 >> x)) ? fg : bg;
|
|
||||||
putpixel(px+x, py+y, color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void erase_char(int px, int py)
|
// Clear last text line
|
||||||
{
|
size_t clear_start = (framebuffer->height - FONT_HEIGHT) * framebuffer->pitch;
|
||||||
for (size_t y=0; y<FONT_HEIGHT; y++)
|
memset(fb + clear_start, 255, FONT_HEIGHT * framebuffer->pitch);
|
||||||
{
|
|
||||||
for (size_t x=0; x<8; x++)
|
|
||||||
{
|
|
||||||
// Black
|
|
||||||
putpixel(px+x, py+y, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void putchar(char c)
|
// Shift line lengths by 1 (for backspace handling)
|
||||||
|
size_t max_lines = term_max_lines();
|
||||||
|
for (size_t i = 1; i < max_lines; i++)
|
||||||
{
|
{
|
||||||
if (c == '\n')
|
lines_length[i - 1] = lines_length[i];
|
||||||
{
|
|
||||||
cursor.x = 0;
|
|
||||||
cursor.y++;
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
lines_length[max_lines - 1] = 0;
|
||||||
// TODO: Improperly handled.
|
|
||||||
// When we're on an empty line it should get to the upper line's last character
|
|
||||||
// NOT just the last position possible; we would need to track the last line's character amount for that
|
|
||||||
if (c == '\b')
|
|
||||||
{
|
|
||||||
if (cursor.x == 0 && cursor.y == 0)
|
|
||||||
{
|
|
||||||
// Top-left corner
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cursor.x == 0)
|
|
||||||
{
|
|
||||||
cursor.y--;
|
|
||||||
cursor.x = (framebuffer->width / FONT_WIDTH) -1; // here
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
cursor.x--;
|
|
||||||
}
|
|
||||||
|
|
||||||
int px = cursor.x * FONT_WIDTH;
|
|
||||||
int py = cursor.y * FONT_HEIGHT;
|
|
||||||
erase_char(px, py);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((cursor.x+1)*FONT_WIDTH >= framebuffer->width)
|
|
||||||
{
|
|
||||||
cursor.x = 0;
|
|
||||||
cursor.y++;
|
|
||||||
}
|
|
||||||
|
|
||||||
int px = cursor.x * FONT_WIDTH;
|
|
||||||
int py = cursor.y * FONT_HEIGHT;
|
|
||||||
draw_char(c, px, py, WHITE, BLACK);
|
|
||||||
cursor.x++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Overhead that could be avoided, right? (for printf)
|
// Overhead that could be avoided, right? (for printf)
|
||||||
void _putchar(char character)
|
void _putchar(char character)
|
||||||
{
|
{
|
||||||
putchar(character);
|
flanterm_write(ft_ctx, &character, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Debug-printing
|
// Debug-printing
|
||||||
void kputs(const char* str)
|
void kputs(const char* str)
|
||||||
{
|
{
|
||||||
unsigned int i=0;
|
size_t i=0;
|
||||||
while (str[i] != 0)
|
while (str[i] != 0)
|
||||||
{
|
{
|
||||||
putchar(str[i]);
|
_putchar(str[i]);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,15 @@
|
|||||||
|
/*
|
||||||
|
* @author xamidev <xamidev@riseup.net>
|
||||||
|
* @brief Framebuffer-based terminal driver
|
||||||
|
* @license GPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef TERM_H
|
#ifndef TERM_H
|
||||||
#define TERM_H
|
#define TERM_H
|
||||||
|
|
||||||
int term_init();
|
int term_init();
|
||||||
void kputs(const char* str);
|
void kputs(const char* str);
|
||||||
void putchar(char c);
|
void _putchar(char character);
|
||||||
|
|
||||||
enum TermColors
|
enum TermColors
|
||||||
{
|
{
|
||||||
@@ -20,4 +26,7 @@ typedef struct
|
|||||||
uint8_t characterSize; // height
|
uint8_t characterSize; // height
|
||||||
} PSF1_Header;
|
} PSF1_Header;
|
||||||
|
|
||||||
|
// debug
|
||||||
|
void term_scroll();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
31
src/kernel.h
31
src/kernel.h
@@ -1,3 +1,9 @@
|
|||||||
|
/*
|
||||||
|
* @author xamidev <xamidev@riseup.net>
|
||||||
|
* @brief Kernel global macros
|
||||||
|
* @license GPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef KERNEL_H
|
#ifndef KERNEL_H
|
||||||
#define KERNEL_H
|
#define KERNEL_H
|
||||||
|
|
||||||
@@ -12,12 +18,37 @@ enum ErrorCodes
|
|||||||
|
|
||||||
#include "io/serial/serial.h"
|
#include "io/serial/serial.h"
|
||||||
#include "io/term/printf.h"
|
#include "io/term/printf.h"
|
||||||
|
#include "idt/idt.h"
|
||||||
|
|
||||||
#define DEBUG(log, ...) fctprintf((void*)&skputc, 0, "debug: [%s]: " log "\r\n", __FILE__, ##__VA_ARGS__)
|
#define DEBUG(log, ...) fctprintf((void*)&skputc, 0, "debug: [%s]: " log "\r\n", __FILE__, ##__VA_ARGS__)
|
||||||
|
|
||||||
|
|
||||||
|
/* #define DEBUG(log, ...) \
|
||||||
|
printf("debug: [%s]: " log "\r\n", __FILE__, ##__VA_ARGS__); \
|
||||||
|
fctprintf((void*)&skputc, 0, "debug: [%s]: " log "\r\n", __FILE__, ##__VA_ARGS__)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define DIE_DEBUG(str) fctprintf((void*)&skputc, 0, str)
|
||||||
|
|
||||||
|
#define CHECK_BIT(var,pos) ((var) & (1<<(pos)))
|
||||||
|
|
||||||
// printf("debug: [%s]: " log "\n", __FILE__, ##__VA_ARGS__);
|
// printf("debug: [%s]: " log "\n", __FILE__, ##__VA_ARGS__);
|
||||||
|
|
||||||
|
void panic(struct cpu_status_t* ctx, const char* str);
|
||||||
void hcf();
|
void hcf();
|
||||||
|
void idle();
|
||||||
|
|
||||||
|
void debug_stack_trace(unsigned int max_frames);
|
||||||
|
const char* debug_find_symbol(uintptr_t rip, uintptr_t* offset);
|
||||||
|
|
||||||
#define assert(check) do { if(!(check)) hcf(); } while(0)
|
#define assert(check) do { if(!(check)) hcf(); } while(0)
|
||||||
|
|
||||||
|
struct boot_context
|
||||||
|
{
|
||||||
|
struct limine_framebuffer* fb;
|
||||||
|
struct limine_memmap_response* mmap;
|
||||||
|
struct limine_hhdm_response* hhdm;
|
||||||
|
struct limine_kernel_address_response* kaddr;
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
168
src/kmain.c
168
src/kmain.c
@@ -1,3 +1,9 @@
|
|||||||
|
/*
|
||||||
|
* @author xamidev <xamidev@riseup.net>
|
||||||
|
* @brief PepperOS kernel entry point
|
||||||
|
* @license GPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <limine.h>
|
#include <limine.h>
|
||||||
@@ -14,106 +20,124 @@
|
|||||||
#include "mem/paging/paging.h"
|
#include "mem/paging/paging.h"
|
||||||
#include "mem/paging/vmm.h"
|
#include "mem/paging/vmm.h"
|
||||||
#include "mem/heap/kheap.h"
|
#include "mem/heap/kheap.h"
|
||||||
|
#include "sched/process.h"
|
||||||
|
#include "sched/scheduler.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "io/term/flanterm.h"
|
||||||
|
#include "io/term/flanterm_backends/fb.h"
|
||||||
|
|
||||||
// Limine version used
|
// Limine version used
|
||||||
__attribute__((used, section(".limine_requests")))
|
__attribute__((used, section(".limine_requests")))
|
||||||
static volatile LIMINE_BASE_REVISION(3);
|
volatile LIMINE_BASE_REVISION(3);
|
||||||
|
|
||||||
// Framebuffer request
|
struct flanterm_context *ft_ctx;
|
||||||
__attribute__((used, section(".limine_requests")))
|
|
||||||
static volatile struct limine_framebuffer_request framebuffer_request = {
|
|
||||||
.id = LIMINE_FRAMEBUFFER_REQUEST,
|
|
||||||
.revision = 0
|
|
||||||
};
|
|
||||||
|
|
||||||
// Memory map request
|
// Halt and catch fire (makes machine stall)
|
||||||
__attribute__((used, section(".limine_requests")))
|
|
||||||
static volatile struct limine_memmap_request memmap_request = {
|
|
||||||
.id = LIMINE_MEMMAP_REQUEST,
|
|
||||||
.revision = 0
|
|
||||||
};
|
|
||||||
|
|
||||||
// Higher Half Direct Map
|
|
||||||
__attribute__((used, section(".limine_requests")))
|
|
||||||
static volatile struct limine_hhdm_request hhdm_request = {
|
|
||||||
.id = LIMINE_HHDM_REQUEST,
|
|
||||||
.revision = 0
|
|
||||||
};
|
|
||||||
|
|
||||||
// Executable Address/Kernel Address (find base phys/virt address of kernel)
|
|
||||||
__attribute__((used, section(".limine_requests")))
|
|
||||||
static volatile struct limine_kernel_address_request kerneladdr_request = {
|
|
||||||
.id = LIMINE_KERNEL_ADDRESS_REQUEST,
|
|
||||||
.revision = 0
|
|
||||||
};
|
|
||||||
|
|
||||||
__attribute__((used, section(".limine_requests_start")))
|
|
||||||
static volatile LIMINE_REQUESTS_START_MARKER;
|
|
||||||
|
|
||||||
__attribute__((used, section(".limine_requests_end")))
|
|
||||||
static volatile LIMINE_REQUESTS_END_MARKER;
|
|
||||||
|
|
||||||
struct limine_framebuffer* framebuffer;
|
|
||||||
|
|
||||||
// Panic (should dump registers etc. in the future)
|
|
||||||
void hcf()
|
void hcf()
|
||||||
{
|
{
|
||||||
for (;;)
|
CLEAR_INTERRUPTS; for (;;)asm("hlt");
|
||||||
{
|
|
||||||
asm("hlt");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Doing nothing (can be interrupted)
|
||||||
|
void idle() {SET_INTERRUPTS; for(;;)asm("hlt");}
|
||||||
|
|
||||||
|
uint8_t kernel_stack[KERNEL_STACK_SIZE] __attribute__((aligned(16)));
|
||||||
|
|
||||||
|
struct boot_context boot_ctx;
|
||||||
|
|
||||||
|
extern volatile struct limine_framebuffer_request framebuffer_request;
|
||||||
|
extern volatile struct limine_memmap_request memmap_request;
|
||||||
|
extern volatile struct limine_hhdm_request hhdm_request;
|
||||||
|
extern volatile struct limine_kernel_address_request kerneladdr_request;
|
||||||
|
|
||||||
|
extern struct process_t* processes_list;
|
||||||
|
extern struct process_t* current_process;
|
||||||
|
|
||||||
|
void pedicel_main(void* arg)
|
||||||
|
{
|
||||||
|
//printf("Hello, world from a KERNEL PROCESS!");
|
||||||
|
}
|
||||||
|
|
||||||
|
void two_main(void* arg)
|
||||||
|
{
|
||||||
|
//printf("...process 2 speaking!!!");
|
||||||
|
}
|
||||||
|
|
||||||
|
void idle_main(void* arg)
|
||||||
|
{
|
||||||
|
for(;;)asm("hlt");
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is our entry point
|
// This is our entry point
|
||||||
void kmain()
|
void kmain()
|
||||||
{
|
{
|
||||||
if (!LIMINE_BASE_REVISION_SUPPORTED) hcf();
|
if (!LIMINE_BASE_REVISION_SUPPORTED) hcf();
|
||||||
if (framebuffer_request.response == NULL || framebuffer_request.response->framebuffer_count < 1) hcf();
|
|
||||||
|
|
||||||
// We should probably grab all the boot info in a boot context struct
|
// Populate boot context
|
||||||
// that would be a bit cleaner than this mess
|
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;
|
||||||
|
|
||||||
// Get the first framebuffer from the response
|
pmm_init(boot_ctx.mmap, boot_ctx.hhdm);
|
||||||
framebuffer = framebuffer_request.response->framebuffers[0];
|
|
||||||
|
// Remap kernel , HHDM and framebuffer
|
||||||
|
paging_init(boot_ctx.kaddr, boot_ctx.fb);
|
||||||
|
|
||||||
|
uint32_t bgColor = 0x252525;
|
||||||
|
ft_ctx = flanterm_fb_init(
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
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->green_mask_size, boot_ctx.fb->green_mask_shift,
|
||||||
|
boot_ctx.fb->blue_mask_size, boot_ctx.fb->blue_mask_shift,
|
||||||
|
NULL,
|
||||||
|
NULL, NULL,
|
||||||
|
&bgColor, NULL, // &bgColor
|
||||||
|
NULL, NULL,
|
||||||
|
NULL, 0, 0, 1,
|
||||||
|
0, 0,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
serial_init();
|
serial_init();
|
||||||
|
|
||||||
if (memmap_request.response == NULL) hcf();
|
memmap_display(boot_ctx.mmap);
|
||||||
memmap_display(memmap_request.response);
|
hhdm_display(boot_ctx.hhdm);
|
||||||
|
DEBUG("kernel: phys_base=0x%p virt_base=0x%p", boot_ctx.kaddr->physical_base, boot_ctx.kaddr->virtual_base);
|
||||||
if (hhdm_request.response == NULL) hcf();
|
|
||||||
hhdm_display(hhdm_request.response);
|
|
||||||
|
|
||||||
if (kerneladdr_request.response == NULL) hcf();
|
|
||||||
DEBUG("kernel: phys_base=0x%p virt_base=0x%p", kerneladdr_request.response->physical_base, kerneladdr_request.response->virtual_base);
|
|
||||||
|
|
||||||
CLEAR_INTERRUPTS;
|
CLEAR_INTERRUPTS;
|
||||||
gdt_init();
|
gdt_init();
|
||||||
idt_init();
|
idt_init();
|
||||||
timer_init();
|
timer_init();
|
||||||
SET_INTERRUPTS;
|
|
||||||
|
|
||||||
pmm_init(memmap_request.response, hhdm_request.response);
|
|
||||||
|
|
||||||
// Remap kernel , HHDM and framebuffer
|
|
||||||
paging_init(kerneladdr_request.response, framebuffer);
|
|
||||||
|
|
||||||
kheap_init();
|
kheap_init();
|
||||||
|
|
||||||
void* ptr = kmalloc(10); DEBUG("(KMALLOC TEST) Allocated 10 bytes at 0x%p", ptr);
|
|
||||||
void* ptr2 = kmalloc(200); DEBUG("(KMALLOC TEST) Allocated 200 bytes at 0x%p", ptr2);
|
|
||||||
kfree(ptr);
|
|
||||||
void* ptr3 = kmalloc(5); DEBUG("(KMALLOC TEST) Allocated 5 bytes at 0x%p", ptr3);
|
|
||||||
|
|
||||||
vmm_init();
|
vmm_init();
|
||||||
|
|
||||||
keyboard_init(FR);
|
struct process_t* idle_proc = process_create("idle", (void*)idle_main, 0);
|
||||||
|
struct process_t* pedicel = process_create("pedicel", (void*)pedicel_main, 0);
|
||||||
|
struct process_t* two = process_create("two", (void*)two_main, 0);
|
||||||
|
|
||||||
term_init();
|
process_display_list(processes_list);
|
||||||
// Draw something
|
|
||||||
printf("%s, %s!\n", "Hello", "world");
|
scheduler_init();
|
||||||
// Yoohoooooo!
|
|
||||||
//DEBUG("kernel initialized successfully! hanging... wow=%d", 42);
|
current_process = idle_proc;
|
||||||
printf("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non justo a magna bibendum auctor viverra rutrum diam. In hac habitasse platea dictumst. Vestibulum suscipit ipsum eget tortor maximus lobortis. Donec vel ipsum id lacus fringilla bibendum id eget risus. Fusce vestibulum diam sit amet nunc ultricies, nec rutrum nibh congue. Donec fringilla a dui sit amet ullamcorper. Donec pharetra quis tortor id congue. Aliquam erat volutpat. Duis suscipit nulla vel ligula iaculis, in gravida mauris pellentesque. Vestibulum nunc nisl, posuere eu eros et, dictum molestie dolor. Donec posuere laoreet hendrerit. Suspendisse potenti. Proin fringilla vehicula malesuada. Quisque a dui est. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur nec aliquam lacus, at lacinia enim. ");
|
current_process->status = RUNNING;
|
||||||
hcf();
|
|
||||||
|
SET_INTERRUPTS;
|
||||||
|
|
||||||
|
keyboard_init(FR);
|
||||||
|
//term_init();
|
||||||
|
|
||||||
|
//printf(PEPPEROS_SPLASH);
|
||||||
|
|
||||||
|
//printf("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur eu diam id sem tincidunt vestibulum. Etiam sed congue nisl, vitae aliquet orci. Donec magna turpis, semper sed ipsum eget, semper blandit dolor. Morbi faucibus posuere sapien. Vestibulum aliquet mi vel orci finibus, vestibulum rhoncus tellus sagittis. Vivamus a arcu suscipit sem iaculis volutpat vel nec est. Nulla malesuada, urna vel pretium pretium, enim tortor pulvinar velit, porttitor dictum lectus turpis id tortor. Quisque egestas ultricies lorem, egestas ultrices tellus elementum porta. Fusce consequat nisi in diam placerat fermentum. Suspendisse tempus turpis nec turpis condimentum fringilla. Maecenas nec orci pharetra, feugiat enim vel, viverra neque. Vivamus placerat purus in tincidunt ultricies. Pellentesque vel mi molestie, congue nibh nec, cursus nisl. Cras dapibus lectus mauris, sed interdum risus tristique non. ");
|
||||||
|
|
||||||
|
flanterm_write(ft_ctx, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur eu diam id sem tincidunt vestibulum. Etiam sed congue nisl, vitae aliquet orci. Donec magna turpis, semper sed ipsum eget, semper blandit dolor. Morbi faucibus posuere sapien. Vestibulum aliquet mi vel orci finibus, vestibulum rhoncus tellus sagittis. Vivamus a arcu suscipit sem iaculis volutpat vel nec est. Nulla malesuada, urna vel pretium pretium, enim tortor pulvinar velit, porttitor dictum lectus turpis id tortor. Quisque egestas ultricies lorem, egestas ultrices tellus elementum porta. Fusce consequat nisi in diam placerat fermentum. Suspendisse tempus turpis nec turpis condimentum fringilla. Maecenas nec orci pharetra, feugiat enim vel, viverra neque. Vivamus placerat purus in tincidunt ultricies. Pellentesque vel mi molestie, congue nibh nec, cursus nisl. Cras dapibus lectus mauris, sed interdum risus tristique non.", sizeof("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur eu diam id sem tincidunt vestibulum. Etiam sed congue nisl, vitae aliquet orci. Donec magna turpis, semper sed ipsum eget, semper blandit dolor. Morbi faucibus posuere sapien. Vestibulum aliquet mi vel orci finibus, vestibulum rhoncus tellus sagittis. Vivamus a arcu suscipit sem iaculis volutpat vel nec est. Nulla malesuada, urna vel pretium pretium, enim tortor pulvinar velit, porttitor dictum lectus turpis id tortor. Quisque egestas ultricies lorem, egestas ultrices tellus elementum porta. Fusce consequat nisi in diam placerat fermentum. Suspendisse tempus turpis nec turpis condimentum fringilla. Maecenas nec orci pharetra, feugiat enim vel, viverra neque. Vivamus placerat purus in tincidunt ultricies. Pellentesque vel mi molestie, congue nibh nec, cursus nisl. Cras dapibus lectus mauris, sed interdum risus tristique non. "));
|
||||||
|
|
||||||
|
idle();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
/*
|
||||||
|
* @author xamidev <xamidev@riseup.net>
|
||||||
|
* @brief Global Descriptor Table (for legacy reasons)
|
||||||
|
* @license GPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
#include "gdt.h"
|
#include "gdt.h"
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "io/serial/serial.h"
|
#include "io/serial/serial.h"
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
/*
|
||||||
|
* @author xamidev <xamidev@riseup.net>
|
||||||
|
* @brief Global Descriptor Table (for legacy reasons)
|
||||||
|
* @license GPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef GDT_H
|
#ifndef GDT_H
|
||||||
#define GDT_H
|
#define GDT_H
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,16 @@
|
|||||||
|
/*
|
||||||
|
* @author xamidev <xamidev@riseup.net>
|
||||||
|
* @brief Kernel heap
|
||||||
|
* @license GPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
#include "kheap.h"
|
#include "kheap.h"
|
||||||
#include "mem/paging/paging.h"
|
#include "mem/paging/paging.h"
|
||||||
#include "mem/paging/pmm.h"
|
#include "mem/paging/pmm.h"
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <kernel.h>
|
#include <kernel.h>
|
||||||
|
#include "sched/process.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;
|
||||||
@@ -15,12 +23,24 @@ static uintptr_t end;
|
|||||||
// Kernel root table (level 4)
|
// Kernel root table (level 4)
|
||||||
extern uint64_t *kernel_pml4;
|
extern uint64_t *kernel_pml4;
|
||||||
|
|
||||||
static void kheap_map_page()
|
static void kheap_grow(size_t size)
|
||||||
|
{
|
||||||
|
size_t pages = ALIGN_UP(size + sizeof(struct heap_block_t), PAGE_SIZE) / PAGE_SIZE;
|
||||||
|
|
||||||
|
if (pages == 0) pages = 1;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < pages; i++)
|
||||||
|
{
|
||||||
|
kheap_map_page();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void kheap_map_page()
|
||||||
{
|
{
|
||||||
uintptr_t phys = pmm_alloc();
|
uintptr_t phys = pmm_alloc();
|
||||||
paging_map_page(kernel_pml4, end, phys, PTE_PRESENT | PTE_WRITABLE | PTE_NOEXEC);
|
paging_map_page(kernel_pml4, end, phys, PTE_PRESENT | PTE_WRITABLE | PTE_NOEXEC);
|
||||||
end += PAGE_SIZE;
|
end += PAGE_SIZE;
|
||||||
DEBUG("Mapped first kheap page");
|
//DEBUG("Mapped first kheap page");
|
||||||
}
|
}
|
||||||
|
|
||||||
void kheap_init()
|
void kheap_init()
|
||||||
@@ -43,6 +63,7 @@ void* kmalloc(size_t size)
|
|||||||
{
|
{
|
||||||
// No size, no memory allocated!
|
// No size, no memory allocated!
|
||||||
if (!size) return NULL;
|
if (!size) return NULL;
|
||||||
|
size = ALIGN(size);
|
||||||
|
|
||||||
struct heap_block_t* curr = head;
|
struct heap_block_t* curr = head;
|
||||||
|
|
||||||
@@ -52,17 +73,16 @@ void* kmalloc(size_t size)
|
|||||||
if (curr->free && curr->size >= size)
|
if (curr->free && curr->size >= size)
|
||||||
{
|
{
|
||||||
// We split the block if it is big enough
|
// We split the block if it is big enough
|
||||||
if (curr->size > size + sizeof(struct heap_block_t))
|
if (curr->size >= size + BLOCK_MIN_SIZE)
|
||||||
{
|
{
|
||||||
struct heap_block_t* new_block = (struct heap_block_t*)((uintptr_t)curr + sizeof(struct heap_block_t) + size);
|
//struct heap_block_t* new_block = (struct heap_block_t*)((uintptr_t)curr + sizeof(struct heap_block_t) + size);
|
||||||
// We have to subtract the size of our block struct
|
struct heap_block_t* split = (struct heap_block_t*)((uintptr_t)curr + sizeof(*curr) + size);
|
||||||
new_block->size = curr->size - size - sizeof(struct heap_block_t);
|
|
||||||
new_block->free = true;
|
|
||||||
|
|
||||||
// Then we chain up the block in the list
|
split->size = curr->size - size - sizeof(*curr);
|
||||||
new_block->next = curr->next;
|
split->free = true;
|
||||||
curr->next = new_block;
|
split->next = curr->next;
|
||||||
|
|
||||||
|
curr->next = split;
|
||||||
curr->size = size;
|
curr->size = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,14 +94,14 @@ void* kmalloc(size_t size)
|
|||||||
curr = curr->next;
|
curr = curr->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we're hear it means we didn't have enough memory
|
// If we're here it means we didn't have enough memory
|
||||||
// for the block allocation. So we will allocate more..
|
// for the block allocation. So we will allocate more..
|
||||||
uintptr_t old_end = end;
|
uintptr_t old_end = end;
|
||||||
kheap_map_page();
|
kheap_grow(size + sizeof(struct heap_block_t));
|
||||||
|
|
||||||
struct heap_block_t* block = (struct heap_block_t*)old_end;
|
struct heap_block_t* block = (struct heap_block_t*)old_end;
|
||||||
block->size = PAGE_SIZE - sizeof(struct heap_block_t);
|
block->size = ALIGN_UP(end - old_end - sizeof(struct heap_block_t), 16);
|
||||||
block->free = false;
|
block->free = true;
|
||||||
block->next = NULL;
|
block->next = NULL;
|
||||||
|
|
||||||
// Put the block at the end of the list
|
// Put the block at the end of the list
|
||||||
@@ -92,7 +112,7 @@ void* kmalloc(size_t size)
|
|||||||
}
|
}
|
||||||
curr->next = block;
|
curr->next = block;
|
||||||
|
|
||||||
return (void*)((uintptr_t)block + sizeof(struct heap_block_t));
|
return kmalloc(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void kfree(void* ptr)
|
void kfree(void* ptr)
|
||||||
@@ -103,4 +123,25 @@ void kfree(void* ptr)
|
|||||||
// Set it free!
|
// Set it free!
|
||||||
struct heap_block_t* block = (struct heap_block_t*)((uintptr_t)ptr - sizeof(struct heap_block_t));
|
struct heap_block_t* block = (struct heap_block_t*)((uintptr_t)ptr - sizeof(struct heap_block_t));
|
||||||
block->free = true;
|
block->free = true;
|
||||||
|
|
||||||
|
// merge adjacent free blocks (coalescing)
|
||||||
|
struct heap_block_t* curr = head;
|
||||||
|
while (curr && curr->next)
|
||||||
|
{
|
||||||
|
if (curr->free && curr->next->free)
|
||||||
|
{
|
||||||
|
curr->size += sizeof(*curr) + curr->next->size;
|
||||||
|
curr->next = curr->next->next;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
curr = curr->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should alloc enough for a stack (at least 64kb) to be used for a process.
|
||||||
|
// Should return a pointer to top of the stack (as stack grows DOWNWARDS)
|
||||||
|
void* kalloc_stack()
|
||||||
|
{
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,9 @@
|
|||||||
|
/*
|
||||||
|
* @author xamidev <xamidev@riseup.net>
|
||||||
|
* @brief Kernel heap
|
||||||
|
* @license GPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef KHEAP_H
|
#ifndef KHEAP_H
|
||||||
#define KHEAP_H
|
#define KHEAP_H
|
||||||
|
|
||||||
@@ -6,9 +12,6 @@
|
|||||||
// When the kernel heap is ready, we can alloc our VM object linked list
|
// When the kernel heap is ready, we can alloc our VM object linked list
|
||||||
// and then continue working on the VMM.
|
// and then continue working on the VMM.
|
||||||
|
|
||||||
// 16MB should be enough for some linked lists
|
|
||||||
#define KHEAP_SIZE (16*1024*1024)
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
@@ -22,5 +25,7 @@ struct heap_block_t
|
|||||||
void kheap_init();
|
void kheap_init();
|
||||||
void* kmalloc(size_t size);
|
void* kmalloc(size_t size);
|
||||||
void kfree(void* ptr);
|
void kfree(void* ptr);
|
||||||
|
void* kalloc_stack();
|
||||||
|
void kheap_map_page();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -1,3 +1,9 @@
|
|||||||
|
/*
|
||||||
|
* @author xamidev <xamidev@riseup.net>
|
||||||
|
* @brief Common memory utilities
|
||||||
|
* @license GPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <limine.h>
|
#include <limine.h>
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
/*
|
||||||
|
* @author xamidev <xamidev@riseup.net>
|
||||||
|
* @brief Common memory utilities
|
||||||
|
* @license GPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef MEM_UTILS_H
|
#ifndef MEM_UTILS_H
|
||||||
#define MEM_UTILS_H
|
#define MEM_UTILS_H
|
||||||
|
|
||||||
@@ -8,6 +14,7 @@ void* memset(void* s, int c, size_t n);
|
|||||||
void* memmove(void *dest, const void* src, size_t n);
|
void* memmove(void *dest, const void* src, size_t n);
|
||||||
int memcmp(const void* s1, const void* s2, size_t n);
|
int memcmp(const void* s1, const void* s2, size_t n);
|
||||||
|
|
||||||
|
// DEBUG
|
||||||
void memmap_display(struct limine_memmap_response* response);
|
void memmap_display(struct limine_memmap_response* response);
|
||||||
void hhdm_display(struct limine_hhdm_response* hhdm);
|
void hhdm_display(struct limine_hhdm_response* hhdm);
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,15 @@
|
|||||||
|
/*
|
||||||
|
* @author xamidev <xamidev@riseup.net>
|
||||||
|
* @brief x64 4-level paging implementation
|
||||||
|
* @license GPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
#include "paging.h"
|
#include "paging.h"
|
||||||
#include "pmm.h"
|
#include "pmm.h"
|
||||||
#include <kernel.h>
|
#include <kernel.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <limine.h>
|
#include <limine.h>
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Paging on x86 uses four different page table levels:
|
Paging on x86 uses four different page table levels:
|
||||||
@@ -17,7 +24,7 @@ If we use 1GB huge pages: PML4 -> PDPT -> 1gb pages
|
|||||||
4KB (regular size): PML4 -> PDPT -> PD -> PT -> 4kb pages
|
4KB (regular size): PML4 -> PDPT -> PD -> PT -> 4kb pages
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static inline void load_cr3(uint64_t value) {
|
void load_cr3(uint64_t value) {
|
||||||
asm volatile ("mov %0, %%cr3" :: "r"(value) : "memory");
|
asm volatile ("mov %0, %%cr3" :: "r"(value) : "memory");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,7 +76,7 @@ void paging_map_page(uint64_t* root_table, uint64_t virt, uint64_t phys, uint64_
|
|||||||
root_table[pml4_i] = VIRT_TO_PHYS(pdpt) | PTE_PRESENT | PTE_WRITABLE;
|
root_table[pml4_i] = VIRT_TO_PHYS(pdpt) | PTE_PRESENT | PTE_WRITABLE;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
pdpt = (uint64_t *)PHYS_TO_VIRT(root_table[pml4_i] & ~0xFFFULL);
|
pdpt = (uint64_t *)PHYS_TO_VIRT(root_table[pml4_i] & PTE_ADDR_MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
// PDPT: same here
|
// PDPT: same here
|
||||||
@@ -79,7 +86,7 @@ void paging_map_page(uint64_t* root_table, uint64_t virt, uint64_t phys, uint64_
|
|||||||
pdpt[pdpt_i] = VIRT_TO_PHYS(pd) | PTE_PRESENT | PTE_WRITABLE;
|
pdpt[pdpt_i] = VIRT_TO_PHYS(pd) | PTE_PRESENT | PTE_WRITABLE;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
pd = (uint64_t *)PHYS_TO_VIRT(pdpt[pdpt_i] & ~0xFFFULL);
|
pd = (uint64_t *)PHYS_TO_VIRT(pdpt[pdpt_i] & PTE_ADDR_MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
// PD: and here
|
// PD: and here
|
||||||
@@ -89,7 +96,7 @@ void paging_map_page(uint64_t* root_table, uint64_t virt, uint64_t phys, uint64_
|
|||||||
pd[pd_i] = VIRT_TO_PHYS(pt) | PTE_PRESENT | PTE_WRITABLE;
|
pd[pd_i] = VIRT_TO_PHYS(pt) | PTE_PRESENT | PTE_WRITABLE;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
pt = (uint64_t *)PHYS_TO_VIRT(pd[pd_i] & ~0xFFFULL);
|
pt = (uint64_t *)PHYS_TO_VIRT(pd[pd_i] & PTE_ADDR_MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
// PT: finally, populate the page table entry
|
// PT: finally, populate the page table entry
|
||||||
@@ -102,13 +109,16 @@ void paging_map_page(uint64_t* root_table, uint64_t virt, uint64_t phys, uint64_
|
|||||||
uint64_t kernel_phys_base;
|
uint64_t kernel_phys_base;
|
||||||
uint64_t kernel_virt_base;
|
uint64_t kernel_virt_base;
|
||||||
|
|
||||||
void paging_init(struct limine_kernel_address_response* kaddr, struct limine_framebuffer* fb)
|
extern struct boot_context boot_ctx;
|
||||||
|
|
||||||
|
void paging_init()
|
||||||
{
|
{
|
||||||
// We should map the kernel, GDT, IDT, stack, framebuffer.
|
// We should map the kernel, GDT, IDT, stack, framebuffer.
|
||||||
// Optionally we could map ACPI tables (we can find them in the Limine memmap)
|
// Optionally we could map ACPI tables (we can find them in the Limine memmap)
|
||||||
|
|
||||||
kernel_phys_base = kaddr->physical_base;
|
kernel_phys_base = boot_ctx.kaddr->physical_base;
|
||||||
kernel_virt_base = kaddr->virtual_base;
|
kernel_virt_base = boot_ctx.kaddr->virtual_base;
|
||||||
|
struct limine_framebuffer* fb = boot_ctx.fb;
|
||||||
|
|
||||||
DEBUG("Kernel lives at virt=0x%p phys=0x%p", kernel_virt_base, kernel_phys_base);
|
DEBUG("Kernel lives at virt=0x%p phys=0x%p", kernel_virt_base, kernel_phys_base);
|
||||||
|
|
||||||
@@ -117,14 +127,38 @@ void paging_init(struct limine_kernel_address_response* kaddr, struct limine_fra
|
|||||||
// for debug
|
// for debug
|
||||||
uint64_t page_count = 0;
|
uint64_t page_count = 0;
|
||||||
|
|
||||||
// HHDM map first 1 GB using given offset
|
// Find max physical address from limine memmap
|
||||||
for (uint64_t i=0; i<0x40000000; i += PAGE_SIZE)
|
uint64_t max_phys = 0;
|
||||||
|
for (uint64_t i=0; i<boot_ctx.mmap->entry_count; i++)
|
||||||
|
{
|
||||||
|
struct limine_memmap_entry* entry = boot_ctx.mmap->entries[i];
|
||||||
|
if (entry->length == 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
uint64_t top = entry->base + entry->length;
|
||||||
|
if (top > max_phys)
|
||||||
|
{
|
||||||
|
max_phys = top;
|
||||||
|
}
|
||||||
|
//DEBUG("max_phys=0x%p", max_phys);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4GB
|
||||||
|
if (max_phys > 0x100000000)
|
||||||
|
{
|
||||||
|
DEBUG("WARNING: max_phys capped to 4GB (0x100000000) (from max_phys=%p)", max_phys);
|
||||||
|
max_phys = 0x100000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
// HHDM map up to max_phys or 4GB, whichever is smaller, using given offset
|
||||||
|
for (uint64_t i=0; i<max_phys; i += PAGE_SIZE)
|
||||||
{
|
{
|
||||||
//paging_kmap_page(i+hhdm_off, i, PTE_WRITABLE);
|
//paging_kmap_page(i+hhdm_off, i, PTE_WRITABLE);
|
||||||
paging_map_page(kernel_pml4, i+hhdm_off, i, PTE_WRITABLE);
|
paging_map_page(kernel_pml4, i+hhdm_off, i, PTE_WRITABLE | PTE_PRESENT);
|
||||||
page_count++;
|
page_count++;
|
||||||
}
|
}
|
||||||
DEBUG("Mapped %u pages for first 1GB (HHDM)", page_count); page_count = 0;
|
DEBUG("Mapped %u pages up to 0x%p (HHDM)", page_count, max_phys); page_count = 0;
|
||||||
|
|
||||||
// Map the kernel (according to virt/phys_base given by Limine)
|
// Map the kernel (according to virt/phys_base given by Limine)
|
||||||
// SOME DAY when we want a safer kernel we should map .text as Read/Exec
|
// SOME DAY when we want a safer kernel we should map .text as Read/Exec
|
||||||
@@ -153,6 +187,14 @@ void paging_init(struct limine_kernel_address_response* kaddr, struct limine_fra
|
|||||||
}
|
}
|
||||||
DEBUG("Mapped %u pages for framebuffer", page_count);
|
DEBUG("Mapped %u pages for framebuffer", page_count);
|
||||||
|
|
||||||
|
// test for flanterm
|
||||||
|
// When 10 pages are mapped, SOMETIMES (1 out of 50 times) it prints everything without problem!
|
||||||
|
// Other times it prints garbage (almost full cursors) and/or panics.
|
||||||
|
/* for (uint64_t i=0; i<10; i++)
|
||||||
|
{
|
||||||
|
paging_map_page(kernel_pml4, 0, kernel_phys_base+KERNEL_SIZE+i*PAGE_SIZE, PTE_WRITABLE);
|
||||||
|
} */
|
||||||
|
|
||||||
// Finally, we load the physical address of our PML4 (root table) into cr3
|
// Finally, we load the physical address of our PML4 (root table) into cr3
|
||||||
load_cr3(VIRT_TO_PHYS(kernel_pml4));
|
load_cr3(VIRT_TO_PHYS(kernel_pml4));
|
||||||
DEBUG("cr3 loaded, we're still alive");
|
DEBUG("cr3 loaded, we're still alive");
|
||||||
|
|||||||
@@ -1,24 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* @author xamidev <xamidev@riseup.net>
|
||||||
|
* @brief x64 4-level paging implementation
|
||||||
|
* @license GPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef PAGING_H
|
#ifndef PAGING_H
|
||||||
#define PAGING_H
|
#define PAGING_H
|
||||||
|
|
||||||
#define PAGE_SIZE 4096
|
#define PAGE_SIZE 4096
|
||||||
#define BITS_PER_ROW 64
|
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <limine.h>
|
#include <limine.h>
|
||||||
|
#include "mem/heap/kheap.h"
|
||||||
|
|
||||||
void paging_init(struct limine_kernel_address_response* kaddr, struct limine_framebuffer* fb);
|
void paging_init();
|
||||||
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);
|
||||||
|
|
||||||
|
// To swap root page tables
|
||||||
|
void load_cr3(uint64_t value);
|
||||||
|
|
||||||
extern uint64_t hhdm_off;
|
extern uint64_t hhdm_off;
|
||||||
|
|
||||||
#define PHYS_TO_VIRT(x) ((void*)((uintptr_t)(x) + hhdm_off))
|
#define PHYS_TO_VIRT(x) ((void*)((uintptr_t)(x) + hhdm_off))
|
||||||
#define VIRT_TO_PHYS(x) ((uintptr_t)(x) - hhdm_off)
|
#define VIRT_TO_PHYS(x) ((uintptr_t)(x) - hhdm_off)
|
||||||
|
|
||||||
|
#define PTE_ADDR_MASK 0x000FFFFFFFFFF000
|
||||||
// Stole it
|
// Stole it
|
||||||
#define ALIGN_UP(x, align) (((x) + ((align) - 1)) & ~((align) - 1))
|
#define ALIGN_UP(x, align) (((x) + ((align) - 1)) & ~((align) - 1))
|
||||||
#define ALIGN_DOWN(x, align) ((x) & ~((align) - 1))
|
#define ALIGN_DOWN(x, align) ((x) & ~((align) - 1))
|
||||||
#define PAGE_ALIGN_DOWN(x) ((x) & ~0xFFFULL)
|
#define PAGE_ALIGN_DOWN(x) ((x) & PTE_ADDR_MASK)
|
||||||
|
|
||||||
|
#define ALIGN(size) ALIGN_UP(size, 16)
|
||||||
|
#define BLOCK_MIN_SIZE (sizeof(struct heap_block_t) + 16)
|
||||||
|
|
||||||
#define PML4_INDEX(x) (((x) >> 39) & 0x1FF)
|
#define PML4_INDEX(x) (((x) >> 39) & 0x1FF)
|
||||||
#define PDPT_INDEX(x) (((x) >> 30) & 0x1FF)
|
#define PDPT_INDEX(x) (((x) >> 30) & 0x1FF)
|
||||||
@@ -35,10 +48,4 @@ extern uint64_t hhdm_off;
|
|||||||
#define PTE_HUGE (1ULL << 7)
|
#define PTE_HUGE (1ULL << 7)
|
||||||
#define PTE_NOEXEC (1ULL << 63)
|
#define PTE_NOEXEC (1ULL << 63)
|
||||||
|
|
||||||
// Specified in linker.ld
|
|
||||||
#define KERNEL_BASE 0xFFFFFFFF80000000ULL
|
|
||||||
|
|
||||||
// 2 MB should be enough (as of now, the whole kernel ELF is around 75kb)
|
|
||||||
#define KERNEL_SIZE 0x200000
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -1,4 +1,8 @@
|
|||||||
// OMG here we are. I'm cooked.
|
/*
|
||||||
|
* @author xamidev <xamidev@riseup.net>
|
||||||
|
* @brief Physical memory manager from freelist
|
||||||
|
* @license GPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
pmm - Physical Memory Manager
|
pmm - Physical Memory Manager
|
||||||
@@ -62,7 +66,10 @@ static uintptr_t g_freelist = 0;
|
|||||||
|
|
||||||
uintptr_t pmm_alloc()
|
uintptr_t pmm_alloc()
|
||||||
{
|
{
|
||||||
if (!g_freelist) return 0;
|
if (!g_freelist)
|
||||||
|
{
|
||||||
|
panic(NULL, "PMM is out of memory!");
|
||||||
|
}
|
||||||
uintptr_t addr = g_freelist;
|
uintptr_t addr = g_freelist;
|
||||||
g_freelist = *(uintptr_t*) PHYS_TO_VIRT(g_freelist);
|
g_freelist = *(uintptr_t*) PHYS_TO_VIRT(g_freelist);
|
||||||
return addr;
|
return addr;
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
/*
|
||||||
|
* @author xamidev <xamidev@riseup.net>
|
||||||
|
* @brief Physical memory manager from freelist
|
||||||
|
* @license GPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef PAGING_PMM_H
|
#ifndef PAGING_PMM_H
|
||||||
#define PAGING_PMM_H
|
#define PAGING_PMM_H
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
/*
|
||||||
|
* @author xamidev <xamidev@riseup.net>
|
||||||
|
* @brief Virtual memory manager
|
||||||
|
* @license GPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The VMM (virtual memory manager) will have two roles:
|
The VMM (virtual memory manager) will have two roles:
|
||||||
- mapping pages
|
- mapping pages
|
||||||
@@ -49,7 +55,7 @@ void vmm_setup_pt_root()
|
|||||||
DEBUG("VMM setup: vmm_pt_root=0x%p (phys=0x%p)", vmm_pt_root, phys);
|
DEBUG("VMM setup: vmm_pt_root=0x%p (phys=0x%p)", vmm_pt_root, phys);
|
||||||
}
|
}
|
||||||
|
|
||||||
void* vmm_alloc(size_t length, size_t flags)
|
/* 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
|
// 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
|
// the next page so its coherent with the PMM
|
||||||
@@ -58,7 +64,7 @@ void* vmm_alloc(size_t length, size_t flags)
|
|||||||
// Need to implement this (as linked list)
|
// Need to implement this (as linked list)
|
||||||
// but for now kernel heap is sufficient
|
// but for now kernel heap is sufficient
|
||||||
// The VMM will prob be more useful when we have userspace
|
// The VMM will prob be more useful when we have userspace
|
||||||
}
|
} */
|
||||||
|
|
||||||
void vmm_init()
|
void vmm_init()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
/*
|
||||||
|
* @author xamidev <xamidev@riseup.net>
|
||||||
|
* @brief Virtual memory manager
|
||||||
|
* @license GPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef VMM_H
|
#ifndef VMM_H
|
||||||
#define VMM_H
|
#define VMM_H
|
||||||
|
|
||||||
|
|||||||
176
src/sched/process.c
Normal file
176
src/sched/process.c
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
/*
|
||||||
|
* @author xamidev <xamidev@riseup.net>
|
||||||
|
* @brief Process linked list implementation
|
||||||
|
* @license GPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include "process.h"
|
||||||
|
#include "mem/heap/kheap.h"
|
||||||
|
#include "kernel.h"
|
||||||
|
#include "string/string.h"
|
||||||
|
#include "mem/gdt/gdt.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "io/serial/serial.h"
|
||||||
|
|
||||||
|
struct process_t* processes_list;
|
||||||
|
struct process_t* current_process;
|
||||||
|
|
||||||
|
extern uint64_t *kernel_pml4;
|
||||||
|
|
||||||
|
size_t next_free_pid = 0;
|
||||||
|
|
||||||
|
void process_init()
|
||||||
|
{
|
||||||
|
processes_list = NULL;
|
||||||
|
current_process = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only for debug
|
||||||
|
void process_display_list(struct process_t* processes_list)
|
||||||
|
{
|
||||||
|
int process_view_id = 0;
|
||||||
|
struct process_t* tmp = processes_list;
|
||||||
|
while (tmp != NULL)
|
||||||
|
{
|
||||||
|
DEBUG("{%d: %p} -> ", process_view_id, tmp);
|
||||||
|
tmp = tmp->next;
|
||||||
|
process_view_id++;
|
||||||
|
}
|
||||||
|
DEBUG("NULL");
|
||||||
|
}
|
||||||
|
|
||||||
|
struct process_t* process_create(char* name, void(*function)(void*), void* arg)
|
||||||
|
{
|
||||||
|
CLEAR_INTERRUPTS;
|
||||||
|
struct process_t* proc = (struct process_t*)kmalloc(sizeof(struct process_t));
|
||||||
|
|
||||||
|
struct cpu_status_t* ctx = (struct cpu_status_t*)kmalloc(sizeof(struct cpu_status_t));
|
||||||
|
|
||||||
|
// No more memory?
|
||||||
|
if (!proc) return NULL;
|
||||||
|
if (!ctx) return NULL;
|
||||||
|
|
||||||
|
strncpy(proc->name, name, PROCESS_NAME_MAX);
|
||||||
|
proc->pid = next_free_pid++;
|
||||||
|
proc->status = READY;
|
||||||
|
|
||||||
|
uint64_t* stack_top = (uint64_t*)kalloc_stack();
|
||||||
|
// push return address to the stack so when "ret" hits we jmp to exit instead of idk what
|
||||||
|
// stack grows DOWNWARDS!!
|
||||||
|
*(--stack_top) = (uint64_t)process_exit;
|
||||||
|
|
||||||
|
proc->context = ctx;
|
||||||
|
proc->context->iret_ss = KERNEL_DATA_SEGMENT; // process will live in kernel mode
|
||||||
|
proc->context->iret_rsp = (uint64_t)stack_top;
|
||||||
|
proc->context->iret_flags = 0x202; //bit 2 and 9 set (Interrupt Flag)
|
||||||
|
proc->context->iret_cs = KERNEL_CODE_SEGMENT;
|
||||||
|
proc->context->iret_rip = (uint64_t)function; // beginning of executable code
|
||||||
|
proc->context->rdi = (uint64_t)arg; // 1st arg is in rdi (as per x64 calling convention)
|
||||||
|
proc->context->rbp = 0;
|
||||||
|
|
||||||
|
// Kernel PML4 as it already maps code/stack (when switching to userland we'll have to change that)
|
||||||
|
proc->root_page_table = kernel_pml4;
|
||||||
|
|
||||||
|
proc->next = 0;
|
||||||
|
|
||||||
|
process_add(&processes_list, proc);
|
||||||
|
|
||||||
|
SET_INTERRUPTS;
|
||||||
|
return proc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void process_add(struct process_t** processes_list, struct process_t* process)
|
||||||
|
{
|
||||||
|
if (!process) return;
|
||||||
|
process->next = NULL;
|
||||||
|
|
||||||
|
if (*processes_list == NULL)
|
||||||
|
{
|
||||||
|
// List is empty
|
||||||
|
*processes_list = process;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct process_t* tmp = *processes_list;
|
||||||
|
while (tmp->next != NULL)
|
||||||
|
{
|
||||||
|
tmp = tmp->next;
|
||||||
|
}
|
||||||
|
// We're at last process before NULL
|
||||||
|
tmp->next = process;
|
||||||
|
// process->next = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void process_delete(struct process_t** processes_list, struct process_t* process)
|
||||||
|
{
|
||||||
|
if (!processes_list || !*processes_list || !process) return;
|
||||||
|
|
||||||
|
if (*processes_list == process)
|
||||||
|
{
|
||||||
|
// process to delete is at head
|
||||||
|
*processes_list = process->next;
|
||||||
|
process->next = NULL;
|
||||||
|
kfree(process);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct process_t* tmp = *processes_list;
|
||||||
|
while (tmp->next && tmp->next != process)
|
||||||
|
{
|
||||||
|
tmp = tmp->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tmp->next == NULL)
|
||||||
|
{
|
||||||
|
// Didn't find the process
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We're at process before the one we want to delete
|
||||||
|
tmp->next = process->next;
|
||||||
|
process->next = NULL;
|
||||||
|
kfree(process);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct process_t* process_get_next(struct process_t* process)
|
||||||
|
{
|
||||||
|
if (!process) return NULL;
|
||||||
|
return process->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
// (from gdt) This will switch tasks ONLY in ring 0
|
||||||
|
// KERNEL CS = 0x08
|
||||||
|
// KERNEL SS = 0x10
|
||||||
|
__attribute__((naked, noreturn))
|
||||||
|
void process_switch(uint64_t stack_addr, uint64_t code_addr)
|
||||||
|
{
|
||||||
|
asm volatile(" \
|
||||||
|
push $0x10 \n\
|
||||||
|
push %0 \n\
|
||||||
|
push $0x202 \n\
|
||||||
|
push $0x08 \n\
|
||||||
|
push %1 \n\
|
||||||
|
iretq \n\
|
||||||
|
" :: "r"(stack_addr), "r"(code_addr));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Will be used to clean up resources (if any, when we implement it)
|
||||||
|
// Just mark as DEAD then idle. Scheduler will delete process at next timer interrupt % quantum.
|
||||||
|
void process_exit()
|
||||||
|
{
|
||||||
|
DEBUG("Exiting from process '%s'", current_process->name);
|
||||||
|
CLEAR_INTERRUPTS;
|
||||||
|
if (current_process)
|
||||||
|
{
|
||||||
|
current_process->status = DEAD;
|
||||||
|
}
|
||||||
|
SET_INTERRUPTS;
|
||||||
|
|
||||||
|
outb(0x20, 0x20);
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
asm("hlt");
|
||||||
|
}
|
||||||
|
}
|
||||||
42
src/sched/process.h
Normal file
42
src/sched/process.h
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* @author xamidev <xamidev@riseup.net>
|
||||||
|
* @brief Process definition
|
||||||
|
* @license GPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PROCESS_H
|
||||||
|
#define PROCESS_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include "config.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
READY,
|
||||||
|
RUNNING,
|
||||||
|
DEAD
|
||||||
|
} status_t;
|
||||||
|
|
||||||
|
struct process_t
|
||||||
|
{
|
||||||
|
size_t pid;
|
||||||
|
char name[PROCESS_NAME_MAX];
|
||||||
|
|
||||||
|
status_t status;
|
||||||
|
struct cpu_status_t* context;
|
||||||
|
void* root_page_table; // Process PML4 (should contain kernel PML4 in higher half [256-511]
|
||||||
|
struct process_t* next;
|
||||||
|
};
|
||||||
|
|
||||||
|
void process_init();
|
||||||
|
struct process_t* process_create(char* name, void(*function)(void*), void* arg);
|
||||||
|
void process_add(struct process_t** processes_list, struct process_t* process);
|
||||||
|
void process_delete(struct process_t** processes_list, struct process_t* process);
|
||||||
|
struct process_t* process_get_next(struct process_t* process);
|
||||||
|
void process_switch(uint64_t stack_addr, uint64_t code_addr);
|
||||||
|
void process_exit();
|
||||||
|
|
||||||
|
void process_display_list(struct process_t* processes_list);
|
||||||
|
|
||||||
|
#endif
|
||||||
55
src/sched/scheduler.c
Normal file
55
src/sched/scheduler.c
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* @author xamidev <xamidev@riseup.net>
|
||||||
|
* @brief Round-robin scheduler
|
||||||
|
* @license GPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "kernel.h"
|
||||||
|
#include "process.h"
|
||||||
|
#include "mem/paging/paging.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "io/serial/serial.h"
|
||||||
|
|
||||||
|
extern struct process_t* processes_list;
|
||||||
|
extern struct process_t* current_process;
|
||||||
|
|
||||||
|
void scheduler_init()
|
||||||
|
{
|
||||||
|
// Choose first process?
|
||||||
|
current_process = processes_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct cpu_status_t* scheduler_schedule(struct cpu_status_t* context)
|
||||||
|
{
|
||||||
|
current_process->context = context;
|
||||||
|
//current_process->status = READY;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
struct process_t* prev_process = current_process;
|
||||||
|
if (current_process->next != NULL)
|
||||||
|
{
|
||||||
|
current_process = current_process->next;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
current_process = processes_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current_process != NULL && current_process->status == DEAD)
|
||||||
|
{
|
||||||
|
process_delete(&prev_process, current_process);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
current_process->status = RUNNING;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Current_process gets wrong context?? (iret_rip points to other stuff than process function; like putpixel() for example)
|
||||||
|
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));
|
||||||
|
DEBUG("loaded process pml4 into cr3");
|
||||||
|
|
||||||
|
return current_process->context;
|
||||||
|
}
|
||||||
13
src/sched/scheduler.h
Normal file
13
src/sched/scheduler.h
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
/*
|
||||||
|
* @author xamidev <xamidev@riseup.net>
|
||||||
|
* @brief Round-robin scheduler
|
||||||
|
* @license GPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SCHEDULER_H
|
||||||
|
#define SCHEDULER_H
|
||||||
|
|
||||||
|
struct cpu_status_t* scheduler_schedule(struct cpu_status_t* context);
|
||||||
|
void scheduler_init();
|
||||||
|
|
||||||
|
#endif
|
||||||
7
src/sched/task.S
Normal file
7
src/sched/task.S
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
; Task (process) switching
|
||||||
|
|
||||||
|
bits 64
|
||||||
|
|
||||||
|
global switch_to_task
|
||||||
|
switch_to_task:
|
||||||
|
|
||||||
@@ -1,6 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* @author xamidev <xamidev@riseup.net>
|
||||||
|
* @brief String manipulation utilities
|
||||||
|
* @license GPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
char* strcpy(char *dest, const char *src)
|
char* strcpy(char *dest, const char *src)
|
||||||
{
|
{
|
||||||
char *temp = dest;
|
char *temp = dest;
|
||||||
while((*dest++ = *src++));
|
while((*dest++ = *src++));
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://stackoverflow.com/questions/2488563/strcat-implementation
|
||||||
|
char *strcat(char *dest, const char *src){
|
||||||
|
size_t i,j;
|
||||||
|
for (i = 0; dest[i] != '\0'; i++)
|
||||||
|
;
|
||||||
|
for (j = 0; src[j] != '\0'; j++)
|
||||||
|
dest[i+j] = src[j];
|
||||||
|
dest[i+j] = '\0';
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://stackoverflow.com/questions/14159625/implementation-of-strncpy
|
||||||
|
void strncpy(char* dst, const char* src, size_t n)
|
||||||
|
{
|
||||||
|
size_t i = 0;
|
||||||
|
while(i++ != n && (*dst++ = *src++));
|
||||||
|
}
|
||||||
@@ -1,6 +1,14 @@
|
|||||||
|
/*
|
||||||
|
* @author xamidev <xamidev@riseup.net>
|
||||||
|
* @brief String manipulation functions
|
||||||
|
* @license GPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef STRING_H
|
#ifndef STRING_H
|
||||||
#define STRING_H
|
#define STRING_H
|
||||||
|
|
||||||
char *strcpy(char *dest, const char *src);
|
char *strcpy(char *dest, const char *src);
|
||||||
|
char *strcat(char *dest, const char *src);
|
||||||
|
void strncpy(char* dst, const char* src, size_t n);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -1,3 +1,9 @@
|
|||||||
|
/*
|
||||||
|
* @author xamidev <xamidev@riseup.net>
|
||||||
|
* @brief Programmable Interval Timer init and enabling
|
||||||
|
* @license GPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "io/serial/serial.h"
|
#include "io/serial/serial.h"
|
||||||
#include <kernel.h>
|
#include <kernel.h>
|
||||||
@@ -44,7 +50,7 @@ void pic_enable()
|
|||||||
// Enabling IRQ0 (unmasking it) but not the others
|
// Enabling IRQ0 (unmasking it) but not the others
|
||||||
uint8_t mask = inb(0x21);
|
uint8_t mask = inb(0x21);
|
||||||
mask &= ~(1 << 0); // Set IRQ0 (timer, clear bit 0)
|
mask &= ~(1 << 0); // Set IRQ0 (timer, clear bit 0)
|
||||||
mask &= ~(1 << 1); // Set IRQ1 (PS/2 Keyboard, clear bit 1)
|
//mask &= ~(1 << 1); // Set IRQ1 (PS/2 Keyboard, clear bit 1)
|
||||||
outb(0x21, mask);
|
outb(0x21, mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,6 +71,17 @@ void pit_init()
|
|||||||
outb(0x40, (divisor >> 8) & 0xFF);
|
outb(0x40, (divisor >> 8) & 0xFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Wait n ticks
|
||||||
|
// Given that there's a tick every 1ms, wait n milliseconds
|
||||||
|
void timer_wait(uint64_t wait_ticks)
|
||||||
|
{
|
||||||
|
uint64_t then = ticks + wait_ticks;
|
||||||
|
while (ticks < then)
|
||||||
|
{
|
||||||
|
asm("hlt");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
void timer_init()
|
void timer_init()
|
||||||
{
|
{
|
||||||
// Remapping the PIC, because at startup it conflicts with
|
// Remapping the PIC, because at startup it conflicts with
|
||||||
|
|||||||
@@ -1,6 +1,13 @@
|
|||||||
|
/*
|
||||||
|
* @author xamidev <xamidev@riseup.net>
|
||||||
|
* @brief PIT functions
|
||||||
|
* @license GPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef TIMER_H
|
#ifndef TIMER_H
|
||||||
#define TIMER_H
|
#define TIMER_H
|
||||||
|
|
||||||
void timer_init();
|
void timer_init();
|
||||||
|
void timer_wait(unsigned int wait_ticks);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
33
symbols.py
Normal file
33
symbols.py
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# Make assembly file from ELF symbols map
|
||||||
|
# Then link it to kernel so it's aware of symbol names
|
||||||
|
# then we can use that for the stack trace.
|
||||||
|
|
||||||
|
print("Extracting symbols from map file to assembly...")
|
||||||
|
|
||||||
|
with open("symbols.map", "r") as f:
|
||||||
|
lines = f.readlines()
|
||||||
|
|
||||||
|
symbols = []
|
||||||
|
for line in lines:
|
||||||
|
parts = line.split()
|
||||||
|
# output is formed like "address name"
|
||||||
|
symbols.append((parts[0], parts[1]))
|
||||||
|
|
||||||
|
with open("symbols.S", "w") as f:
|
||||||
|
f.write("section .rodata\n")
|
||||||
|
f.write("global symbol_table\n")
|
||||||
|
f.write("global symbol_count\n")
|
||||||
|
f.write("symbol_table:\n")
|
||||||
|
|
||||||
|
for i, (addr, name) in enumerate(symbols):
|
||||||
|
f.write(f" dq 0x{addr}\n")
|
||||||
|
f.write(f" dq sym_name_{i}\n")
|
||||||
|
|
||||||
|
f.write("\nsymbol_count: dq " + str(len(symbols)) + "\n\n")
|
||||||
|
|
||||||
|
for i, (addr, name) in enumerate(symbols):
|
||||||
|
# escaping quotes
|
||||||
|
safe_name = name.replace('"', '\\"')
|
||||||
|
f.write(f'sym_name_{i}: db "{safe_name}", 0\n')
|
||||||
|
|
||||||
|
print("Done!")
|
||||||
Reference in New Issue
Block a user