Initial commit - slab allocator, kmalloc, other re

factors
This commit is contained in:
ssimnb 2026-01-22 08:05:47 +01:00
parent 1dd7b8b07f
commit 4e40a040dd
39 changed files with 863 additions and 412 deletions

6
.vscode/settings.json vendored Normal file
View file

@ -0,0 +1,6 @@
{
"clangd.arguments": [
"--background-index"
]
}

View file

@ -48,7 +48,7 @@ all:
$(CC) -c src/flanterm/src/flanterm.c -o $(BUILD_DIR)/flanterm.o $(CFLAGS) $(CC) -c src/flanterm/src/flanterm.c -o $(BUILD_DIR)/flanterm.o $(CFLAGS)
$(CC) -c src/flanterm/src/flanterm_backends/fb.c -o $(BUILD_DIR)/fb.o $(CFLAGS) $(CC) -c src/flanterm/src/flanterm_backends/fb.c -o $(BUILD_DIR)/fb.o $(CFLAGS)
$(CC) -c src/lib/string.c -o $(BUILD_DIR)/string.o $(CFLAGS) $(CC) -c src/lib/string.c -o $(BUILD_DIR)/string.o $(CFLAGS)
$(CC) -c src/lib/stdio.c -o $(BUILD_DIR)/stdio.o $(CFLAGS) $(CC) -c src/lib/kprint.c -o $(BUILD_DIR)/kprint.o $(CFLAGS)
$(CC) -c src/lib/io.c -o $(BUILD_DIR)/io.o $(CFLAGS) $(CC) -c src/lib/io.c -o $(BUILD_DIR)/io.o $(CFLAGS)
$(CC) -c src/lib/spinlock.c -o $(BUILD_DIR)/spinlock.o $(CFLAGS) $(CC) -c src/lib/spinlock.c -o $(BUILD_DIR)/spinlock.o $(CFLAGS)
@ -61,8 +61,11 @@ all:
$(CC) -c src/hal/timer.c -o $(BUILD_DIR)/timer.o $(CFLAGS) $(CC) -c src/hal/timer.c -o $(BUILD_DIR)/timer.o $(CFLAGS)
$(CC) -c src/hal/smp.c -o $(BUILD_DIR)/smp.o $(CFLAGS) $(CC) -c src/hal/smp.c -o $(BUILD_DIR)/smp.o $(CFLAGS)
$(CC) -c src/hal/tsc.c -o $(BUILD_DIR)/tsc.o $(CFLAGS) $(CC) -c src/hal/tsc.c -o $(BUILD_DIR)/tsc.o $(CFLAGS)
$(CC) -c src/sys/rand.c -o $(BUILD_DIR)/rand.o $(CFLAGS)
$(CC) -c src/mm/pmm.c -o $(BUILD_DIR)/pmm.o $(CFLAGS) $(CC) -c src/mm/pmm.c -o $(BUILD_DIR)/pmm.o $(CFLAGS)
$(CC) -c src/mm/vmm.c -o $(BUILD_DIR)/vmm.o $(CFLAGS) $(CC) -c src/mm/vmm.c -o $(BUILD_DIR)/vmm.o $(CFLAGS)
$(CC) -c src/mm/page.c -o $(BUILD_DIR)/page.o $(CFLAGS)
$(CC) -c src/mm/slab.c -o $(BUILD_DIR)/slab.o $(CFLAGS)
$(CC) -c src/mm/kmalloc.c -o $(BUILD_DIR)/kmalloc.o $(CFLAGS) $(CC) -c src/mm/kmalloc.c -o $(BUILD_DIR)/kmalloc.o $(CFLAGS)
$(CC) -c src/sys/acpi.c -o $(BUILD_DIR)/acpi.o $(CFLAGS) $(CC) -c src/sys/acpi.c -o $(BUILD_DIR)/acpi.o $(CFLAGS)
$(CC) -c src/sys/pci.c -o $(BUILD_DIR)/pci.o $(CFLAGS) $(CC) -c src/sys/pci.c -o $(BUILD_DIR)/pci.o $(CFLAGS)
@ -100,3 +103,5 @@ disk:
dd if=/dev/zero of=disk.img bs=1M count=128 dd if=/dev/zero of=disk.img bs=1M count=128
elftest: elftest:
$(CC) src/elf/elftest.c -o $(BUILD_DIR)/elftest -ffreestanding -Isrc/include -static -fPIE -nostdlib $(CC) src/elf/elftest.c -o $(BUILD_DIR)/elftest -ffreestanding -Isrc/include -static -fPIE -nostdlib
clean:
rm -r build/

View file

@ -3,11 +3,12 @@
# Args are fed to QEMU, then GDB and everything else does shit automagically # Args are fed to QEMU, then GDB and everything else does shit automagically
# 1st arg: terminal name to spawn GDB # 1st arg: terminal name to spawn GDB
# 2nd arg: place to breakpoint in # 2nd arg: place to breakpoint in
# 3rd+ arguments all get passed to QEMU
termname=$1 termname=$1
breakpoint=$2 breakpoint=$2
shift 2 shift 2
qemu-system-x86_64 "$@" & qemu-system-x86_64 -s -S "$@" &
sleep 1 sleep 1

View file

@ -1,64 +0,0 @@
#include <stddef.h>
#include <stdint.h>
#include "slaballoc.h"
char memory[4096 * 10];
int cnt = 0;
struct ma_kcache *head = NULL; // create standard sizes
uint64_t *alloc_contigious_pages(int num){
uint64_t *ret = (uint64_t*)(memory + cnt*4096);
cnt+=num;
return ret;
}
struct ma_slab *_ma_alloc_initial_slab(struct ma_kcache *kcache){
uint64_t *p = alloc_contigious_pages(1);
int bufnum = (4096 - sizeof(struct ma_slab)) / kcache->objsize; // Calculate the number of buffers in this slab
for(int i = 0; i < bufnum; i++){
(uint64_t*)((uint64_t)p + i * kcache->objsize)
}
}
struct ma_kcache *ma_cache_create(char *name, size_t size, uint32_t flags, void (*constructor)(void *, size_t), void (*destructor)(void *, size_t)){
struct ma_kcache *kcache = (struct ma_kcache*)alloc_contigious_pages(1);
head->next = kcache;
kcache->prev = head;
head = kcache;
int bufnum = (4096 - sizeof(struct ma_slab)) / size; // Calculate the number of buffers in this slab
struct ma_slab *slab_structure = (struct ma_slab*)((uint64_t)kcache - sizeof(struct ma_slab));
kcache->slabs_free = slab_structure;
return kcache;
}
void *ma_cache_alloc(struct ma_kcache *cache, uint64_t flags){
if(cache->slabs_free == NULL){
if(cache->slabs_partial == NULL){
}
}
common:
}
int main(){
}

View file

@ -1,38 +0,0 @@
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#define KCACHE_NAME_LEN 5
struct ma_bufctrl {
struct ma_bufctrl *next;
size_t *startaddr;
};
struct ma_slab {
struct ma_slab *next;
struct ma_slab *prev;
struct ma_bufctrl *buf_list;
uint32_t refcount;
};
struct ma_kcache {
struct ma_kcache *next;
struct ma_kcache *prev;
uint32_t objsize;
uint32_t flags;
uint32_t num;
struct ma_slab *slabs_free;
struct ma_slab *slabs_partial;
struct ma_slab *slabs_used;
struct ma_bufctrl *bufctrl_arr;
char name[KCACHE_NAME_LEN];
};

View file

