Compare commits
18 commits
master
...
memory_all
Author | SHA1 | Date | |
---|---|---|---|
|
fe30349d17 | ||
|
256efe6b22 | ||
|
5b8f5cac54 | ||
|
8ae1816819 | ||
|
a537ac162e | ||
|
3af5ab06a7 | ||
|
c66bb87aaf | ||
|
200e58b6f6 | ||
|
9589e2f804 | ||
|
5e1a12239a | ||
|
5c8f8defe0 | ||
|
831b49d8dd | ||
|
2064d1a802 | ||
|
d547432270 | ||
|
a042169845 | ||
|
4f214b2d5a | ||
|
fafe06ed2b | ||
|
ea9f4c6e49 |
8 changed files with 487 additions and 97 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -1 +1,5 @@
|
|||
target/
|
||||
|
||||
.idea/
|
||||
CMakeLists.txt
|
||||
cmake-build-debug/
|
||||
|
|
|
@ -37,7 +37,7 @@ The kernel is based on [the bare bones kernel from the OSDev wiki](https://wiki.
|
|||
- [ ] Write files in directory
|
||||
- [ ] Tests
|
||||
- [ ] Running executables from filesystem
|
||||
- [ ] Better memory management
|
||||
- [x] Better memory management
|
||||
- [ ] Better shell
|
||||
|
||||
As a test, I've implemented day 1 of [advent of code](https://adventofcode.com/) on the [AoC branch](https://github.com/Robbe7730/RoBoot/tree/AoC).
|
||||
|
|
|
@ -290,7 +290,7 @@ repnz movsd
|
|||
or ax, ax
|
||||
jnz .elf_ph_loop
|
||||
|
||||
.start_kernel
|
||||
.start_kernel:
|
||||
|
||||
cmp edi, KERNEL_START
|
||||
je .invalid_elf
|
||||
|
|
|
@ -16,17 +16,17 @@
|
|||
#include "memory.c"
|
||||
#include "interrupts.c"
|
||||
#include "shell.c"
|
||||
#include "util/printer.c"
|
||||
|
||||
static inline bool are_interrupts_enabled() {
|
||||
unsigned long flags;
|
||||
asm volatile ( "pushf\n\t"
|
||||
"pop %0"
|
||||
: "=g"(flags) );
|
||||
: "=g"(flags));
|
||||
return flags & (1 << 9);
|
||||
}
|
||||
|
||||
void kernel_main(void)
|
||||
{
|
||||
void kernel_main(void) {
|
||||
/* Initialize terminal interface */
|
||||
terminal_initialize();
|
||||
|
||||
|
@ -37,31 +37,46 @@ void kernel_main(void)
|
|||
terminal_putchar('o');
|
||||
|
||||
terminal_setcolor(vga_entry_color(VGA_COLOR_GREEN, VGA_COLOR_BLACK));
|
||||
terminal_writestring(" kernel");
|
||||
print(" kernel");
|
||||
terminal_setcolor(vga_entry_color(VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK));
|
||||
terminal_writestring(" World!\n");
|
||||
terminal_writestring("Newlines!\n");
|
||||
print(" World!\n");
|
||||
print("Newlines!\n");
|
||||
|
||||
char* memory_str = alloc(sizeof(char) * 7);
|
||||
char *memory_str = alloc(sizeof(char) * 7);
|
||||
for (int i = 0; i < 6; i++) {
|
||||
memory_str[i] = "Memory"[i];
|
||||
}
|
||||
memory_str[6] = 0;
|
||||
|
||||
char* management_str = alloc(sizeof(char) * 13);
|
||||
char *management_str = alloc(sizeof(char) * 13);
|
||||
for (int i = 0; i < 13; i++) {
|
||||
management_str[i] = " management!\n"[i];
|
||||
}
|
||||
management_str[13] = 0;
|
||||
|
||||
terminal_writestring(memory_str);
|
||||
terminal_writestring(management_str);
|
||||
print(memory_str);
|
||||
print(management_str);
|
||||
|
||||
terminal_writestring((are_interrupts_enabled())? "Interrupts!\n": "No interrupts :(\n");
|
||||
free(memory_str);
|
||||
free(management_str);
|
||||
|
||||
// Some dummy allocations to demonstrate the states of memory and to showcase the memory dump printout.
|
||||
void* ptr = alloc(30);
|
||||
alloc(30);
|
||||
alloc(31);
|
||||
free(ptr);
|
||||
|
||||
void* ptr2 = alloc(64);
|
||||
alloc(61);
|
||||
free(ptr2);
|
||||
|
||||
print((are_interrupts_enabled()) ? "Interrupts!\n" : "No interrupts :(\n");
|
||||
|
||||
interrupt_init();
|
||||
|
||||
for(;;) {
|
||||
print_memory();
|
||||
|
||||
for (;;) {
|
||||
shell_step();
|
||||
}
|
||||
}
|
205
kernel/memory.c
205
kernel/memory.c
|
@ -1,13 +1,208 @@
|
|||
#ifndef MEMORY_C
|
||||
#define MEMORY_C
|
||||
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
void* _curr_end = (void*) 0x200000;
|
||||
#include "terminal.c"
|
||||
#include "util/printer.c"
|
||||
|
||||
void* alloc(size_t size) {
|
||||
void* thanks_jp = _curr_end;
|
||||
_curr_end += size;
|
||||
return thanks_jp;
|
||||
#define MEMORY_START 0x200000
|
||||
//#define MEMORY_END 0x300000
|
||||
|
||||
#define PAGE_ALIGNMENT 4
|
||||
|
||||
//size_t total_memory = MEMORY_END - MEMORY_START;
|
||||
|
||||
typedef struct page_tag {
|
||||
size_t size;
|
||||
size_t realsize;
|
||||
|
||||
struct page_tag *prev;
|
||||
struct page_tag *next;
|
||||
} page_tag;
|
||||
|
||||
|
||||
page_tag *start = (void *) MEMORY_START;;
|
||||
|
||||
size_t calculate_realsize(size_t size) {
|
||||
if (size % PAGE_ALIGNMENT == 0) return size;
|
||||
return size + PAGE_ALIGNMENT - (size % PAGE_ALIGNMENT);
|
||||
}
|
||||
|
||||
void *alloc(size_t size) {
|
||||
page_tag *curr_page = start;
|
||||
|
||||
while (curr_page->next != NULL) {
|
||||
page_tag *new_page = ((void *) curr_page) + sizeof(page_tag) + curr_page->realsize;
|
||||
size_t realsize = calculate_realsize(size);
|
||||
if ((void *) new_page + sizeof(page_tag) + realsize <= (void *) curr_page->next) {
|
||||
|
||||
new_page->size = size;
|
||||
new_page->realsize = realsize;
|
||||
|
||||
curr_page->next->prev = new_page;
|
||||
new_page->next = curr_page->next;
|
||||
|
||||
curr_page->next = new_page;
|
||||
new_page->prev = curr_page;
|
||||
|
||||
return new_page + 1;
|
||||
}
|
||||
curr_page = curr_page->next;
|
||||
}
|
||||
|
||||
page_tag *new_page = ((void *) curr_page) + sizeof(page_tag) + curr_page->realsize;
|
||||
new_page->size = size;
|
||||
new_page->realsize = calculate_realsize(size);
|
||||
|
||||
curr_page->next = new_page;
|
||||
new_page->prev = curr_page;
|
||||
new_page->next = NULL;
|
||||
return new_page + 1;
|
||||
}
|
||||
|
||||
void free(void *data) {
|
||||
page_tag *data_tag = data - sizeof(page_tag);
|
||||
|
||||
data_tag->prev->next = data_tag->next;
|
||||
data_tag->next->prev = data_tag->prev;
|
||||
}
|
||||
|
||||
int amount_of_digits(int x) {
|
||||
if (x == 0) return 1;
|
||||
int n = 0;
|
||||
while (x != 0) {
|
||||
n += 1;
|
||||
x /= 10;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
#define MEM_SIZE_WIDTH 3
|
||||
#define SPACED_ARRAY {' ', ' ', ' '};
|
||||
|
||||
void print_memory() {
|
||||
print("____________________\n");
|
||||
print(" === MEM DUMP === \n");
|
||||
print("--------------------\n");
|
||||
print("Page tag size: %d bytes\n", sizeof(page_tag));
|
||||
print("Memory alignment: %d bytes\n", PAGE_ALIGNMENT);
|
||||
print("=> idx: [page_tag_address] [data_address (size|aligment_padding_size)]\n\n");
|
||||
page_tag *curr_page = start;
|
||||
int i = 0;
|
||||
bool left = true;
|
||||
while (curr_page != NULL) {
|
||||
char padding[MEM_SIZE_WIDTH] = SPACED_ARRAY;
|
||||
padding[MEM_SIZE_WIDTH - amount_of_digits(curr_page->size)] = '\0';
|
||||
print("%d: [%x] [%x (%s%d|%d)]",
|
||||
i,
|
||||
curr_page,
|
||||
(curr_page + 1), padding, curr_page->size,
|
||||
curr_page->realsize - curr_page->size);
|
||||
|
||||
if (left) {
|
||||
print(" | ");
|
||||
} else {
|
||||
print("\n");
|
||||
}
|
||||
left = !left;
|
||||
|
||||
bool empty_print = false;
|
||||
void *empty_start = (void *) curr_page + sizeof(page_tag) + curr_page->realsize;
|
||||
if (empty_start + sizeof(page_tag) < (void *) curr_page->next) {
|
||||
size_t memory_left = (void *) curr_page->next -
|
||||
(empty_start + sizeof(page_tag));
|
||||
char empty_padding[MEM_SIZE_WIDTH] = SPACED_ARRAY;
|
||||
empty_padding[MEM_SIZE_WIDTH - amount_of_digits(memory_left)] = '\0';
|
||||
|
||||
print("_: free space (%d + %s%d| ) ",
|
||||
sizeof(page_tag),
|
||||
empty_padding,
|
||||
memory_left
|
||||
);
|
||||
empty_print = true;
|
||||
} else if (empty_start < (void *) curr_page->next) {
|
||||
size_t memory_left = (void *) curr_page->next - empty_start;
|
||||
|
||||
char empty_padding[MEM_SIZE_WIDTH] = SPACED_ARRAY;
|
||||
empty_padding[MEM_SIZE_WIDTH - amount_of_digits(memory_left)] = '\0';
|
||||
|
||||
print("_: not enough room (%s%d| ) ",
|
||||
empty_padding,
|
||||
memory_left);
|
||||
empty_print = true;
|
||||
}
|
||||
if (empty_print) {
|
||||
if (left) {
|
||||
print(" | ");
|
||||
} else {
|
||||
print("\n");
|
||||
}
|
||||
left = !left;
|
||||
}
|
||||
|
||||
|
||||
curr_page = curr_page->next;
|
||||
i += 1;
|
||||
}
|
||||
if (!left) {
|
||||
print("\n");
|
||||
}
|
||||
print("____________________\n");
|
||||
}
|
||||
|
||||
int command_mem_dump(char *string) {
|
||||
print_memory();
|
||||
}
|
||||
|
||||
//
|
||||
//void test_allocs() {
|
||||
// void *ptr0 = __alloc(64);
|
||||
// void *ptr1 = __alloc(64);
|
||||
// void *ptr4 = __alloc(64);
|
||||
// print();
|
||||
//
|
||||
// printf("Free nr 2 -> %p\n", ptr1);
|
||||
// __free(ptr1);
|
||||
// print();
|
||||
//
|
||||
// printf("Alloc 32 bytes\n");
|
||||
// void *ptr2 = __alloc(32);
|
||||
// print();
|
||||
//
|
||||
// printf("Alloc 32 bytes\n");
|
||||
// __alloc(32);
|
||||
// print();
|
||||
//
|
||||
// printf("Alloc 8 bytes\n");
|
||||
// void *ptr3 = __alloc(8);
|
||||
// print();
|
||||
//
|
||||
// __free(ptr2);
|
||||
// print();
|
||||
// __free(ptr4);
|
||||
// print();
|
||||
// __free(ptr3);
|
||||
// print();
|
||||
//
|
||||
// __free(ptr0);
|
||||
// print();
|
||||
//
|
||||
// printf("#########\nTry almost fill\n");
|
||||
// __alloc(160);
|
||||
// print();
|
||||
// __alloc(50);
|
||||
// print();
|
||||
//
|
||||
//
|
||||
//}
|
||||
//
|
||||
//int main() {
|
||||
// start = malloc(sizeof(size_t) * 1000);
|
||||
// start->next = NULL;
|
||||
// start->prev = NULL;
|
||||
// test_allocs();
|
||||
//}
|
||||
|
||||
#endif // MEMORY_C
|
105
kernel/shell.c
105
kernel/shell.c
|
@ -8,28 +8,29 @@
|
|||
#include "terminal.c"
|
||||
#include "inline_asm.c"
|
||||
#include "drivers/keyboard/keyboard.c"
|
||||
#include "memory.c"
|
||||
|
||||
char buffer[SHELL_CMD_BUFFER_SIZE];
|
||||
int buffer_idx = 0;
|
||||
|
||||
int echo(char* input) {
|
||||
int echo(char *input) {
|
||||
terminal_writestring(input);
|
||||
terminal_putchar('\n');
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hello(char* unused) {
|
||||
int hello(char *unused) {
|
||||
terminal_writestring("Hello, world!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cls(char* unused) {
|
||||
int cls(char *unused) {
|
||||
terminal_initialize();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_gdt(char* unused) {
|
||||
gdt_desc desc = {2,2};
|
||||
int get_gdt(char *unused) {
|
||||
gdt_desc desc = {2, 2};
|
||||
sgdt(&desc);
|
||||
terminal_writestring("limit = ");
|
||||
terminal_writeint(desc.limit, 10);
|
||||
|
@ -37,8 +38,8 @@ int get_gdt(char* unused) {
|
|||
terminal_writeint(desc.base, 16);
|
||||
terminal_putchar('\n');
|
||||
|
||||
gdt_entry* entries = (gdt_entry*) desc.base;
|
||||
int num_entries = (desc.limit+1) / 8;
|
||||
gdt_entry *entries = (gdt_entry *) desc.base;
|
||||
int num_entries = (desc.limit + 1) / 8;
|
||||
for (int entry_num = 0; entry_num < num_entries; entry_num++) {
|
||||
gdt_entry entry = entries[entry_num];
|
||||
uint32_t base = entry.base_lower | entry.base_middle << 16 | entry.base_higher << 24;
|
||||
|
@ -48,68 +49,66 @@ int get_gdt(char* unused) {
|
|||
|
||||
//terminal_writestring("\nEntry ");
|
||||
//terminal_writeint(entry_num, 10);
|
||||
terminal_writestring("base = 0x");
|
||||
terminal_writeint(base, 16);
|
||||
terminal_writestring("\nlimit = 0x");
|
||||
terminal_writeint(limit, 16);
|
||||
terminal_writestring("\nflags = 0b");
|
||||
terminal_writeint((entry.flags_limit_higher >> 4), 2);
|
||||
print("base = %x\n", base);
|
||||
print("limit = %x\n", limit);
|
||||
print("flags = %b\n", (entry.flags_limit_higher >> 4));
|
||||
|
||||
if ((flags & 0b1000) == 0) {
|
||||
terminal_writestring(" (byte granularity");
|
||||
print(" (byte granularity");
|
||||
} else {
|
||||
terminal_writestring(" (page granularity");
|
||||
print(" (page granularity");
|
||||
}
|
||||
|
||||
if ((flags & 0b0100) == 0) {
|
||||
terminal_writestring(", 16 bit)");
|
||||
print(", 16 bit)");
|
||||
} else {
|
||||
terminal_writestring(", 32 bit)");
|
||||
print(", 32 bit)");
|
||||
}
|
||||
print("\n");
|
||||
|
||||
terminal_writestring("\naccess = 0b");
|
||||
terminal_writeint(entry.access_byte, 2);
|
||||
terminal_writestring(" (ring ");
|
||||
terminal_writeint((entry.access_byte & 0b01100000) >> 5, 10);
|
||||
print("access = %b (ring %d",
|
||||
entry.access_byte,
|
||||
(entry.access_byte & 0b01100000) >> 5
|
||||
);
|
||||
if ((entry.access_byte & 0b00010000) == 0) {
|
||||
terminal_writestring(", System");
|
||||
print(", System");
|
||||
}
|
||||
if (is_data) {
|
||||
terminal_writestring(", Data");
|
||||
print(", Data");
|
||||
|
||||
if((entry.access_byte & 0b00000100) == 0) {
|
||||
terminal_writestring(" (growing up, ");
|
||||
if ((entry.access_byte & 0b00000100) == 0) {
|
||||
print(" (growing up, ");
|
||||
} else {
|
||||
terminal_writestring(" (growing down, ");
|
||||
print(" (growing down, ");
|
||||
}
|
||||
|
||||
if((entry.access_byte & 0b00000010) == 0) {
|
||||
terminal_writestring("r--)");
|
||||
if ((entry.access_byte & 0b00000010) == 0) {
|
||||
print("r--)");
|
||||
} else {
|
||||
terminal_writestring("rw-)");
|
||||
print("rw-)");
|
||||
}
|
||||
} else {
|
||||
terminal_writestring(", Code");
|
||||
print(", Code");
|
||||
|
||||
if((entry.access_byte & 0b00000100) == 0) {
|
||||
terminal_writestring(" (non-conforming, ");
|
||||
if ((entry.access_byte & 0b00000100) == 0) {
|
||||
print(" (non-conforming, ");
|
||||
} else {
|
||||
terminal_writestring(" (conforming, ");
|
||||
print(" (conforming, ");
|
||||
}
|
||||
|
||||
if((entry.access_byte & 0b00000010) == 0) {
|
||||
terminal_writestring("--x)");
|
||||
if ((entry.access_byte & 0b00000010) == 0) {
|
||||
print("--x)");
|
||||
} else {
|
||||
terminal_writestring("r-x)");
|
||||
print("r-x)");
|
||||
}
|
||||
}
|
||||
|
||||
terminal_writestring(")\n");
|
||||
print(")\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ree(char* unused) {
|
||||
int ree(char *unused) {
|
||||
terminal_initialize();
|
||||
terminal_putchar('R');
|
||||
for (int i = 1; i < VGA_WIDTH * VGA_HEIGHT; i++) {
|
||||
|
@ -118,27 +117,41 @@ int ree(char* unused) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int save_text(char *text) {
|
||||
char *mem_block = alloc(strlen(text) * sizeof(char));
|
||||
char *c;
|
||||
int i = 0;
|
||||
for (c = text; *c != '\0'; c++) {
|
||||
mem_block[i] = *c;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO This is ugly, fix this
|
||||
const char* shell_commands_strings[] = {
|
||||
const char *shell_commands_strings[] = {
|
||||
"echo",
|
||||
"hello",
|
||||
"cls",
|
||||
"ree",
|
||||
"getgdt",
|
||||
"memdump",
|
||||
"savetext",
|
||||
NULL
|
||||
};
|
||||
|
||||
int (*shell_commands_functions[]) (char*) = {
|
||||
int (*shell_commands_functions[])(char *) = {
|
||||
echo,
|
||||
hello,
|
||||
cls,
|
||||
ree,
|
||||
get_gdt
|
||||
get_gdt,
|
||||
command_mem_dump,
|
||||
save_text
|
||||
};
|
||||
|
||||
int run_command(char* buffer) {
|
||||
int run_command(char *buffer) {
|
||||
|
||||
if(buffer[0] == 0) {
|
||||
if (buffer[0] == 0) {
|
||||
return 0;
|
||||
}
|
||||
char command[SHELL_CMD_BUFFER_SIZE] = {0};
|
||||
|
@ -150,9 +163,9 @@ int run_command(char* buffer) {
|
|||
|
||||
int command_idx = 0;
|
||||
|
||||
while(shell_commands_strings[command_idx] != NULL) {
|
||||
while (shell_commands_strings[command_idx] != NULL) {
|
||||
int check_idx = 0;
|
||||
while(command[check_idx] != 0 && shell_commands_strings[command_idx][check_idx] == command[check_idx]) {
|
||||
while (command[check_idx] != 0 && shell_commands_strings[command_idx][check_idx] == command[check_idx]) {
|
||||
check_idx++;
|
||||
}
|
||||
if (command[check_idx] == 0 && shell_commands_strings[command_idx][check_idx] == 0) {
|
||||
|
@ -176,7 +189,7 @@ void shell_step() {
|
|||
buffer_idx = 0;
|
||||
|
||||
if (result == -1) {
|
||||
terminal_writestring("No such command\n");
|
||||
print("No such command\n");
|
||||
}
|
||||
} else if (curr_char == 0x08) {
|
||||
if (buffer_idx != 0) {
|
||||
|
|
91
kernel/tests/tests.c
Normal file
91
kernel/tests/tests.c
Normal file
|
@ -0,0 +1,91 @@
|
|||
#ifndef TESTS_TESTS_C
|
||||
#define TESTS_TESTS_C
|
||||
|
||||
#define TESTS_ENABLED
|
||||
#ifdef TESTS_ENABLED
|
||||
|
||||
|
||||
#define mu_assert(message, test) do { if (!(test)) return message; } while (0)
|
||||
#define mu_run_test(test) do { char *message = test(); tests_run++; \
|
||||
if (message) return message; } while (0)
|
||||
extern int tests_run;
|
||||
|
||||
#include "../memory.c"
|
||||
#include <stddef.h>
|
||||
|
||||
|
||||
int tests_run = 0;
|
||||
|
||||
|
||||
static char *test_memory() {
|
||||
|
||||
ll_node *ll_head = __new_node();
|
||||
ll_head->data = malloc(sizeof(size_t) * 5000);
|
||||
ll_head->used = true;
|
||||
ll_head->size = 1;
|
||||
void *ptr0 = __alloc(ll_head, 5);
|
||||
void *ptr1 = __alloc(ll_head, 5);
|
||||
void *ptr4 = __alloc(ll_head, 5);
|
||||
print(ll_head);
|
||||
mu_assert("Error: chain should be complete at 1", ll_head->next != NULL);
|
||||
mu_assert("Error: chain should be complete at 2", ll_head->next->next != NULL);
|
||||
mu_assert("Error: chain should be complete at 3", ll_head->next->next->next != NULL);
|
||||
mu_assert("Error: chain should be complete at 4", ll_head->next->next->next->next == NULL);
|
||||
|
||||
ll_node *current = ll_head;
|
||||
while (current->next != NULL) {
|
||||
current = current->next;
|
||||
|
||||
mu_assert("Error: block should have size 5", current->size == 5);
|
||||
mu_assert("Error: block should be in use", current->used == true);
|
||||
}
|
||||
|
||||
__free(ll_head, ptr1);
|
||||
mu_assert("", ll_head->next->used == true);
|
||||
mu_assert("", ll_head->next->next->used == false);
|
||||
mu_assert("", ll_head->next->next->next->used == true);
|
||||
|
||||
printf("Alloc 3 bytes\n");
|
||||
void *ptr2 = __alloc(ll_head, 3);
|
||||
print(ll_head);
|
||||
|
||||
printf("Alloc 3 bytes\n");
|
||||
__alloc(ll_head, 3);
|
||||
print(ll_head);
|
||||
|
||||
printf("Alloc 2 bytes\n");
|
||||
void *ptr3 = __alloc(ll_head, 2);
|
||||
print(ll_head);
|
||||
|
||||
__free(ll_head, ptr2);
|
||||
print(ll_head);
|
||||
__free(ll_head, ptr4);
|
||||
print(ll_head);
|
||||
__free(ll_head, ptr3);
|
||||
print(ll_head);
|
||||
|
||||
__free(ll_head, ptr0);
|
||||
print(ll_head);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *all_tests() {
|
||||
mu_run_test(test_memory);
|
||||
return 0;
|
||||
}
|
||||
//
|
||||
//int main(int argc, char **argv) {
|
||||
// char *result = all_tests();
|
||||
// if (result != 0) {
|
||||
// printf("%s\n", result);
|
||||
// } else {
|
||||
// printf("ALL TESTS PASSED\n");
|
||||
// }
|
||||
// printf("Tests run: %d\n", tests_run);
|
||||
//
|
||||
// return result != 0;
|
||||
//}
|
||||
|
||||
#endif // TESTS_ENABLED
|
||||
|
||||
#endif // TESTS_TESTS_C
|
72
kernel/util/printer.c
Normal file
72
kernel/util/printer.c
Normal file
|
@ -0,0 +1,72 @@
|
|||
#ifndef UTIL_PRINTER_C
|
||||
#define UTIL_PRINTER_C
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "../terminal.c"
|
||||
|
||||
/**
|
||||
* fmt is a string with specifiers where variables can be inserted.
|
||||
*
|
||||
* ex: ("Hello %s", "world") -> "Hello world"
|
||||
*
|
||||
* Specifiers are
|
||||
* - %c: character
|
||||
* - %d: digit (integer)
|
||||
* - %x: hexadecimal value. Can be used to print pointers to
|
||||
* - %b: binary value. Digits with base 2
|
||||
* @param fmt Formatter string
|
||||
* @param ... Variable amount of arguments to be inserted
|
||||
*/
|
||||
void print(const char *fmt, ...) {
|
||||
const char *p;
|
||||
va_list argp;
|
||||
int i;
|
||||
char *s;
|
||||
char fmtbuf[256];
|
||||
|
||||
va_start(argp, fmt);
|
||||
|
||||
for (p = fmt; *p != '\0'; p++)
|
||||
if (*p != '%') {
|
||||
terminal_putchar(*p);
|
||||
} else {
|
||||
switch (*++p) {
|
||||
case 'c':
|
||||
i = va_arg(argp, int);
|
||||
|
||||
terminal_putchar((char) i);
|
||||
break;
|
||||
case 'd':
|
||||
i = va_arg(argp, int);
|
||||
s = itoa(i, fmtbuf, 10);
|
||||
terminal_writestring(s);
|
||||
break;
|
||||
case 's':
|
||||
s = va_arg(argp, char *);
|
||||
terminal_writestring(s);
|
||||
break;
|
||||
case 'x':
|
||||
terminal_writestring("0x");
|
||||
|
||||
i = va_arg(argp, int);
|
||||
s = itoa(i, fmtbuf, 16);
|
||||
terminal_writestring(s);
|
||||
break;
|
||||
case 'b':
|
||||
terminal_writestring("0b");
|
||||
|
||||
i = va_arg(argp, int);
|
||||
s = itoa(i, fmtbuf, 2);
|
||||
terminal_writestring(s);
|
||||
break;
|
||||
case '%':
|
||||
terminal_putchar('%');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
va_end(argp);
|
||||
}
|
||||
|
||||
#endif //UTIL_PRINTER_C
|
Loading…
Reference in a new issue