mirror of
https://github.com/encounter/osdev.git
synced 2026-07-10 12:18:43 -07:00
Primitive VFS & commands; debugging malloc issues
This commit is contained in:
@@ -43,7 +43,8 @@ set(SOURCE_FILES
|
||||
tests/tests.h
|
||||
tests/vector
|
||||
tests/fatfs
|
||||
tests/stdio)
|
||||
tests/stdio
|
||||
tests/path)
|
||||
if (${CMAKE_BUILD_TYPE} MATCHES "Debug")
|
||||
set(SOURCE_FILES ${SOURCE_FILES} debug/ubsan debug/dwarf)
|
||||
endif ()
|
||||
|
||||
+44
-17
@@ -16,8 +16,7 @@ union overlay64 {
|
||||
} words;
|
||||
};
|
||||
|
||||
uint64_t __ashldi3(uint64_t num, unsigned int shift)
|
||||
{
|
||||
uint64_t __ashldi3(uint64_t num, unsigned int shift) {
|
||||
union overlay64 output;
|
||||
|
||||
output.longw = num;
|
||||
@@ -25,8 +24,7 @@ uint64_t __ashldi3(uint64_t num, unsigned int shift)
|
||||
output.words.higher = output.words.lower << (shift - 32);
|
||||
output.words.lower = 0;
|
||||
} else {
|
||||
if (!shift)
|
||||
return num;
|
||||
if (!shift) return num;
|
||||
output.words.higher = (output.words.higher << shift) |
|
||||
(output.words.lower >> (32 - shift));
|
||||
output.words.lower = output.words.lower << shift;
|
||||
@@ -34,8 +32,7 @@ uint64_t __ashldi3(uint64_t num, unsigned int shift)
|
||||
return output.longw;
|
||||
}
|
||||
|
||||
uint64_t __lshrdi3(uint64_t num, unsigned int shift)
|
||||
{
|
||||
uint64_t __lshrdi3(uint64_t num, unsigned int shift) {
|
||||
union overlay64 output;
|
||||
|
||||
output.longw = num;
|
||||
@@ -43,8 +40,7 @@ uint64_t __lshrdi3(uint64_t num, unsigned int shift)
|
||||
output.words.lower = output.words.higher >> (shift - 32);
|
||||
output.words.higher = 0;
|
||||
} else {
|
||||
if (!shift)
|
||||
return num;
|
||||
if (!shift) return num;
|
||||
output.words.lower = output.words.lower >> shift |
|
||||
(output.words.higher << (32 - shift));
|
||||
output.words.higher = output.words.higher >> shift;
|
||||
@@ -54,16 +50,14 @@ uint64_t __lshrdi3(uint64_t num, unsigned int shift)
|
||||
|
||||
#define MAX_32BIT_UINT ((((uint64_t)1) << 32) - 1)
|
||||
|
||||
static uint64_t _64bit_divide(uint64_t dividend, uint64_t divider, uint64_t *rem_p)
|
||||
{
|
||||
static uint64_t _64bit_divide(uint64_t dividend, uint64_t divider, uint64_t *rem_p) {
|
||||
uint64_t result = 0;
|
||||
|
||||
/*
|
||||
* If divider is zero - let the rest of the system care about the
|
||||
* exception.
|
||||
*/
|
||||
if (!divider)
|
||||
return 1 / (uint32_t)divider;
|
||||
if (!divider) return 1 / (uint32_t) divider;
|
||||
|
||||
/* As an optimization, let's not use 64 bit division unless we must. */
|
||||
if (dividend <= MAX_32BIT_UINT) {
|
||||
@@ -72,9 +66,8 @@ static uint64_t _64bit_divide(uint64_t dividend, uint64_t divider, uint64_t *rem
|
||||
if (rem_p)
|
||||
*rem_p = divider;
|
||||
} else {
|
||||
result = (uint32_t)dividend / (uint32_t)divider;
|
||||
if (rem_p)
|
||||
*rem_p = (uint32_t)dividend % (uint32_t)divider;
|
||||
result = (uint32_t) dividend / (uint32_t) divider;
|
||||
if (rem_p) *rem_p = (uint32_t) dividend % (uint32_t) divider;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -92,8 +85,7 @@ static uint64_t _64bit_divide(uint64_t dividend, uint64_t divider, uint64_t *rem
|
||||
dividend -= locald;
|
||||
}
|
||||
|
||||
if (rem_p)
|
||||
*rem_p = dividend;
|
||||
if (rem_p) *rem_p = dividend;
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -108,4 +100,39 @@ uint64_t __umoddi3(uint64_t num, uint64_t den) {
|
||||
uint64_t v = 0;
|
||||
_64bit_divide(num, den, &v);
|
||||
return v;
|
||||
}
|
||||
|
||||
// Returns the number of leading 0-bits in x, starting at the most significant bit position.
|
||||
// If x is zero, the result is undefined.
|
||||
_unused
|
||||
int __clzsi2(unsigned x) {
|
||||
// This uses a binary search (counting down) algorithm from Hacker's Delight.
|
||||
unsigned y;
|
||||
int n = 32;
|
||||
y = x >>16; if (y != 0) {n = n -16; x = y;}
|
||||
y = x >> 8; if (y != 0) {n = n - 8; x = y;}
|
||||
y = x >> 4; if (y != 0) {n = n - 4; x = y;}
|
||||
y = x >> 2; if (y != 0) {n = n - 2; x = y;}
|
||||
y = x >> 1; if (y != 0) return n - 2;
|
||||
return n - x;
|
||||
}
|
||||
|
||||
// Returns the number of trailing 0-bits in x, starting at the least significant bit position.
|
||||
// If x is zero, the result is undefined.
|
||||
_unused
|
||||
int __ctzsi2(unsigned x) {
|
||||
// This uses a binary search algorithm from Hacker's Delight.
|
||||
int n = 1;
|
||||
if ((x & 0x0000FFFF) == 0) {n = n +16; x = x >>16;}
|
||||
if ((x & 0x000000FF) == 0) {n = n + 8; x = x >> 8;}
|
||||
if ((x & 0x0000000F) == 0) {n = n + 4; x = x >> 4;}
|
||||
if ((x & 0x00000003) == 0) {n = n + 2; x = x >> 2;}
|
||||
return n - (x & 1);
|
||||
}
|
||||
|
||||
// Returns the index of the least significant 1-bit in x, or the value zero if x is zero.
|
||||
// The least significant bit is index one.
|
||||
_unused
|
||||
int __ffsdi2 (unsigned x) {
|
||||
return (x == 0) ? 0 : __builtin_ctz(x) + 1;
|
||||
}
|
||||
@@ -6,18 +6,6 @@
|
||||
|
||||
#define VIDEO_ADDRESS ((uint16_t *) 0xC00B8000)
|
||||
|
||||
/**********************************************************
|
||||
* Private kernel functions *
|
||||
**********************************************************/
|
||||
|
||||
/**
|
||||
* Innermost print function for our kernel, directly accesses the video memory
|
||||
*
|
||||
* If 'col' and 'row' are negative, we will print at current cursor location
|
||||
* If 'attr' is zero it will use 'white on black' as default
|
||||
* Returns the offset of the next character
|
||||
* Sets the video cursor to the returned offset
|
||||
*/
|
||||
int vga_print_char(char c, int col, int row, char attr) {
|
||||
if (!attr) attr = WHITE_ON_BLACK;
|
||||
|
||||
|
||||
+18
-15
@@ -54,7 +54,9 @@ bool _check_elf_header(elf_header_t *header) {
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
#ifdef ELF_DEBUG
|
||||
printf("_check_elf_header: Got bad magic %04u != %04u\n", header->magic, ELF_HEADER_MAGIC_LE);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -70,7 +72,10 @@ static bool _elf_read_header(elf_file_t *file) {
|
||||
return false;
|
||||
}
|
||||
read = fread(buf, header_size, 1, file->fd);
|
||||
if (ferror(file->fd) || !read || !_check_elf_header(buf)) return false; // FIXME memory leak
|
||||
if (ferror(file->fd) || !read || !_check_elf_header(buf)) {
|
||||
free(buf);
|
||||
return false;
|
||||
}
|
||||
|
||||
file->header = buf;
|
||||
return true;
|
||||
@@ -93,7 +98,10 @@ static bool _elf_read_section_header_table(elf_file_t *file) {
|
||||
return false;
|
||||
}
|
||||
read = fread(buf, sh_table_size, 1, file->fd);
|
||||
if (ferror(file->fd) || !read) return false; // FIXME memory leak
|
||||
if (ferror(file->fd) || !read) {
|
||||
free(buf);
|
||||
return false;
|
||||
}
|
||||
|
||||
file->sht_start = buf;
|
||||
return true;
|
||||
@@ -194,7 +202,8 @@ static const char *elf_section_type(elf_section_header_type_t type) {
|
||||
}
|
||||
|
||||
void elf_print_sections(elf_file_t *file) {
|
||||
if (!_elf_read_section_header_table(file)
|
||||
if (!_elf_read_header(file)
|
||||
|| !_elf_read_section_header_table(file)
|
||||
|| !_elf_read_sht_str_section(file))
|
||||
return;
|
||||
|
||||
@@ -211,21 +220,15 @@ void elf_print_sections(elf_file_t *file) {
|
||||
}
|
||||
|
||||
bool elf_open(elf_file_t *file, const char *filename) {
|
||||
struct stat st;
|
||||
|
||||
if (fstat(filename, &st) || !st.st_size) goto fail;
|
||||
|
||||
file->fd = fopen(filename, "r");
|
||||
if (ferror(file->fd))
|
||||
goto fail;
|
||||
|
||||
if (!_elf_read_header(file) || !_elf_read_section_header_table(file)) goto fail;
|
||||
if (ferror(file->fd)
|
||||
|| !_elf_read_header(file)
|
||||
|| !_elf_read_section_header_table(file)) {
|
||||
elf_close(file);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
fail:
|
||||
printf("Failed to read ELF file: %d\n", errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
void elf_close(elf_file_t *file) {
|
||||
|
||||
+4
-2
@@ -34,17 +34,19 @@ void kernel_main(uint32_t multiboot_magic, void *multiboot_info) {
|
||||
// uint32_t i = UINT32_MAX / 16;
|
||||
// while(i--); // stall
|
||||
|
||||
bool fs_mounted = false;
|
||||
printf("Mounting drive 0... ");
|
||||
FATFS fs;
|
||||
FRESULT ret = f_mount(&fs, "", 1);
|
||||
if (ret == FR_OK) {
|
||||
printf("OK\n");
|
||||
fs_mounted = true;
|
||||
} else {
|
||||
printf("fail %d\n", ret);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_DWARF
|
||||
dwarf_find_debug_info();
|
||||
// dwarf_find_debug_info();
|
||||
#endif
|
||||
|
||||
console_set_vga_enabled(vga_enabled);
|
||||
@@ -58,7 +60,7 @@ void kernel_main(uint32_t multiboot_magic, void *multiboot_info) {
|
||||
#ifdef KDEBUG
|
||||
kprint("Setting up IRQ handlers...\n");
|
||||
#endif
|
||||
shell_init();
|
||||
shell_init(fs_mounted);
|
||||
|
||||
#ifdef KDEBUG
|
||||
kprint("Enabling maskable interrupts...\n");
|
||||
|
||||
+2
-1
@@ -3,7 +3,7 @@
|
||||
#include "console.h"
|
||||
|
||||
#define PAGE_OFFSET 0xC0000000
|
||||
#define KERNEL_OFFSET 0x100000 // FIXME
|
||||
#define KERNEL_OFFSET 0x200000 // FIXME
|
||||
|
||||
extern void *malloc_memory_start;
|
||||
extern void *malloc_memory_end;
|
||||
@@ -13,6 +13,7 @@ void multiboot_init(uint32_t magic, void *info_ptr) {
|
||||
panic("multiboot_magic: Invalid magic "PRIX32"\n", magic);
|
||||
}
|
||||
|
||||
// XXX: uintptr_t hack b/c of compiler optimization which then triggers ubsan ¯\_(ツ)_/¯
|
||||
struct multiboot_info *info = (struct multiboot_info *) ((uintptr_t) info_ptr + PAGE_OFFSET);
|
||||
printf("multiboot_info = "PRIXPTR", flags = "PRIx32"\n", info, info->flags);
|
||||
|
||||
|
||||
+132
-8
@@ -8,12 +8,17 @@
|
||||
#include "drivers/pci.h"
|
||||
#include "drivers/pci_registry.h"
|
||||
#include "drivers/ata.h"
|
||||
#include "elf.h"
|
||||
|
||||
// FIXME
|
||||
#include "fatfs/ff.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
#include <vector.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define KEY_BUFFER_INITIAL_SIZE 0x100
|
||||
static char *key_buffer;
|
||||
@@ -24,6 +29,8 @@ static size_t key_buffer_printed;
|
||||
static vc_vector *shell_history;
|
||||
static size_t shell_history_offset = 0;
|
||||
|
||||
static bool _fs_mounted = false;
|
||||
|
||||
void command_lspci() {
|
||||
vc_vector *pci_devices = pci_get_devices();
|
||||
for (pci_device_t *device = vc_vector_begin(pci_devices);
|
||||
@@ -49,11 +56,115 @@ void command_lsata() {
|
||||
for (uint8_t i = 0; i < 4; i++) {
|
||||
if (ide_devices[i].reserved == 1) {
|
||||
const char *type_str = ((const char *[]) {"ATA ", "ATAPI"}[ide_devices[i].type]);
|
||||
printf("%d: %s | %016lu sectors | %s\n", i, type_str, ide_devices[i].size, ide_devices[i].model);
|
||||
printf("%d: %s | %016u sectors | %s\n", i, type_str, ide_devices[i].size, ide_devices[i].model);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static char curr_path[512] = "/";
|
||||
|
||||
static uint8_t command_mkdir(const char *path) {
|
||||
if (!_fs_mounted) return 255;
|
||||
|
||||
FRESULT fret;
|
||||
char buf[512];
|
||||
|
||||
path_append(buf, curr_path, path, sizeof(buf));
|
||||
if ((fret = f_mkdir(buf)) != FR_OK) {
|
||||
printf("Error mkdir %s: %d\n", buf, fret);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint8_t command_cd(const char *path) {
|
||||
if (!_fs_mounted) return 255;
|
||||
|
||||
DIR dir;
|
||||
FRESULT fret;
|
||||
char buf[512];
|
||||
|
||||
path_append(buf, curr_path, path, sizeof(buf));
|
||||
if ((fret = f_opendir(&dir, buf)) != FR_OK) {
|
||||
printf("Error opening %s: %d\n", buf, fret);
|
||||
return 1;
|
||||
}
|
||||
if ((fret = f_closedir(&dir)) != FR_OK) {
|
||||
printf("Error closing %s: %d\n", buf, fret);
|
||||
return 2;
|
||||
}
|
||||
strncpy(curr_path, buf, sizeof(curr_path));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint8_t command_ls(const char *path) {
|
||||
if (!_fs_mounted) return 255;
|
||||
|
||||
DIR dir;
|
||||
FILINFO info;
|
||||
FRESULT fret;
|
||||
char buf[512];
|
||||
size_t count = 0;
|
||||
|
||||
path_append(buf, curr_path, path, sizeof(buf));
|
||||
if ((fret = f_opendir(&dir, buf)) != FR_OK) {
|
||||
printf("Error opening %s: %d\n", buf, fret);
|
||||
return 1;
|
||||
}
|
||||
fret = f_readdir(&dir, &info);
|
||||
while (fret == FR_OK && info.fname[0] != 0) {
|
||||
count++;
|
||||
printf(". %s\n", info.fname);
|
||||
fret = f_readdir(&dir, &info);
|
||||
}
|
||||
if (fret != FR_OK && fret != FR_NO_FILE) {
|
||||
printf("Error listing files: %d\n", fret);
|
||||
return 2;
|
||||
}
|
||||
printf("total %zu\n", count);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint8_t command_rm(const char *path) {
|
||||
if (!_fs_mounted) return 255;
|
||||
|
||||
FRESULT fret;
|
||||
char buf[512];
|
||||
|
||||
path_append(buf, curr_path, path, sizeof(buf));
|
||||
if ((fret = f_unlink(buf)) != FR_OK) {
|
||||
printf("Error removing %s: %d\n", buf, fret);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint8_t command_objdump(const char *path) {
|
||||
if (!_fs_mounted) return 255;
|
||||
|
||||
elf_file_t file = {};
|
||||
char buf[512];
|
||||
|
||||
path_append(buf, curr_path, path, sizeof(buf));
|
||||
if (!elf_open(&file, buf)) {
|
||||
printf("Error opening %s: %d\n", buf, errno);
|
||||
return 1;
|
||||
}
|
||||
|
||||
elf_print_sections(&file);
|
||||
elf_close(&file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void print_prompt(unsigned char ret) {
|
||||
if (_fs_mounted) {
|
||||
printf("%d %s # ", ret, curr_path);
|
||||
} else {
|
||||
printf("%d # ", ret);
|
||||
}
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
static void shell_callback(char *input) {
|
||||
printf("\n");
|
||||
|
||||
@@ -67,7 +178,7 @@ static void shell_callback(char *input) {
|
||||
reboot();
|
||||
} else if (strcmp(input, "clear") == 0) {
|
||||
clear_screen();
|
||||
printf("# ");
|
||||
print_prompt(0);
|
||||
return;
|
||||
} else if (strncmp(input, "echo ", 5) == 0) {
|
||||
printf("%s\n", input + 5);
|
||||
@@ -95,18 +206,31 @@ static void shell_callback(char *input) {
|
||||
ret = (unsigned char) !fatfs_test();
|
||||
} else if (strcmp(input, "test stdio") == 0) {
|
||||
ret = (unsigned char) !stdio_test();
|
||||
} else if (strcmp(input, "test path") == 0) {
|
||||
ret = (unsigned char) !path_test();
|
||||
} else if (strcmp(input, "test") == 0 ||
|
||||
strncmp(input, "test ", 5) == 0) {
|
||||
printf("Available tests:\n vector\n fatfs\n");
|
||||
printf("Available tests:\n vector\n fatfs\n stdio\n path\n");
|
||||
} else if (strcmp(input, "lspci") == 0) {
|
||||
command_lspci();
|
||||
ret = 0;
|
||||
} else if (strcmp(input, "lsata") == 0) {
|
||||
command_lsata();
|
||||
ret = 0;
|
||||
} else if (strncmp(input, "mkdir ", 6) == 0) {
|
||||
ret = command_mkdir(input + 6);
|
||||
} else if (strncmp(input, "cd ", 3) == 0) {
|
||||
ret = command_cd(input + 3);
|
||||
} else if (strncmp(input, "ls ", 3) == 0 || strncmp(input, "ll ", 3) == 0) {
|
||||
ret = command_ls(input + 3);
|
||||
} else if (strcmp(input, "ls") == 0 || strcmp(input, "ll") == 0) {
|
||||
ret = command_ls(NULL);
|
||||
} else if (strncmp(input, "rm ", 3) == 0) {
|
||||
ret = command_rm(input + 3);
|
||||
} else if (strncmp(input, "objdump ", 8) == 0) {
|
||||
ret = command_objdump(input + 8);
|
||||
}
|
||||
printf("%d # ", ret);
|
||||
fflush(stdout);
|
||||
print_prompt(ret);
|
||||
|
||||
if (save && input[0] != '\0') {
|
||||
char *value = strdup(input);
|
||||
@@ -118,11 +242,11 @@ static void shell_history_free_func(void *data) {
|
||||
free(*(char **) data);
|
||||
}
|
||||
|
||||
void shell_init() {
|
||||
void shell_init(bool fs_mounted) {
|
||||
_fs_mounted = fs_mounted;
|
||||
shell_history = vc_vector_create(0x100, sizeof(char *), shell_history_free_func);
|
||||
init_keyboard();
|
||||
printf("# ");
|
||||
fflush(stdout);
|
||||
print_prompt((unsigned char) !fs_mounted);
|
||||
}
|
||||
|
||||
void shell_read() {
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
#include <common.h>
|
||||
|
||||
void shell_init();
|
||||
void shell_init(bool fs_mounted);
|
||||
|
||||
void shell_read();
|
||||
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
#include <common.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define CHECK(s1, s2, len) { \
|
||||
if (strncmp(s1, s2, len) != 0) { \
|
||||
printf("path_test fail line %d: Expected: %s, actual: %s\n", __LINE__, s2, s1); \
|
||||
return false; \
|
||||
} \
|
||||
}
|
||||
|
||||
bool path_test() {
|
||||
char buf[512];
|
||||
size_t len = sizeof(buf);
|
||||
|
||||
path_append(buf, "/test", "123", len);
|
||||
CHECK(buf, "/test/123", len);
|
||||
|
||||
path_append(buf, "/test/", "/123", len);
|
||||
CHECK(buf, "/123", len);
|
||||
|
||||
path_append(buf, "/test/", "/123/test 456/../test 567", len);
|
||||
CHECK(buf, "/123/test 567", len);
|
||||
|
||||
path_append(buf, "/test//", "123/", len);
|
||||
CHECK(buf, "/test/123/", len);
|
||||
|
||||
path_append(buf, "/test", "..", len);
|
||||
CHECK(buf, "/", len);
|
||||
|
||||
path_append(buf, "/", "..", len);
|
||||
CHECK(buf, "/", len);
|
||||
|
||||
path_append(buf, "/test/..", "123", len);
|
||||
CHECK(buf, "/123", len);
|
||||
|
||||
path_append(buf, "/test/", "123/..", len);
|
||||
CHECK(buf, "/test/", len);
|
||||
|
||||
path_append(buf, "/test/.", "123/./456", len);
|
||||
CHECK(buf, "/test/123/456", len);
|
||||
|
||||
path_append(buf, "test 1", "test 2", len);
|
||||
CHECK(buf, "test 1/test 2", len);
|
||||
|
||||
path_append(buf, "/1/2/3/4/5/6/7/8/9/../9", "10/", len);
|
||||
CHECK(buf, "/1/2/3/4/5/6/7/8/9/10/", len);
|
||||
|
||||
// FIXME later
|
||||
// path_append(buf, "/1/2/3/4/5/./6/./7/8/9/../9", "10/.", len);
|
||||
// CHECK(buf, "/1/2/3/4/5/6/7/8/9/10/", len);
|
||||
|
||||
path_append(buf, "/dev/", "", len);
|
||||
CHECK(buf, "/dev/", len);
|
||||
|
||||
path_append(buf, "/dev/", ".null", len);
|
||||
CHECK(buf, "/dev/.null", len);
|
||||
|
||||
path_append(buf, "", ".config", len);
|
||||
CHECK(buf, ".config", len);
|
||||
|
||||
path_append(buf, "", NULL, len);
|
||||
CHECK(buf, "", len);
|
||||
|
||||
path_append(buf, "test", NULL, len);
|
||||
CHECK(buf, "test", len);
|
||||
|
||||
path_append(buf, "/test", ".", len);
|
||||
CHECK(buf, "/test", len);
|
||||
|
||||
printf("path_test: passed\n");
|
||||
return true;
|
||||
}
|
||||
@@ -6,4 +6,6 @@ bool vc_vector_run_tests();
|
||||
|
||||
bool fatfs_test();
|
||||
|
||||
bool stdio_test();
|
||||
bool stdio_test();
|
||||
|
||||
bool path_test();
|
||||
+21
-14
@@ -1,10 +1,11 @@
|
||||
#include "malloc.h"
|
||||
#include "stdio.h"
|
||||
#include "../kernel/console.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
// #define MALLOC_DEBUG
|
||||
#define MALLOC_DEBUG
|
||||
|
||||
void *malloc_memory_start = (void *) 0x1000000; // 1 MiB, start of x86 upper memory
|
||||
void *malloc_memory_end = NULL;
|
||||
@@ -14,7 +15,7 @@ struct chunk_header {
|
||||
struct chunk_header *next;
|
||||
struct chunk_header *prev;
|
||||
size_t size;
|
||||
bool used;
|
||||
unsigned short used;
|
||||
};
|
||||
|
||||
static_assert(sizeof(struct chunk_header) % 4 == 0, "chunk_header is misaligned");
|
||||
@@ -29,17 +30,18 @@ static bool try_reclaim(struct chunk_header *start, size_t size) {
|
||||
struct chunk_header *next_chunk = current_chunk->next;
|
||||
if (next_chunk == NULL) {
|
||||
#ifdef MALLOC_DEBUG
|
||||
kprint("unused until end of chunks\n");
|
||||
printf("unused until end of chunks\n");
|
||||
#endif
|
||||
start->next = NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
unused += ((void *) current_chunk) - ((void *) current_chunk->prev);
|
||||
unused += (uintptr_t) current_chunk - (uintptr_t) current_chunk->prev;
|
||||
#ifdef MALLOC_DEBUG
|
||||
kprint("found unused size "); kprint_uint32(unused); kprint("\n");
|
||||
printf("found unused size %zu\n", unused);
|
||||
#endif
|
||||
if (unused >= size) {
|
||||
// FIXME do i need ALIGN here?
|
||||
if (unused >= ALIGN(size, 4) + sizeof(struct chunk_header)) {
|
||||
next_chunk->prev = start;
|
||||
start->next = next_chunk;
|
||||
return true;
|
||||
@@ -58,7 +60,7 @@ static void *find_unused_chunk(const size_t chunk_size) {
|
||||
|
||||
// First chunk @ start of memory
|
||||
#ifdef MALLOC_DEBUG
|
||||
kprint("new chunk @ start: "); kprint_uint32(chunk_size); kprint("\n");
|
||||
printf("new chunk @ start: %zu\n", chunk_size);
|
||||
#endif
|
||||
struct chunk_header *header = malloc_memory_start;
|
||||
memset(header, 0, sizeof(struct chunk_header));
|
||||
@@ -71,7 +73,7 @@ static void *find_unused_chunk(const size_t chunk_size) {
|
||||
if (header->size >= chunk_size) {
|
||||
// Unused chunk is large enough, go ahead and use it
|
||||
#ifdef MALLOC_DEBUG
|
||||
kprint("reusing large enough chunk "); kprint_uint32(header->size); kprint(" for "); kprint_uint32(chunk_size); kprint("\n");
|
||||
printf("reusing large enough chunk %zu for %zu\n", header->size, chunk_size);
|
||||
#endif
|
||||
return header;
|
||||
} else if (try_reclaim(header, chunk_size)) {
|
||||
@@ -83,7 +85,7 @@ static void *find_unused_chunk(const size_t chunk_size) {
|
||||
// Allocate new chunk if end
|
||||
if (header->next == NULL) {
|
||||
#ifdef MALLOC_DEBUG
|
||||
kprint("alloc new chunk size: "); kprint_uint32(chunk_size); kprint("\n");
|
||||
printf("alloc new chunk size: %zu\n", chunk_size);
|
||||
#endif
|
||||
void *next = (void *) header + sizeof(struct chunk_header) + ALIGN(header->size, 4);
|
||||
if (next + chunk_size > malloc_memory_end) break; // Don't overcommit new chunk
|
||||
@@ -96,11 +98,14 @@ static void *find_unused_chunk(const size_t chunk_size) {
|
||||
|
||||
// Find space in between chunks
|
||||
uintptr_t end_of_chunk = (uintptr_t) header + sizeof(struct chunk_header) + ALIGN(header->size, 4);
|
||||
if (end_of_chunk > (uintptr_t) header->next) {
|
||||
panic("found misaligned chunk %P. Expected end: %P, actual next: %P\n", header, end_of_chunk, header->next);
|
||||
}
|
||||
uintptr_t unused_size = (uintptr_t) header->next - end_of_chunk;
|
||||
if (unused_size > chunk_size + sizeof(struct chunk_header)) {
|
||||
#ifdef MALLOC_DEBUG
|
||||
kprint("found size between chunk: "); kprint_uint32(unused_size); kprint(" > "); kprint_uint32(chunk_size); kprint("\n");
|
||||
kprint("chunk 1: "); kprint_uint32((uintptr_t) header); kprint(" | chunk 2: "); kprint_uint32((uintptr_t) header->next); kprint("\n");
|
||||
printf("found size between chunk: %zu > %zu\n", unused_size, chunk_size);
|
||||
printf(" chunk 1: %P (size %zu) | chunk 2: %P\n", header, header->size, header->next);
|
||||
#endif
|
||||
struct chunk_header *next_header = (struct chunk_header *) end_of_chunk;
|
||||
memset(next_header, 0, sizeof(struct chunk_header));
|
||||
@@ -134,12 +139,13 @@ void free(void *ptr) {
|
||||
struct chunk_header *header = ptr - sizeof(struct chunk_header);
|
||||
header->used = false;
|
||||
#ifdef MALLOC_DEBUG
|
||||
kprint("freeing chunk w/ size "); kprint_uint32(header->size); kprint("\n");
|
||||
printf("freeing chunk w/ size %zu\n", header->size);
|
||||
#endif
|
||||
}
|
||||
|
||||
void *realloc(void *ptr, size_t new_size) {
|
||||
if (ptr == NULL) return malloc(new_size);
|
||||
|
||||
struct chunk_header *header = ptr - sizeof(struct chunk_header);
|
||||
if (header->size >= new_size || try_reclaim(header, new_size)) {
|
||||
header->size = new_size;
|
||||
@@ -173,7 +179,8 @@ static unsigned digits(uint32_t n) {
|
||||
1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5,
|
||||
5, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10,
|
||||
};
|
||||
unsigned bits = sizeof(n) * CHAR_BIT - __builtin_clz(n);
|
||||
extern int __clzsi2(unsigned); // FIXME
|
||||
unsigned bits = sizeof(n) * CHAR_BIT - __clzsi2(n);
|
||||
unsigned digits = max_digits[bits];
|
||||
if (n < powers[digits - 1]) --digits;
|
||||
return digits;
|
||||
@@ -201,7 +208,7 @@ void print_chunk_debug(void *ptr, bool recursive) {
|
||||
struct chunk_header *header = ptr - sizeof(struct chunk_header);
|
||||
do {
|
||||
char *str_size = pretty_bytes(header->size);
|
||||
printf("chunk @ %p | next: %p, prev: %p, used: %d, size: %s\n",
|
||||
printf("chunk @ %P | next: %P, prev: %P, used: %d, size: %s\n",
|
||||
header, header->next, header->prev, header->used, str_size);
|
||||
free(str_size);
|
||||
|
||||
|
||||
+117
-1
@@ -123,7 +123,7 @@ char *strncpy(char *restrict s1, const char *restrict s2, size_t n) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
char *strdup(char *str) {
|
||||
char *strdup(const char *str) {
|
||||
size_t len = strlen(str) + 1;
|
||||
char *new = malloc(len);
|
||||
if (new == NULL) return NULL;
|
||||
@@ -152,3 +152,119 @@ char *strchr(const char *s, int c) {
|
||||
char *r = __strchrnul(s, c);
|
||||
return *(unsigned char *) r == (unsigned char) c ? r : 0;
|
||||
}
|
||||
|
||||
size_t strlcpy(char *d, const char *s, size_t n) {
|
||||
char *d0 = d;
|
||||
size_t *wd;
|
||||
|
||||
if (!n--) goto finish;
|
||||
#ifdef __GNUC__
|
||||
typedef size_t __attribute__((__may_alias__)) word;
|
||||
const word *ws;
|
||||
if (((uintptr_t) s & _ALIGN) == ((uintptr_t) d & _ALIGN)) {
|
||||
for (; ((uintptr_t) s & _ALIGN) && n && (*d = *s); n--, s++, d++);
|
||||
if (n && *s) {
|
||||
wd = (void *) d;
|
||||
ws = (const void *) s;
|
||||
for (; n >= sizeof(size_t) && !_HASZERO(*ws);
|
||||
n -= sizeof(size_t), ws++, wd++)
|
||||
*wd = *ws;
|
||||
d = (void *) wd;
|
||||
s = (const void *) ws;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
for (; n && (*d = *s); n--, s++, d++);
|
||||
*d = 0;
|
||||
finish:
|
||||
return d - d0 + strlen(s);
|
||||
}
|
||||
|
||||
|
||||
#define PATH_LOOKAHEAD(p, i, c) ((i < len) && (p[i] == c))
|
||||
|
||||
// FIXME insane crazy stupid code but it works, I guess
|
||||
void path_append(char *dest, const char *path, const char *app, size_t len) {
|
||||
size_t i = 0, out_idx = 0, dir_idx = 0;
|
||||
|
||||
// Skip existing path if necessary
|
||||
if (app != NULL && app[0] == '/') goto append;
|
||||
|
||||
while (i < len && out_idx < len && path[i] != 0) {
|
||||
if (path[i] == '/') {
|
||||
if (PATH_LOOKAHEAD(path, i + 1, '.')) {
|
||||
if (PATH_LOOKAHEAD(path, i + 2, '.')
|
||||
&& (PATH_LOOKAHEAD(path, i + 3, '/')
|
||||
|| PATH_LOOKAHEAD(path, i + 3, 0))) {
|
||||
out_idx = dir_idx + 1;
|
||||
i += 3;
|
||||
while (PATH_LOOKAHEAD(path, i, '/')) i++;
|
||||
continue;
|
||||
} else if (PATH_LOOKAHEAD(path, i + 2, '/')
|
||||
|| PATH_LOOKAHEAD(path, i + 2, 0)) {
|
||||
i += 2;
|
||||
continue;
|
||||
}
|
||||
} else if (PATH_LOOKAHEAD(path, i + 1, '/')) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
dir_idx = out_idx;
|
||||
}
|
||||
|
||||
dest[out_idx] = path[i];
|
||||
i++;
|
||||
out_idx++;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
if (app == NULL || app[0] == 0) goto close;
|
||||
|
||||
// Check for leading . or ..
|
||||
if (app[i] == '.') {
|
||||
if (PATH_LOOKAHEAD(app, i + 1, '/')) {
|
||||
i += 2;
|
||||
} else if (PATH_LOOKAHEAD(app, i + 1, 0)) {
|
||||
goto close;
|
||||
} else if (PATH_LOOKAHEAD(app, i + 1, '.')
|
||||
&& (PATH_LOOKAHEAD(app, i + 2, '/')
|
||||
|| PATH_LOOKAHEAD(app, i + 2, 0))) {
|
||||
out_idx = dir_idx + 1;
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (out_idx && dest[out_idx - 1] != '/' && out_idx < len) dest[dir_idx = out_idx++] = '/'; // Add trailing slash
|
||||
while (i < len && app[i] == '/') i++; // Skip leading slash(es)
|
||||
|
||||
append:
|
||||
while (i < len && out_idx < len && app[i] != 0) {
|
||||
if (app[i] == '/') {
|
||||
if (PATH_LOOKAHEAD(app, i + 1, '.')) {
|
||||
if (PATH_LOOKAHEAD(app, i + 2, '.')
|
||||
&& (PATH_LOOKAHEAD(app, i + 3, '/')
|
||||
|| PATH_LOOKAHEAD(app, i + 3, 0))) {
|
||||
out_idx = dir_idx + 1;
|
||||
i += 3;
|
||||
while (PATH_LOOKAHEAD(app, i, '/')) i++;
|
||||
continue;
|
||||
} else if (PATH_LOOKAHEAD(app, i + 2, '/')
|
||||
|| PATH_LOOKAHEAD(app, i + 2, 0)) {
|
||||
i += 2;
|
||||
continue;
|
||||
}
|
||||
} else if (PATH_LOOKAHEAD(app, i + 1, '/')) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
dir_idx = out_idx;
|
||||
}
|
||||
|
||||
dest[out_idx] = app[i];
|
||||
i++;
|
||||
out_idx++;
|
||||
}
|
||||
|
||||
close:
|
||||
dest[out_idx] = 0;
|
||||
}
|
||||
+6
-2
@@ -27,6 +27,10 @@ char *strcpy(char *destination, const char *source);
|
||||
|
||||
char *strncpy(char *restrict s1, const char *restrict s2, size_t n);
|
||||
|
||||
char *strdup(char *str);
|
||||
char *strdup(const char *str);
|
||||
|
||||
char *strchr(const char *s, int c);
|
||||
char *strchr(const char *s, int c);
|
||||
|
||||
size_t strlcpy(char *d, const char *s, size_t n);
|
||||
|
||||
void path_append(char *dest, const char *path, const char *app, size_t len);
|
||||
Reference in New Issue
Block a user