17 Commits
Author SHA1 Message Date
PoliEcho c74ea060e5 kmallllllllllllloc 2026-09-28 19:14:54 +02:00
PoliEcho a2cd3aa1b1 add vmm_free 2026-09-28 14:50:13 +02:00
PoliEcho 92268b70fc kmalloc slowest path 2026-09-28 14:47:02 +02:00
PoliEcho 6dd0823c93 native features! 2026-09-27 21:10:28 +02:00
PoliEcho ffa23b1dba handle non-canonical addresses in vmm 2026-09-27 17:04:41 +02:00
PoliEcho 6c609e9840 vmm bullshit 2026-09-27 15:10:18 +02:00
PoliEcho 318fe96319 maybe fix colors in kmalloc 2026-09-25 17:20:56 +02:00
PoliEcho b0ab02c634 basic vmm_alloc structure 2026-09-25 17:20:24 +02:00
PoliEcho a95839c7c6 add RNG test to main 2026-09-25 17:20:01 +02:00
PoliEcho 3fe3d05b1b random numer generation 2026-09-25 17:18:40 +02:00
PoliEcho 700b1ec4b4 add EEXIST to errno.h 2026-09-25 16:08:22 +02:00
PoliEcho 07bd738566 fix limits 2026-09-25 13:07:33 +02:00
PoliEcho 16fde28a8b more limits 2026-09-25 13:02:22 +02:00
PoliEcho 7c0ac01110 partialy freelist madness 2026-09-24 20:58:16 +02:00
PoliEcho b917ebe973 used brain (kmalloc.h)
improve type clarity
2026-09-24 20:46:08 +02:00
PoliEcho 675ff8519a void********************* 2026-09-24 17:34:14 +02:00
PoliEcho 8ab7e5a33d add limit6 2026-09-24 12:21:54 +02:00
12 changed files with 518 additions and 91 deletions
+1 -1
View File
@@ -14,7 +14,7 @@ Low-Level Hardware & Interrupts
[x] IDT [x] IDT
[x] Basic IRQs (Internal/Legacy) [x] Basic IRQs (Internal/Legacy)
[x] Proper fault handling (Exceptions, Page Faults, #GP) [x] Proper fault handling (Exceptions, Page Faults, #GP)
[ ] Check for features with CPUID (NX-bit, SSE, AVX) [-] Check for features with CPUID (NX-bit, SSE, AVX)
[ ] APIC driver (Local APIC & I/O APIC) [ ] APIC driver (Local APIC & I/O APIC)
[ ] ACPI driver (Parsing RSDP/MADT for multi-core/APIC) [ ] ACPI driver (Parsing RSDP/MADT for multi-core/APIC)
[ ] HPET driver (High precision timing) [ ] HPET driver (High precision timing)
+1
View File
@@ -30,6 +30,7 @@ enum {
EILLSEQ, // Illegal byte sequence EILLSEQ, // Illegal byte sequence
EOVERFLOW, // EOVERFLOW, //
EALIGN, // Not aligned EALIGN, // Not aligned
EEXIST, // already exists
}; };
#endif #endif
+76 -34
View File
@@ -15,48 +15,90 @@ void* kzalloc(size_t size);
// zeroed-out memory. Returns a pointer to allocated memory or NULL. // zeroed-out memory. Returns a pointer to allocated memory or NULL.
void* kcalloc(size_t count, size_t size); void* kcalloc(size_t count, size_t size);
// 9 bytes in 8 bytes
#define TAG_SHIFT 56
#define TAG_MASK ((uintptr_t)0xFF << TAG_SHIFT)
#define SIGN_BIT ((uintptr_t)1 << 55)
typedef struct {
uintptr_t bits;
} tagged_ptr;
static inline tagged_ptr tp_make(void* p, uint8_t tag) {
uintptr_t addr = (uintptr_t)p & ~TAG_MASK;
return (tagged_ptr){addr | ((uintptr_t)tag << TAG_SHIFT)};
}
static inline uint8_t tp_tag(tagged_ptr t) {
return (uint8_t)(t.bits >> TAG_SHIFT);
}
static inline void* tp_ptr(tagged_ptr t) {
/* Bits 48..55 were untouched and still equal the canonical sign.
Copy bit 55 into bits 56..63. */
uintptr_t addr =
(t.bits & SIGN_BIT) ? (t.bits | TAG_MASK) : (t.bits & ~TAG_MASK);
return (void*)addr;
}
// powers of 2 // powers of 2
#define KMALLOC_MAX_SIZE 17 #define KMALLOC_MAX_SIZE 17
#define LOWEST_POWER 3
union per_cpu_freelist_cache { struct freelist {
void* freelists[KMALLOC_MAX_SIZE]; struct freelist* nextnode;
};
struct partialy_freelist {
struct freelist* freelist_nextnode;
struct partialy_freelist* partialy_freelist_nextnode;
};
// this is used when object is too small to hold the big one in this case we use
// first object as pointer storage and dont allocate it
struct partialy_freelist_short {
struct partialy_freelist_short* partialy_freelist_nextnode;
};
union freelists_list {
struct freelist* freelists[KMALLOC_MAX_SIZE];
struct { struct {
void* kmalloc_8; struct freelist* kmalloc_8;
void* kmalloc_16; struct freelist* kmalloc_16;
void* kmalloc_32; struct freelist* kmalloc_32;
void* kmalloc_64; struct freelist* kmalloc_64;
void* kmalloc_128; struct freelist* kmalloc_128;
void* kmalloc_256; struct freelist* kmalloc_256;
void* kmalloc_512; struct freelist* kmalloc_512;
void* kmalloc_1024; struct freelist* kmalloc_1024;
void* kmalloc_2048; struct freelist* kmalloc_2048;
void* kmalloc_4096; struct freelist* kmalloc_4096;
void* kmalloc_8192; struct freelist* kmalloc_8192;
void* kmalloc_16384; struct freelist* kmalloc_16384;
void* kmalloc_32768; struct freelist* kmalloc_32768;
void* kmalloc_65536; struct freelist* kmalloc_65536;
void* kmalloc_131072; struct freelist* kmalloc_131072;
}; };
}; };
union partial_list { union partialy_freelists_list {
void* freelists[KMALLOC_MAX_SIZE]; struct partialy_freelist* partialy_freelists[KMALLOC_MAX_SIZE];
struct { struct {
void* kmalloc_8; struct partialy_freelist* kmalloc_8;
void* kmalloc_16; struct partialy_freelist* kmalloc_16;
void* kmalloc_32; struct partialy_freelist* kmalloc_32;
void* kmalloc_64; struct partialy_freelist* kmalloc_64;
void* kmalloc_128; struct partialy_freelist* kmalloc_128;
void* kmalloc_256; struct partialy_freelist* kmalloc_256;
void* kmalloc_512; struct partialy_freelist* kmalloc_512;
void* kmalloc_1024; struct partialy_freelist* kmalloc_1024;
void* kmalloc_2048; struct partialy_freelist* kmalloc_2048;
void* kmalloc_4096; struct partialy_freelist* kmalloc_4096;
void* kmalloc_8192; struct partialy_freelist* kmalloc_8192;
void* kmalloc_16384; struct partialy_freelist* kmalloc_16384;
void* kmalloc_32768; struct partialy_freelist* kmalloc_32768;
void* kmalloc_65536; struct partialy_freelist* kmalloc_65536;
void* kmalloc_131072; struct partialy_freelist* kmalloc_131072;
}; };
}; };
+31
View File
@@ -0,0 +1,31 @@
#ifndef _LIMIT_H
#define _LIMIT_H
#define CHAR_BIT 8
#define INT8_WIDTH 8
#define INT16_WIDTH 16
#define INT32_WIDTH 32
#define INT64_WIDTH 64
#define UINT8_WIDTH 8
#define UINT16_WIDTH 16
#define UINT32_WIDTH 32
#define UINT64_WIDTH 64
#define INT8_MAX 127
#define INT16_MAX 32767
#define INT32_MAX 2147483647
#define INT64_MAX 9223372036854775807LL
#define INT8_MIN (-128)
#define INT16_MIN (-32768)
#define INT32_MIN (-2147483647 - 1)
#define INT64_MIN (-9223372036854775807LL - 1LL)
#define UINT8_MAX 255U
#define UINT16_MAX 65535U
#define UINT32_MAX 4294967295U
#define UINT64_MAX 18446744073709551615ULL
#endif
+8
View File
@@ -0,0 +1,8 @@
#ifndef _RANDOM_H
#define _RANDOM_H
#include <types.h>
void rand_init(bool rdrand, bool rdseed);
extern uint64_t (*get_random_number)();
#endif
+4
View File
@@ -9,6 +9,8 @@
* CPUID * CPUID
*/ */
enum { enum {
CPUID_FEAT_EBX_RDSEED = 1 << 18,
CPUID_FEAT_ECX_SSE3 = 1 << 0, CPUID_FEAT_ECX_SSE3 = 1 << 0,
CPUID_FEAT_ECX_PCLMUL = 1 << 1, CPUID_FEAT_ECX_PCLMUL = 1 << 1,
CPUID_FEAT_ECX_DTES64 = 1 << 2, CPUID_FEAT_ECX_DTES64 = 1 << 2,
@@ -87,4 +89,6 @@ void outl(uint16_t port, uint32_t data);
void cli(void); void cli(void);
void sti(void); void sti(void);
extern uint8_t (*popcountll)(uint64_t num);
void detect_processor_features();
#endif #endif
+10
View File
@@ -0,0 +1,10 @@
#ifndef _VMM_H
#define _VMM_H
#include "types.h"
#define CANONICAL_MASK_KERNEL 0xFFFF800000000000
#define CANONICAL_MASK_USER 0x00007FFFFFFFFFF000
int vmm_alloc(void** vaddr, uint64_t count, uint64_t flags);
int vmm_free(void* vaddr);
#endif
+36 -15
View File
@@ -1,22 +1,28 @@
#include "errno.h"
#include "types.h"
#include <bootloader.h> #include <bootloader.h>
#include <kernel.h>
#include <paging.h>
#include <serial.h>
#include <splash.h>
#include <system.h>
#include <gdt.h> #include <gdt.h>
#include <isr.h> #include <isr.h>
#include <kernel.h>
#include <paging.h>
#include <pmm.h> #include <pmm.h>
#include <random.h>
#include <serial.h>
#include <splash.h>
#include <string.h>
#include <system.h>
#include <vmm.h>
__noreturn __noreturn void _start(void) {
void _start(void) {
int err = 0; int err = 0;
// Serial console for debugging // Serial console for debugging
if ((err = serial_init(COM1)) < 0) panic(NULL, "Failed to initialize Serial driver. (%d)", err); if ((err = serial_init(COM1)) < 0)
panic(NULL, "Failed to initialize Serial driver. (%d)", err);
// Load structures from bootloader // Load structures from bootloader
if ((err = boot_init()) < 0) panic(NULL, "Failed to parse bootloader structures. (%d)", err); if ((err = boot_init()) < 0)
panic(NULL, "Failed to parse bootloader structures. (%d)", err);
// CPUID thingy :p // CPUID thingy :p
uint32_t eax = 0; uint32_t eax = 0;
@@ -24,18 +30,33 @@ void _start(void) {
cpuid(&eax, (void*)&s[0], (void*)&s[8], (void*)&s[4]); cpuid(&eax, (void*)&s[0], (void*)&s[8], (void*)&s[4]);
pr_info("[kernel] CPUID_GETVENDORID: %s\n", s); pr_info("[kernel] CPUID_GETVENDORID: %s\n", s);
// enable processor extensions
detect_processor_features();
// System init // System init
if ((err = gdt_init()) < 0) panic(NULL, "Failed to initalize GDT. (%d)", err); if ((err = gdt_init()) < 0)
if ((err = isr_init()) < 0) panic(NULL, "Failed to initalize ISRs. (%d)", err); panic(NULL, "Failed to initalize GDT. (%d)", err);
if ((err = isr_init()) < 0)
panic(NULL, "Failed to initalize ISRs. (%d)", err);
// Memory management // Memory management
if ((err = pmm_init()) < 0) panic(NULL, "Failed to initalize Physical Memory Manager. (%d)", err); if ((err = pmm_init()) < 0)
if ((err = pag_init()) < 0) panic(NULL, "Failed to initalize Paging. (%d)", err); panic(NULL, "Failed to initalize Physical Memory Manager. (%d)",
err);
if ((err = pag_init()) < 0)
panic(NULL, "Failed to initalize Paging. (%d)", err);
// test random number generation
printk("Random number generation test:\n");
for (uint8_t i = 0; i <= 16; i++) {
printk("%d: %lu\n", i, get_random_number());
}
// The most important function in the world. // The most important function in the world.
splash(); splash();
// Patiently wait for things to do :) // Patiently wait for things to do :)
while (1); while (1)
;
}; };
+128 -3
View File
@@ -1,10 +1,17 @@
#include "errno.h"
#include "kernel.h"
#include "paging.h"
#include "types.h" #include "types.h"
#include "vmm.h"
#include <kmalloc.h> #include <kmalloc.h>
#include <limits.h>
#include <string.h> #include <string.h>
#include <system.h>
// this file contains SLUB inspired HEAP allocator // this file contains SLUB inspired HEAP allocator
// TODO this will be an allocated array later when we have APIC MADT // TODO this will be an allocated array later when we have APIC MADT
union per_cpu_freelist_cache freelists_all_cpus[1]; union freelists_list freelists_all_cpus[1];
union partialy_freelists_list partial_free_lists[1];
void* kcalloc(size_t count, size_t size) { void* kcalloc(size_t count, size_t size) {
size_t size_to_alloc; size_t size_to_alloc;
@@ -46,7 +53,125 @@ void* kmalloc(size_t size) {
: "eax", "edx"); : "eax", "edx");
// freelists_all_cpus[core_id]; // freelists_all_cpus[core_id];
// TODO enable when we actualy know how many CPUs we have // TODO disable when we actualy know how many CPUs we have
if () { core_id = 0;
size_t alloc_index;
{
// TODO remove buildin
uint8_t leading_zeros = __builtin_clzll(size);
if (popcountll(size) == 1) {
alloc_index = leading_zeros;
} else {
alloc_index = sizeof(size) * CHAR_BIT - leading_zeros;
}
if (alloc_index > KMALLOC_MAX_SIZE) {
// NOT IMPLEMENTED
printk("Cannot allocate [%lu] bytes: \e[1mNOT "
"IMPLEMENTED!\e[0m\n",
size);
return NULL;
}
alloc_index -= LOWEST_POWER;
}
size_t object_size = (1 << (alloc_index + LOWEST_POWER));
struct freelist* selected_freelist =
freelists_all_cpus[core_id].freelists[alloc_index];
if (selected_freelist != NULL) {
// fast path
if (selected_freelist->nextnode == NULL) {
freelists_all_cpus[core_id].freelists[alloc_index] =
NULL;
} else {
freelists_all_cpus[core_id].freelists[alloc_index] =
selected_freelist->nextnode;
}
return selected_freelist;
} else {
// slower path
if (partial_free_lists[core_id]
.partialy_freelists[alloc_index] != NULL) {
// partialy freelist available
struct partialy_freelist* selected_partialy_freelist =
partial_free_lists[core_id]
.partialy_freelists[alloc_index];
if (selected_partialy_freelist->freelist_nextnode ==
NULL) {
// only one free object available
if (selected_partialy_freelist
->partialy_freelist_nextnode != NULL) {
// next partialy free list
// available
partial_free_lists[core_id]
.partialy_freelists[alloc_index] =
selected_partialy_freelist
->partialy_freelist_nextnode;
} else {
// no other partialy free list
// available
partial_free_lists[core_id]
.partialy_freelists[alloc_index] =
NULL;
}
} else {
// multiple free objects available
partial_free_lists[core_id]
.partialy_freelists[alloc_index] =
selected_partialy_freelist
->partialy_freelist_nextnode;
freelists_all_cpus[core_id]
.freelists[alloc_index] =
selected_partialy_freelist
->freelist_nextnode;
}
return selected_partialy_freelist;
} else {
// slowest path
uint8_t page_count =
object_size < PAGE_SIZE
? 1
: (object_size * 2) / PAGE_SIZE;
void** alloc_addr = 0;
{
int ret;
ret = vmm_alloc((void**)&alloc_addr, page_count,
0);
if (ret != SUCCESS) {
return NULL;
} }
} }
// construct the linked list
// start at offset if object too small for partial free
// list pointer
for (size_t i =
object_size < sizeof(struct partialy_freelist)
? object_size
: 0;
i < page_count * PAGE_SIZE; i += object_size) {
if ((i + 1) * object_size >=
page_count * PAGE_SIZE) {
alloc_addr[i * object_size] = NULL;
} else {
alloc_addr[i * object_size] =
alloc_addr +
((i + 1) * object_size);
}
}
freelists_all_cpus[core_id].freelists[alloc_index] =
(struct freelist*)(alloc_addr + object_size);
return alloc_addr;
}
}
}
void* kfree(void* p) {}
+50
View File
@@ -0,0 +1,50 @@
#include "kernel.h"
#include <system.h>
#include <types.h>
uint64_t (*get_random_number)();
// this starting value it truly random i have thrown a dice few times
uint64_t LFSR = 61113534451;
// RDSEED may be backdoored by NSA
extern uint64_t rand_rdrand();
asm(".intel_syntax noprefix\n"
".global rand_rdrand\n"
"rand_rdrand:"
" rdrand rax\n"
" ret\n"
".att_syntax prefix\n");
uint64_t rand_software() {
uint64_t lsb = LFSR & 1;
LFSR >>= 1;
if (lsb) {
LFSR ^= 0x800000000000000DULL;
}
return LFSR;
}
void rand_init(bool rdrand, bool rdseed) {
// check for RDRAND
if (rdrand) {
get_random_number = rand_rdrand;
} else {
printk("[\e[33mWARNING\e[0m] RDRAND not available falling back "
"to software\n");
// check for RDSEED
if (rdseed) {
asm(".intel_syntax noprefix\n"
"rdseed %0\n"
".att_syntax prefix\n"
: "=r"(LFSR));
} else {
printk("[\e[\e[33mWARNING\e[0m] RDSEED not available "
"falling back "
"to developers dice trows\n");
}
get_random_number = rand_software;
}
printk("[\e[32mINFO\e[0m] RNG initialized!\n");
}
+49 -8
View File
@@ -1,6 +1,7 @@
#include "types.h"
#include <kernel.h> #include <kernel.h>
#include <random.h>
#include <system.h> #include <system.h>
void cpuid(uint32_t* eax, uint32_t* ebx, uint32_t* ecx, uint32_t* edx) { void cpuid(uint32_t* eax, uint32_t* ebx, uint32_t* ecx, uint32_t* edx) {
__asm__ volatile("cpuid" __asm__ volatile("cpuid"
: "=a"(*eax), "=b"(*ebx), "=c"(*ecx), "=d"(*edx) : "=a"(*eax), "=b"(*ebx), "=c"(*ecx), "=d"(*edx)
@@ -8,9 +9,7 @@ void cpuid(uint32_t* eax, uint32_t* ebx, uint32_t* ecx, uint32_t* edx) {
: "memory"); : "memory");
} }
void iowait(void) { void iowait(void) { outb(0x80, 0); }
outb(0x80, 0);
}
uint8_t inb(uint16_t port) { uint8_t inb(uint16_t port) {
uint8_t r; uint8_t r;
@@ -42,11 +41,53 @@ void outl(uint16_t port, uint32_t data) {
__asm__ volatile("outl %1, %0" ::"dN"(port), "a"(data)); __asm__ volatile("outl %1, %0" ::"dN"(port), "a"(data));
} }
void cli(void) { void cli(void) { __asm__ volatile("cli"); }
__asm__ volatile ("cli");
void sti(void) { __asm__ volatile("sti"); }
uint8_t (*popcountll)(uint64_t num);
extern uint8_t popcountll_native(uint64_t num);
asm(".intel_syntax noprefix\n"
".global popcountll_native\n"
"popcountll_native:"
" popcnt rax, rdi\n"
" ret\n"
".att_syntax prefix\n");
// I have no idea how this works but it is apperently called SWAR
uint8_t popcountll_software(uint64_t num) {
num = num - ((num >> 1) & 0x5555555555555555ULL);
num = (num & 0x3333333333333333ULL) +
((num >> 2) & 0x3333333333333333ULL);
num = (num + (num >> 4)) & 0x0f0f0f0f0f0f0f0fULL;
return (int)((num * 0x0101010101010101ULL) >> 56);
} }
void sti(void) { void detect_processor_features() {
__asm__ volatile ("sti"); // leaf 1
uint32_t eax = 1, ebx = 0, ecx = 0, edx = 0;
cpuid(&eax, &ebx, &ecx, &edx);
bool rdrand = false;
if (ecx & CPUID_FEAT_ECX_RDRAND) {
rdrand = true;
} }
if (ecx & CPUID_FEAT_ECX_POPCNT) {
popcountll = popcountll_native;
} else {
popcountll = popcountll_software;
}
// leaf 7
eax = 7, ebx = 0, ecx = 0, edx = 0;
cpuid(&eax, &ebx, &ecx, &edx);
bool rdseed = false;
if (ebx & CPUID_FEAT_EBX_RDSEED) {
rdseed = true;
}
// init rng
rand_init(rdrand, rdseed);
}
+94
View File
@@ -0,0 +1,94 @@
#include "vmm.h"
#include "kernel.h"
#include <errno.h>
#include <isr.h>
#include <limits.h>
#include <paging.h>
#include <pmm.h>
#include <random.h>
#include <types.h>
// allocates set number of pages at address provided
// if address is NULL address is chosen internaly
int vmm_alloc(void** vaddr, uint64_t count, uint64_t flags) {
if (flags == 0) {
flags = PTE_FLAG_PRESENT | PTE_FLAG_WRITE | PTE_FLAG_NOEXEC;
}
bool random_vaddr = *vaddr ? false : true;
uint64_t* pml4 = pag_get_pml4();
{
uint8_t limit_counter = 0;
while (true) {
if (random_vaddr) {
retry_selection:
*vaddr = (void*)ALIGN_DOWN(get_random_number(),
PAGE_SIZE);
*vaddr = (void*)((uint64_t)(*vaddr) &
CANONICAL_MASK_USER);
if (!(flags & PTE_FLAG_USER)) {
*vaddr = (void*)((uint64_t)(*vaddr) |
CANONICAL_MASK_KERNEL);
}
} else {
if (flags & PTE_FLAG_USER) {
if ((void*)((uint64_t)(*vaddr) &
CANONICAL_MASK_KERNEL)) {
return -EINVAL;
}
} else {
if (!((void*)((uint64_t)(*vaddr) &
CANONICAL_MASK_KERNEL))) {
return -EINVAL;
}
}
}
for (uint64_t i = 0; i < count; i++) {
uint64_t* pte =
pag_get_pte(pml4, *vaddr + (i * PAGE_SIZE));
if (!IS_ERR(pte) && (*pte & PTE_FLAG_PRESENT)) {
if (!random_vaddr) {
return -EEXIST;
} else {
if (limit_counter < UINT8_MAX) {
goto retry_selection;
} else {
return -EAGAIN;
}
}
}
}
break;
}
}
for (uint64_t i = 0; i < count; i++) {
void* paddr = pmm_alloc();
int pag_map_ret =
pag_map(pml4, *vaddr + (i * PAGE_SIZE), paddr, flags);
if (pag_map_ret != SUCCESS) {
if (i != 0) {
for (i -= 1; i != UINT64_MAX; i--) {
if (pag_unmap(pml4,
*vaddr +
(i * PAGE_SIZE)) !=
SUCCESS) {
panic(NULL,
"failed to unmap "
"previously mapped "
"page. %s:%d",
__FILE_NAME__, __LINE__);
}
}
}
return pag_map_ret;
}
}
return SUCCESS;
}
int vmm_free(void* vaddr) {
uint64_t* pml4 = pag_get_pml4();
return pag_unmap(pml4, vaddr);
}