acpi, fix mboot memory map, fix kalloc, fix virtalloc node allocator, add kprintf, other changes

This commit is contained in:
Freya Murphy 2024-02-01 12:48:55 -05:00
parent 7a59ef37b8
commit 192a4ccd6b
Signed by: freya
GPG key ID: 744AB800E383AE52
17 changed files with 836 additions and 137 deletions

View file

@ -52,5 +52,7 @@ run: all
qemu-system-x86_64 \ qemu-system-x86_64 \
-cdrom $(BUILD_DIR)/$(ISO_NAME) \ -cdrom $(BUILD_DIR)/$(ISO_NAME) \
-serial stdio \ -serial stdio \
-display gtk,show-menubar=off,zoom-to-fit=on \
-m 4G \ -m 4G \
-enable-kvm \
-name corn -name corn

View file

@ -1,5 +1,6 @@
#pragma once #pragma once
#include <stdarg.h>
#include <stddef.h> #include <stddef.h>
/** /**
@ -123,6 +124,14 @@ char *itoa(int n, char *buffer, int radix);
*/ */
char *ltoa(long int n, char *buffer, int radix); char *ltoa(long int n, char *buffer, int radix);
/**
* Converts a long long to asci inside a string with a given radix (base).
* @param n - the number to conver
* @param buffer - the string buffer
* @param radix - the base to convert
*/
char *lltoa(long long int n, char *buffer, int radix);
/** /**
* Converts a unsigned integer to asci inside a string with a given radix (base). * Converts a unsigned integer to asci inside a string with a given radix (base).
* @param n - the number to conver * @param n - the number to conver
@ -139,6 +148,14 @@ char *utoa(unsigned int n, char *buffer, int radix);
*/ */
char *ultoa(unsigned long int n, char *buffer, int radix); char *ultoa(unsigned long int n, char *buffer, int radix);
/**
* Converts a unsigned long long to asci inside a string with a given radix (base).
* @param n - the number to conver
* @param buffer - the string buffer
* @param radix - the base to convert
*/
char *ulltoa(unsigned long long int n, char *buffer, int radix);
/** /**
* Converts the string in str to an int value based on the given base. * Converts the string in str to an int value based on the given base.
* The endptr is updated to where the string was no longer valid. * The endptr is updated to where the string was no longer valid.
@ -168,3 +185,30 @@ long int strtol(const char *str, char **endptr, int base);
* @returns 0 on error or success, error if endptr is still equal to str * @returns 0 on error or success, error if endptr is still equal to str
*/ */
long long int strtoll(const char *str, char **endptr, int base); long long int strtoll(const char *str, char **endptr, int base);
/**
* Prints out a char
* @param c - the char
*/
void kputc(char c);
/**
* Prints out a null terminated string
* @param s - the string
*/
void kputs(const char *s);
/**
* Prints out a formatted string
* @param format - the format string
* @param ... - variable args for the format
*/
void kvprintf(const char *format, va_list args);
/**
* Prints out a formatted string
* @param format - the format string
* @param ... - variable args for the format
*/
__attribute__((format(printf, 1, 2)))
void kprintf(const char *format, ...);

View file

@ -5,4 +5,4 @@
int serial_init(void); int serial_init(void);
uint8_t serial_in(void); uint8_t serial_in(void);
void serial_out(uint8_t ch); void serial_out(uint8_t ch);
void serial_out_str(char *str); void serial_out_str(const char *str);

View file