@ -1,6 +1,6 @@
#include <SFB25.h> #include <SFB25.h>
#include <stdio.h> #include <kprint.h>
#include "../hal/apic.h" #include "../hal/apic.h"
#include "../sys/pci.h" #include "../sys/pci.h"
#include "../mm/vmm.h" #include "../mm/vmm.h"
@ -34,7 +34,7 @@ void ahci_init(){
pci_header_0_t *header = (pci_header_0_t *)pci_find_device(AHCI_CLASS_ID, AHCI_SUBCLASS_ID); pci_header_0_t *header = (pci_header_0_t *)pci_find_device(AHCI_CLASS_ID, AHCI_SUBCLASS_ID);
if(!header){ if(!header){
klog(LOG_ERROR, __func__, "AHCI controller not found!"); klog(__func__, "AHCI controller not found!");
kkill(); kkill();
} }
@ -50,7 +50,7 @@ void ahci_init(){
header->header.command |= AHCI_MSE | AHCI_BME | AHCI_INT_ENABLED; header->header.command |= AHCI_MSE | AHCI_BME | AHCI_INT_ENABLED;
/* Map the AHCI registers */ /* Map the AHCI registers */
kernel_map_pages((uint64_t*)ahci_base_address, 1, PTE_BIT_RW | PTE_BIT_NX | PTE_BIT_UNCACHABLE); kmap_pages((uint64_t*)ahci_base_address, 1, PTE_BIT_RW | PTE_BIT_NX | PTE_BIT_UNCACHABLE);
ahci_base_address += hhdmoffset; ahci_base_address += hhdmoffset;

View file

@ -1,5 +1,5 @@
#include "../sys/acpi.h" #include "../sys/acpi.h"
#include <stdio.h> #include <kprint.h>
#include <SFB25.h> #include <SFB25.h>
#include <io.h> #include <io.h>
@ -27,7 +27,7 @@ uint64_t pmt_read_reg(gas_t X_PMTimerBlock){
return inl(X_PMTimerBlock.address); return inl(X_PMTimerBlock.address);
}else{ }else{
serial_kprintf("address id: 0x{xn}", X_PMTimerBlock.address_space_id); serial_kprintf("address id: 0x{xn}", X_PMTimerBlock.address_space_id);
klog(LOG_ERROR, __func__, "X_PMTimerBlock address space id isn't supported!"); klog(__func__, "X_PMTimerBlock address space id isn't supported!");
return 0; return 0;
} }
} }
@ -36,7 +36,7 @@ int pmt_init(){
fadt = (fadt_t*)((uint64_t)find_acpi_table("FACP")); fadt = (fadt_t*)((uint64_t)find_acpi_table("FACP"));
if(!fadt){ if(!fadt){
klog(LOG_ERROR, __func__, "Didn't find FADT table"); klog(__func__, "Didn't find FADT table");
kkill(); kkill();
} }

View file

@ -1,7 +1,7 @@
#include "../sys/acpi.h" #include "../sys/acpi.h"
#include "../hal/ioapic.h" #include "../hal/ioapic.h"
#include <io.h> #include <io.h>
#include <stdio.h> #include <kprint.h>
#define COM1 0x3F8 #define COM1 0x3F8
@ -43,7 +43,7 @@ void serial_init(){
outb(COM1, 0xAE); outb(COM1, 0xAE);
if(inb(COM1) != 0xAE){ if(inb(COM1) != 0xAE){
klog(LOG_WARN, __func__, "Serial controller failed test, serial output will not work"); klog(__func__, "Serial controller failed test, serial output will not work");
return; return;
} }

View file

@ -4,7 +4,7 @@
#include "timer.h" #include "timer.h"
#include "ioapic.h" #include "ioapic.h"
#include <lock.h> #include <lock.h>
#include <stdio.h> #include <kprint.h>
#include <SFB25.h> #include <SFB25.h>
#include <cpuid.h> // GCC specific #include <cpuid.h> // GCC specific
@ -55,7 +55,7 @@ void apic_sleep(uint64_t ms){
atomic_flag lapic_timer_flag = ATOMIC_FLAG_INIT; atomic_flag lapic_timer_flag = ATOMIC_FLAG_INIT;
void lapic_timer_init(int us){ void lapic_timer_init(int us){
acquire_lock(&lapic_timer_flag); acquire_spinlock(&lapic_timer_flag);
/* Stop the APIC timer */ /* Stop the APIC timer */
lapic_write_reg(LAPIC_TIMER_INITIAL_CNT_REG, 0); lapic_write_reg(LAPIC_TIMER_INITIAL_CNT_REG, 0);
@ -80,7 +80,7 @@ void lapic_timer_init(int us){
/* Set the inital count to the calibration */ /* Set the inital count to the calibration */
lapic_write_reg(LAPIC_TIMER_INITIAL_CNT_REG, calibration); lapic_write_reg(LAPIC_TIMER_INITIAL_CNT_REG, calibration);
free_lock(&lapic_timer_flag); free_spinlock(&lapic_timer_flag);
} }

View file

@ -1,5 +1,5 @@
#include "gdt.h" #include "gdt.h"
#include <stdio.h> #include <kprint.h>
gdt_descriptor gdt[5] = {0}; gdt_descriptor gdt[5] = {0};

View file

@ -1,7 +1,7 @@
#include "idt.h" #include "idt.h"
#include "error.h" #include "error.h"
#include "timer.h" #include "timer.h"
#include <stdio.h> #include <kprint.h>
#include <lock.h> #include <lock.h>
#include <SFB25.h> #include <SFB25.h>
idt_descriptor idt[256] = {0}; idt_descriptor idt[256] = {0};
@ -60,10 +60,10 @@ atomic_flag irq_register_lock = ATOMIC_FLAG_INIT;
/* Registers an IRQ with the specified vector. */ /* Registers an IRQ with the specified vector. */
kstatus register_irq_vector(uint8_t vector, void *base, uint8_t flags){ kstatus register_irq_vector(uint8_t vector, void *base, uint8_t flags){
acquire_lock(&irq_register_lock); acquire_spinlock(&irq_register_lock);
if(!irq_list[vector].in_use){ if(!irq_list[vector].in_use){
free_lock(&irq_register_lock); free_spinlock(&irq_register_lock);
return KERNEL_STATUS_ERROR; return KERNEL_STATUS_ERROR;
} }
@ -74,27 +74,27 @@ kstatus register_irq_vector(uint8_t vector, void *base, uint8_t flags){
s_load_idt(); s_load_idt();
free_lock(&irq_register_lock); free_spinlock(&irq_register_lock);
return KERNEL_STATUS_SUCCESS; return KERNEL_STATUS_SUCCESS;
} }
/* Registers an IRQ and returns the vector */ /* Registers an IRQ and returns the vector */
int register_irq(void *base, uint8_t flags){ int register_irq(void *base, uint8_t flags){
acquire_lock(&irq_register_lock); acquire_spinlock(&irq_register_lock);
for(size_t i = 0; i < MAX_IRQ; i++){ for(size_t i = 0; i < MAX_IRQ; i++){
if(!irq_list[i].in_use) { if(!irq_list[i].in_use) {
set_idt_descriptor(i, base, flags); set_idt_descriptor(i, base, flags);
irq_list[i].base = base; irq_list[i].base = base;
irq_list[i].in_use = true; irq_list[i].in_use = true;
free_lock(&irq_register_lock); free_spinlock(&irq_register_lock);
s_load_idt(); s_load_idt();
return i; return i;
} }
} }
free_lock(&irq_register_lock); free_spinlock(&irq_register_lock);
return -1; return -1;
} }

View file

@ -1,6 +1,6 @@
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <kprint.h>
#include <SFB25.h> #include <SFB25.h>
#include "../sys/acpi.h" #include "../sys/acpi.h"
#include "error.h" #include "error.h"
@ -53,7 +53,7 @@ void ioapic_init(void){
ioapic_t *ioapic = (ioapic_t*) find_ics(0x1); ioapic_t *ioapic = (ioapic_t*) find_ics(0x1);
if(!ioapic){ if(!ioapic){
klog(LOG_ERROR, __func__, "IOAPIC ICS not found\n"); klog(__func__, "IOAPIC ICS not found\n");
kkill(); kkill();
} }

View file

@ -1,7 +1,7 @@
#include <limine.h> #include <limine.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <kprint.h>
#include <SFB25.h> #include <SFB25.h>
#include "gdt.h" #include "gdt.h"
#include "smp.h" #include "smp.h"
@ -42,7 +42,7 @@ atomic_flag ap_init_lock = ATOMIC_FLAG_INIT;
void ap_init(struct limine_smp_info *smp_info){ void ap_init(struct limine_smp_info *smp_info){
acquire_lock(&ap_init_lock); acquire_spinlock(&ap_init_lock);
/* Load the GDT */ /* Load the GDT */
s_load_gdt(); s_load_gdt();
@ -71,7 +71,7 @@ void ap_init(struct limine_smp_info *smp_info){
/* Initialize APIC & APIC timer */ /* Initialize APIC & APIC timer */
ap_apic_init(); ap_apic_init();
free_lock(&ap_init_lock); free_spinlock(&ap_init_lock);
for(;;); for(;;);
@ -81,7 +81,7 @@ void ap_init(struct limine_smp_info *smp_info){
void smp_init(){ void smp_init(){
if(!smp_request.response){ if(!smp_request.response){
klog(LOG_ERROR, __func__, "Failed to get SMP request"); klog(__func__, "Failed to get SMP request");
kkill(); kkill();
} }

View file

@ -3,7 +3,7 @@
#include "../hal/apic.h" #include "../hal/apic.h"
#include "../drivers/pmt.h" #include "../drivers/pmt.h"
#include "timer.h" #include "timer.h"
#include <stdio.h> #include <kprint.h>
#include <SFB25.h> #include <SFB25.h>
/* Determines which timer will be used for calibration */ /* Determines which timer will be used for calibration */
@ -11,7 +11,7 @@ int calibration_timer = -1;
void timer_init(void){ void timer_init(void){
if(pmt_init() == -1){ if(pmt_init() == -1){
klog(LOG_INFO, __func__, "PMT Timer not found, falling back"); klog(__func__, "PMT Timer not found, falling back");
/* Fall back to PIT */ /* Fall back to PIT */
}else{ }else{
calibration_timer = PMT; calibration_timer = PMT;

View file

@ -1,5 +1,5 @@
#include <cpuid.h> #include <cpuid.h>
#include <stdio.h> #include <kprint.h>
#include <stdint.h> #include <stdint.h>
#include "error.h" #include "error.h"
#include "../drivers/pmt.h" #include "../drivers/pmt.h"

View file

@ -15,4 +15,6 @@ typedef char link_symbol_ptr[];
#define PAGE_ROUND_UP(size) ALIGN_UP(size, PAGE_SIZE) #define PAGE_ROUND_UP(size) ALIGN_UP(size, PAGE_SIZE)
#define PAGE_ROUND_DOWN(size) ALIGN_DOWN(size, PAGE_SIZE) #define PAGE_ROUND_DOWN(size) ALIGN_DOWN(size, PAGE_SIZE)
#define SIZE_IN_PAGES(size) size/PAGE_SIZE
void *kmalloc(uint64_t size); void *kmalloc(uint64_t size);

1
src/include/kmath.h Normal file
View file

@ -0,0 +1 @@
#define abs(x) (x<0) ? -x : x

View file

@ -8,7 +8,7 @@ enum {
LOG_SUCCESS, LOG_SUCCESS,
}; };
void klog(int level, const char *func, const char *msg); void klog(const char *func, const char *msg);
int kprintf(const char *format_string, ...); int kprintf(const char *format_string, ...);

View file

@ -3,7 +3,7 @@
#ifndef SPINLOCK_H #ifndef SPINLOCK_H
#define SPINLOCK_H #define SPINLOCK_H
void acquire_lock(atomic_flag *lock); void acquire_spinlock(atomic_flag *lock);
void free_lock(atomic_flag *lock); void free_spinlock(atomic_flag *lock);
#endif #endif

View file

@ -3,7 +3,7 @@
#include <stdbool.h> #include <stdbool.h>
#include <string.h> #include <string.h>
#include <lock.h> #include <lock.h>
#include "../include/stdio.h" #include "../include/kprint.h"
#include "../drivers/serial.h" #include "../drivers/serial.h"
#include "../hal/tsc.h" #include "../hal/tsc.h"
@ -22,39 +22,14 @@
extern bool serial_enabled; extern bool serial_enabled;
void klog(int level, const char *func, const char *msg){ void klog(const char *func, const char *msg){
switch (level) { kprintf("{ksk}: {s}\n", ANSI_COLOR_MAGENTA, func, ANSI_COLOR_RESET, msg);
case LOG_INFO: serial_kprintf("{ksk}: {s}\n", ANSI_COLOR_MAGENTA, func, ANSI_COLOR_RESET, msg);
kprintf("[{d}] info: {s}: {sn}", tsc_get_timestamp(), func, msg);
if(serial_enabled){
serial_kprintf("{k}KLOG_INFO{k}: {s}: {sn}", ANSI_COLOR_MAGENTA, ANSI_COLOR_RESET, func, msg);
}
return;
case LOG_WARN:
kprintf("[{d}] {k}warning{k}: {s}: {sn}", tsc_get_timestamp(), ANSI_COLOR_YELLOW, ANSI_COLOR_RESET, func, msg);
if(serial_enabled){
serial_kprintf("{k}KLOG_WARN{k}: {s}: {sn}", ANSI_COLOR_YELLOW, ANSI_COLOR_RESET, func, msg);
}
return;
case LOG_ERROR:
kprintf("[{d}] {k}error{k}: {s}: {sn}", tsc_get_timestamp(), ANSI_COLOR_RED, ANSI_COLOR_RESET, func, msg);
if(serial_enabled){
serial_kprintf("{k}KLOG_ERROR{k}: {s}: {sn}", ANSI_COLOR_RED, ANSI_COLOR_RESET, func, msg);
}
return;
case LOG_SUCCESS:
kprintf("[{d}] {k}success{k}: {s}: {sn}", tsc_get_timestamp(), ANSI_COLOR_GREEN, ANSI_COLOR_RESET, func, msg);
if(serial_enabled){
serial_kprintf("{k}KLOG_SUCCESS{k}: {s}: {sn}", ANSI_COLOR_GREEN, ANSI_COLOR_RESET, func, msg);
}
return;
}
return; return;
} }
atomic_flag printf_lock = ATOMIC_FLAG_INIT; atomic_flag printf_lock = ATOMIC_FLAG_INIT;
/* /*
@ -75,7 +50,7 @@ atomic_flag printf_lock = ATOMIC_FLAG_INIT;
int kprintf(const char *format_string, ...){ int kprintf(const char *format_string, ...){
extern struct flanterm_context *ft_ctx; extern struct flanterm_context *ft_ctx;
acquire_lock(&printf_lock); acquire_spinlock(&printf_lock);
int state = NORMAL; int state = NORMAL;
va_list a_list; va_list a_list;
va_start(a_list, format_string); va_start(a_list, format_string);
@ -138,7 +113,7 @@ int kprintf(const char *format_string, ...){
} }
va_end(a_list); va_end(a_list);
free_lock(&printf_lock); free_spinlock(&printf_lock);
return 0; return 0;
} }

View file

@ -1,8 +1,8 @@
#include <lock.h> #include <lock.h>
#include <stdatomic.h> #include <stdatomic.h>
#include <stdio.h> #include <kprint.h>
void acquire_lock(atomic_flag *lock){ void acquire_spinlock(atomic_flag *lock){
while(atomic_flag_test_and_set_explicit(lock, memory_order_acquire)){ while(atomic_flag_test_and_set_explicit(lock, memory_order_acquire)){
asm volatile("nop"); asm volatile("nop");
} }
@ -10,6 +10,6 @@ void acquire_lock(atomic_flag *lock){
atomic_thread_fence(memory_order_acquire); atomic_thread_fence(memory_order_acquire);
} }
void free_lock(atomic_flag *lock){ void free_spinlock(atomic_flag *lock){
atomic_flag_clear_explicit(lock, memory_order_release); atomic_flag_clear_explicit(lock, memory_order_release);
} }

View file

@ -1,6 +1,6 @@
#include <stdint.h> #include <stdint.h>
#include <stddef.h> #include <stddef.h>
#include <stdio.h> #include <kprint.h>
void *memset(void *dest, int c, uint64_t n){ void *memset(void *dest, int c, uint64_t n){
uint8_t *p = (uint8_t *)dest; uint8_t *p = (uint8_t *)dest;

View file

@ -1,8 +1,10 @@
#include <stdint.h> #include <stdint.h>
#include <stddef.h> #include <stddef.h>
#include <SFB25.h> #include <SFB25.h>
#include <kprint.h>
#include <string.h>
#include "error.h"
#include "limine.h" #include "limine.h"
#include "include/stdio.h"
#include "../flanterm/src/flanterm.h" #include "../flanterm/src/flanterm.h"
#include "flanterm/src/flanterm_backends/fb.h" #include "flanterm/src/flanterm_backends/fb.h"
#include "hal/gdt.h" #include "hal/gdt.h"
@ -12,7 +14,9 @@
#include "hal/smp.h" #include "hal/smp.h"
#include "hal/tsc.h" #include "hal/tsc.h"
#include "mm/pmm.h" #include "mm/pmm.h"
#include "mm/slab.h"
#include "mm/vmm.h" #include "mm/vmm.h"
#include "mm/page.h"
#include "mm/kmalloc.h" #include "mm/kmalloc.h"
#include "sys/acpi.h" #include "sys/acpi.h"
#include "sys/pci.h" #include "sys/pci.h"
@ -20,6 +24,7 @@
#include "drivers/pmt.h" #include "drivers/pmt.h"
#include "drivers/ahci.h" #include "drivers/ahci.h"
#include "scheduler/sched.h" #include "scheduler/sched.h"
#include "sys/rand.h"
static volatile struct limine_framebuffer_request framebuffer_request = { static volatile struct limine_framebuffer_request framebuffer_request = {
.id = LIMINE_FRAMEBUFFER_REQUEST, .id = LIMINE_FRAMEBUFFER_REQUEST,
@ -77,46 +82,73 @@ void _start(void){
extern link_symbol_ptr text_start_addr, text_end_addr; extern link_symbol_ptr text_start_addr, text_end_addr;
klog(LOG_INFO, "serial", "Initalizing serial controller");
serial_init(); serial_init();
klog(LOG_SUCCESS, "serial", "Done!"); krand_init();
klog(LOG_INFO, "gdt", "Setting up the GDT");
set_gdt(); set_gdt();
klog(LOG_SUCCESS, "gdt", "Done!");
klog(LOG_INFO, "idt", "Setting up the IDT");
set_idt(); set_idt();
klog(LOG_SUCCESS, "idt", "Done!");;
klog(LOG_INFO, "acpi", "Reading ACPI tables"); klog("acpi", "Reading ACPI tables");
acpi_init(); acpi_init();
klog(LOG_SUCCESS, "acpi", "Done!");
klog(LOG_INFO, "apic", "Initalizing APIC");
klog("apic", "Initalizing APIC");
apic_init(); apic_init();
klog(LOG_SUCCESS, "apic", "Done!");
tsc_init(); tsc_init();
klog(LOG_INFO, "pmm", "Setting up the PMM"); klog("pmm", "Setting up the PMM");
pmm_init(); pmm_init();
klog(LOG_SUCCESS, "pmm", "Done!");
klog(LOG_INFO, "vmm", "Setting up the page tables");
klog("vmm", "Setting up the page tables");
vmm_init(); vmm_init();
klog(LOG_SUCCESS, "vmm", "Done!"); init_page_array();
kernel_heap_init();
klog(LOG_INFO, "smp", "Starting APs"); //struct ma_kcache *cache = ma_cache_create("bird", 1048576, 0, 0, 0);
//uint64_t *d = ma_cache_alloc(cache, 0);
//cache_info(cache);
//memset(d, 0, 1048576);
//for(;;);
//cache_info(cache);
_kmalloc_init();
int *my_int;
for(int i = 0;i < 3000;i++){
my_int = kmalloc(512);
*my_int = rand();
kprintf("my int: {d} on iter: {d}\n", *my_int, i);
kstatus status = kfree(my_int);
if(status != KERNEL_STATUS_SUCCESS){
kprintf("status: {d}\n", status);
}
}
kprintf("my int: {d}\n", *my_int);
//for(;;){}
klog("smp", "Starting APs");
smp_init(); smp_init();
klog(LOG_SUCCESS, "smp", "Done!");
klog(LOG_INFO, "pci", "Getting le pci");
klog("pci", "Getting le pci");
pci_init(); pci_init();
klog(LOG_SUCCESS, "pci", "Done!");
scheduler_init(); scheduler_init();

View file

@ -1,167 +1,51 @@
#include <stdbool.h> #include "slab.h"
#include <stdint.h> #include <stddef.h>
#include <limine.h> #include <kprint.h>
#include <stdio.h> #include <kmath.h>
#include <SFB25.h> struct ma_kcache *kmalloc_caches[14] = {0};
#include <string.h>
#include <lock.h>
#include "pmm.h"
#include "vmm.h"
#include "kmalloc.h"
#define KERNEL_MAX_BLOCK 512 // Create various sizes of caches to be used by kmalloc
void _kmalloc_init(void){
typedef struct block_t { kmalloc_caches[0] = ma_cache_create("kmalloc16", 16, 0, NULL, NULL);
uint64_t addr; kmalloc_caches[1] = ma_cache_create("kmalloc32", 32, 0, NULL, NULL);
uint32_t size; kmalloc_caches[2] = ma_cache_create("kmalloc64", 64, 0, NULL, NULL);
bool free; kmalloc_caches[3] = ma_cache_create("kmalloc128", 128, 0, NULL, NULL);
} block_t; kmalloc_caches[4] = ma_cache_create("kmalloc256", 256, 0, NULL, NULL);
kmalloc_caches[5] = ma_cache_create("kmalloc512", 512, 0, NULL, NULL);
block_t *base = NULL; kmalloc_caches[6] = ma_cache_create("kmalloc1K", 1024, 0, NULL, NULL);
uint64_t *heap_addr = NULL; kmalloc_caches[7] = ma_cache_create("kmalloc4K", 4096, 0, NULL, NULL);
kmalloc_caches[8] = ma_cache_create("kmalloc8K", 8192, 0, NULL, NULL);
void kernel_heap_init(){ kmalloc_caches[9] = ma_cache_create("kmalloc32K", 32768, 0, NULL, NULL);
extern struct limine_memmap_response *memmap_response; kmalloc_caches[10] = ma_cache_create("kmalloc64K", 65536, 0, NULL, NULL);
extern uint64_t pmm_page_count; kmalloc_caches[11] = ma_cache_create("kmalloc131K", 131072, 0, NULL, NULL);
kmalloc_caches[12] = ma_cache_create("kmalloc524K", 524288, 0, NULL, NULL);
/* Allocate memory for the blocks*/ kmalloc_caches[13] = ma_cache_create("kmalloc1M", 1048576, 0, NULL, NULL);
base = kernel_allocate_memory(KERNEL_MAX_BLOCK * sizeof(block_t), PTE_BIT_RW | PTE_BIT_NX);
if(!base){
klog(LOG_ERROR, __func__, "Failed to allocate memory for kernel heap blocks");
kkill();
}
memset(base, 0, KERNEL_MAX_BLOCK * sizeof(block_t));
/* Allocate memory for the heap */
heap_addr = kernel_allocate_memory(KERNEL_HEAP_SIZE, PTE_BIT_RW | PTE_BIT_NX);
if(!heap_addr){
klog(LOG_ERROR, __func__, "Failed to allocate memory for the kernel heap");
kkill();
}
base->free = true;
} }
void *kmalloc(uint64_t size){ size_t sizes[14] = {16, 32, 64, 128, 256, 512, 1024, 4096, 8192, 32768, 65536, 131072, 524288, 1048756};
/* First check if there is a free block which fits the size requirement */ void *kmalloc(size_t size){
for(int i = 0; i < KERNEL_MAX_BLOCK; i++){ if(size > 1048576){
if(base[i].addr && base[i].free && base[i].size >= size){ klog(__func__, "Attempted to allocate more than max size (1M)");
base[i].free = false;
return (void*)base[i].addr;
}
}
int i = 0;
/* Parse the list until you find the next free block */
while (!base[i].free && !base[i].addr){
if(i > KERNEL_MAX_BLOCK){
/* Over max block limit */
return NULL;
}
i++;
}
/* Fill this block in */
uint64_t addr = (uint64_t)heap_addr;
/* Calculate address offset */
for(int j = 0; j < i; j++){
if(addr > ((uint64_t)heap_addr + KERNEL_HEAP_SIZE)){
/* Out of heap memory */
return NULL;
}
addr += base[j].size;
}
memset((uint64_t*)addr, 0, size);
base[i].addr = addr;
base[i].free = false;
base[i].size = size;
return (void*)addr;
}
void kfree(void *addr){
for(int i = 0; i < KERNEL_MAX_BLOCK; i++){
if(base[i].addr == (uint64_t)addr){
base[i].free = true;
memset((void*)base[i].addr, 0, base[i].size);
return;
}
}
kprintf("kfree: attempted to free non-heap address!\n");
kkill();
}
void *krealloc(void *addr, uint64_t size) {
if (addr == NULL) {
return kmalloc(size);
}
if (size == 0) {
kfree(addr);
return NULL; return NULL;
} }
// Find the block corresponding to the pointer void *addr = NULL;
int i; for(int i = 0; i < 14; i++){
for (i = 0; i < KERNEL_MAX_BLOCK; i++) { if(sizes[i] >= size){
if (base[i].addr == (uint64_t)addr) { addr = ma_cache_alloc(kmalloc_caches[i], 0);
break; break;
} }
} }
if (i == KERNEL_MAX_BLOCK) { if(addr == NULL){
kprintf("krealloc: attempted to realloc non-heap address!\n"); klog(__func__, "Failed to allocate heap memory!");
kkill();
} }
block_t *block = &base[i]; return addr;
uint64_t old_size = block->size;
// If the current size is already sufficient, return the same pointer }
if (old_size >= size) {
return addr;
}
// Check if this block is the last allocated block in the array kstatus kfree(void *addr){
bool is_last = true; return ma_cache_dealloc(addr);
for (int j = i + 1; j < KERNEL_MAX_BLOCK; j++) {
if (base[j].addr != 0) {
is_last = false;
break;
}
}
// If it's the last block, check if there's enough space to expand
if (is_last) {
uint64_t current_end = block->addr + block->size;
uint64_t heap_end = (uint64_t)heap_addr + KERNEL_HEAP_SIZE;
uint64_t available = heap_end - current_end;
if (available >= (size - old_size)) {
// Expand the block in place
block->size = size;
return addr;
}
}
// Allocate a new block, copy data, and free the old block
void *new_ptr = kmalloc(size);
if (!new_ptr) {
return NULL; // Allocation failed
}
memcpy(new_ptr, addr, old_size);
kfree(addr);
return new_ptr;
} }

View file

@ -1,10 +1,7 @@
#include "error.h"
#include <stdint.h> #include <stdint.h>
void kernel_heap_init();
void heap_free(uint64_t *addr); void _kmalloc_init(void);
uint64_t *heap_alloc();
void *kmalloc(uint64_t size); void *kmalloc(uint64_t size);
void kfree(void *addr); kstatus kfree(void *addr);
#define KERNEL_HEAP_SIZE 0x10000000

61
src/mm/page.c Normal file
View file

@ -0,0 +1,61 @@
#include "page.h"
#include <limine.h>
#include "vmm.h"
#include <SFB25.h>
#include <stdatomic.h>
#include <kprint.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
struct page *pages; // "virtually sparse array", it holds all the pages between the start of the first usable address to the last one.
extern struct limine_memmap_response *memmap_response;
extern uint64_t hhdmoffset;
// Get the page object which is associated with the page that the address `addr` resides in
struct page *get_page(void *addr){
void *canonical_addr = (void*)PAGE_ROUND_DOWN((uint64_t)addr);
uint64_t phys_addr = kget_phys_addr(canonical_addr);
if(phys_addr == 0){
return NULL;
}
uint64_t index = phys_addr / PAGE_SIZE;
return &pages[index];
}
void init_page_array(){
struct limine_memmap_entry **entries = memmap_response->entries;
size_t firstaddr = 0;
size_t lastaddr = 0;
for(size_t i = 0; i < memmap_response->entry_count; i++){
switch(entries[i]->type){
case LIMINE_MEMMAP_USABLE:
if(firstaddr == 0){
firstaddr = entries[i]->base;
}else{
lastaddr = entries[i]->base + entries[i]->length;
}
}
}
size_t page_count = (lastaddr - firstaddr) / PAGE_SIZE;
pages = va_alloc_contigious_pages((page_count * sizeof(struct page)) / PAGE_SIZE);
if(pages == NULL){
klog(__func__, "Couldn't allocate page structure");
kkill();
return;
}
memset(pages, 0, (page_count * sizeof(struct page)) / PAGE_SIZE);
}

10
src/mm/page.h Normal file
View file

@ -0,0 +1,10 @@
#include "slab.h"
typedef struct page {
struct ma_bufctl *bufctls; // The bufctls associated with the slab stored on this page. NULL if page isn't associated with a slab
struct ma_slab *slab;
}page;
struct page *get_page(void *addr);
void init_page_array();

View file

@ -1,7 +1,6 @@
#include <limine.h> #include <limine.h>
#include <stdio.h> #include <kprint.h>
#include <SFB25.h> #include <SFB25.h>
#include <string.h>
#include <lock.h> #include <lock.h>
#include "pmm.h" #include "pmm.h"
#include "kmalloc.h" #include "kmalloc.h"
@ -25,7 +24,7 @@ uint64_t *free_list = NULL;
atomic_flag pmm_lock = ATOMIC_FLAG_INIT; atomic_flag pmm_lock = ATOMIC_FLAG_INIT;
void pmm_free(uint64_t *addr){ void pmm_free(uint64_t *addr){
acquire_lock(&pmm_lock); acquire_spinlock(&pmm_lock);
uint64_t *virt_addr = (uint64_t*)((uint64_t)addr+hhdmoffset); uint64_t *virt_addr = (uint64_t*)((uint64_t)addr+hhdmoffset);
/* Make the given page point to the previous free page */ /* Make the given page point to the previous free page */
@ -35,12 +34,12 @@ void pmm_free(uint64_t *addr){
free_list = virt_addr; free_list = virt_addr;
pmm_free_page_count++; pmm_free_page_count++;
free_lock(&pmm_lock); free_spinlock(&pmm_lock);
return; return;
} }
uint64_t *pmm_alloc(){ uint64_t *pmm_alloc(){
acquire_lock(&pmm_lock); acquire_spinlock(&pmm_lock);
if(pmm_free_page_count <= 0){ if(pmm_free_page_count <= 0){
return NULL; return NULL;
} }
@ -49,20 +48,19 @@ uint64_t *pmm_alloc(){
uint64_t *addr = (uint64_t*)((uint64_t)free_list - hhdmoffset); uint64_t *addr = (uint64_t*)((uint64_t)free_list - hhdmoffset);
free_list = (uint64_t*)(*free_list); free_list = (uint64_t*)(*free_list);
pmm_free_page_count--; pmm_free_page_count--;
free_lock(&pmm_lock); free_spinlock(&pmm_lock);
return addr; return addr;
} }
void pmm_init(){ void pmm_init(){
if(memmap_request.response == NULL){ if(memmap_request.response == NULL){
klog(LOG_ERROR, __func__, "Memmap response is null"); klog(__func__, "Memmap response is null");
kkill(); kkill();
} }
memmap_response = memmap_request.response; memmap_response = memmap_request.response;
struct limine_memmap_entry **entries = memmap_response->entries; struct limine_memmap_entry **entries = memmap_response->entries;
for(uint64_t i = 0; i < memmap_response->entry_count; i++){ for(uint64_t i = 0; i < memmap_response->entry_count; i++){

View file

@ -10,5 +10,4 @@ typedef struct free_page_t {
void pmm_init(void); void pmm_init(void);
uint64_t *pmm_alloc(); uint64_t *pmm_alloc();
void pmm_free(uint64_t *addr); void pmm_free(uint64_t *addr);

437
src/mm/slab.c Normal file
View file

@ -0,0 +1,437 @@
#include <stdatomic.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include "error.h"
#include "vmm.h"
#include "page.h"
#include "slab.h"
#include <kprint.h>
#include <SFB25.h>
#include <lock.h>
struct ma_kcache *caches = NULL;
atomic_flag caches_lock = ATOMIC_FLAG_INIT;
enum SLAB_STATE {
FREE = 0,
PARTIAL,
USED
};
// Gets free object from slab and handles stuff
uint64_t *_ma_slab_get_free_obj(struct ma_slab *slab){
if(slab->free == NULL){
return NULL;
}
uint64_t *addr = slab->free->startaddr;
if(addr == NULL){
return NULL;
}
if(slab->free->next != NULL){
slab->free = slab->free->next;
}else{
slab->free = NULL;
}
// Move the slab from the free to the partial list on the first time it's allocated from
if(slab->refcount == 0){
if(slab->prev != NULL){
slab->prev->next = slab->next;
}else{
slab->cache->slabs_free = NULL;
}
/* If there is a partial slab head then make it the head and do other stuff */
if(slab->cache->slabs_partial != NULL){
slab->cache->slabs_partial->next = slab;
slab->prev = slab->cache->slabs_partial;
}
slab->next = NULL;
slab->cache->slabs_partial = slab;
}
slab->refcount++;
return addr;
}
kstatus _ma_alloc_slab(struct ma_kcache *kcache){
struct ma_slab *slab_structure = (struct ma_slab*)va_alloc_contigious_pages(1);
memset(slab_structure, 0, PAGE_SIZE);
// Put the addresses in the slab structure into the bufctls
if(kcache->objsize >= 512){
slab_structure->free = (struct ma_bufctl*)(va_alloc_contigious_pages(1)); // Store the bufctls off-page
memset(slab_structure->free, 0, 4096);
uint64_t slabsize = kcache->slabsize;
void *mstart = va_alloc_contigious_pages(kcache->slabsize);
for(size_t j = 0; j < kcache->slabsize; j++){
get_page((void*)((uint64_t)mstart + j*PAGE_SIZE))->slab = slab_structure;
get_page((void*)((uint64_t)mstart + j*PAGE_SIZE))->bufctls = slab_structure->free;
}
for(size_t i = 0; i < (PAGE_SIZE * slabsize)/kcache->objsize; i++){
((struct ma_bufctl*)((uint64_t)slab_structure->free + sizeof(struct ma_bufctl)*(i)))->startaddr = (size_t*)((uint64_t)mstart + i * kcache->objsize);
((struct ma_bufctl*)((uint64_t)slab_structure->free + sizeof(struct ma_bufctl)*(i)))->next = (struct ma_bufctl*)((uint64_t)slab_structure->free + sizeof(struct ma_bufctl)*(i+1));
}
}else{
/* In this case the objects acts as bufctl structures. Small downside: there will always be a max of 252 objects per slab, no matter the size of the object, since
* they have to have enough space to store a bufctl structure (16 bytes).
*
* Their startaddr is the same as the address of the bufctl, since the objects act as the bufctls.
*/
slab_structure->free = va_alloc_contigious_pages(kcache->slabsize);
get_page(slab_structure->free)->slab = slab_structure;
get_page(slab_structure->free)->bufctls = slab_structure->free;
uint64_t size = (kcache->objsize >= sizeof(struct ma_bufctl)) ? kcache->objsize : sizeof(struct ma_bufctl);
for(size_t i = 0; i < kcache->num; i++){
((struct ma_bufctl*)((uint64_t)slab_structure->free + size*i))->startaddr = (size_t*)((uint64_t)slab_structure->free + i * size);
if(i+1 < kcache->num){
((struct ma_bufctl*)((uint64_t)slab_structure->free + size*i))->next = (struct ma_bufctl*)((uint64_t)slab_structure->free + size*(i+1));
}else{
((struct ma_bufctl*)((uint64_t)slab_structure->free + size*i))->next = NULL;
}
}
}
if(kcache->slabs_free == NULL){
kcache->slabs_free = slab_structure;
}else{
// Change head
kcache->slabs_free->next = slab_structure;
slab_structure->prev = kcache->slabs_free;
kcache->slabs_free = slab_structure;
}
slab_structure->cache = kcache;
return KERNEL_STATUS_SUCCESS;
}
void _ma_move_slab(struct ma_slab *slab, enum SLAB_STATE newstate){
struct ma_kcache *cache = slab->cache;
struct ma_slab *sb = 0;
switch (newstate) {
case FREE:
if(cache->slabs_partial != NULL){
sb = cache->slabs_partial;
while(sb != NULL){
if(sb == slab){
goto free_common;
}
sb = sb->prev;
}
}
if(cache->slabs_used != NULL){
sb = cache->slabs_used;
while(sb != NULL){
if(sb == slab){
goto free_common;
}
sb = sb->prev;
}
}
return;
case PARTIAL:
if(cache->slabs_free != NULL){
sb = cache->slabs_free;
while(sb != NULL){
if(sb == slab){
goto partial_common;
}
sb = sb->prev;
}
}
if(cache->slabs_used != NULL){
sb = cache->slabs_used;
while(sb != NULL){
if(sb == slab){
goto partial_common;
}
sb = sb->prev;
}
}
return;
case USED:
if(cache->slabs_free != NULL){
sb = cache->slabs_free;
while(sb != NULL){
if(sb == slab){
goto used_common;
}
sb = sb->prev;
}
}
if(cache->slabs_partial != NULL){
sb = cache->slabs_partial;
while(sb != NULL){
if(sb == slab){
goto used_common;
}
sb = sb->prev;
}
}
return;
}
free_common:
// Preserve the linkage
if(sb->prev != NULL){
if(sb->next != NULL){
sb->next->prev = sb->prev;
}
sb->prev->next = sb->next;
}
if(cache->slabs_free != NULL){
cache->slabs_free->next = slab;
slab->prev = cache->slabs_free;
}
cache->slabs_free = slab;
return;
partial_common:
if(sb->prev != NULL){
if(sb->next != NULL){
sb->next->prev = sb->prev;
}
sb->prev->next = sb->next;
}
if(cache->slabs_partial != NULL){
cache->slabs_partial->next = slab;
slab->prev = cache->slabs_partial;
}
cache->slabs_partial = slab;
return;
used_common:
if(sb->prev != NULL){
if(sb->next != NULL){
sb->next->prev = sb->prev;
}
sb->prev->next = sb->next;
}
if(cache->slabs_used != NULL){
cache->slabs_used->next = slab;
slab->prev = cache->slabs_used;
}
cache->slabs_used = slab;
return;
}
struct ma_kcache *ma_cache_create(char *name, size_t size, uint32_t flags, void (*constructor)(void *, size_t), void (*destructor)(void *, size_t)){
acquire_spinlock(&caches_lock);
struct ma_kcache *kcache = (struct ma_kcache*)va_alloc_contigious_pages(1);
memset(kcache, 0, 4096);
memcpy(kcache->name, name, 16);
kcache->slabsize = (size / PAGE_SIZE) + 1;
kcache->num = (4096 * kcache->slabsize - sizeof(struct ma_slab)) / ((size >= sizeof(struct ma_bufctl)) ? size : sizeof(struct ma_bufctl)); // Calculate the number of buffers in this slab
kcache->objsize = size;
memset(&kcache->lock, 0, sizeof(atomic_flag));
_ma_alloc_slab(kcache);
if(caches != NULL){
caches->next = kcache;
kcache->prev = caches;
}
caches = kcache;
free_spinlock(&caches_lock);
return kcache;
}
void *ma_cache_alloc(struct ma_kcache *kcache, uint32_t flags){
acquire_spinlock(&kcache->lock);
struct ma_slab *slab = NULL;
if(kcache->slabs_free == NULL){
if(kcache->slabs_partial == NULL){
_ma_alloc_slab(kcache);
slab = kcache->slabs_free;
}else{
slab = kcache->slabs_partial;
}
}else{
slab = kcache->slabs_free;
}
uint64_t *addr = _ma_slab_get_free_obj(slab);
if(addr == NULL){
slab->free = NULL;
if(kcache->slabs_partial->prev != NULL){
kcache->slabs_partial = kcache->slabs_partial->prev;
}else{
kcache->slabs_partial = NULL;
}
if(kcache->slabs_used != NULL){
kcache->slabs_used->next = slab;
slab->prev = kcache->slabs_used;
kcache->slabs_used = slab;
}else{
kcache->slabs_used = slab;
}
_ma_alloc_slab(kcache);
addr = _ma_slab_get_free_obj(kcache->slabs_free);
}
free_spinlock(&kcache->lock);
return addr;
}
void cache_info(struct ma_kcache *cache){
kprintf("name: {s}\n", cache->name);
kprintf("objsize: {d}\n", cache->objsize);
kprintf("num: {d}\n", cache->num);
kprintf("slabsize: {d}\n", cache->slabsize);
int slabsfreecnt = 0;
if(cache->slabs_free == NULL){
kprintf("slabsfree: 0\n");
}else{
if(cache->slabs_free->prev == NULL){
kprintf("slabsfree: 1\n");
}else{
struct ma_slab *slab = cache->slabs_free;
while(slab->prev != NULL){
slab = slab->prev;
slabsfreecnt++;
}
kprintf("slabsfree : {d}\n", slabsfreecnt);
}
}
int slabspartcnt = 0;
if(cache->slabs_partial == NULL){
kprintf("slabspartial: 0\n");
}else{
if(cache->slabs_partial->prev == NULL){
kprintf("slabspartial: 1\n");
}else{
struct ma_slab *slab = cache->slabs_partial;
while(slab->prev != NULL){
slab = slab->prev;
slabspartcnt++;
}
kprintf("slabspartial: {d}\n", slabspartcnt+1);
}
}
int slabsfullcnt = 0;
if(cache->slabs_used == NULL){
kprintf("slabsused: 0\n");
}else{
if(cache->slabs_used->prev == NULL){
kprintf("slabsused: 1\n");
}else{
struct ma_slab *slab = cache->slabs_used;
while(slab->prev != NULL){
slab = slab->prev;
slabsfullcnt++;
}
kprintf("slabsused : {d}\n", slabsfullcnt);
}
}
}
struct ma_bufctl *addr_to_bufctl(void *object){
struct ma_slab *slab = get_page(object)->slab;
if(slab == NULL){
return NULL;
}
struct ma_bufctl *bufs = get_page(object)->bufctls;
if(bufs == NULL){
return NULL;
}
for(size_t i = 0; i < slab->cache->num; i++){
if((bufs + i)->startaddr == object){
return (bufs + i);
}
}
return NULL;
}
kstatus ma_cache_dealloc(void *object){
struct ma_slab *slab = get_page(object)->slab;
if(slab == NULL){
klog(__func__, "slab == null");
return KERNEL_STATUS_ERROR;
}
struct ma_bufctl *buf = addr_to_bufctl(object);
if(buf == NULL){
klog(__func__, "bufctl not found");
return KERNEL_STATUS_ERROR;
}
buf->next = slab->free;
slab->free = buf;
slab->refcount--;
if(slab->refcount == slab->cache->num - 1){
_ma_move_slab(slab, PARTIAL);
}else if(slab->refcount == 0){
_ma_move_slab(slab, FREE);
}
return KERNEL_STATUS_SUCCESS;
}

57
src/mm/slab.h Normal file
View file

@ -0,0 +1,57 @@
#include <stdatomic.h>
#include <stddef.h>
#include <stdint.h>
#include <error.h>
#include <stdbool.h>
#pragma once
#define KCACHE_NAME_LEN 16
struct ma_bufctl {
struct ma_bufctl *next;
size_t *startaddr;
};
struct ma_slab {
struct ma_kcache *cache;
struct ma_slab *next;
struct ma_slab *prev;
uint32_t refcount; // The amount of active (not free) objects in the slabs
struct ma_bufctl *free; // Linked list of free buffers in the slab. Is equal to NULL once there are no more free objects
};
/* objrefs are used to be able to quickly find out which slab and cache a object belongs to. objrefs belonging to the same slab are kept in one page, there is no mixing. */
struct ma_objref {
struct ma_objref *next;
struct ma_objref *prev;
void *addr; // Addr of the object
struct ma_slab *slab; // The slab which the obj belongs to
struct ma_kcache *kcache; // The cache which the obj belongs to
};
struct ma_kcache {
struct ma_kcache *next;
struct ma_kcache *prev;
uint32_t objsize; // Size of the object which the cache stores
uint16_t flags; // Not useful yet
uint32_t num; // Number of objects per slab
uint32_t slabsize; // How many pages does a single slab take up. Useful for objects > PAGE_SIZE
struct ma_slab *slabs_free;
struct ma_slab *slabs_partial;
struct ma_slab *slabs_used;
atomic_flag lock;
char name[KCACHE_NAME_LEN];
};
void *ma_cache_alloc(struct ma_kcache *kcache, uint32_t flags);
kstatus ma_cache_dealloc(void *object);
struct ma_kcache *ma_cache_create(char *name, size_t size, uint32_t flags, void (*constructor)(void *, size_t), void (*destructor)(void *, size_t));
void cache_info(struct ma_kcache *cache);

View file

@ -1,6 +1,7 @@
#include <lock.h> #include <lock.h>
#include <stdatomic.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <kprint.h>
#include <SFB25.h> #include <SFB25.h>
#include <string.h> #include <string.h>
#include <limine.h> #include <limine.h>
@ -38,13 +39,13 @@ void vmm_init(){
struct limine_kernel_address_response *kernel_address = kernel_addr_request.response; struct limine_kernel_address_response *kernel_address = kernel_addr_request.response;
if(!kernel_address){ if(!kernel_address){
klog(LOG_ERROR, __func__, "Kernel address not recieved"); klog(__func__, "Kernel address not recieved");
} }
kernel_page_map = (uint64_t*)((uint64_t)pmm_alloc() + hhdmoffset); kernel_page_map = (uint64_t*)((uint64_t)pmm_alloc() + hhdmoffset);
if(!kernel_page_map){ if(!kernel_page_map){
klog(LOG_ERROR, __func__, "Allocating block for page map failed"); klog(__func__, "Allocating block for page map failed");
} }
memset(kernel_page_map, 0, PAGE_SIZE); memset(kernel_page_map, 0, PAGE_SIZE);
@ -157,7 +158,7 @@ uint64_t *get_lower_table(uint64_t *page_map, uint64_t offset){
uint64_t *ret = pmm_alloc(); uint64_t *ret = pmm_alloc();
if(!ret){ if(!ret){
klog(LOG_ERROR, __func__, "Failed to allocate page table"); klog(__func__, "Failed to allocate page table");
kprintf("page_map: 0x{xn}", (uint64_t)page_map); kprintf("page_map: 0x{xn}", (uint64_t)page_map);
kprintf("offset: 0x{xn}", offset); kprintf("offset: 0x{xn}", offset);
@ -177,7 +178,7 @@ atomic_flag page_table_lock = ATOMIC_FLAG_INIT;
void vmm_map_page(uint64_t *page_map, uint64_t virt_addr, uint64_t phys_addr, uint64_t flags){ void vmm_map_page(uint64_t *page_map, uint64_t virt_addr, uint64_t phys_addr, uint64_t flags){
/* Probably slow, fix in future */ /* Probably slow, fix in future */
acquire_lock(&page_table_lock); acquire_spinlock(&page_table_lock);
uint64_t pml4_offset = (virt_addr >> 39) & 0x1ff; uint64_t pml4_offset = (virt_addr >> 39) & 0x1ff;
uint64_t pdp_offset = (virt_addr >> 30) & 0x1ff; uint64_t pdp_offset = (virt_addr >> 30) & 0x1ff;
@ -187,24 +188,28 @@ void vmm_map_page(uint64_t *page_map, uint64_t virt_addr, uint64_t phys_addr, ui
uint64_t *pdp = get_lower_table(page_map, pml4_offset); uint64_t *pdp = get_lower_table(page_map, pml4_offset);
if(!pdp){ if(!pdp){
klog(LOG_ERROR, __func__, "Failed to allocate PDP"); klog( __func__, "Failed to allocate PDP");
kkill(); kkill();
} }
uint64_t *pd = get_lower_table(pdp, pdp_offset); uint64_t *pd = get_lower_table(pdp, pdp_offset);
if(!pd){ if(!pd){
klog(LOG_ERROR, __func__, "Failed to allocate PD"); klog(__func__, "Failed to allocate PD");
kkill(); kkill();
} }
uint64_t *pt = get_lower_table(pd, pd_offset); uint64_t *pt = get_lower_table(pd, pd_offset);
if(!pt){ if(!pt){
klog(LOG_ERROR, __func__, "Failed to allocate PT"); klog( __func__, "Failed to allocate PT");
kkill(); kkill();
} }
if(pt[pt_offset] != 0){
goto end;
}
pt[pt_offset] = phys_addr | flags; pt[pt_offset] = phys_addr | flags;
asm volatile( asm volatile(
@ -213,7 +218,9 @@ void vmm_map_page(uint64_t *page_map, uint64_t virt_addr, uint64_t phys_addr, ui
: : : "rax" : : : "rax"
); );
free_lock(&page_table_lock); end:
free_spinlock(&page_table_lock);
} }
@ -227,14 +234,14 @@ void vmm_free_page(uint64_t *page_map, uint64_t virt_addr){
if(!pdp){ if(!pdp){
klog(LOG_ERROR, __func__, "Failed to allocate PDP"); klog(__func__, "Failed to allocate PDP");
kkill(); kkill();
} }
uint64_t *pd = get_lower_table(pdp, pdp_offset); uint64_t *pd = get_lower_table(pdp, pdp_offset);
if(!pd){ if(!pd){
klog(LOG_ERROR, __func__, "Failed to allocate PD"); klog( __func__, "Failed to allocate PD");
kkill(); kkill();
} }
@ -242,7 +249,7 @@ void vmm_free_page(uint64_t *page_map, uint64_t virt_addr){
uint64_t *pt = get_lower_table(pd, pd_offset); uint64_t *pt = get_lower_table(pd, pd_offset);
if(!pt){ if(!pt){
klog(LOG_ERROR, __func__, "Failed to allocate PT"); klog(__func__, "Failed to allocate PT");
kkill(); kkill();
} }
@ -259,8 +266,37 @@ void vmm_free_page(uint64_t *page_map, uint64_t virt_addr){
); );
} }
uint64_t vmm_get_phys_addr(uint64_t *page_map, uint64_t virt_addr){
uint64_t pml4_offset = (virt_addr >> 39) & 0x1ff;
uint64_t pdp_offset = (virt_addr >> 30) & 0x1ff;
uint64_t pd_offset = (virt_addr >> 21) & 0x1ff;
uint64_t pt_offset = (virt_addr >> 12) & 0x1ff;
uint64_t pml4e = page_map[pml4_offset];
if (!(pml4e & 1)) return 0; //
uint64_t *pdp = (uint64_t *)((pml4e & 0x000ffffffffff000) + hhdmoffset);
uint64_t pdpe = pdp[pdp_offset];
if (!(pdpe & 1)) return 0;
uint64_t *pd = (uint64_t *)((pdpe & 0x000ffffffffff000) + hhdmoffset);
uint64_t pde = pd[pd_offset];
if (!(pde & 1)) return 0;
uint64_t *pt = (uint64_t *)((pde & 0x000ffffffffff000) + hhdmoffset);
uint64_t pte = pt[pt_offset];
if (!(pte & 1)) return 0;
return pte & 0x000ffffffffff000;
}
uint64_t kget_phys_addr(uint64_t *virt_addr){
return vmm_get_phys_addr(kernel_page_map, (uint64_t)virt_addr);
}
/* Maps `size` number of free pages at the specified virtual address */ /* Maps `size` number of free pages at the specified virtual address */
int vmm_map_continous_pages(uint64_t *page_map, uint64_t virt_addr, uint64_t phys_addr, uint64_t size, uint64_t flags){ int vmm_map_contigious_pages(uint64_t *page_map, uint64_t virt_addr, uint64_t phys_addr, uint64_t size, uint64_t flags){
for(uint64_t i = 0; i < size; i++){ for(uint64_t i = 0; i < size; i++){
vmm_map_page(page_map, virt_addr + i * PAGE_SIZE, (uint64_t)phys_addr, flags); vmm_map_page(page_map, virt_addr + i * PAGE_SIZE, (uint64_t)phys_addr, flags);
} }
@ -268,38 +304,49 @@ int vmm_map_continous_pages(uint64_t *page_map, uint64_t virt_addr, uint64_t phy
return 0; return 0;
} }
#define VA_BASE 0x800815000
uint64_t va_base = VA_BASE;
atomic_flag va_lock = ATOMIC_FLAG_INIT;
/* Allocates some pages from the PMM and makes them contigious in the kernels memory map. */
void *va_alloc_contigious_pages(size_t pages){
acquire_spinlock(&va_lock);
/* Allocates and maps memory into the kernel address space */ if(pages == 0){
void *kernel_allocate_memory(uint64_t size, uint64_t flags){ free_spinlock(&va_lock);
if(size == 0){
return NULL; return NULL;
} }
void *ret = NULL; size_t i;
for(uint64_t i = 0; i < size; i += PAGE_SIZE){ for(i = 0; i < pages; i++){
ret = pmm_alloc(); void *t = pmm_alloc();
if(t == NULL){
if(!ret){ free_spinlock(&va_lock);
return NULL; return NULL;
} }
vmm_map_page(kernel_page_map, (uint64_t)ret + hhdmoffset, (uint64_t)ret, PTE_BIT_PRESENT | flags); vmm_map_page(kernel_page_map, va_base+hhdmoffset+i*PAGE_SIZE, (uint64_t)t, PTE_BIT_RW | PTE_BIT_PRESENT);
} }
uint64_t va_base_old = va_base;
va_base += i*PAGE_SIZE;
free_spinlock(&va_lock);
return (void*)(va_base_old+hhdmoffset);
return (void*)((uint64_t)ret + hhdmoffset);
} }
/* Maps pages from phys_addr to phys_addr+size into the kernels address space */ /* Maps pages from phys_addr to phys_addr+size into the kernels address space */
void kernel_map_pages(void *phys_addr, uint64_t size, uint64_t flags){ void kmap_pages(void *phys_addr, uint64_t size, uint64_t flags){
for(uint64_t i = 0; i < size; i++){ for(uint64_t i = 0; i < size; i++){
vmm_map_page(kernel_page_map, (uint64_t)phys_addr + hhdmoffset + (i * PAGE_SIZE), (uint64_t)phys_addr + (i * PAGE_SIZE), PTE_BIT_PRESENT | flags); vmm_map_page(kernel_page_map, (uint64_t)phys_addr + hhdmoffset + (i * PAGE_SIZE), (uint64_t)phys_addr + (i * PAGE_SIZE), PTE_BIT_PRESENT | flags);
} }
} }
void kernel_unmap_pages(void *addr, uint64_t size){ void kunmap_pages(void *addr, uint64_t size){
for(uint64_t i = 0; i < size; i++){ for(uint64_t i = 0; i < size; i++){
vmm_free_page(kernel_page_map, (uint64_t)addr + i*PAGE_SIZE); vmm_free_page(kernel_page_map, (uint64_t)addr + i*PAGE_SIZE);
} }

View file

@ -11,13 +11,15 @@
void tlb_flush(void); void tlb_flush(void);
void vmm_map_page(uint64_t *page_map, uint64_t virt_address, uint64_t phys_address, uint64_t flags); void vmm_map_page(uint64_t *page_map, uint64_t virt_address, uint64_t phys_address, uint64_t flags);
int vmm_map_continous_pages(uint64_t *page_map, uint64_t virt_addr, uint64_t phys_addr, uint64_t size, uint64_t flags); int vmm_map_contigious_pages(uint64_t *page_map, uint64_t virt_addr, uint64_t phys_addr, uint64_t size, uint64_t flags);
void vmm_free_page(uint64_t *page_map, uint64_t virt_addr); void vmm_free_page(uint64_t *page_map, uint64_t virt_addr);
void vmm_init(); void vmm_init();
void vmm_set_ctx(uint64_t *page_map); void vmm_set_ctx(uint64_t *page_map);
void *kernel_allocate_memory(uint64_t size, uint64_t flags); uint64_t vmm_get_phys_addr(uint64_t *page_map, uint64_t virt_addr);
void kernel_map_pages(void *phys_addr, uint64_t size, uint64_t flags); uint64_t kget_phys_addr(uint64_t *virt_addr);
void kernel_unmap_pages(void *addr, uint64_t size); void *va_alloc_contigious_pages(uint64_t size);
void kmap_pages(void *phys_addr, uint64_t size, uint64_t flags);
void kunmap_pages(void *addr, uint64_t size);
typedef char link_symbol_ptr[]; typedef char link_symbol_ptr[];

View file

@ -1,4 +1,4 @@
#include <stdio.h> #include <kprint.h>
#include <string.h> #include <string.h>
#include <SFB25.h> #include <SFB25.h>
#include "../hal/smp.h" #include "../hal/smp.h"
@ -61,7 +61,7 @@ kstatus add_task(uint64_t *entry){
proc *proc = alloc_process(); proc *proc = alloc_process();
if (proc == NULL) { if (proc == NULL) {
klog(LOG_ERROR, __func__, "proc == null!"); klog(__func__, "proc == null!");
kkill(); kkill();
} }

View file

@ -1,6 +1,6 @@
#include <limine.h> #include <limine.h>
#include <stddef.h> #include <stddef.h>
#include <stdio.h> #include <kprint.h>
#include <SFB25.h> #include <SFB25.h>
#include <string.h> #include <string.h>
#include <stdalign.h> #include <stdalign.h>
@ -53,7 +53,7 @@ uint64_t *find_acpi_table(char *signature){
void acpi_init(void){ void acpi_init(void){
if(rsdp_request.response == NULL){ if(rsdp_request.response == NULL){
klog(LOG_ERROR, "acpi", "RSDP request is NULL"); klog("acpi", "RSDP request is NULL");
kkill(); kkill();
} }
@ -65,21 +65,21 @@ void acpi_init(void){
if(rsdp->revision >= 2){ if(rsdp->revision >= 2){
rsdt = NULL; rsdt = NULL;
xsdt = (xsdt_t*)(rsdp->xsdt_address + hhdmoffset); xsdt = (xsdt_t*)(rsdp->xsdt_address + hhdmoffset);
klog(LOG_INFO, "acpi", "Using XSDT header"); klog("acpi", "Using XSDT header");
kprintf("XSDT address: 0x{xn}", (uint64_t)xsdt); kprintf("XSDT address: 0x{x}\n", (uint64_t)xsdt);
kprintf("OEMID: {ccccccn}", xsdt->header.oemid[0], xsdt->header.oemid[1], xsdt->header.oemid[2], xsdt->header.oemid[3], xsdt->header.oemid[4], xsdt->header.oemid[5]); kprintf("OEMID: {cccccc}\n", xsdt->header.oemid[0], xsdt->header.oemid[1], xsdt->header.oemid[2], xsdt->header.oemid[3], xsdt->header.oemid[4], xsdt->header.oemid[5]);
}else{ }else{
xsdt = NULL; xsdt = NULL;
rsdt = (rsdt_t*)(rsdp->rsdt_address + hhdmoffset); rsdt = (rsdt_t*)(rsdp->rsdt_address + hhdmoffset);
klog(LOG_INFO, "acpi", "Using RSDT header"); klog("acpi", "Using RSDT header");
kprintf("RSDT address: 0x{xn}", (uint64_t)rsdt); kprintf("RSDT address: 0x{x}\n", (uint64_t)rsdt);
kprintf("OEMID: {ccccccn}", rsdt->header.oemid[0], rsdt->header.oemid[1], rsdt->header.oemid[2], rsdt->header.oemid[3], rsdt->header.oemid[4], rsdt->header.oemid[5]); kprintf("OEMID: {cccccc}\n", rsdt->header.oemid[0], rsdt->header.oemid[1], rsdt->header.oemid[2], rsdt->header.oemid[3], rsdt->header.oemid[4], rsdt->header.oemid[5]);
} }
madt = (madt_t*)find_acpi_table("APIC"); madt = (madt_t*)find_acpi_table("APIC");
if(!madt){ if(!madt){
klog(LOG_ERROR, __func__, "MADT table not found"); klog(__func__, "MADT table not found");
kkill(); kkill();
} }
} }

View file

@ -1,5 +1,5 @@
#include <SFB25.h> #include <SFB25.h>
#include <stdio.h> #include <kprint.h>
#include <string.h> #include <string.h>
#include <lock.h> #include <lock.h>
#include "acpi.h" #include "acpi.h"
@ -34,13 +34,13 @@ extern uint64_t *kernel_page_map;
atomic_flag pci_array_lock = ATOMIC_FLAG_INIT; atomic_flag pci_array_lock = ATOMIC_FLAG_INIT;
void pci_add_device(pci_structure structure){ void pci_add_device(pci_structure structure){
acquire_lock(&pci_array_lock); acquire_spinlock(&pci_array_lock);
int i = 0; int i = 0;
/* Find first unused space */ /* Find first unused space */
while(pci_array[i].func_addr[0] != 0){ while(pci_array[i].func_addr[0] != 0){
if(i >= PCI_DEVICE_BUS){ if(i >= PCI_DEVICE_BUS){
klog(LOG_ERROR, __func__, "No more space in the PCI array!"); klog(__func__, "No more space in the PCI array!");
kkill(); kkill();
} }
i++; i++;
@ -56,24 +56,24 @@ void pci_add_device(pci_structure structure){
} }
} }
free_lock(&pci_array_lock); free_spinlock(&pci_array_lock);
return; return;
} }
pci_structure *pci_get_device(pci_structure structure){ pci_structure *pci_get_device(pci_structure structure){
acquire_lock(&pci_array_lock); acquire_spinlock(&pci_array_lock);
pci_structure ret = {0}; pci_structure ret = {0};
for(int i = 0; i < PCI_DEVICE_BUS; i++){ for(int i = 0; i < PCI_DEVICE_BUS; i++){
if( structure.segment == pci_array[i].segment && if( structure.segment == pci_array[i].segment &&
structure.bus == pci_array[i].bus && structure.bus == pci_array[i].bus &&
structure.device == pci_array[i].device){ structure.device == pci_array[i].device){
free_spinlock(&pci_array_lock);
return &pci_array[i]; return &pci_array[i];
free_lock(&pci_array_lock);
} }
} }
free_lock(&pci_array_lock); free_spinlock(&pci_array_lock);
return NULL; return NULL;
} }
@ -170,7 +170,7 @@ void pci_init(){
mcfg = (mcfg_t*)find_acpi_table("MCFG"); mcfg = (mcfg_t*)find_acpi_table("MCFG");
if(!mcfg){ if(!mcfg){
klog(LOG_ERROR, __func__, "Failed to find MCFG table"); klog(__func__, "Failed to find MCFG table");
kprintf("pci: device: PCIe not supported! Halting"); kprintf("pci: device: PCIe not supported! Halting");
kkill(); kkill();
} }
@ -180,13 +180,13 @@ void pci_init(){
parse_conf_space(); parse_conf_space();
/* Map the config space */ /* Map the config space */
kernel_map_pages((uint64_t*)(config_space_base_addr - hhdmoffset), (PCIE_CONF_SPACE_WIDTH * end_pci_num) / PAGE_SIZE, PTE_BIT_RW | PTE_BIT_NX); kmap_pages((uint64_t*)(config_space_base_addr - hhdmoffset), (PCIE_CONF_SPACE_WIDTH * end_pci_num) / PAGE_SIZE, PTE_BIT_RW | PTE_BIT_NX);
/* Stores enough for an entire configuration space */ /* Stores enough for an entire configuration space */
pci_array = kmalloc((256 * 32) * sizeof(pci_structure)); pci_array = kmalloc((256 * 32) * sizeof(pci_structure));
if(!pci_array){ if(!pci_array){
klog(LOG_ERROR, __func__, "Failed to allocate memory for PCI structures!"); klog(__func__, "Failed to allocate memory for PCI structures!");
kkill(); kkill();
} }

36
src/sys/rand.c Normal file
View file

@ -0,0 +1,36 @@
#include <stddef.h>
#include <stdint.h>
#include <kprint.h>
#include <cpuid.h>
uint32_t next = 0;
uint16_t rand(void){
next = next * 1103515245 + 12345;
return (size_t) (next / 65536) % 32768;
}
void srand(uint32_t seed){
next = seed;
}
void krand_init(){
uint32_t unused, ecx;
__get_cpuid(0x01, &unused, &unused, &ecx, &unused);
ecx = (ecx & 2) >> 1;
if(ecx == 1){
/* RDRAND supported */
klog(__func__, "using RDRAND for random number seed\n");
uint32_t rand;
asm volatile (
"rdrand %0"
: "=r" (rand)
);
srand(rand);
}else{
next = 0;
}
}

3
src/sys/rand.h Normal file
View file

@ -0,0 +1,3 @@
#include <stddef.h>
void krand_init();
size_t rand(void);

View file

@ -3,7 +3,7 @@
#include "mm/vmm.h" #include "mm/vmm.h"
#include "mm/kmalloc.h" #include "mm/kmalloc.h"
#include <limine.h> #include <limine.h>
#include <stdio.h> #include <kprint.h>
#include <SFB25.h> #include <SFB25.h>
#include <io.h> #include <io.h>