Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
3f9b78b05e
|
|||
|
42c7a55d3f
|
|||
|
5e9c582833
|
|||
| 77d9df6f48 | |||
|
90dc26ee11
|
|||
|
c8a72244b1
|
|||
|
b9f55d89f6
|
|||
|
a7d9e70a61
|
|||
| 95c801b991 |
@@ -10,3 +10,4 @@ iso_root
|
||||
.gdb_history
|
||||
symbols.map
|
||||
symbols.S
|
||||
*.log
|
||||
@@ -1,13 +1,11 @@
|
||||
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
|
||||
SOURCES = src/debug/misc.c src/io/term/flanterm_backends/fb.c src/io/term/flanterm.c src/debug/panic.c src/debug/stacktrace.c src/boot/boot.c src/sched/scheduler.c src/sched/process.c src/mem/heap/kheap.c src/mem/paging/vmm.c src/mem/paging/paging.c src/mem/paging/pmm.c src/string/string.c src/io/kbd/ps2.c src/io/serial/serial.c src/io/term/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:
|
||||
rm -f *.o
|
||||
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
|
||||
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
|
||||
@@ -37,7 +35,7 @@ build-iso: limine/limine build
|
||||
./limine/limine bios-install pepper.iso
|
||||
|
||||
debug:
|
||||
/usr/bin/qemu-system-x86_64 -drive file=pepper.iso -s -S -d int -no-reboot -no-shutdown &
|
||||
/usr/bin/qemu-system-x86_64 -drive file=pepper.iso -s -S -d int -D qemu.log -no-reboot -no-shutdown &
|
||||
gdb pepperk --command=debug.gdb
|
||||
|
||||
debug2:
|
||||
|
||||
@@ -41,8 +41,10 @@ PepperOS wouldn't be possible without the following freely-licensed software:
|
||||
|
||||
- the [Limine](https://codeberg.org/Limine/Limine) portable bootloader
|
||||
- Marco Paland's freestanding [printf implementation](https://github.com/mpaland)
|
||||
- the [ZAP](https://www.zap.org.au/projects/console-fonts-zap/) PSF console fonts
|
||||
- Mintuski's [Flanterm](https://codeberg.org/Mintsuki/Flanterm) terminal emulator
|
||||
|
||||
...and without these amazing resources:
|
||||
|
||||
- the [OSDev](https://osdev.org) wiki & forums
|
||||
- Intel 64 and IA-32 Architectures Software Developer's Manual
|
||||
- Documentation for the [GNU Compiler Collection](https://gcc.gnu.org/onlinedocs/gcc/)
|
||||
@@ -1,3 +1,7 @@
|
||||
target remote localhost:1234
|
||||
set disassembly-flavor intel
|
||||
display/4i $rip
|
||||
|
||||
# Trying to debug that flanterm page fault
|
||||
|
||||
# b plot_char_unscaled_uncanvas if $rdi == 0 || $rsi == 0 || $rdx == 0 || $r10 == 0
|
||||
@@ -1,6 +1,6 @@
|
||||
OUTPUT_FORMAT(elf64-x86-64)
|
||||
|
||||
ENTRY(_start)
|
||||
ENTRY(kmain)
|
||||
|
||||
PHDRS
|
||||
{
|
||||
|
||||
+2
-2
@@ -11,7 +11,7 @@
|
||||
#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"
|
||||
#define PEPPEROS_SPLASH "\x1b[38;5;196mPepperOS\x1b[0m version "PEPPEROS_VERSION_MAJOR"."PEPPEROS_VERSION_MINOR"."PEPPEROS_VERSION_PATCH"\n"
|
||||
|
||||
/* process */
|
||||
#define PROCESS_NAME_MAX 64
|
||||
@@ -30,7 +30,7 @@
|
||||
#define KERNEL_STACK_SIZE 65536
|
||||
|
||||
/* heap */
|
||||
#define KHEAP_SIZE (16*1024*1024)
|
||||
#define KHEAP_SIZE (32*1024*1024)
|
||||
|
||||
/* term */
|
||||
#define TERM_HISTORY_MAX_LINES 256
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
#include <kernel.h>
|
||||
#include "limine.h"
|
||||
#include "string/string.h"
|
||||
|
||||
extern struct boot_context boot_ctx;
|
||||
|
||||
// Display the memmap so we see how the memory is laid out at handoff
|
||||
void memmap_display(struct limine_memmap_response* response)
|
||||
{
|
||||
DEBUG("Got memory map from Limine: revision %u, %u entries", response->revision, response->entry_count);
|
||||
|
||||
for (size_t i=0; i<response->entry_count; i++)
|
||||
{
|
||||
struct limine_memmap_entry* entry = response->entries[i];
|
||||
char type[32] = {0};
|
||||
switch(entry->type)
|
||||
{
|
||||
case LIMINE_MEMMAP_USABLE:
|
||||
strcpy(type, "USABLE");
|
||||
break;
|
||||
case LIMINE_MEMMAP_RESERVED:
|
||||
strcpy(type, "RESERVED");
|
||||
break;
|
||||
case LIMINE_MEMMAP_ACPI_RECLAIMABLE:
|
||||
strcpy(type, "ACPI_RECLAIMABLE");
|
||||
break;
|
||||
case LIMINE_MEMMAP_ACPI_NVS:
|
||||
strcpy(type, "ACPI_NVS");
|
||||
break;
|
||||
case LIMINE_MEMMAP_BAD_MEMORY:
|
||||
strcpy(type, "BAD_MEMORY");
|
||||
break;
|
||||
case LIMINE_MEMMAP_BOOTLOADER_RECLAIMABLE:
|
||||
strcpy(type, "BOOTLOADER_RECLAIMABLE");
|
||||
break;
|
||||
case LIMINE_MEMMAP_KERNEL_AND_MODULES:
|
||||
strcpy(type, "KERNEL_AND_MODULES");
|
||||
break;
|
||||
case LIMINE_MEMMAP_FRAMEBUFFER:
|
||||
strcpy(type, "FRAMEBUFFER");
|
||||
break;
|
||||
default:
|
||||
strcpy(type, "UNKNOWN");
|
||||
break;
|
||||
}
|
||||
DEBUG("entry %02u: [0x%016x | %016u bytes] - %s", i, entry->base, entry->length, type);
|
||||
}
|
||||
}
|
||||
|
||||
// Display the HHDM
|
||||
void hhdm_display(struct limine_hhdm_response* hhdm)
|
||||
{
|
||||
DEBUG("Got HHDM revision=%u offset=0x%p", hhdm->revision, hhdm->offset);
|
||||
}
|
||||
|
||||
void boot_mem_display()
|
||||
{
|
||||
memmap_display(boot_ctx.mmap);
|
||||
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);
|
||||
}
|
||||
@@ -9,7 +9,9 @@ void panic(struct cpu_status_t* ctx, const char* str)
|
||||
if (ctx == NULL)
|
||||
{
|
||||
DEBUG("\x1b[38;5;231m\x1b[48;5;196mKernel panic!!!\x1b[0m Something went horribly wrong! (no cpu ctx)");
|
||||
fctprintf((void*)&skputc, 0, "\x1b[38;5;231m\x1b[48;5;27m");
|
||||
DIE_DEBUG(str);
|
||||
fctprintf((void*)&skputc, 0, "\x1b[0m");
|
||||
skputc('\r');
|
||||
skputc('\n');
|
||||
DEBUG("\x1b[38;5;231m\x1b[48;5;196mend Kernel panic - halting...\x1b[0m");
|
||||
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
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
|
||||
+2
-1
@@ -151,12 +151,13 @@ vector_7_handler:
|
||||
align 16
|
||||
vector_8_handler:
|
||||
; No error code, we only push vector number
|
||||
push qword 1
|
||||
push qword 8
|
||||
jmp interrupt_stub
|
||||
|
||||
; Coprocessor Segment Overrun
|
||||
align 16
|
||||
vector_9_handler:
|
||||
push qword 0
|
||||
push qword 9
|
||||
jmp interrupt_stub
|
||||
|
||||
|
||||
+4
-7
@@ -22,7 +22,7 @@ struct idtr idt_reg;
|
||||
extern char vector_0_handler[];
|
||||
|
||||
// Timer ticks
|
||||
extern uint64_t ticks;
|
||||
extern volatile uint64_t ticks;
|
||||
|
||||
void idt_set_entry(uint8_t vector, void* handler, uint8_t dpl)
|
||||
{
|
||||
@@ -52,9 +52,8 @@ void idt_load(void* idt_addr)
|
||||
|
||||
void idt_init()
|
||||
{
|
||||
// We set 256 entries, but we have only the first few stubs.
|
||||
// Undefined behavior?
|
||||
for (size_t i=0; i<256; i++)
|
||||
// Hardcoded...
|
||||
for (size_t i=0; i<=33; i++)
|
||||
{
|
||||
// Each vector handler is 16-byte aligned, so <vector_no>*16 = address of that handler
|
||||
idt_set_entry(i, vector_0_handler + (i*16), 0);
|
||||
@@ -203,9 +202,6 @@ struct cpu_status_t* interrupt_dispatch(struct cpu_status_t* context)
|
||||
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;
|
||||
@@ -213,6 +209,7 @@ struct cpu_status_t* interrupt_dispatch(struct cpu_status_t* context)
|
||||
case 33:
|
||||
DEBUG("Keyboard Interrupt");
|
||||
keyboard_handler();
|
||||
outb(0x20, 0x20);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
+18
-7
@@ -17,6 +17,8 @@ uint8_t key_status = 0b00000000;
|
||||
unsigned char* keymap;
|
||||
unsigned char* keymap_shifted;
|
||||
|
||||
extern struct init_status init;
|
||||
|
||||
unsigned char kbdus[128] =
|
||||
{
|
||||
0, 27, '1', '2', '3', '4', '5', '6', '7', '8', /* 9 */
|
||||
@@ -176,9 +178,6 @@ void keyboard_handler()
|
||||
key_status &= ~ALT_PRESSED_BIT;
|
||||
break;
|
||||
}
|
||||
|
||||
// Send EOI
|
||||
outb(0x20, 0x20);
|
||||
return;
|
||||
}
|
||||
else
|
||||
@@ -199,21 +198,26 @@ void keyboard_handler()
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
// Avoiding buffer overflow from extended keys lol
|
||||
if (scancode < 128)
|
||||
{
|
||||
// Should we get a SHIFTED char or a regular one?
|
||||
unsigned char c = (key_status & SHIFT_PRESSED_BIT) ? keymap_shifted[scancode] : keymap[scancode];
|
||||
|
||||
if (c)
|
||||
{
|
||||
if (c == '\n')
|
||||
{
|
||||
_putchar('\r');
|
||||
}
|
||||
// Should probably have a keyboard buffer here... instead of this
|
||||
_putchar(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// End of Interrupt (to master PIC)
|
||||
outb(0x20, 0x20);
|
||||
}
|
||||
}
|
||||
|
||||
void keyboard_init(unsigned char layout)
|
||||
@@ -233,14 +237,21 @@ void keyboard_init(unsigned char layout)
|
||||
break;
|
||||
|
||||
default:
|
||||
skputs("Unsupported layout.");
|
||||
panic(NULL, "Unsupported keyboard layout");
|
||||
return;
|
||||
}
|
||||
|
||||
// Flush keyboard buffer
|
||||
while (inb(0x64) & 1)
|
||||
{
|
||||
inb(0x60);
|
||||
}
|
||||
|
||||
// Unmask IRQ1
|
||||
uint8_t mask = inb(0x21);
|
||||
mask &= ~(1 << 1);
|
||||
outb(0x21, mask);
|
||||
|
||||
DEBUG("PS/2 Keyboard initialized");
|
||||
init.keyboard = true;
|
||||
}
|
||||
@@ -7,6 +7,8 @@
|
||||
#include <kernel.h>
|
||||
#include "serial.h"
|
||||
|
||||
extern struct init_status init;
|
||||
|
||||
void outb(int port, unsigned char data)
|
||||
{
|
||||
__asm__ __volatile__("outb %%al, %%dx" :: "a" (data),"d" (port));
|
||||
@@ -42,7 +44,8 @@ int serial_init()
|
||||
// Set normal operation mode
|
||||
outb(PORT + 4, 0x0F);
|
||||
|
||||
DEBUG("serial initialized");
|
||||
DEBUG("*** Welcome to PepperOS! ***");
|
||||
init.serial = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -54,6 +57,7 @@ static int is_transmit_empty()
|
||||
// Serial kernel putchar
|
||||
void skputc(char c)
|
||||
{
|
||||
// TODO: Spinlock here (serial access)
|
||||
while (!is_transmit_empty()); // wait for free spot
|
||||
outb(PORT, c);
|
||||
}
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <kernel.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
#error "Please do not compile Flanterm as C++ code! Flanterm should be compiled as C99 or newer."
|
||||
#endif
|
||||
@@ -662,6 +664,17 @@ static void plot_char_unscaled_canvas(struct flanterm_context *_ctx, struct flan
|
||||
}
|
||||
|
||||
static void plot_char_unscaled_uncanvas(struct flanterm_context *_ctx, struct flanterm_fb_char *c, size_t x, size_t y) {
|
||||
|
||||
if (_ctx == NULL)
|
||||
{
|
||||
panic(NULL, "plot_char_unscaled_uncanvas: _ctx is NULL");
|
||||
}
|
||||
|
||||
if (c == NULL)
|
||||
{
|
||||
panic(NULL, "plot_char_unscaled_uncanvas: c is NULL");
|
||||
}
|
||||
|
||||
struct flanterm_fb_context *ctx = (void *)_ctx;
|
||||
|
||||
if (x >= _ctx->cols || y >= _ctx->rows) {
|
||||
@@ -953,6 +966,12 @@ static void draw_cursor(struct flanterm_context *_ctx) {
|
||||
}
|
||||
|
||||
static void flanterm_fb_double_buffer_flush(struct flanterm_context *_ctx) {
|
||||
|
||||
if (_ctx == NULL)
|
||||
{
|
||||
panic(NULL, "flanterm_fb_double_buffer_flush: _ctx is NULL");
|
||||
}
|
||||
|
||||
struct flanterm_fb_context *ctx = (void *)_ctx;
|
||||
|
||||
if (_ctx->cursor_enabled) {
|
||||
|
||||
+37
-90
@@ -11,107 +11,22 @@ because this shitty implementation will be replaced one day by Flanterm
|
||||
(once memory management is okay: paging & kernel malloc)
|
||||
*/
|
||||
|
||||
#include <limine.h>
|
||||
#include <stddef.h>
|
||||
#include <kernel.h>
|
||||
#include "term.h"
|
||||
#include "mem/misc/utils.h"
|
||||
#include "config.h"
|
||||
#include "flanterm.h"
|
||||
|
||||
extern struct boot_context boot_ctx;
|
||||
|
||||
// Importing the PSF object file
|
||||
extern unsigned char _binary_zap_light16_psf_start[];
|
||||
extern unsigned char _binary_zap_light16_psf_end[];
|
||||
|
||||
PSF1_Header* font = (PSF1_Header*)_binary_zap_light16_psf_start;
|
||||
uint8_t* glyphs = _binary_zap_light16_psf_start + sizeof(PSF1_Header);
|
||||
|
||||
#define FONT_WIDTH 8
|
||||
#define FONT_HEIGHT font->characterSize
|
||||
#include "flanterm_backends/fb.h"
|
||||
#include "mem/heap/kheap.h"
|
||||
#include "limine.h"
|
||||
|
||||
extern struct flanterm_context* ft_ctx;
|
||||
|
||||
// Character cursor
|
||||
typedef struct
|
||||
{
|
||||
size_t x;
|
||||
size_t y;
|
||||
} Cursor;
|
||||
|
||||
static Cursor cursor = {0, 0};
|
||||
|
||||
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()
|
||||
{
|
||||
// Get framebuffer address from Limine struct
|
||||
|
||||
if (!boot_ctx.fb)
|
||||
{
|
||||
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
|
||||
// AKA they should just be seen here (kind of like private functions in cpp)
|
||||
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
|
||||
size_t pos = x*4 + y*framebuffer->pitch;
|
||||
fb[pos] = color & 255; // blue channel
|
||||
fb[pos+1] = (color >> 8) & 255; // green
|
||||
fb[pos+2] = (color >> 16) & 255; // blue
|
||||
}
|
||||
|
||||
void term_scroll()
|
||||
{
|
||||
// Erase first text line
|
||||
memset(fb, 255, FONT_HEIGHT*framebuffer->pitch);
|
||||
|
||||
// Move whole framebuffer up by one text line
|
||||
memmove(fb, fb+(FONT_HEIGHT*framebuffer->pitch), (framebuffer->height-FONT_HEIGHT)*framebuffer->pitch);
|
||||
|
||||
// Clear last text line
|
||||
size_t clear_start = (framebuffer->height - FONT_HEIGHT) * framebuffer->pitch;
|
||||
memset(fb + clear_start, 255, FONT_HEIGHT * framebuffer->pitch);
|
||||
|
||||
// Shift line lengths by 1 (for backspace handling)
|
||||
size_t max_lines = term_max_lines();
|
||||
for (size_t i = 1; i < max_lines; i++)
|
||||
{
|
||||
lines_length[i - 1] = lines_length[i];
|
||||
}
|
||||
lines_length[max_lines - 1] = 0;
|
||||
}
|
||||
extern struct init_status init;
|
||||
|
||||
// Overhead that could be avoided, right? (for printf)
|
||||
void _putchar(char character)
|
||||
{
|
||||
// TODO: Spinlock here (terminal access)
|
||||
flanterm_write(ft_ctx, &character, 1);
|
||||
}
|
||||
|
||||
@@ -124,4 +39,36 @@ void kputs(const char* str)
|
||||
_putchar(str[i]);
|
||||
i++;
|
||||
}
|
||||
_putchar('\r');
|
||||
}
|
||||
|
||||
extern struct flanterm_context* ft_ctx;
|
||||
extern struct boot_context boot_ctx;
|
||||
|
||||
void flanterm_free_wrapper(void* ptr, size_t size)
|
||||
{
|
||||
(void)size;
|
||||
kfree(ptr);
|
||||
}
|
||||
|
||||
void term_init()
|
||||
{
|
||||
uint32_t bgColor = 0x252525;
|
||||
ft_ctx = flanterm_fb_init(
|
||||
kmalloc,
|
||||
flanterm_free_wrapper,
|
||||
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,
|
||||
NULL, NULL,
|
||||
NULL, 0, 0, 1,
|
||||
0, 0,
|
||||
0,
|
||||
0
|
||||
);
|
||||
init.terminal = true;
|
||||
}
|
||||
+1
-19
@@ -7,26 +7,8 @@
|
||||
#ifndef TERM_H
|
||||
#define TERM_H
|
||||
|
||||
int term_init();
|
||||
void kputs(const char* str);
|
||||
void _putchar(char character);
|
||||
|
||||
enum TermColors
|
||||
{
|
||||
BLACK = 0x000000,
|
||||
WHITE = 0xffffff
|
||||
};
|
||||
|
||||
#define PSF1_FONT_MAGIC 0x0436
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t magic;
|
||||
uint8_t fontMode;
|
||||
uint8_t characterSize; // height
|
||||
} PSF1_Header;
|
||||
|
||||
// debug
|
||||
void term_scroll();
|
||||
void term_init();
|
||||
|
||||
#endif
|
||||
|
||||
+14
-1
@@ -19,9 +19,11 @@ enum ErrorCodes
|
||||
#include "io/serial/serial.h"
|
||||
#include "io/term/printf.h"
|
||||
#include "idt/idt.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#define DEBUG(log, ...) fctprintf((void*)&skputc, 0, "debug: [%s]: " log "\r\n", __FILE__, ##__VA_ARGS__)
|
||||
extern volatile uint64_t ticks;
|
||||
|
||||
#define DEBUG(log, ...) fctprintf((void*)&skputc, 0, "[%8u] debug: <%s>: " log "\r\n", ticks, __func__, ##__VA_ARGS__)
|
||||
|
||||
/* #define DEBUG(log, ...) \
|
||||
printf("debug: [%s]: " log "\r\n", __FILE__, ##__VA_ARGS__); \
|
||||
@@ -38,8 +40,10 @@ void panic(struct cpu_status_t* ctx, const char* str);
|
||||
void hcf();
|
||||
void idle();
|
||||
|
||||
/* debug */
|
||||
void debug_stack_trace(unsigned int max_frames);
|
||||
const char* debug_find_symbol(uintptr_t rip, uintptr_t* offset);
|
||||
void boot_mem_display();
|
||||
|
||||
#define assert(check) do { if(!(check)) hcf(); } while(0)
|
||||
|
||||
@@ -51,4 +55,13 @@ struct boot_context
|
||||
struct limine_kernel_address_response* kaddr;
|
||||
};
|
||||
|
||||
// Are these modules initialized yet?
|
||||
struct init_status
|
||||
{
|
||||
bool terminal;
|
||||
bool serial;
|
||||
bool keyboard;
|
||||
bool timer;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
+29
-58
@@ -30,8 +30,6 @@
|
||||
__attribute__((used, section(".limine_requests")))
|
||||
volatile LIMINE_BASE_REVISION(3);
|
||||
|
||||
struct flanterm_context *ft_ctx;
|
||||
|
||||
// Halt and catch fire (makes machine stall)
|
||||
void hcf()
|
||||
{
|
||||
@@ -41,9 +39,9 @@ void hcf()
|
||||
// Doing nothing (can be interrupted)
|
||||
void idle() {SET_INTERRUPTS; for(;;)asm("hlt");}
|
||||
|
||||
uint8_t kernel_stack[KERNEL_STACK_SIZE] __attribute__((aligned(16)));
|
||||
|
||||
struct flanterm_context *ft_ctx;
|
||||
struct boot_context boot_ctx;
|
||||
struct init_status init = {0};
|
||||
|
||||
extern volatile struct limine_framebuffer_request framebuffer_request;
|
||||
extern volatile struct limine_memmap_request memmap_request;
|
||||
@@ -52,92 +50,65 @@ extern volatile struct limine_kernel_address_request kerneladdr_request;
|
||||
|
||||
extern struct process_t* processes_list;
|
||||
extern struct process_t* current_process;
|
||||
struct process_t* idle_proc;
|
||||
|
||||
bool iran = false;
|
||||
|
||||
// Never gets executed although pedicel is scheduled?
|
||||
void pedicel_main(void* arg)
|
||||
{
|
||||
//printf("Hello, world from a KERNEL PROCESS!");
|
||||
}
|
||||
|
||||
void two_main(void* arg)
|
||||
{
|
||||
//printf("...process 2 speaking!!!");
|
||||
bool iran = true;
|
||||
// FROM THE NEXT LINE ONWARDS, CANNOT WRITE TO FRAMEBUFFER WITHOUT PAGE FAULT!
|
||||
//printf("\n\nWelcome to PepperOS! Pedicel speaking.\nNothing left to do, halting the system!");
|
||||
}
|
||||
|
||||
void idle_main(void* arg)
|
||||
{
|
||||
for(;;)asm("hlt");
|
||||
for (;;)
|
||||
{
|
||||
asm("hlt");
|
||||
}
|
||||
}
|
||||
|
||||
extern uintptr_t kheap_start;
|
||||
|
||||
// This is our entry point
|
||||
void kmain()
|
||||
{
|
||||
CLEAR_INTERRUPTS;
|
||||
if (!LIMINE_BASE_REVISION_SUPPORTED) hcf();
|
||||
|
||||
serial_init();
|
||||
timer_init();
|
||||
|
||||
// Populate boot context
|
||||
boot_ctx.fb = framebuffer_request.response ? framebuffer_request.response->framebuffers[0] : NULL;
|
||||
boot_ctx.mmap = memmap_request.response ? memmap_request.response : NULL;
|
||||
boot_ctx.hhdm = hhdm_request.response ? hhdm_request.response : NULL;
|
||||
boot_ctx.kaddr = kerneladdr_request.response ? kerneladdr_request.response : NULL;
|
||||
|
||||
boot_mem_display();
|
||||
pmm_init(boot_ctx.mmap, boot_ctx.hhdm);
|
||||
|
||||
// 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();
|
||||
|
||||
memmap_display(boot_ctx.mmap);
|
||||
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);
|
||||
|
||||
CLEAR_INTERRUPTS;
|
||||
gdt_init();
|
||||
idt_init();
|
||||
timer_init();
|
||||
|
||||
kheap_init();
|
||||
|
||||
vmm_init();
|
||||
keyboard_init(FR);
|
||||
|
||||
struct process_t* idle_proc = process_create("idle", (void*)idle_main, 0);
|
||||
term_init();
|
||||
|
||||
gdt_init();
|
||||
idt_init();
|
||||
|
||||
process_init();
|
||||
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);
|
||||
|
||||
process_display_list(processes_list);
|
||||
|
||||
scheduler_init();
|
||||
|
||||
current_process = idle_proc;
|
||||
current_process->status = RUNNING;
|
||||
|
||||
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. "));
|
||||
|
||||
kputs(PEPPEROS_SPLASH);
|
||||
idle();
|
||||
}
|
||||
|
||||
+30
-47
@@ -23,40 +23,36 @@ static uintptr_t end;
|
||||
// Kernel root table (level 4)
|
||||
extern uint64_t *kernel_pml4;
|
||||
|
||||
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();
|
||||
paging_map_page(kernel_pml4, end, phys, PTE_PRESENT | PTE_WRITABLE | PTE_NOEXEC);
|
||||
end += PAGE_SIZE;
|
||||
//DEBUG("Mapped first kheap page");
|
||||
}
|
||||
|
||||
void kheap_init()
|
||||
{
|
||||
kheap_start = ALIGN_UP(kernel_virt_base + KERNEL_SIZE, PAGE_SIZE);
|
||||
end = kheap_start;
|
||||
|
||||
// At least 1 page must be mapped for it to work
|
||||
kheap_map_page();
|
||||
size_t heap_pages = ALIGN_UP(KHEAP_SIZE, PAGE_SIZE) / PAGE_SIZE;
|
||||
DEBUG("Mapping %d kernel heap pages at 0x%p", heap_pages, kheap_start);
|
||||
|
||||
uintptr_t current_addr = kheap_start;
|
||||
|
||||
// Map/alloc enough pages for heap (KHEAP_SIZE)
|
||||
for (size_t i=0; i<heap_pages; i++)
|
||||
{
|
||||
uintptr_t phys = pmm_alloc();
|
||||
if (phys == 0)
|
||||
{
|
||||
panic(NULL, "Not enough memory available to initialize kernel heap.");
|
||||
}
|
||||
|
||||
paging_map_page(kernel_pml4, current_addr, phys, PTE_PRESENT | PTE_WRITABLE);
|
||||
current_addr += PAGE_SIZE;
|
||||
}
|
||||
|
||||
end = current_addr;
|
||||
|
||||
// Give linked list head its properties
|
||||
head = (struct heap_block_t*)kheap_start;
|
||||
head->size = PAGE_SIZE - sizeof(struct heap_block_t);
|
||||
head->size = (end-kheap_start) - sizeof(struct heap_block_t);
|
||||
head->free = true;
|
||||
head->next = NULL;
|
||||
DEBUG("kheap initialized, head=0x%p, size=%u", head, head->size);
|
||||
DEBUG("Kernel heap initialized, head=0x%p, size=%u bytes", head, head->size);
|
||||
}
|
||||
|
||||
void* kmalloc(size_t size)
|
||||
@@ -73,12 +69,12 @@ void* kmalloc(size_t size)
|
||||
if (curr->free && curr->size >= size)
|
||||
{
|
||||
// We split the block if it is big enough
|
||||
if (curr->size >= size + BLOCK_MIN_SIZE)
|
||||
if (curr->size >= size + sizeof(struct heap_block_t) + 16)
|
||||
{
|
||||
//struct heap_block_t* new_block = (struct heap_block_t*)((uintptr_t)curr + sizeof(struct heap_block_t) + size);
|
||||
struct heap_block_t* split = (struct heap_block_t*)((uintptr_t)curr + sizeof(*curr) + size);
|
||||
struct heap_block_t* split = (struct heap_block_t*)((uintptr_t)curr + sizeof(struct heap_block_t) + size);
|
||||
|
||||
split->size = curr->size - size - sizeof(*curr);
|
||||
split->size = curr->size - size - sizeof(struct heap_block_t);
|
||||
split->free = true;
|
||||
split->next = curr->next;
|
||||
|
||||
@@ -94,25 +90,12 @@ void* kmalloc(size_t size)
|
||||
curr = curr->next;
|
||||
}
|
||||
|
||||
// If we're here it means we didn't have enough memory
|
||||
// for the block allocation. So we will allocate more..
|
||||
uintptr_t old_end = end;
|
||||
kheap_grow(size + sizeof(struct heap_block_t));
|
||||
|
||||
struct heap_block_t* block = (struct heap_block_t*)old_end;
|
||||
block->size = ALIGN_UP(end - old_end - sizeof(struct heap_block_t), 16);
|
||||
block->free = true;
|
||||
block->next = NULL;
|
||||
|
||||
// Put the block at the end of the list
|
||||
curr = head;
|
||||
while (curr->next)
|
||||
{
|
||||
curr = curr->next;
|
||||
}
|
||||
curr->next = block;
|
||||
|
||||
return kmalloc(size);
|
||||
// No growing. If we're here it means the initial pool
|
||||
// wasn't sufficient. Too bad.
|
||||
DEBUG("Kernel heap is OUT OF MEMORY!");
|
||||
// if we were terrorists maybe we should panic
|
||||
// or just wait for others to free stuff?
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void kfree(void* ptr)
|
||||
|
||||
@@ -14,13 +14,15 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct heap_block_t
|
||||
{
|
||||
size_t size;
|
||||
bool free;
|
||||
bool free; // 1byte
|
||||
uint8_t reserved[7]; // (7+1 = 8 bytes)
|
||||
struct heap_block_t* next;
|
||||
};
|
||||
} __attribute__((aligned(16)));
|
||||
|
||||
void kheap_init();
|
||||
void* kmalloc(size_t size);
|
||||
|
||||
@@ -77,52 +77,3 @@ int memcmp(const void* s1, const void* s2, size_t n)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Display the memmap so we see how the memory is laid out at handoff
|
||||
void memmap_display(struct limine_memmap_response* response)
|
||||
{
|
||||
DEBUG("Got memory map from Limine: revision %u, %u entries", response->revision, response->entry_count);
|
||||
|
||||
for (size_t i=0; i<response->entry_count; i++)
|
||||
{
|
||||
struct limine_memmap_entry* entry = response->entries[i];
|
||||
char type[32] = {0};
|
||||
switch(entry->type)
|
||||
{
|
||||
case LIMINE_MEMMAP_USABLE:
|
||||
strcpy(type, "USABLE");
|
||||
break;
|
||||
case LIMINE_MEMMAP_RESERVED:
|
||||
strcpy(type, "RESERVED");
|
||||
break;
|
||||
case LIMINE_MEMMAP_ACPI_RECLAIMABLE:
|
||||
strcpy(type, "ACPI_RECLAIMABLE");
|
||||
break;
|
||||
case LIMINE_MEMMAP_ACPI_NVS:
|
||||
strcpy(type, "ACPI_NVS");
|
||||
break;
|
||||
case LIMINE_MEMMAP_BAD_MEMORY:
|
||||
strcpy(type, "BAD_MEMORY");
|
||||
break;
|
||||
case LIMINE_MEMMAP_BOOTLOADER_RECLAIMABLE:
|
||||
strcpy(type, "BOOTLOADER_RECLAIMABLE");
|
||||
break;
|
||||
case LIMINE_MEMMAP_KERNEL_AND_MODULES:
|
||||
strcpy(type, "KERNEL_AND_MODULES");
|
||||
break;
|
||||
case LIMINE_MEMMAP_FRAMEBUFFER:
|
||||
strcpy(type, "FRAMEBUFFER");
|
||||
break;
|
||||
default:
|
||||
strcpy(type, "UNKNOWN");
|
||||
break;
|
||||
}
|
||||
DEBUG("entry %02u: [0x%016x | %016u bytes] - %s", i, entry->base, entry->length, type);
|
||||
}
|
||||
}
|
||||
|
||||
// Display the HHDM
|
||||
void hhdm_display(struct limine_hhdm_response* hhdm)
|
||||
{
|
||||
DEBUG("Got HHDM revision=%u offset=0x%p", hhdm->revision, hhdm->offset);
|
||||
}
|
||||
@@ -68,5 +68,6 @@ void vmm_setup_pt_root()
|
||||
|
||||
void vmm_init()
|
||||
{
|
||||
vmm_setup_pt_root();
|
||||
// NO U
|
||||
//vmm_setup_pt_root();
|
||||
}
|
||||
+4
-18
@@ -13,6 +13,9 @@
|
||||
#include "config.h"
|
||||
#include "io/serial/serial.h"
|
||||
|
||||
#include "io/term/flanterm.h"
|
||||
extern struct flanterm_context* ft_ctx;
|
||||
|
||||
struct process_t* processes_list;
|
||||
struct process_t* current_process;
|
||||
|
||||
@@ -139,23 +142,6 @@ struct process_t* process_get_next(struct process_t* process)
|
||||
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()
|
||||
@@ -168,7 +154,7 @@ void process_exit()
|
||||
}
|
||||
SET_INTERRUPTS;
|
||||
|
||||
outb(0x20, 0x20);
|
||||
//outb(0x20, 0x20);
|
||||
for (;;)
|
||||
{
|
||||
asm("hlt");
|
||||
|
||||
@@ -34,7 +34,6 @@ 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);
|
||||
|
||||
+14
-2
@@ -12,6 +12,7 @@
|
||||
|
||||
extern struct process_t* processes_list;
|
||||
extern struct process_t* current_process;
|
||||
extern struct process_t* idle_proc;
|
||||
|
||||
void scheduler_init()
|
||||
{
|
||||
@@ -21,6 +22,17 @@ void scheduler_init()
|
||||
|
||||
struct cpu_status_t* scheduler_schedule(struct cpu_status_t* context)
|
||||
{
|
||||
if (context == NULL)
|
||||
{
|
||||
panic(NULL, "Scheduler called with NULL context");
|
||||
}
|
||||
|
||||
if (current_process == NULL)
|
||||
{
|
||||
// If no more processes, then set IDLE as the current process, that's it.
|
||||
current_process = idle_proc;
|
||||
}
|
||||
|
||||
current_process->context = context;
|
||||
//current_process->status = READY;
|
||||
|
||||
@@ -37,6 +49,8 @@ struct cpu_status_t* scheduler_schedule(struct cpu_status_t* context)
|
||||
if (current_process != NULL && current_process->status == DEAD)
|
||||
{
|
||||
process_delete(&prev_process, current_process);
|
||||
current_process = NULL;
|
||||
return idle_proc->context;
|
||||
} else
|
||||
{
|
||||
current_process->status = RUNNING;
|
||||
@@ -44,8 +58,6 @@ struct cpu_status_t* scheduler_schedule(struct cpu_status_t* context)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 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));
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
; Task (process) switching
|
||||
|
||||
bits 64
|
||||
|
||||
global switch_to_task
|
||||
switch_to_task:
|
||||
|
||||
@@ -18,6 +18,8 @@ interested in multi-core functionnality like SMP)
|
||||
|
||||
volatile uint64_t ticks = 0;
|
||||
|
||||
extern struct init_status init;
|
||||
|
||||
void pic_remap()
|
||||
{
|
||||
uint8_t master_mask = inb(0x21);
|
||||
@@ -91,4 +93,5 @@ void timer_init()
|
||||
pic_enable();
|
||||
pit_init();
|
||||
DEBUG("PIT initialized");
|
||||
init.timer = true;
|
||||
}
|
||||
Binary file not shown.
Reference in New Issue
Block a user