@ -3,6 +3,7 @@
#include <memory.h> #include <memory.h>
#define CMDLINE_MAX 32 #define CMDLINE_MAX 32
#define MMAP_MAX_ENTRY 64
struct memory_segment { struct memory_segment {
uint64_t addr; uint64_t addr;
@ -12,8 +13,7 @@ struct memory_segment {
struct memory_map { struct memory_map {
uint32_t entry_count; uint32_t entry_count;
uint32_t entry_length; struct memory_segment entries[MMAP_MAX_ENTRY];
struct memory_segment *entries;
}; };
struct boot_info { struct boot_info {

View file

@ -31,7 +31,7 @@ struct rsdp {
char oemid[6]; char oemid[6];
uint8_t revision; uint8_t revision;
uint32_t rsdt_addr; uint32_t rsdt_addr;
} __attribute__((packed)); };
// eXtended system descriptor pointer // eXtended system descriptor pointer
// ACPI 2.0 // ACPI 2.0
@ -46,7 +46,7 @@ struct xsdp {
uint64_t xsdt_addr; uint64_t xsdt_addr;
uint8_t extendeid_checksum; uint8_t extendeid_checksum;
uint8_t reserved[3]; uint8_t reserved[3];
} __attribute__((packed)); };
// root system descriptor table // root system descriptor table
// ACPI 1.0 // ACPI 1.0
@ -161,10 +161,8 @@ static bool checksum(uint8_t *data, size_t len) {
} }
static int read_s5_addr(struct acpi_state *state) { static int read_s5_addr(struct acpi_state *state) {
serial_out_str("a");
uintptr_t ptr = state->fadt.dsdt; uintptr_t ptr = state->fadt.dsdt;
char *s5_addr = (void*) (ptr + 36); char *s5_addr = (void*) (ptr + 36);
serial_out_str("a");
int dsdt_len = *((int*) (ptr+1)) - 36; int dsdt_len = *((int*) (ptr+1)) - 36;
while (0 < dsdt_len--) { while (0 < dsdt_len--) {
@ -256,6 +254,7 @@ int acpi_init_rsdt(struct rsdt *rsdt) {
int acpi_init_xsdt(struct xsdt *xsdt) { int acpi_init_xsdt(struct xsdt *xsdt) {
xsdt = mmap(xsdt, sizeof(struct xsdt)); xsdt = mmap(xsdt, sizeof(struct xsdt));
return -1;
state.dst.xsdt = xsdt; state.dst.xsdt = xsdt;
state.version = 2; state.version = 2;

View file

@ -90,6 +90,8 @@ start:
push DWORD 0 push DWORD 0
push ebx push ebx
push DWORD 0
push eax
mov edi, 0x1000 mov edi, 0x1000
mov cr3, edi mov cr3, edi
@ -143,8 +145,10 @@ code64:
xor rbp, rbp ; set ebp to 0 so we know where to end stack traces xor rbp, rbp ; set ebp to 0 so we know where to end stack traces
pop rdi pop rdi
pop rsi
call amd64_shim call amd64_shim
mov rdi, rax mov rdi, rax
xor rsi, rsi
sti sti
call kmain call kmain

38
src/arch/amd64/linker.ld Normal file
View file

@ -0,0 +1,38 @@
ENTRY(start)
SECTIONS {
. = 1M;
kernel_start = .;
.boot BLOCK(4K) : ALIGN(4K)
{
*(.multiboot)
}
.rodata BLOCK(4K) : ALIGN(4K)
{
*(.rodata)
}
.data BLOCK(4K) : ALIGN(4K)
{
*(.data)
}
text_start = .;
.text BLOCK(4K) : ALIGN(4K)
{
*(.text)
}
text_end = .;
.bss BLOCK(4K) : ALIGN(4K)
{
*(.bss)
}
kernel_end = .;
}

View file

@ -1,17 +1,25 @@
#include "mboot.h" #include <shim.h>
#include "serial.h"
#include "shim.h"
#include <lib.h> #include <lib.h>
#include <stdint.h> #include <stdint.h>
#include <panic.h>
#include "mboot.h"
#define MBOOT_HEADER_MAGIC 0x36D76289
#define MBOOT_CMDLINE 1
#define MBOOT_MEMORY_MAP 6
#define MBOOT_ELF_SYMBOLS 9
#define MBOOT_OLD_RSDP 14
#define MBOOT_NEW_RSDP 15
extern char symtab; extern char symtab;
#define kaddr(addr) ((uintptr_t)(&addr)) #define kaddr(addr) ((uintptr_t)(&addr))
typedef unsigned char mboot_uint8_t; typedef uint8_t mboot_uint8_t;
typedef unsigned short mboot_uint16_t; typedef uint16_t mboot_uint16_t;
typedef unsigned int mboot_uint32_t; typedef uint32_t mboot_uint32_t;
typedef unsigned long long mboot_uint64_t; typedef uint64_t mboot_uint64_t;
struct mboot_info { struct mboot_info {
mboot_uint32_t total_size; mboot_uint32_t total_size;
@ -25,24 +33,17 @@ struct mboot_tag {
char data[]; char data[];
}; };
enum mboot_tag_type { struct mboot_tag_elf_sections {
MBOOT_CMDLINE = 0,
MBOOT_MEMORYMAP = 6,
MBOOT_SYMBOLS = 9,
MBOOT_RSDP = 14,
MBOOT_XSDP = 15,
};
struct mboot_elf_header_layout {
mboot_uint32_t type; mboot_uint32_t type;
mboot_uint32_t size; mboot_uint32_t size;
mboot_uint32_t num; mboot_uint16_t num;
mboot_uint32_t entsize; mboot_uint16_t entsize;
mboot_uint32_t shndx; mboot_uint16_t shndx;
char elf_section_headers[]; mboot_uint16_t reserved;
char sections[];
}; };
struct mboot_elf_section_header { struct mboot_tag_elf_sections_entry {
mboot_uint32_t sh_name; mboot_uint32_t sh_name;
mboot_uint32_t sh_type; mboot_uint32_t sh_type;
mboot_uint64_t sh_flags; mboot_uint64_t sh_flags;
@ -55,45 +56,46 @@ struct mboot_elf_section_header {
mboot_uint64_t sh_entsize; mboot_uint64_t sh_entsize;
}; };
struct mboot_memory_segment { struct mboot_mmap_entry {
mboot_uint64_t addr; mboot_uint64_t addr;
mboot_uint64_t len; mboot_uint64_t len;
mboot_uint32_t type; mboot_uint32_t type;
mboot_uint32_t reserved; mboot_uint32_t zero;
}; };
struct mboot_memory_map { struct mboot_tag_mmap {
mboot_uint32_t tag; mboot_uint32_t type;
mboot_uint32_t size; mboot_uint32_t size;
mboot_uint32_t entry_size; mboot_uint32_t entry_size;
mboot_uint32_t entry_version; mboot_uint32_t entry_version;
struct memory_segment entries[]; struct mboot_mmap_entry entries[];
}; };
struct mboot_rsdp {
mboot_uint32_t tag; struct mboot_tag_old_rsdp {
mboot_uint32_t type;
mboot_uint32_t size; mboot_uint32_t size;
mboot_uint8_t rsdp[]; mboot_uint8_t rsdp[];
}; };
struct mboot_xsdp { struct mboot_tag_new_rsdp {
mboot_uint32_t tag; mboot_uint32_t type;
mboot_uint32_t size; mboot_uint32_t size;
mboot_uint8_t xsdp[]; mboot_uint8_t rsdp[];
}; };
struct mboot_cmdline { struct mboot_tag_cmdline {
mboot_uint32_t tag; mboot_uint32_t type;
mboot_uint32_t size; mboot_uint32_t size;
char cmdline[]; mboot_uint8_t cmdline[];
}; };
static void read_symbols( static void read_symbols(
struct boot_info *shim_info, struct boot_info *shim_info,
struct mboot_elf_header_layout *layout struct mboot_tag_elf_sections *sections
) { ) {
shim_info->symbol_table = layout->elf_section_headers; shim_info->symbol_table = sections->sections;
// struct mboot_elf_section_header *section = // struct mboot_elf_section_header *section =
// (struct mboot_elf_section_header *) (layout->elf_section_headers); // (struct mboot_elf_section_header *) (layout->elf_section_headers);
@ -130,7 +132,7 @@ static void read_symbols(
static void read_cmdline( static void read_cmdline(
struct boot_info *shim_info, struct boot_info *shim_info,
struct mboot_cmdline *cmdline struct mboot_tag_cmdline *cmdline
) { ) {
mboot_uint32_t size = cmdline->size - 8; mboot_uint32_t size = cmdline->size - 8;
if (size >= CMDLINE_MAX) if (size >= CMDLINE_MAX)
@ -139,39 +141,49 @@ static void read_cmdline(
shim_info->cmdline[size] = '\0'; shim_info->cmdline[size] = '\0';
} }
static void read_memorymap( static void read_memory_map(
struct boot_info *shim_info, struct boot_info *shim_info,
struct mboot_memory_map *map struct mboot_tag_mmap *map
) { ) {
int size = map->size - sizeof(mboot_uint32_t) * 4; int idx = 0;
int count = size / map->entry_size; uintptr_t i = (uintptr_t)map->entries;
for ( ;
shim_info->map.entry_count = count; i < (uintptr_t)map->entries + map->size;
shim_info->map.entry_length = map->entry_size; i += map->entry_size, idx++
shim_info->map.entries = map->entries; ) {
struct mboot_mmap_entry *seg = (struct mboot_mmap_entry *) i;
shim_info->map.entries[idx].addr = seg->addr;
shim_info->map.entries[idx].type = seg->type;
shim_info->map.entries[idx].len = seg->len;
}
shim_info->map.entry_count = idx;
} }
static void read_rsdp( static void read_old_rsdp(
struct boot_info *shim_info, struct boot_info *shim_info,
struct mboot_rsdp *rsdp struct mboot_tag_old_rsdp *rsdp
) { ) {
if (shim_info->acpi_table != NULL) if (shim_info->acpi_table != NULL)
return; // xsdp is newer and has been loaded return; // xsdp is newer and has been loaded
shim_info->acpi_table = rsdp->rsdp; shim_info->acpi_table = rsdp->rsdp;
} }
static void read_xsdp( static void read_new_rsdp(
struct boot_info *shim_info, struct boot_info *shim_info,
struct mboot_xsdp *xsdp struct mboot_tag_new_rsdp *rsdp
) { ) {
shim_info->acpi_table = xsdp->xsdp; shim_info->acpi_table = rsdp->rsdp;
} }
void mboot_load_info( void mboot_load_info(
long mboot_magic,
const void *mboot_data_ptr, const void *mboot_data_ptr,
struct boot_info *shim_info struct boot_info *shim_info
) { ) {
if (mboot_magic != MBOOT_HEADER_MAGIC)
panic("invalid multiboot magic");
memset(shim_info, 0, sizeof(struct boot_info)); memset(shim_info, 0, sizeof(struct boot_info));
struct mboot_info *mboot_info = (struct mboot_info *) mboot_data_ptr; struct mboot_info *mboot_info = (struct mboot_info *) mboot_data_ptr;
@ -186,31 +198,31 @@ void mboot_load_info(
case MBOOT_CMDLINE: case MBOOT_CMDLINE:
read_cmdline( read_cmdline(
shim_info, shim_info,
(struct mboot_cmdline *) tag (struct mboot_tag_cmdline *) tag
); );
break; break;
case MBOOT_MEMORYMAP: case MBOOT_MEMORY_MAP:
read_memorymap( read_memory_map(
shim_info, shim_info,
(struct mboot_memory_map *) tag (struct mboot_tag_mmap *) tag
); );
break; break;
case MBOOT_SYMBOLS: case MBOOT_ELF_SYMBOLS:
read_symbols( read_symbols(
shim_info, shim_info,
(struct mboot_elf_header_layout *) tag (struct mboot_tag_elf_sections *) tag
); );
break; break;
case MBOOT_RSDP: case MBOOT_OLD_RSDP:
read_rsdp( read_old_rsdp(
shim_info, shim_info,
(struct mboot_rsdp *) tag (struct mboot_tag_old_rsdp *) tag
); );
break; break;
case MBOOT_XSDP: case MBOOT_NEW_RSDP:
read_xsdp( read_new_rsdp(
shim_info, shim_info,
(struct mboot_xsdp *) tag (struct mboot_tag_new_rsdp *) tag
); );
break; break;
default: default:

View file

@ -8,4 +8,4 @@
* @param mboot_info - the pointer passed from multiboot2 * @param mboot_info - the pointer passed from multiboot2
* @param shim_info - the info to be collected by shim * @param shim_info - the info to be collected by shim
*/ */
void mboot_load_info(const void *mboot_info, struct boot_info *shim_info); void mboot_load_info(long mboot_magic, const void *mboot_info, struct boot_info *shim_info);

View file

@ -40,7 +40,7 @@ void serial_out(uint8_t ch) {
outb(PORT, ch); outb(PORT, ch);
} }
void serial_out_str(char *str) { void serial_out_str(const char *str) {
for(; *str != '\0'; str++) { for(; *str != '\0'; str++) {
serial_out(*str); serial_out(*str);
} }

View file

@ -11,14 +11,13 @@
static struct boot_info boot_info; static struct boot_info boot_info;
void* amd64_shim(void *mboot_data_ptr) { void* amd64_shim(long mboot_magic, void *mboot_data_ptr) {
serial_init(); serial_init();
paging_init(); paging_init();
pic_remap(); pic_remap();
idt_init(); idt_init();
mboot_load_info(mboot_data_ptr, &boot_info); mboot_load_info(mboot_magic, mboot_data_ptr, &boot_info);
return &boot_info; return &boot_info;
} }

View file

@ -10,11 +10,13 @@ void kmain(struct boot_info *info) {
//acpi_init(info->acpi_table); //acpi_init(info->acpi_table);
//fb_init(1024, 768); //fb_init(1024, 768);
serial_out_str("entered kmain\n"); kprintf("enterd kmain\n");
*(char*)(0xB8000 + 0x144) = 'h'; *(char*)(0xB8000 + 0x144) = 'h';
*(char*)(0xB8000 + 0x146) = 'i'; *(char*)(0xB8000 + 0x146) = 'i';
while (1) { while (1) {
//kprintf("ret: 0x%p\n", kalloc(2));
// loop so we dont halt // loop so we dont halt
// this allows interrupts to fire // this allows interrupts to fire
} }

View file

@ -1,5 +1,5 @@
#include "memory.h"
#include <lib.h> #include <lib.h>
#include <stddef.h> #include <stddef.h>
int memcmp(const void *restrict vl, const void *restrict vr, unsigned long n) { int memcmp(const void *restrict vl, const void *restrict vr, unsigned long n) {
@ -31,6 +31,7 @@ void *memmove(void *dest, const void *src, unsigned long n) {
} }
void *memset(void *restrict dest, int c, unsigned long n) { void *memset(void *restrict dest, int c, unsigned long n) {
unsigned char *d = dest; unsigned char *d = dest;
for (; n; n--) *d++ = c; for (; n; n--) *d++ = c;
return dest; return dest;
@ -149,6 +150,7 @@ int ctoi(char c) {
UXTOA(int, utoa) UXTOA(int, utoa)
UXTOA(long int, ultoa) UXTOA(long int, ultoa)
UXTOA(long long int, ulltoa)
#define XTOA(type, name) \ #define XTOA(type, name) \
char *name(type n, char* buffer, int radix) { \ char *name(type n, char* buffer, int radix) { \
@ -176,6 +178,7 @@ UXTOA(long int, ultoa)
XTOA(int, itoa) XTOA(int, itoa)
XTOA(long int, ltoa) XTOA(long int, ltoa)
XTOA(long long int, lltoa)
#define STRTOX(name, type) \ #define STRTOX(name, type) \
type name(const char *s, char **endptr, int radix) { \ type name(const char *s, char **endptr, int radix) { \

View file

@ -1,10 +1,8 @@
#include "serial.h"
#include <memory.h> #include <memory.h>
#include <stdint.h> #include <stdint.h>
#include <lib.h> #include <lib.h>
#ifdef MEMORY_PANIC
#include <panic.h> #include <panic.h>
#endif
#define MAGIC 0xBEEFCAFE #define MAGIC 0xBEEFCAFE
@ -18,8 +16,8 @@ struct page_header {
}; };
static const size_t header_len = sizeof(struct page_header); static const size_t header_len = sizeof(struct page_header);
struct page_header *start_header = NULL; static struct page_header *start_header = NULL;
struct page_header *end_header = NULL; static struct page_header *end_header = NULL;
struct page_header* get_header(void *ptr) { struct page_header* get_header(void *ptr) {
struct page_header *header = struct page_header *header =
@ -36,6 +34,7 @@ struct page_header* get_header(void *ptr) {
void *kalloc_new(size_t size) { void *kalloc_new(size_t size) {
size_t pages = ((size + header_len) / PAGE_SIZE) + 1; size_t pages = ((size + header_len) / PAGE_SIZE) + 1;
void *addr = alloc_pages(pages); void *addr = alloc_pages(pages);
void *mem = (char *)addr + header_len; void *mem = (char *)addr + header_len;
@ -54,20 +53,20 @@ void *kalloc_new(size_t size) {
} }
struct page_header *header = addr; struct page_header *header = addr;
header->magic = MAGIC; header->magic = 0xBEEFCAFE;
header->used = size; header->used = size;
header->free = free; header->free = free;
header->prev = end_header; header->prev = end_header;
header->next = NULL; header->next = NULL;
header->node_number = node; header->node_number = node;
if (end_header == NULL) { if (start_header == NULL) {
start_header = header; start_header = header;
} else {
end_header->next = header;
} }
end_header = header; if (end_header != NULL) {
end_header->next = header;
}
return mem; return mem;
} }
@ -97,6 +96,9 @@ void *kalloc(size_t size) {
for (; header != NULL; header = header->next) { for (; header != NULL; header = header->next) {
size_t free = header->free; size_t free = header->free;
if (free < header_len) {
continue;
}
if (size <= (free - header_len)) { // we must be able to fit data + header if (size <= (free - header_len)) { // we must be able to fit data + header
break; break;
} }
@ -129,21 +131,13 @@ void *krealloc(void *src, size_t dst_len) {
header = get_header(src); header = get_header(src);
if (header == NULL) { if (header == NULL) {
#ifdef MEMORY_PANIC
panic("attempted to realloc on a invalid ptr"); panic("attempted to realloc on a invalid ptr");
#else
return NULL; // invalid pointer passed
#endif
} }
src_len = header->used; src_len = header->used;
if (src_len == 0) { if (src_len == 0) {
#ifdef MEMORY_PANIC
panic("attempted to realloc on an empty ptr"); panic("attempted to realloc on an empty ptr");
#else
return NULL; // likely double free :(
#endif
} }
dst = kalloc(dst_len); dst = kalloc(dst_len);
@ -166,11 +160,7 @@ void kfree(void *ptr) {
header = get_header(ptr); header = get_header(ptr);
if (header == NULL || header->used == 0) { if (header == NULL || header->used == 0) {
#ifdef MEMORY_PANIC
panic("attempted to kfree invalid pointer"); panic("attempted to kfree invalid pointer");
#else
return;
#endif
} }
header->free += header->used; header->free += header->used;

View file

@ -1,3 +1,4 @@
#include "serial.h"
#include <memory.h> #include <memory.h>
#include <stdint.h> #include <stdint.h>
#include <lib.h> #include <lib.h>
@ -63,6 +64,10 @@ static inline bool bitmap_get(int i) {
} }
static inline void bitmap_set(int i, bool v) { static inline void bitmap_set(int i, bool v) {
if (v)
free_memory -= PAGE_SIZE;
else
free_memory += PAGE_SIZE;
int idx = i / 64; int idx = i / 64;
bitmap[idx] &= ~(1 << i % 64); bitmap[idx] &= ~(1 << i % 64);
bitmap[idx] |= (v << i % 64); bitmap[idx] |= (v << i % 64);
@ -115,11 +120,11 @@ void free_phys_pages(void *ptr, int pages) {
} }
static bool segment_invalid(const struct memory_segment *segment) { static bool segment_invalid(const struct memory_segment *segment) {
if (segment->type != 1) return false; if (segment->type != 1) return true;
if (segment->addr < kaddr(kernel_start)) return false; if (segment->addr < kaddr(kernel_start)) return true;
if (segment->addr + segment->len < memory_start) return false; if (segment->addr + segment->len < memory_start) return true;
if (segment->addr + segment->len < kaddr(kernel_start)) return false; if (segment->addr + segment->len < kaddr(kernel_start)) return true;
return true; return false;
} }
static struct memory_area segment_to_area(const struct memory_segment *segment) { static struct memory_area segment_to_area(const struct memory_segment *segment) {
@ -195,18 +200,28 @@ void memory_init(struct memory_map *map) {
struct memory_area *area = page_start; struct memory_area *area = page_start;
kprintf("MEMORY MAP\n");
for(uint32_t i = 0; i < map->entry_count; i++) { for(uint32_t i = 0; i < map->entry_count; i++) {
struct memory_segment *segment = &map->entries[i]; struct memory_segment *segment = &map->entries[i];
if (segment_invalid(segment)) if (segment_invalid(segment))
continue; continue;
kprintf("addr: 0x%16p\tlen: %ld\n", (void *)segment->addr, segment->len);
struct memory_area temp = segment_to_area(segment); struct memory_area temp = segment_to_area(segment);
*area = temp; *area = temp;
area++; area++;
} }
total_memory = page_count * PAGE_SIZE;
page_count -= bitmap_pages; page_count -= bitmap_pages;
free_memory = page_count * PAGE_SIZE;
kprintf("\nMEMORY USAGE\n");
kprintf("mem total: %ld\n", memory_total());
kprintf("mem free: %ld\n", memory_free());
kprintf("mem used: %ld\n\n", memory_used());
memory_unlock(); memory_unlock();

View file

@ -1,6 +1,9 @@
#include "lib.h"
#include "panic.h"
#include <stdint.h> #include <stdint.h>
#include <stddef.h> #include <stddef.h>
#include <memory.h> #include <memory.h>
#include <string.h>
#define MEMORY_INTERNAL #define MEMORY_INTERNAL
#include <memory/virtalloc.h> #include <memory/virtalloc.h>
@ -10,34 +13,60 @@ struct addr_node {
uintptr_t end; uintptr_t end;
struct addr_node *next; struct addr_node *next;
struct addr_node *prev; struct addr_node *prev;
uint8_t is_alloc; uint8_t is_alloc; // if node is storing allocated data
uint8_t is_bss; uint8_t is_used; // if node is in use by virtalloc
}; };
#define BOOTSTRAP_BSS_NODES 16 #define BSS_NODES 64
static uint8_t bss_nodes = 0; static struct addr_node bootstrap_nodes[BSS_NODES];
static struct addr_node nodes[BOOTSTRAP_BSS_NODES]; static struct addr_node *alloc_nodes = NULL;
static size_t free_node_start = 0;
static size_t alloc_node_count = 0;
static size_t used_node_count = 0;
static bool is_allocating = false;
static struct addr_node *start_node; static struct addr_node *start_node = NULL;
static struct addr_node *alloc_node(void) { static struct addr_node *get_node_idx(int idx) {
struct addr_node *node = NULL; if (idx < BSS_NODES) {
if (bss_nodes >= BOOTSTRAP_BSS_NODES) { return &bootstrap_nodes[idx];
node = kalloc(sizeof(struct addr_node));
if (node == NULL)
return NULL;
node->is_bss = false;
} else { } else {
node = &nodes[bss_nodes]; return &alloc_nodes[idx - BSS_NODES];
bss_nodes += 1;
node->is_bss = true;
} }
}
static struct addr_node *get_node(void) {
size_t count = BSS_NODES + alloc_node_count;
if (!is_allocating && used_node_count + 16 >= count) {
is_allocating = true;
int new_alloc = alloc_node_count * 2;
if (new_alloc < 8)
new_alloc = 8;
int allocated = new_alloc - alloc_node_count;
int old = new_alloc - allocated;
alloc_nodes = krealloc(alloc_nodes, sizeof(struct addr_node) * new_alloc);
memset(alloc_nodes + old, 0, sizeof(struct addr_node) + allocated);;
alloc_node_count = new_alloc;
is_allocating = false;
count = BSS_NODES + alloc_node_count;
}
size_t idx = free_node_start;
for (; idx < count; idx++) {
struct addr_node *node = get_node_idx(idx);
if (!node->is_used) {
used_node_count++;
return node; return node;
}
}
panic("could not get virtaddr node");
} }
static void free_node(struct addr_node *node) { static void free_node(struct addr_node *node) {
if (!node->is_bss) node->is_used = false;
kfree(node); used_node_count--;
} }
void virtaddr_init(void) { void virtaddr_init(void) {
@ -47,11 +76,11 @@ void virtaddr_init(void) {
.next = NULL, .next = NULL,
.prev = NULL, .prev = NULL,
.is_alloc = false, .is_alloc = false,
.is_bss = true, .is_used = true,
}; };
nodes[0] = init; memset(bootstrap_nodes, 0, sizeof(bootstrap_nodes));
start_node = &nodes[0]; bootstrap_nodes[0] = init;
bss_nodes++; start_node = &bootstrap_nodes[0];
} }
void *virtaddr_alloc(int n_pages) { void *virtaddr_alloc(int n_pages) {
@ -69,10 +98,7 @@ void *virtaddr_alloc(int n_pages) {
long length = node->end - node->start; long length = node->end - node->start;
if (length >= n_length) { if (length >= n_length) {
struct addr_node *new = alloc_node(); struct addr_node *new = get_node();
if (node == NULL) {
return NULL;
}
if (node->prev != NULL) { if (node->prev != NULL) {
node->prev->next = new; node->prev->next = new;
} }
@ -82,6 +108,7 @@ void *virtaddr_alloc(int n_pages) {
new->end = new->start + n_length; new->end = new->start + n_length;
node->start = new->end; node->start = new->end;
new->is_alloc = true; new->is_alloc = true;
new->is_used = true;
new->next = node; new->next = node;
return (void *) new->start; return (void *) new->start;
} }

564
src/print.c Normal file
View file

@ -0,0 +1,564 @@
#include <lib.h>
#include <serial.h>
#include <stdarg.h>
void kputc(char c) {
serial_out(c);
}
void kputs(const char *s) {
serial_out_str(s);
}
enum format_flag {
FLG_NONE = 0x00,
FLG_ALTERNATE = 0x01,
FLG_ZERO = 0x02,
FLG_LEFT_ALIGN = 0x04,
FLG_ADD_SIGN = 0x08
};
struct format_width {
bool defined;
bool varys;
int value;
};
struct format_precision {
bool defined;
bool varys;
int value;
};
enum format_modifier {
MOD_NONE,
MOD_INVALID,
MOD_HALF_HALF,
MOD_HALF,
MOD_LONG_LONG,
MOD_LONG,
};
enum format_conversion {
FMT_INT,
FMT_UINT,
FMT_OCT,
FMT_HEX,
FMT_HEX_UPPER,
FMT_CHAR,
FMT_STR,
FMT_PTR,
FMT_PTR_UPPER,
FMT_PERCENT,
FMT_INVALID
};
static enum format_flag read_flag(const char *format, const char **end) {
enum format_flag flag = FLG_NONE;
for (; *format != '\0'; format++) {
switch (*format) {
case '#':
flag |= FLG_ALTERNATE;
break;
case '0':
flag |= FLG_ZERO;
break;
case '-':
flag |= FLG_LEFT_ALIGN;
break;
case '+':
flag |= FLG_ADD_SIGN;
break;
default:
*end = format;
return flag;
}
}
*end = format;
return flag;
}
static struct format_width read_width(const char *format, const char **end) {
struct format_width width;
width.defined = false;
width.varys = false;
width.value = 0;
int value = 0;
for (; *format != '\0'; format++) {
char c = *format;
if (c == '*' && width.defined == false) {
width.defined = true;
width.varys = true;
break;
}
if (!isdigit(c))
break;
int i = c - '0';
value *= 10;
value += i;
width.value = value;
width.defined = true;
width.varys = false;
}
*end = format;
return width;
}
static struct format_precision read_precision(const char *format, const char **end) {
struct format_precision precision;
precision.varys = false;
precision.defined = false;
precision.value = 0;
if (*format != '.') {
*end = format;
return precision;
}
format++;
int value = 0;
for (; *format != '\0'; format++) {
char c = *format;
if (c == '*' && precision.defined == false) {
precision.defined = true;
precision.varys = true;
break;
}
if (!isdigit(c))
break;
int i = c - '0';
value *= 10;
value += i;
precision.value = value;
precision.defined = true;
precision.varys = false;
}
*end = format;
return precision;
}
static enum format_modifier read_modifier(const char *format, const char **end) {
enum format_modifier mod = MOD_NONE;
for (; *format != '\0'; format++) {
*end = format;
switch (*format) {
case 'l':
if (mod == MOD_NONE)
mod = MOD_LONG;
else if (mod == MOD_LONG)
return MOD_LONG_LONG;
else
return MOD_INVALID;
break;
case 'L':
if (mod == MOD_NONE)
return MOD_LONG_LONG;
else
return MOD_INVALID;
break;
case 'h':
if (mod == MOD_NONE)
mod = MOD_HALF;
else if (mod == MOD_HALF)
return MOD_HALF_HALF;
else
return MOD_INVALID;
break;
case 'H':
if (mod == MOD_NONE)
return MOD_HALF_HALF;
else
return MOD_INVALID;
break;
default:
return mod;
}
}
return MOD_INVALID;
}
static enum format_conversion read_conversion(const char *format, const char **end) {
*end = format + 1;
switch (*format) {
case 'd':
case 'i':
return FMT_INT;
case 'o':
return FMT_OCT;
case 'u':
return FMT_UINT;
case 'x':
return FMT_HEX;
case 'X':
return FMT_HEX_UPPER;
case 'c':
return FMT_CHAR;
case 's':
return FMT_STR;
case 'p':
return FMT_PTR;
case 'P':
return FMT_PTR_UPPER;
case '%':
return FMT_PERCENT;
default:
return FMT_INVALID;
}
}
static void print_string(
const char *str,
enum format_flag flag,
struct format_width width,
struct format_precision precision
) {
size_t max_len = 0;
size_t min_len = 0;
size_t len = 0;
if (width.defined)
min_len = width.value;
if (precision.defined) {
max_len = precision.value;
len = max_len;
if (max_len < min_len)
min_len = max_len;
} else {
len = strlen(str);
}
if (!(flag & FLG_LEFT_ALIGN) && len < min_len) {
for (size_t i = 0; i < (min_len - len); i++) {
kputc(' ');
}
}
for (size_t i = 0; i < len; i++) {
kputc(str[i]);
}
if ((flag & FLG_LEFT_ALIGN) && len < min_len) {
for (size_t i = 0; i < (min_len - len); i++) {
kputc(' ');
}
}
}
static char get_letter(
char c,
char base
) {
if (c >= 0 && c <= 9)
return c + '0';
c -= 10;
return c + base;
}
static char *get_decimal(
long long num,
char *buf,
char sign,
int radix,
char base
) {
*buf = '\0';
buf--;
if (num == 0) {
*buf = '0';
buf--;
}
while (num != 0) {
char i = num % radix;
char c = get_letter(i, base);
*buf = c;
buf--;
num /= radix;
}
if (sign) {
*buf = sign;
buf--;
}
buf++;
return buf;
}
static void print_unum(
unsigned long long num,
enum format_flag flag,
struct format_width width,
struct format_precision precision,
bool isneg,
int radix,
char base
) {
size_t max_len = 0;
size_t min_len = 0;
size_t len = 0;
char sign = 0;
if (isneg)
sign = '-';
else if (flag & FLG_ADD_SIGN)
sign = '+';
char buf[1024];
char *str = get_decimal(
num,
buf,
sign,
radix,
base
);
bool space_pre = (flag & FLG_LEFT_ALIGN) || !(flag & FLG_ZERO);
if (space_pre && radix == 16 && flag & FLG_ALTERNATE) {
char x = base + ('x' - 'a');
serial_out('0');
serial_out(x);
}
if (width.defined)
min_len = width.value;
if (precision.defined) {
max_len = precision.value;
len = max_len;
if (max_len < min_len)
min_len = max_len;
} else {
len = strlen(str);
}
bool zero_padded = false;
if (!(flag & FLG_LEFT_ALIGN) && len < min_len) {
for (size_t i = 0; i < (min_len - len); i++) {
(flag & FLG_ZERO) ? kputc('0') : kputc(' ');
}
if (flag & FLG_ZERO)
zero_padded = true;
}
kputs(str);
if (!zero_padded && (flag & FLG_ALTERNATE) && radix == 8)
kputc('0');
if ((flag & FLG_LEFT_ALIGN) && len < min_len) {
for (size_t i = 0; i < (min_len - len); i++) {
(flag & FLG_ZERO) ? kputc('0') : kputc(' ');
}
}
}
static void print_num(
long long num,
enum format_flag flag,
struct format_width width,
struct format_precision precision,
int radix,
char base
) {
bool isneg = false;
if (num < 0) {
num = ~num;
isneg = true;
}
print_unum(
num,
flag,
width,
precision,
isneg,
radix,
base
);
}
void kvprintf(const char *format, va_list args) {
for (; *format != '\0'; format++) {
char c = *format;
if (c == '%') {
enum format_flag flag;
struct format_width width;
struct format_precision precision;
enum format_modifier modifier;
enum format_conversion conversion;
const char *ptr = format + 1;
flag = read_flag(ptr, &ptr);
width = read_width(ptr, &ptr);
precision = read_precision(ptr, &ptr);
modifier = read_modifier(ptr, &ptr);
if (modifier == MOD_INVALID) {
kputc('%');
continue;
}
conversion = read_conversion(ptr, &ptr);
if (conversion == FMT_INVALID) {
kputc('%');
continue;
}
union {
unsigned long long u;
long long l;
char c;
const char *str;
void *ptr;
} data;
int radix = 0;
char base = 0;
switch (conversion) {
case FMT_INT:
if (modifier == MOD_NONE)
data.l = va_arg(args, int);
else if (modifier == MOD_HALF)
data.l = (short) va_arg(args, int);
else if (modifier == MOD_HALF_HALF)
data.l = (char) va_arg(args, int);
else if (modifier == MOD_LONG)
data.l = va_arg(args, long);
else if (modifier == MOD_LONG_LONG)
data.l = va_arg(args, long long);
radix = 10;
goto printnum;
case FMT_UINT:
case FMT_OCT:
case FMT_HEX_UPPER:
case FMT_HEX:
if (modifier == MOD_NONE)
data.u = va_arg(args, unsigned int);
else if (modifier == MOD_HALF)
data.u = (unsigned short) va_arg(args, unsigned int);
else if (modifier == MOD_HALF_HALF)
data.u = (unsigned char) va_arg(args, unsigned int);
else if (modifier == MOD_LONG)
data.u = va_arg(args, unsigned long);
else if (modifier == MOD_LONG_LONG)
data.u = va_arg(args, unsigned long long);
if (conversion == FMT_UINT) {
radix = 10;
} else if (conversion == FMT_OCT) {
radix = 8;
} else if (conversion == FMT_HEX) {
radix = 16;
base = 'a';
} else if (conversion == FMT_HEX_UPPER) {
radix = 16;
base = 'A';
}
goto printunum;
case FMT_PTR:
case FMT_PTR_UPPER:
flag |= FLG_ZERO;
data.u = va_arg(args, size_t);
radix = 16;
if (conversion == FMT_PTR)
base = 'a';
else
base = 'A';
goto printunum;
printnum:
print_num(
data.l,
flag,
width,
precision,
radix,
base
);
break;
printunum:
print_unum(
data.u,
flag,
width,
precision,
false,
radix,
base
);
break;
case FMT_CHAR: {
char buf[2];
buf[0] = (char) va_arg(args, int);
buf[1] = '\0';
print_string(
buf,
flag,
width,
precision
);
break;
}
case FMT_STR:
data.str = va_arg(args, const char*);
print_string(
data.str,
flag,
width,
precision
);
break;
case FMT_PERCENT:
kputc('%');
break;
case FMT_INVALID:
break;
}
format = ptr - 1;
} else {
kputc(c);
}
}
}
void kprintf(const char *format, ...) {
va_list args;
va_start(args, format);
kvprintf(format, args);
va_end(args);
}