mirror of
https://git.stationery.faith/corn/corn.git
synced 2024-11-22 04:02:17 +00:00
acpi, fix mboot memory map, fix kalloc, fix virtalloc node allocator, add kprintf, other changes
This commit is contained in:
parent
7a59ef37b8
commit
192a4ccd6b
17 changed files with 836 additions and 137 deletions
2
Makefile
2
Makefile
|
@ -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
|
||||||
|
|
|
@ -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, ...);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
#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 {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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
38
src/arch/amd64/linker.ld
Normal 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 = .;
|
||||||
|
}
|
|
@ -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:
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) { \
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
return node;
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
564
src/print.c
Normal 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);
|
||||||
|
}
|
Loading…
Reference in a new issue