Add first C user program
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#define MEMORY_SIZE 0x08000000
|
||||
#define PAGE_SIZE 4096
|
||||
#define PAGE_COUNT (MEMORY_SIZE / PAGE_SIZE)
|
||||
|
||||
#define HEAP_PAGE_COUNT 256
|
||||
#define HEAP_SIZE (HEAP_PAGE_COUNT * PAGE_SIZE)
|
||||
|
||||
#define KERNEL_VIRTUAL_BASE 0xFFFFFFFF80000000ULL
|
||||
#define PHYS_TO_VIRT(phys) ((void *)((uint64_t)(phys) + KERNEL_VIRTUAL_BASE))
|
||||
#define VIRT_TO_PHYS(virt) ((uint64_t)(virt) - KERNEL_VIRTUAL_BASE)
|
||||
|
||||
#define KERNEL_VIRTUAL_PML4 (KERNEL_VIRTUAL_BASE + 0x10000)
|
||||
#define KERNEL_VIRTUAL_CODE (KERNEL_VIRTUAL_PML4 + 0x10000)
|
||||
#define KERNEL_VIRTUAL_HEAP (KERNEL_VIRTUAL_CODE + 0x100000)
|
||||
#define KERNEL_VIRTUAL_UNUSED (KERNEL_VIRTUAL_HEAP + HEAP_SIZE)
|
||||
#define KERNEL_VIRTUAL_STACK (KERNEL_VIRTUAL_BASE + 0xF00000 - PAGE_SIZE)
|
||||
#define KERNEL_VIRTUAL_STACK_TOP (KERNEL_VIRTUAL_STACK + PAGE_SIZE)
|
||||
|
||||
#define USER_VIRTUAL_BASE 0x0000000000000000ULL
|
||||
#define USER_VIRTUAL_CODE (USER_VIRTUAL_BASE + 0x400000)
|
||||
#define USER_VIRTUAL_HEAP (USER_VIRTUAL_CODE + 0x100000)
|
||||
#define USER_VIRTUAL_UNUSED (USER_VIRTUAL_HEAP + HEAP_SIZE)
|
||||
#define USER_VIRTUAL_STACK (0x0000700000000000ULL - PAGE_SIZE)
|
||||
#define USER_VIRTUAL_STACK_TOP (USER_VIRTUAL_STACK + PAGE_SIZE)
|
||||
@@ -0,0 +1,60 @@
|
||||
#include "src/lib/memory.h"
|
||||
#include "src/lib/layout.h"
|
||||
#include "src/lib/util.h"
|
||||
|
||||
#ifdef KERNEL
|
||||
#define HEAP_VIRTUAL_BASE KERNEL_VIRTUAL_HEAP
|
||||
#else
|
||||
#define HEAP_VIRTUAL_BASE USER_VIRTUAL_HEAP
|
||||
#endif
|
||||
|
||||
typedef struct free_chunk {
|
||||
uint64_t size; // header + data
|
||||
struct free_chunk *next;
|
||||
} free_chunk_t;
|
||||
|
||||
static free_chunk_t *free_list;
|
||||
|
||||
void *memory_allocate(uint64_t size) {
|
||||
if (!free_list) {
|
||||
free_list = (free_chunk_t *)HEAP_VIRTUAL_BASE;
|
||||
free_list->size = HEAP_SIZE;
|
||||
free_list->next = NUL;
|
||||
}
|
||||
|
||||
size = sizeof(free_chunk_t) + (size + 7) & (uint64_t)~7;
|
||||
|
||||
free_chunk_t *prev = NUL;
|
||||
free_chunk_t *curr = free_list;
|
||||
|
||||
while (curr) {
|
||||
if (curr->size >= size + (sizeof(free_chunk_t) + 8)) {
|
||||
free_chunk_t *remainder = (free_chunk_t *)((uint8_t *)curr + size);
|
||||
remainder->size = curr->size - size;
|
||||
remainder->next = curr->next;
|
||||
curr->size = size;
|
||||
curr->next = remainder;
|
||||
}
|
||||
if (curr->size >= size) {
|
||||
if (prev) {
|
||||
prev->next = curr->next;
|
||||
} else {
|
||||
free_list = curr->next;
|
||||
}
|
||||
void *result = (void *)((uint8_t *)curr + sizeof(free_chunk_t));
|
||||
memory_set(0, size - sizeof(free_chunk_t), result);
|
||||
return result;
|
||||
}
|
||||
prev = curr;
|
||||
curr = curr->next;
|
||||
}
|
||||
|
||||
return NUL;
|
||||
}
|
||||
|
||||
void memory_free(void *pointer) {
|
||||
free_chunk_t *chunk = (free_chunk_t *)((uint8_t *)pointer - sizeof(free_chunk_t));
|
||||
chunk->next = free_list;
|
||||
free_list = chunk;
|
||||
// TODO Merge adjacent free chunks.
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void *memory_allocate(uint64_t size);
|
||||
|
||||
void memory_free(void *pointer);
|
||||
|
||||
static inline void memory_set(uint8_t value, uint64_t bytes, void *to) {
|
||||
__asm__ volatile("rep stosb" : "=D"(to), "=c"(bytes) : "D"(to), "a"(value), "c"(bytes) : "memory");
|
||||
}
|
||||
|
||||
static inline void memory_move(void *from, uint64_t bytes, void *to) {
|
||||
if (to == from) {
|
||||
return;
|
||||
} else if (to < from) {
|
||||
__asm__ volatile("rep movsb" : "=D"(to), "=S"(from), "=c"(bytes) : "D"(to), "S"(from), "c"(bytes) : "memory");
|
||||
} else {
|
||||
// TODO ASSERT(0, "memory_move: forward overlapping move not implemented");
|
||||
}
|
||||
}
|
||||
|
||||
static inline void memory_copy(const void *from, uint64_t bytes, void *to) {
|
||||
// TODO ASSERT((uint64_t)to + bytes <= (uint64_t)from || (uint64_t)to >= (uint64_t)from + bytes, "memory_copy: overlapping backward
|
||||
// copy");
|
||||
|
||||
__asm__ volatile("rep movsb" : "=D"(to), "=S"(from), "=c"(bytes) : "D"(to), "S"(from), "c"(bytes) : "memory");
|
||||
}
|
||||
@@ -0,0 +1,227 @@
|
||||
#include "src/lib/string.h"
|
||||
#include <stdarg.h>
|
||||
|
||||
uint8_t bytes_equal(const char *l, const char *r, uint64_t count) {
|
||||
while (count--) {
|
||||
if (*l++ != *r++) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t string_empty(const char *s) {
|
||||
return *s == '\0';
|
||||
}
|
||||
|
||||
uint64_t string_length(const char *s) {
|
||||
const char *e = s;
|
||||
while (*e) {
|
||||
e++;
|
||||
}
|
||||
return (uint64_t)(e - s);
|
||||
}
|
||||
|
||||
uint8_t string_equal(const char *l, const char *r) {
|
||||
while (*l && *r) {
|
||||
if (*l != *r) {
|
||||
return 0;
|
||||
}
|
||||
l++;
|
||||
r++;
|
||||
}
|
||||
return *l == *r;
|
||||
}
|
||||
|
||||
uint64_t string_split(char *string, char separator, uint64_t max, char **result) {
|
||||
uint64_t count = 1;
|
||||
*result = string;
|
||||
|
||||
while (*string && count < max) {
|
||||
if (*string == separator) {
|
||||
*string = '\0';
|
||||
result++;
|
||||
*result = string + 1;
|
||||
count++;
|
||||
}
|
||||
string++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
uint64_t string_byte_to_hex(uint8_t value, uint64_t max, char *result) {
|
||||
if (max == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (max == 1) {
|
||||
result[0] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (max == 2) {
|
||||
result[0] = '0';
|
||||
result[1] = '\0';
|
||||
return 1;
|
||||
}
|
||||
|
||||
char tmp[3] = "00";
|
||||
|
||||
uint8_t i = 0;
|
||||
while (value) {
|
||||
uint8_t nibble = value & 0xF;
|
||||
tmp[i++] = nibble < 10 ? '0' + nibble : 'a' + nibble - 10;
|
||||
value >>= 4;
|
||||
}
|
||||
|
||||
result[0] = '0';
|
||||
result[1] = 'x';
|
||||
|
||||
i = 2;
|
||||
while (i < 4 && i < max - 1) {
|
||||
result[i] = tmp[3 - i];
|
||||
i++;
|
||||
}
|
||||
result[i] = '\0';
|
||||
return i;
|
||||
}
|
||||
|
||||
uint64_t string_uint_to_decimal(uint64_t value, uint64_t max, char *result) {
|
||||
if (max == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
char tmp[20];
|
||||
uint8_t len = 0;
|
||||
|
||||
if (value == 0) {
|
||||
tmp[len++] = '0';
|
||||
} else {
|
||||
while (value && len < 20) {
|
||||
tmp[len++] = '0' + (value % 10);
|
||||
value /= 10;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t i = 0;
|
||||
while (i < len && i < max - 1) {
|
||||
result[i] = tmp[len - 1 - i];
|
||||
i++;
|
||||
}
|
||||
result[i] = '\0';
|
||||
return i;
|
||||
}
|
||||
|
||||
uint64_t string_int_to_decimal(int64_t value, uint64_t max, char *result) {
|
||||
if (max == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (value >= 0) {
|
||||
return string_uint_to_decimal((uint64_t)value, max, result);
|
||||
}
|
||||
|
||||
result[0] = '-';
|
||||
return 1 + string_uint_to_decimal((uint64_t)(-value), max - 1, result + 1);
|
||||
}
|
||||
|
||||
uint64_t string_uint_to_hex(uint64_t value, uint64_t max, char *result) {
|
||||
if (max == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (max == 1) {
|
||||
result[0] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (max == 2) {
|
||||
result[0] = '0';
|
||||
result[1] = '\0';
|
||||
return 1;
|
||||
}
|
||||
|
||||
char tmp[17] = "0000000000000000";
|
||||
|
||||
uint8_t i = 0;
|
||||
while (value) {
|
||||
uint8_t nibble = value & 0xF;
|
||||
tmp[i++] = nibble < 10 ? '0' + nibble : 'A' + nibble - 10;
|
||||
value >>= 4;
|
||||
}
|
||||
|
||||
result[0] = '0';
|
||||
result[1] = 'x';
|
||||
|
||||
i = 2;
|
||||
while (i < 18 && i < max - 1) {
|
||||
result[i] = tmp[17 - i];
|
||||
i++;
|
||||
}
|
||||
result[i] = '\0';
|
||||
return i;
|
||||
}
|
||||
|
||||
uint64_t string_format(const char *format, uint64_t max, char *output, ...) {
|
||||
va_list args;
|
||||
va_start(args, output);
|
||||
|
||||
uint64_t limit = max - 1;
|
||||
|
||||
uint64_t fi = 0, ri = 0;
|
||||
while (format[fi] && ri < limit) {
|
||||
if (format[fi] != '%') {
|
||||
output[ri++] = format[fi++];
|
||||
} else {
|
||||
switch (format[fi + 1]) {
|
||||
case 'c':
|
||||
output[ri++] = (char)va_arg(args, int);
|
||||
fi += 2;
|
||||
break;
|
||||
case 'd':
|
||||
string_int_to_decimal(va_arg(args, int64_t), limit - ri, output + ri);
|
||||
while (output[ri]) {
|
||||
ri++;
|
||||
}
|
||||
fi += 2;
|
||||
break;
|
||||
case 'u':
|
||||
string_uint_to_decimal(va_arg(args, uint64_t), limit - ri, output + ri);
|
||||
while (output[ri]) {
|
||||
ri++;
|
||||
}
|
||||
fi += 2;
|
||||
break;
|
||||
case 'x':
|
||||
string_uint_to_hex(va_arg(args, uint64_t), limit - ri, output + ri);
|
||||
while (output[ri]) {
|
||||
ri++;
|
||||
}
|
||||
fi += 2;
|
||||
break;
|
||||
case 's': {
|
||||
char *s = va_arg(args, char *);
|
||||
while (*s && ri < limit) {
|
||||
output[ri++] = *s;
|
||||
s++;
|
||||
}
|
||||
fi += 2;
|
||||
break;
|
||||
}
|
||||
case '%': {
|
||||
output[ri++] = '%';
|
||||
fi += 2;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
output[ri++] = format[fi++];
|
||||
output[ri++] = format[fi++];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
output[ri] = '\0';
|
||||
va_end(args);
|
||||
|
||||
return ri;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
uint8_t bytes_equal(const char *l, const char *r, uint64_t count);
|
||||
|
||||
uint8_t string_empty(const char *s);
|
||||
|
||||
uint64_t string_length(const char *s);
|
||||
|
||||
uint8_t string_equal(const char *l, const char *r);
|
||||
|
||||
uint64_t string_split(char *string, char separator, uint64_t max, char **result);
|
||||
|
||||
uint64_t string_byte_to_hex(uint8_t value, uint64_t max, char *result);
|
||||
|
||||
uint64_t string_uint_to_decimal(uint64_t value, uint64_t max, char *result);
|
||||
|
||||
uint64_t string_int_to_decimal(int64_t value, uint64_t max, char *result);
|
||||
|
||||
uint64_t string_uint_to_hex(uint64_t value, uint64_t max, char *result);
|
||||
|
||||
uint64_t string_format(const char *format, uint64_t max, char *output, ...);
|
||||
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
#define NUL 0 // TODO Fix VSCode thinking `NULL` conflicts with some other definition.
|
||||
Reference in New Issue
Block a user