summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/bits/x86_64/descriptor.h30
-rw-r--r--api/bits/x86_64/msr.h20
-rw-r--r--api/lib/kstdio.h18
-rw-r--r--api/libc/string.h12
-rw-r--r--api/posix/sys/mman.h8
-rw-r--r--boot/Makefile4
-rw-r--r--boot/efi/status.h110
-rw-r--r--boot/efi/system_table.h31
-rw-r--r--boot/efi/table.h26
-rw-r--r--defaults.mk2
-rw-r--r--kc/boot/kc_main.c2
-rw-r--r--kc/core/Makefile10
-rw-r--r--kc/core/cpu/arch_thread.c81
-rw-r--r--kc/core/cpu/arch_thread.h12
-rw-r--r--kc/core/cpu/cpu.c4
-rw-r--r--kc/core/cpu/cpu_task.S54
-rw-r--r--kc/core/cpu/cpu_thread.S57
-rw-r--r--kc/core/cpu/exceptions.h4
-rw-r--r--kc/core/i8042.c18
-rw-r--r--kc/core/kc_main.c4
-rw-r--r--kc/core/memory.h2
-rw-r--r--kc/core/memory/memory.c24
-rw-r--r--kc/core/memory/page_early.c12
-rw-r--r--kc/core/panic.c6
-rw-r--r--kc/core/pic8259.c12
-rw-r--r--kc/core/pit8253.c6
-rw-r--r--kc/core/stdio.c (renamed from kc/core/kstdio.c)8
-rw-r--r--kc/core/task.c439
-rw-r--r--kc/core/task.h35
-rw-r--r--kc/core/video.c6
-rw-r--r--kc/core/vm_tree.c538
-rw-r--r--kc/defaults.mk1
-rw-r--r--lib/api/libc/stdio.h (renamed from api/libc/stdio.h)6
-rw-r--r--lib/api/libc/stdlib.h (renamed from api/libc/stdlib.h)0
-rw-r--r--lib/api/libc/string.h (renamed from api/lib/kstring.h)5
-rw-r--r--lib/api/libc/wchar.h (renamed from api/libc/wchar.h)0
-rw-r--r--lib/elf64.c6
-rw-r--r--lib/heap.c154
-rw-r--r--lib/kprintf.c653
-rw-r--r--lib/libc/memcmp.c (renamed from lib/memcmp.c)0
-rw-r--r--lib/libc/memcpy.c (renamed from lib/memcpy.c)0
-rw-r--r--lib/libc/memmove.c (renamed from lib/memmove.c)0
-rw-r--r--lib/libc/memset.c (renamed from lib/memset.c)0
-rw-r--r--lib/libc/printf.c (renamed from lib/printf.c)86
-rw-r--r--lib/libc/stdio.c (renamed from lib/stdio.c)0
-rw-r--r--lib/libc/string.c (renamed from lib/string.c)0
-rw-r--r--rules.mk11
-rw-r--r--service/Makefile4
-rw-r--r--service/config.h5
-rw-r--r--service/main.c3
50 files changed, 1040 insertions, 1489 deletions
diff --git a/api/bits/x86_64/descriptor.h b/api/bits/x86_64/descriptor.h
index c0c00f6..c55a493 100644
--- a/api/bits/x86_64/descriptor.h
+++ b/api/bits/x86_64/descriptor.h
@@ -1,3 +1,5 @@
+#pragma once
+
#include <stdint.h>
struct descriptor_table_register_long
@@ -16,3 +18,31 @@ struct segment_descriptor
uint8_t base24;
} __attribute__((packed, aligned(8)));
+struct system_segment_descrptor_long
+{
+ struct segment_descriptor segment;
+ uint32_t base32;
+ uint32_t r0;
+} __attribute__((packed, aligned(8)));
+
+struct gate_descriptor
+{
+ uint16_t offset0;
+ uint16_t selector;
+ uint8_t ist;
+ uint8_t access;
+ uint16_t offset16;
+ uint64_t offset32;
+} __attribute__((packed, aligned(8)));
+
+struct task_state_segment_long
+{
+ uint32_t r0;
+ uint64_t rsp[3];
+ uint64_t r1;
+ uint64_t ist[7];
+ uint64_t r2;
+ uint16_t r3;
+ uint16_t iomap_base;
+} __attribute__((packed, aligned(8)));
+
diff --git a/api/bits/x86_64/msr.h b/api/bits/x86_64/msr.h
index a25af7d..95486cc 100644
--- a/api/bits/x86_64/msr.h
+++ b/api/bits/x86_64/msr.h
@@ -1,13 +1,13 @@
+#pragma once
+
#include <stdint.h>
#define MSR_INDEX_EFER 0xc0000080
#define MSR_INDEX_STAR 0xc0000081
#define MSR_INDEX_LSTAR 0xc0000082
-
-union msr_efer
-{
- uint64_t value;
-};
+#define MSR_INDEX_SFMASK 0xc0000084
+#define MSR_INDEX_KERNELGSBASE 0xc0000102
+#define MSR_EFER_SCE 1
union msr_star
{
@@ -27,3 +27,13 @@ union msr_lstar
uint64_t value;
};
+union msr_sfmask
+{
+ struct
+ {
+ uint32_t mask;
+ uint32_t reserved;
+ };
+ uint64_t value;
+};
+
diff --git a/api/lib/kstdio.h b/api/lib/kstdio.h
deleted file mode 100644
index 80e47cc..0000000
--- a/api/lib/kstdio.h
+++ /dev/null
@@ -1,18 +0,0 @@
-#pragma once
-
-#include <lib/kstring.h>
-
-#include <stdarg.h>
-
-typedef struct FILE FILE;
-
-extern FILE *kstdout;
-extern FILE *kstderr;
-
-extern int kfputc(int c, FILE *f);
-
-int kvfprintf(FILE *f, const char *restrict format, va_list arguments);
-int kfprintf(FILE *f, const char *restrict format, ...);
-int kvprintf(const char *restrict format, va_list arguments);
-int kprintf(const char *restrict format, ...);
-
diff --git a/api/libc/string.h b/api/libc/string.h
deleted file mode 100644
index 849275d..0000000
--- a/api/libc/string.h
+++ /dev/null
@@ -1,12 +0,0 @@
-#pragma once
-
-#include <stddef.h>
-
-void *memcpy(void *dest, const void *src, size_t size);
-void *memmove(void *dest, const void *src, size_t size);
-void *memset(void *dest, int val, size_t size);
-int memcmp(const void *str1, const void *str2, size_t count);
-size_t strlen(const char *s);
-int strcmp(const char *s1, const char *s2);
-unsigned long long strtoull(const char *restrict begin, char **restrict end, int base);
-
diff --git a/api/posix/sys/mman.h b/api/posix/sys/mman.h
index dd8d6f5..d347c76 100644
--- a/api/posix/sys/mman.h
+++ b/api/posix/sys/mman.h
@@ -1,6 +1,12 @@
#pragma once
-#define MAP_FAILED ((void *) 1)
+#include <stddef.h>
+
+#include "types.h"
+
+#define MAP_FAILED ((void *) -1)
+
+#define MAP_ANONYMOUS (1 >> 0)
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
int munmap(void *addr, size_t length);
diff --git a/boot/Makefile b/boot/Makefile
index 29151cd..87634d3 100644
--- a/boot/Makefile
+++ b/boot/Makefile
@@ -4,11 +4,11 @@ include ../defaults.mk
$(CC.info)
@$(CC) $(LDFLAGS) -o $@ $^
-VPATH := ../lib ../lib/asm/$(ARCH) efi/
+VPATH := ../lib ../lib/libc ../lib/asm/$(ARCH) efi/
IMAGE := kjarna.efi
-CPPFLAGS += -I../api -I../lib
+CPPFLAGS += -I../api -I../lib -I../lib/api
CFLAGS += --target=$(ARCH)-unknown-windows -fshort-wchar -mno-avx \
-mno-sse -mno-mmx -funsigned-char -Wno-pointer-sign -ggdb \
diff --git a/boot/efi/status.h b/boot/efi/status.h
deleted file mode 100644
index bcb6b96..0000000
--- a/boot/efi/status.h
+++ /dev/null
@@ -1,110 +0,0 @@
-#pragma once
-
-#include <cstddef>
-#include <limits>
-#include <type_traits>
-
-namespace Efi
-{
- class Status
- {
- using size_t = std::size_t;
- using ssize_t = std::make_signed_t<size_t>;
-
- size_t m_Value;
-
- constexpr Status(size_t value)
- : m_Value(value)
- {
- }
-
- constexpr bool IsError() const
- {
- return static_cast<ssize_t>(m_Value) < 0;
- }
-
- constexpr bool IsWarning() const
- {
- return m_Value > 0;
- }
-
- constexpr bool IsSuccess() const
- {
- return m_Value == 0;
- }
-
- constexpr static Status ErrorStatus(size_t code)
- {
- auto errorBit = std::numeric_limits<ssize_t>::min();
- return Status(static_cast<size_t>(errorBit) | code);
- }
-
- constexpr static Status WarningStatus(size_t code)
- {
- return Status(code);
- }
-
- public:
-
- operator size_t() const
- {
- return m_Value;
- }
-
- static const Status Success;
-
- class Warning
- {
- public:
-
- static const Status UnknownGlyph;
- static const Status DeleteFailure;
- static const Status WriteFailure;
- static const Status BufferTooSmall;
- static const Status StaleData;
- static const Status FileSystem;
- static const Status ResetRequired;
- };
-
- class Error
- {
- public:
-
- static const Status LoadError;
- static const Status InvalidParameter;
- static const Status Unsupported;
- static const Status BadBufferSize;
- static const Status BufferTooSmall;
- static const Status NotReady;
- static const Status DeviceError;
- static const Status WriteProtected;
- static const Status OutOfResources;
- static const Status VolumeCorrupted;
- static const Status VolumeFull;
- static const Status NoMedia;
- static const Status MediaChanged;
- static const Status NotFound;
- static const Status AccessDenied;
- static const Status NoResponse;
- static const Status NoMapping;
- static const Status Timeout;
- static const Status NotStarted;
- static const Status AlreadyStarted;
- static const Status Aborted;
- static const Status IcmpError;
- static const Status TftpError;
- static const Status ProtocolError;
- static const Status IncompatibleVersion;
- static const Status SecurityViolation;
- static const Status CrcError;
- static const Status EndOfMedia;
- static const Status EndOfFile;
- static const Status InvalidLanguage;
- static const Status CompromisedData;
- static const Status IpAddressConflict;
- static const Status HttpError;
- };
-
- };
-}
-
diff --git a/boot/efi/system_table.h b/boot/efi/system_table.h
deleted file mode 100644
index 93e839d..0000000
--- a/boot/efi/system_table.h
+++ /dev/null
@@ -1,31 +0,0 @@
-#pragma once
-
-#include "table.h"
-
-extern "C"
-{
- struct efi_system_table
- {
- void *m_Value;
- };
-}
-
-namespace Efi
-{
- class SystemTable : private Table
- {
- char16_t *m_FirmwareVendor;
- uint32_t m_FirmwareRevision;
- Handle m_ConsoleInHandle;
- void *m_ConIn;
- Handle m_ConsoleOutHandle;
- void *m_ConOut;
- Handle m_StandardErrorHandle;
- void *m_StdErr;
- void *m_RuntimeServices;
- void *m_BootServices;
- size_t m_NumberOfTableEntries;
- void *m_ConfigurationTable;
- };
-}
-
diff --git a/boot/efi/table.h b/boot/efi/table.h
deleted file mode 100644
index 660bd1e..0000000
--- a/boot/efi/table.h
+++ /dev/null
@@ -1,26 +0,0 @@
-#pragma once
-
-#include <cstddef>
-#include <cstdint>
-
-namespace Efi
-{
- class TableHeader
- {
- using uint64_t = std::uint64_t;
- using uint32_t = std::uint32_t;
- using size_t = std::size_t;
-
- uint64_t m_Signature;
- uint32_t m_Revision;
- uint32_t m_HeaderSize;
- uint32_t m_Crc32;
- uint32_t m_Reserved;
- };
-
- class Table
- {
- TableHeader m_Header;
- };
-}
-
diff --git a/defaults.mk b/defaults.mk
index 585e9ab..73e8950 100644
--- a/defaults.mk
+++ b/defaults.mk
@@ -11,7 +11,7 @@ OBJCOPY := objcopy
CFLAGS += -ffreestanding -mno-red-zone -ggdb -std=c2x \
-Wall -Wextra -Werror -fno-stack-protector \
- -Wpedantic
+ -Wpedantic -std=c2x
CXXFLAGS += -ffreestanding -mno-red-zone -ggdb \
-Wall -Wextra -Werror -fno-stack-protector
diff --git a/kc/boot/kc_main.c b/kc/boot/kc_main.c
index 943c082..e0f1786 100644
--- a/kc/boot/kc_main.c
+++ b/kc/boot/kc_main.c
@@ -10,7 +10,7 @@
#include <stdbool.h>
-#include <lib/kstring.h>
+#include <libc/string.h>
#include <lib/elf.h>
#define KERNEL_IMAGE_BASE 0xffffffff80000000
diff --git a/kc/core/Makefile b/kc/core/Makefile
index dbbeef1..730eba7 100644
--- a/kc/core/Makefile
+++ b/kc/core/Makefile
@@ -1,22 +1,20 @@
include ../../defaults.mk
include ../defaults.mk
-VPATH := ../../lib ../ cpu/ memory/
+VPATH := ../../lib ../../lib/libc ../ cpu/ memory/
TARGET := kernel.os
.DEFAULT: $(TARGET)
-CPPFLAGS += -I../../api -I../api -I../../lib -I.
+CPPFLAGS += -I../../api -I../api -I../../lib/api -I. -Icpu/
CFLAGS += -mcmodel=small -Wno-unused-const-variable -Wno-unused-function -fvisibility=hidden -g
-LDSCRIPT := ../kc.ld
-
AOBJS := entry_x86_64.o reloc_x86_64.o dynamic_x86_64.o
-COBJS := mmu.o cpu_task.o irq.o exceptions.o cpu.o msr.o mmu.o port.o
+COBJS := mmu.o cpu_thread.o irq.o exceptions.o cpu.o msr.o mmu.o port.o arch_thread.o
POBJS := pic8259.o pic8259_isr.o pit8253.o i8042.o
GOBJS := serial.o kc_main.o memory.o vm_tree.o panic.o task.o \
kcc_memory.o page_early.o page_stack.o video.o
-LOBJS := kprintf.o memset.o memcpy.o memmove.o memcmp.o kstdio.o string.o
+LOBJS := printf.o memset.o memcpy.o memmove.o memcmp.o stdio.o string.o
OBJS := $(AOBJS) $(COBJS) $(POBJS) $(GOBJS) $(LOBJS)
DEPS := $(patsubst %.o,%.d,$(OBJS))
diff --git a/kc/core/cpu/arch_thread.c b/kc/core/cpu/arch_thread.c
new file mode 100644
index 0000000..c0d707a
--- /dev/null
+++ b/kc/core/cpu/arch_thread.c
@@ -0,0 +1,81 @@
+#include <stdint.h>
+#include <stddef.h>
+#include <stdnoreturn.h>
+
+#include <libc/stdio.h>
+
+#include "task.h"
+
+struct arch_register_context
+{
+ uint64_t
+ r15,
+ r14,
+ r13,
+ r12,
+ r11,
+ r10,
+ r9,
+ r8,
+ rsi,
+ rdi,
+ rdx,
+ rcx,
+ rbx,
+ rax,
+ rbp,
+ rsp;
+};
+
+extern uint64_t *get_tss_rsp0(void);
+
+struct arch_thread_context
+{
+ struct arch_register_context register_context;
+ void *return_address;
+};
+
+extern void arch_swap_thread_stack(
+ void * volatile *outgoing_stack,
+ void *incoming_stack);
+
+extern void arch_begin_thread(
+ void *(func)(void *),
+ void *params);
+
+void arch_create_thread(
+ struct kc_thread *thread,
+ void *(*func)(void *),
+ void *params)
+{
+ uintptr_t stack_pointer = (uintptr_t)thread->kernel_stack_pointer;
+ struct arch_thread_context *context = (struct arch_thread_context *)
+ (stack_pointer -= sizeof(*context));
+ thread->kernel_stack_pointer = (void *)stack_pointer;
+
+ context->return_address = (void *)arch_begin_thread;
+ context->register_context.rdi = (uint64_t)func;
+ context->register_context.rsi = (uint64_t)params;
+ context->register_context.rdx = (uint64_t)thread;
+ context->register_context.rsp = (uint64_t)&context->return_address;
+}
+
+void arch_swap_thread(
+ struct kc_thread *outgoing,
+ struct kc_thread *incoming)
+{
+ arch_swap_thread_stack(&outgoing->kernel_stack_pointer, incoming->kernel_stack_pointer);
+}
+
+void *arch_idle_loop(void *)
+{
+ for (;;) __asm__ ("hlt");
+ return nullptr;
+}
+
+noreturn void arch_terminate_thread(union kc_thread_result result, struct kc_thread *)
+{
+ kct_terminate(result);
+ for (;;) __asm__ ("hlt");
+}
+
diff --git a/kc/core/cpu/arch_thread.h b/kc/core/cpu/arch_thread.h
new file mode 100644
index 0000000..2b8d0fb
--- /dev/null
+++ b/kc/core/cpu/arch_thread.h
@@ -0,0 +1,12 @@
+#pragma once
+
+void * arch_idle_loop(void *);
+
+void arch_create_thread(
+ struct kc_thread *thread,
+ void *(kc_thread_func)(void *),
+ void *params);
+
+void arch_swap_thread(
+ struct kc_thread *outgoing,
+ struct kc_thread *incoming);
diff --git a/kc/core/cpu/cpu.c b/kc/core/cpu/cpu.c
index da55d38..226c9cf 100644
--- a/kc/core/cpu/cpu.c
+++ b/kc/core/cpu/cpu.c
@@ -10,7 +10,7 @@
#include <stddef.h>
#include <stdint.h>
-#include <lib/kstdio.h>
+#include <libc/stdio.h>
#define GDT_ENTRIES 16
#define IDT_ENTRIES 256
@@ -53,7 +53,7 @@ uint64_t *get_tss_rsp0(void)
static void syscall_entry(void)
{
- kprintf("system call\n");
+ printf("system call\n");
halt();
}
diff --git a/kc/core/cpu/cpu_task.S b/kc/core/cpu/cpu_task.S
deleted file mode 100644
index a411028..0000000
--- a/kc/core/cpu/cpu_task.S
+++ /dev/null
@@ -1,54 +0,0 @@
-/* thread switching routines for x86_64
-* adapted from:
-* https://wiki.osdev.org/Brendan%27s_Multi-tasking_Tutorial
-*
-*
-*/
-
-.hidden cpu_set_thread
-.global cpu_set_thread
-.type cpu_set_thread, @function
-cpu_set_thread:
- /* x86_64 SysV ABI
- * must save the following registers to the stack:
- * rbx, rsp, rbp, r12, r13, r14, r15
- * the following are the parameters for switching tasks
- * rdi: pointer to control block of thread being switched to
- * rsi: pointer to control block of the current thread
- * rdx: pointer to this cpu's task state segment rsp0 field
- */
- // test for attempt to switch to same thread
- cmp %rdi,%rsi
- je .Lnothing
- // test for a NULL origin thread
- test %rsi,%rsi
- // skip saving the state for a NULL origin thread
- jz .Lnull_thread
- push %rbx
- push %r12
- push %r13
- push %r14
- push %r15
- push %rbp
- /* the current task will be in rsi */
- mov %rsp, 0(%rsi) // save the stack pointer for the current task
-.Lnull_thread:
- mov 0(%rdi),%rsp // new stack is the next's task's stack
- mov 8(%rdi),%rbx // top of the next task's kernel stack
- mov %rbx,0(%rdx) // save the esp0 to the tss
- mov 16(%rdi),%rax // page map for the next task
- mov %cr3, %rcx // in case we need to change the page map
- cmp %rax,%rcx
- je .Lfinish
- mov %rax,%cr3 // if the page maps are not the same, reload
-.Lfinish:
- pop %rbp // get all the registers off the new task's stack
- pop %r15
- pop %r14
- pop %r13
- pop %r12
- pop %rbx
-.Lnothing: // do nothing if the threads are the same
- ret // leave into the new task
-.size cpu_set_thread, . - cpu_set_thread
-
diff --git a/kc/core/cpu/cpu_thread.S b/kc/core/cpu/cpu_thread.S
new file mode 100644
index 0000000..c4d04e1
--- /dev/null
+++ b/kc/core/cpu/cpu_thread.S
@@ -0,0 +1,57 @@
+.section .text
+
+.extern arch_terminate_thread
+
+.global arch_begin_thread
+arch_begin_thread:
+ movq %rdi, %rax
+ movq %rsi, %rdi
+ pushq %rdx
+ pushq %rbp
+ movq %rsp, %rbp
+ andq $-16, %rsp
+ callq *%rax
+ movq %rax, %rdi
+ movq 8(%rbp), %rsi
+ callq arch_terminate_thread
+
+.global arch_swap_thread_stack
+arch_swap_thread_stack:
+ pushq %rsp
+ pushq %rbp
+ pushq %rax
+ pushq %rbx
+ pushq %rcx
+ pushq %rdx
+ pushq %rdi
+ pushq %rsi
+ pushq %r8
+ pushq %r9
+ pushq %r10
+ pushq %r11
+ pushq %r12
+ pushq %r13
+ pushq %r14
+ pushq %r15
+ movq %rsp, (%rdi)
+ .Lenter_thread:
+ movq %rsi, %rsp
+ popq %r15
+ popq %r14
+ popq %r13
+ popq %r12
+ popq %r11
+ popq %r10
+ popq %r9
+ popq %r8
+ popq %rsi
+ popq %rdi
+ popq %rdx
+ popq %rcx
+ popq %rbx
+ popq %rax
+ popq %rbp
+ popq %rsp
+ retq
+
+
diff --git a/kc/core/cpu/exceptions.h b/kc/core/cpu/exceptions.h
index 7babb65..14a2088 100644
--- a/kc/core/cpu/exceptions.h
+++ b/kc/core/cpu/exceptions.h
@@ -21,7 +21,7 @@
#ifndef __ASSEMBLER__
-#include <lib/kstdio.h>
+#include <libc/stdio.h>
struct isr_context_param_regs
{
@@ -53,7 +53,7 @@ struct isr_context
static inline void print_exception_context(struct isr_context *context)
{
- kprintf(
+ printf(
"exception %#hhx:%x context:\n"
"interrupt entry state:\n"
"rip: %#hx:%p rflags: %#0.16lx\n"
diff --git a/kc/core/i8042.c b/kc/core/i8042.c
index 0ba12dc..f6b63b0 100644
--- a/kc/core/i8042.c
+++ b/kc/core/i8042.c
@@ -2,7 +2,7 @@
#include "port.h"
#include "i8042.h"
#include "pic8259.h"
-#include <lib/kstdio.h>
+#include <libc/stdio.h>
static void i8042_init(void);
static void i8042_enable(void) {}
@@ -99,21 +99,21 @@ static void i8042_set_config(void)
i8042_command(0x20);
uint8_t config_byte;
i8042_read(&config_byte);
- kprintf("i8042: current config: %#0.2x\n", config_byte);
+ printf("i8042: current config: %#0.2x\n", config_byte);
config_byte &= 0xfc;
if (config_byte & (0x1 << 5))
{
maybe_dual_channel = true;
}
config_byte |= 0x01;
- kprintf("i8042: new config: %#0.2x\n", config_byte);
+ printf("i8042: new config: %#0.2x\n", config_byte);
i8042_command(0x60);
i8042_write(config_byte);
i8042_command(0xaa);
uint8_t bist_result;
if (i8042_read(&bist_result) && bist_result != 0x55)
{
- kprintf("i8042: warning: error self-testing device. aborting.\n");
+ printf("i8042: warning: error self-testing device. aborting.\n");
return;
}
@@ -124,11 +124,11 @@ static void i8042_set_config(void)
uint8_t config_byte;
if (i8042_read(&config_byte) && config_byte & (0x1 << 5))
{
- kprintf("i8042: single-channel controller detected\n");
+ printf("i8042: single-channel controller detected\n");
}
else
{
- kprintf("i8042: dual-channel controller detected\n");
+ printf("i8042: dual-channel controller detected\n");
is_dual_channel = true;
}
}
@@ -136,7 +136,7 @@ static void i8042_set_config(void)
outb(PS2_COMMAND, 0xab);
if (inb(PS2_DATA) != 0x00)
{
- kprintf("i8042: failed testing port a\n");
+ printf("i8042: failed testing port a\n");
}
else
{
@@ -147,7 +147,7 @@ static void i8042_set_config(void)
outb(PS2_COMMAND, 0xa9);
if (inb(PS2_DATA) != 0x00)
{
- kprintf("i8042: failed testing port b\n");
+ printf("i8042: failed testing port b\n");
}
else
{
@@ -162,7 +162,7 @@ static void i8042_set_config(void)
i8042_write(0xff);
if(inb(PS2_DATA) == 0xfa && inb(PS2_DATA) == 0xaa)
{
- kprintf("i8042: detected device on channel, type %#0.2x\n", inb(PS2_DATA));
+ printf("i8042: detected device on channel, type %#0.2x\n", inb(PS2_DATA));
}
}
diff --git a/kc/core/kc_main.c b/kc/core/kc_main.c
index 9a84727..4f70d00 100644
--- a/kc/core/kc_main.c
+++ b/kc/core/kc_main.c
@@ -10,7 +10,7 @@
#include "i8042.h"
#include <kernel/entry.h>
-#include <lib/kstdio.h>
+#include <libc/stdio.h>
#include <stdbool.h>
#include <stddef.h>
@@ -27,7 +27,7 @@ unsigned long kc_main(struct kc_boot_data *data)
cpu_init();
serial_init();
video_init();
- kprintf("sophia starting, boot data %#lx\n", boot_data);
+ printf("sophia starting, boot data %#lx\n", boot_data);
memory_init();
pic8259_init();
pit8253_timer_source.init();
diff --git a/kc/core/memory.h b/kc/core/memory.h
index 6f70e57..425c2cd 100644
--- a/kc/core/memory.h
+++ b/kc/core/memory.h
@@ -4,7 +4,7 @@
#include <kernel/memory/paging.h>
#include <kernel/memory/range.h>
-#include <lib/kstring.h>
+#include <libc/string.h>
#include <core/memory.h>
diff --git a/kc/core/memory/memory.c b/kc/core/memory/memory.c
index ee0d9ca..7071018 100644
--- a/kc/core/memory/memory.c
+++ b/kc/core/memory/memory.c
@@ -20,7 +20,7 @@
#include <kc.h>
#include <core/memory.h>
-#include <lib/kstdio.h>
+#include <libc/stdio.h>
#define align_next(x, a) (x + a - 1) & ~(a - 1)
@@ -89,7 +89,7 @@ struct vm_tree *vm_get_tree(void)
void page_init(void)
{
- kprintf("initializing page frame allocator\n");
+ printf("initializing page frame allocator\n");
page_early_init();
page_stack_init();
}
@@ -98,7 +98,7 @@ void page_init_final(void)
{
if (current_alloc_func == boot_page_alloc)
{
- kprintf("finishing page frame allocator initialization\n");
+ printf("finishing page frame allocator initialization\n");
page_early_final();
current_alloc_func = page_stack_alloc;
}
@@ -176,7 +176,7 @@ static void *map_tableset(void *vaddr, uint64_t *tables[TABLESET_COUNT])
}
else
{
- kprintf("error: failed allocating memory for page table\n");
+ printf("error: failed allocating memory for page table\n");
PANIC(OUT_OF_MEMORY);
}
}
@@ -380,7 +380,7 @@ static void temp_page_unmap(void *vaddr)
static void vm_init(void)
{
- kprintf("initializing vm state\n");
+ printf("initializing vm state\n");
struct kc_boot_data *boot_data = get_boot_data();
struct vm_core_static_state *states = &vm_state.statics[0];
@@ -433,7 +433,7 @@ static void vm_init(void)
vm_state.zero_page = page_alloc(PAGE_ALLOC_CONV);
if (!vm_state.zero_page)
{
- kprintf("failed allocating for zero page\n");
+ printf("failed allocating for zero page\n");
PANIC(GENERAL_PANIC);
}
@@ -441,7 +441,7 @@ static void vm_init(void)
if (!zero_temp)
{
- kprintf("failed mapping zero page for initialization\n");
+ printf("failed mapping zero page for initialization\n");
PANIC(GENERAL_PANIC);
}
@@ -492,7 +492,7 @@ void *heap_alloc(size_t size)
if ((void *)-1ULL == heap_root)
{
struct vm_tree_node *heap_node = &vm_state.statics[HEAP_VM_STATE].node;
- kprintf("initializing heap at %#lx of %zu bytes\n",
+ printf("initializing heap at %#lx of %zu bytes\n",
heap_node->key.address, heap_node->key.size);
heap_root = NULL;
header = (struct heap_header *)heap_node->key.address;
@@ -650,7 +650,7 @@ int anonymous_page_handler(
if (!paddr)
{
- kprintf("got zero from page_alloc :|\n");
+ printf("got zero from page_alloc :|\n");
PANIC(OUT_OF_MEMORY);
}
page_map_at(
@@ -676,14 +676,14 @@ void page_fault_handler(struct isr_context *context)
if (!node)
{
print_exception_context(context);
- kprintf("error: page fault in unmanaged address %#lx\n", address);
+ printf("error: page fault in unmanaged address %#lx\n", address);
PANIC(UNHANDLED_FAULT);
}
if (!node->object->handler)
{
print_exception_context(context);
- kprintf("error: vm object at %p has no fault handler\n");
+ printf("error: vm object at %p has no fault handler\n");
PANIC(UNHANDLED_FAULT);
}
@@ -693,7 +693,7 @@ void page_fault_handler(struct isr_context *context)
void general_protection_handler(struct isr_context *context)
{
//TODO: implement #gp handler
- kprintf("general protection violation\n");
+ printf("general protection violation\n");
print_exception_context(context);
PANIC(UNHANDLED_FAULT);
}
diff --git a/kc/core/memory/page_early.c b/kc/core/memory/page_early.c
index 9ac90d2..989f82a 100644
--- a/kc/core/memory/page_early.c
+++ b/kc/core/memory/page_early.c
@@ -1,7 +1,7 @@
#include "page_early.h"
#include "panic.h"
-#include <lib/kstdio.h>
+#include <libc/stdio.h>
static struct page_early_state
{
@@ -13,20 +13,20 @@ early_state;
void page_early_init(void)
{
- kprintf("initializing early page frame allocator\n");
+ printf("initializing early page frame allocator\n");
struct kc_boot_data *boot_data = get_boot_data();
early_state.first = &boot_data->memory.entries[0];
early_state.last = &boot_data->memory.entries[boot_data->memory.count];
early_state.current = early_state.first;
- /*kprintf("memory ranges\n");
+ /*printf("memory ranges\n");
struct memory_range *current = early_state.first;
do
{
- kprintf("base %#0.16lx size %#0.16lx type %d\n", current->base, current->size, current->type);
+ printf("base %#0.16lx size %#0.16lx type %d\n", current->base, current->size, current->type);
current++;
}
while (current != early_state.last);
@@ -37,7 +37,7 @@ void page_early_final(void)
{
if (early_state.first)
{
- kprintf("finalizing early page allocator\n");
+ printf("finalizing early page allocator\n");
for (struct memory_range *current = early_state.first;
current < early_state.last;
current++)
@@ -101,7 +101,7 @@ kc_phys_addr page_early_alloc(enum page_alloc_flags type)
early_state.current++;
}
- kprintf("error: early allocator has run out of memory\n");
+ printf("error: early allocator has run out of memory\n");
PANIC(OUT_OF_MEMORY);
}
diff --git a/kc/core/panic.c b/kc/core/panic.c
index 7844487..02c58c7 100644
--- a/kc/core/panic.c
+++ b/kc/core/panic.c
@@ -1,6 +1,6 @@
#include "panic.h"
-#include <lib/kstdio.h>
+#include <libc/stdio.h>
#include <stdbool.h>
@@ -13,12 +13,12 @@ static char const *reason_strings[] = {
noreturn void panic(const char *file, int line, enum panic_reason reason)
{
- // TODO: kprintf() and friends
+ // TODO: printf() and friends
if (reason > sizeof(reason_strings) / sizeof(*reason_strings))
{
reason = 0;
}
- kprintf(
+ printf(
"kernel panic:%s:%u %s\n",
file,
line,
diff --git a/kc/core/pic8259.c b/kc/core/pic8259.c
index 4ddd2e1..792d0bd 100644
--- a/kc/core/pic8259.c
+++ b/kc/core/pic8259.c
@@ -4,7 +4,7 @@
#include <stdbool.h>
-#include <lib/kstdio.h>
+#include <libc/stdio.h>
#define ICW1_ICW4 0x1
#define ICW1_SINGLE 0x2
@@ -28,7 +28,7 @@ void pic8259_irq_install(uint8_t irq, pic8259_handler_func h)
{
if (irq_handlers[irq])
{
- kprintf("attempt to overwrite irq handler for %u\n", irq);
+ printf("attempt to overwrite irq handler for %u\n", irq);
return;
}
irq_handlers[irq] = h;
@@ -43,7 +43,7 @@ static void wait(void)
void pic8259_init(void)
{
- kprintf("initializing legacy pic\n");
+ printf("initializing legacy pic\n");
// basic init. not gonna fret with this too much
outb(PIC_PRI_CMD, ICW1_INIT|ICW1_ICW4);
wait();
@@ -171,7 +171,7 @@ void pic8259_irq_begin(uint8_t irq)
// check for spurious activations
if (irq_is_spurious(irq))
{
- kprintf("spurious activation of irq%hhu\n", irq);
+ printf("spurious activation of irq%hhu\n", irq);
return;
}
@@ -181,12 +181,12 @@ void pic8259_irq_begin(uint8_t irq)
if (result)
{
- kprintf("error handling irq%hhu: % d\n", irq, result);
+ printf("error handling irq%hhu: % d\n", irq, result);
}
}
else
{
- kprintf("unhandled irq%hhu\n", irq);
+ printf("unhandled irq%hhu\n", irq);
}
pic8259_irq_end(irq);
diff --git a/kc/core/pit8253.c b/kc/core/pit8253.c
index 360808f..31cf349 100644
--- a/kc/core/pit8253.c
+++ b/kc/core/pit8253.c
@@ -5,7 +5,7 @@
#include <stdatomic.h>
-#include <lib/kstdio.h>
+#include <libc/stdio.h>
#define PIT8253_DATA0 0x40
#define PIT8253_CMD 0x43
@@ -82,9 +82,9 @@ void pit8253_set_frequency(uint32_t frequency)
if (d > UINT16_MAX)
{
- kprintf("warning: %uHz is too slow for 8253 pit\n", PIT_HZ/d);
+ printf("warning: %uHz is too slow for 8253 pit\n", PIT_HZ/d);
d = UINT16_MAX;
- kprintf("warning: set timer to minimum frequency\n");
+ printf("warning: set timer to minimum frequency\n");
}
set_divisor(d);
diff --git a/kc/core/kstdio.c b/kc/core/stdio.c
index 680eb07..66c539f 100644
--- a/kc/core/kstdio.c
+++ b/kc/core/stdio.c
@@ -4,12 +4,12 @@
#include <stdint.h>
#include <stdbool.h>
-#include <lib/kstdio.h>
-#include <lib/kstring.h>
+#include <libc/stdio.h>
+#include <libc/string.h>
-FILE *kstdout;
+FILE *stdout;
-int kfputc(int c, FILE *f)
+int fputc(int c, FILE *f)
{
(void)f;
video_putchar(c);
diff --git a/kc/core/task.c b/kc/core/task.c
index 3e0288d..a298a05 100644
--- a/kc/core/task.c
+++ b/kc/core/task.c
@@ -12,13 +12,9 @@
#include <stdbool.h>
#include <lib/elf.h>
-#include <lib/kstdio.h>
+#include <libc/stdio.h>
-static const size_t INTERRUPT_STACK_SIZE = 4096;
-static const size_t THREAD_SIZE = 16834;
-static const enum vm_alloc_flags ALLOC_FLAGS = VM_ALLOC_ANY|VM_ALLOC_ANONYMOUS;
-
-extern uint64_t *get_tss_rsp0(void);
+#include "arch_thread.h"
static void lock_scheduler(void);
static void unlock_scheduler(void);
@@ -27,7 +23,7 @@ static void unlock_preempt(void);
static void update_time(void);
-static struct kc_thread *create_thread(void (*thread_entry)(void));
+static struct kc_thread *create_thread(void *(*thread_f)(void *), void *p);
static void destroy_thread(struct kc_thread *thread);
static void set_thread(struct kc_thread *thread);
static void block_thread(enum kc_thread_status reason);
@@ -37,10 +33,6 @@ static void sleep_thread_until(uint64_t nanoseconds);
static int sleeping_thread_callback(uint64_t nanoseconds);
-static struct kc_thread *ready_thread_pop(void);
-static void ready_thread_push(struct kc_thread *thread);
-static void ready_thread_push_back(struct kc_thread *thread);
-
const struct timer_source * timesource;
/* static threads that are always present
@@ -50,130 +42,138 @@ static struct kc_thread *idle_thread;
// thread lists for the scheduler to manipulate
static struct kc_thread *current_thread;
-static struct kc_thread *first_ready_thread;
-static struct kc_thread *last_ready_thread;
-static struct kc_thread *sleeping_threads;
+
+struct thread_queue
+{
+ struct kc_thread
+ *first,
+ *last;
+};
+
+static void thread_queue_push(struct thread_queue *queue, struct kc_thread *thread);
+static void thread_queue_push_back(struct thread_queue *queue, struct kc_thread *thread);
+
+static void thread_queue_push(struct thread_queue *queue, struct kc_thread *thread)
+{
+ thread->next = queue->first;
+ queue->first = thread;
+
+ if (!queue->last)
+ {
+ thread_queue_push_back(queue, thread);
+ }
+}
+
+static void thread_queue_push_back(struct thread_queue *queue, struct kc_thread *thread)
+{
+ if (!queue->first)
+ {
+ thread_queue_push(queue, thread);
+ }
+ else if (queue->last)
+ {
+ queue->last->next = thread;
+ }
+
+ queue->last = thread;
+}
+
+struct kc_thread *thread_queue_pop(struct thread_queue *queue)
+{
+ if (!queue->first)
+ {
+ return nullptr;
+ }
+
+ struct kc_thread *thread = queue->first;
+ queue->first = thread->next;
+ thread->next = nullptr;
+ if (!queue->first)
+ {
+ queue->last = nullptr;
+ }
+
+ return thread;
+}
+
+bool thread_queue_any(struct thread_queue queue)
+{
+ return queue.first && queue.last;
+}
+
+static struct thread_queue ready_queue;
+static struct thread_queue sleep_queue;
+static struct thread_queue wait_queue;
static volatile atomic_uint_fast64_t preempt_switch_count = 0;
static volatile atomic_bool preempt_switch_flag = false;
-static void idle_thread_entry(void)
+static void *idle_thread_entry(void *)
{
- kprintf("idle thread started\n");
- unlock_scheduler();
-
- __asm__ ("sti");
+ printf("idle thread started\n");
+ __asm__ ("sti");
+
+
while (true)
{
__asm__ ("hlt;");
}
-}
-
-#define PS2INPUT 0x60
-#define PS2STATUS 0x64
-#define PS2STATUS_IBF 0x1
-static void keyboard_input_loop(void)
-{
- bool has_bytes = true;
- while (has_bytes)
- {
- has_bytes = inb(PS2STATUS) & PS2STATUS_IBF;
- if (has_bytes)
- {
- kprintf("read byte from keyboard input: %hhd\n", inb(PS2INPUT));
- }
- else
- {
- kprintf("no bytes in keyboard input\n");
- }
- }
+ return nullptr;
}
-static void sleepy_thread_entry(void)
+static void *sleepy_thread_entry(void *p)
{
+ uint64_t sleep_nanoseconds = (uint64_t)p;
int thread_slept_count = 0;
while (true)
{
- sleep_thread(1000000000);
+ sleep_thread(sleep_nanoseconds);
thread_slept_count++;
- //keyboard_input_loop();
+ printf("thread slept %d times\n", thread_slept_count);
}
(void)thread_slept_count;
+ return nullptr;
}
-static void create_interrupt_stack(size_t size)
-{
- char *rsp0 = vm_alloc(size, ALLOC_FLAGS);
- memset(rsp0, 0, size);
- *get_tss_rsp0() = (uintptr_t)rsp0 + size;
-}
-noreturn void task_init(void)
-{
- lock_scheduler();
- timesource = &pit8253_timer_source;
- timesource->append_callback(sleeping_thread_callback);
- timesource->start();
- kprintf(
- "starting task management, timesource delta %luns\n",
- timesource->nanoseconds_delta());
- // XXX: unfuck this mess at some point
- // XXX: make this also not demand-allocated or it's gonna fail
- create_interrupt_stack(INTERRUPT_STACK_SIZE);
-
- // initalize static threads
- idle_thread = create_thread(idle_thread_entry);
- struct kc_thread *sleepy_thread = create_thread(sleepy_thread_entry);
-
- current_thread = idle_thread;
- ready_thread_push_back(sleepy_thread);
+static uint64_t scheduler_flags;
- idle_thread->status = RUNNING;
- cpu_set_thread(&idle_thread->state, NULL, get_tss_rsp0());
+static inline bool check_preempt_count()
+{
+ if (atomic_load(&preempt_switch_count) > 0)
+ {
+ return true;
+ }
- // shouldn't ever get here
- PANIC(DEAD_END);
+ return false;
}
void task_schedule(void)
{
- if (atomic_load(&preempt_switch_count))
- {
- preempt_switch_flag = true;
- return;
- }
+ if(check_preempt_count())
+ {
+ preempt_switch_flag = true;
+ return;
+ }
- if (first_ready_thread)
- {
- struct kc_thread *this_thread = ready_thread_pop();
+ struct kc_thread *t = thread_queue_pop(&ready_queue);
- if (this_thread == idle_thread)
- {
- if (first_ready_thread)
- {
- this_thread->status = READY;
- this_thread = ready_thread_pop();
- ready_thread_push(idle_thread);
- }
- else if (current_thread->status == RUNNING)
- {
- return;
- }
- else
- {
- // NULL statement????? idon't like
- }
- }
- set_thread(this_thread);
- }
-}
+ if (t == idle_thread)
+ {
+ thread_queue_push_back(&ready_queue, t);
+ t = thread_queue_pop(&ready_queue);
+ }
-static uint64_t scheduler_flags;
+ if (t && current_thread->status != RUNNING)
+ {
+ set_thread(t);
+ }
+}
static void lock_scheduler(void)
{
@@ -193,7 +193,7 @@ static void unlock_scheduler(void)
static void unlock_preempt(void)
{
- if (atomic_load(&preempt_switch_count) >= 1)
+ if (atomic_load(&preempt_switch_count) > 0)
{
preempt_switch_count--;
}
@@ -220,42 +220,21 @@ void update_time(void)
}
}
-static struct kc_thread *create_thread(void (*thread_f)(void))
-{
- char *task_bottom = vm_alloc(16384, ALLOC_FLAGS);
- struct kc_thread *thread =
- (struct kc_thread *)(task_bottom + 16384 - sizeof(*thread));
-
- thread->next = NULL;
-
- thread->time_elapsed = 0;
- thread->sleep_expiration = 0;
+#define KC_THREAD_SIZE 0x3000
- thread->state.stack = (uintptr_t)thread;
- thread->state.stack_top = *get_tss_rsp0();
- thread->state.page_map = mmu_get_map();
-
- // set up the expected stack values for the state
- struct task_register_state
- {
- uint64_t rbp;
- uint64_t r15;
- uint64_t r14;
- uint64_t r13;
- uint64_t r12;
- uint64_t rbx;
- uint64_t rip;
- }
- *register_state =
- (struct task_register_state *)
- (thread->state.stack -= sizeof(*register_state));
+static struct kc_thread *create_thread(void *(*thread_f)(void *), void *p)
+{
+ void *buffer = vm_alloc(KC_THREAD_SIZE, VM_ALLOC_ANONYMOUS|VM_ALLOC_ANY);
+ memset(buffer, 0, KC_THREAD_SIZE);
- memset(register_state, 0, sizeof(*register_state));
+ uintptr_t stack_head = (uintptr_t)buffer + KC_THREAD_SIZE;
+ struct kc_thread *thread = (struct kc_thread *)(stack_head -= sizeof(*thread));
- register_state->rip = (uint64_t)thread_f;
- register_state->rbp = thread->state.stack;
+ thread->kernel_stack_head = (void *)stack_head;
+ thread->kernel_stack_pointer = (void *)stack_head;
+ thread->status = READY;
- thread->status = READY;
+ arch_create_thread(thread, thread_f, p);
return thread;
}
@@ -267,11 +246,17 @@ static void destroy_thread(struct kc_thread *thread)
static void set_thread(struct kc_thread *thread)
{
+ if (thread == current_thread)
+ {
+ return;
+ }
+
if (atomic_load(&preempt_switch_count))
{
preempt_switch_flag = true;
return;
}
+
update_time();
struct kc_thread *previous_thread = current_thread;
current_thread = thread;
@@ -279,15 +264,11 @@ static void set_thread(struct kc_thread *thread)
if (previous_thread->status == RUNNING)
{
previous_thread->status = READY;
- ready_thread_push(previous_thread);
+ thread_queue_push(&ready_queue, previous_thread);
}
- cpu_set_thread(
- &current_thread->state,
- &previous_thread->state,
- get_tss_rsp0());
-
current_thread->status = RUNNING;
+ arch_swap_thread(previous_thread, current_thread);
}
static void block_thread(enum kc_thread_status reason)
@@ -304,14 +285,14 @@ static void unblock_thread(struct kc_thread *thread)
thread->status = READY;
- if (!first_ready_thread || (current_thread == idle_thread))
+ if (!thread_queue_any(ready_queue) || (current_thread == idle_thread))
{
unlock_preempt();
set_thread(thread);
}
else
{
- ready_thread_push_back(thread);
+ thread_queue_push_back(&ready_queue, thread);
}
unlock_scheduler();
@@ -332,89 +313,149 @@ static void sleep_thread_until(uint64_t nanoseconds)
return;
}
-// kprintf("time elapsed is now %ld\r\n", timesource->nanoseconds_elapsed());
-// kprintf("thread will now sleep until %ld\r\n", nanoseconds);
current_thread->sleep_expiration = nanoseconds;
- current_thread->next = sleeping_threads;
- sleeping_threads = current_thread;
+
+ thread_queue_push_back(&sleep_queue, current_thread);
unlock_preempt();
block_thread(SLEEPING);
}
-static struct kc_thread *ready_thread_pop(void)
+static int sleeping_thread_callback(uint64_t timestamp)
{
- struct kc_thread *thread = first_ready_thread;
+ lock_preempt();
- if (thread)
- {
- first_ready_thread = thread->next;
- }
+ struct thread_queue queue = sleep_queue;
- if (!first_ready_thread)
- {
- last_ready_thread = NULL;
- }
+ sleep_queue = (struct thread_queue){ nullptr, nullptr };
- return thread;
+ {
+ struct kc_thread *t;
+ while((t = thread_queue_pop(&queue)) != nullptr)
+ {
+ if (t->sleep_expiration <= timestamp)
+ {
+ t->sleep_expiration = 0;
+ unblock_thread(t);
+ }
+ else
+ {
+ thread_queue_push(&sleep_queue, t);
+ }
+ }
+ }
+
+ unlock_preempt();
+ lock_scheduler();
+ task_schedule();
+ unlock_scheduler();
+
+ return 0;
}
-static void ready_thread_push(struct kc_thread *thread)
-{
- thread->next = first_ready_thread;
- first_ready_thread = thread;
+typedef void (locked_scheduler_action)(void *);
- if (!last_ready_thread)
- {
- last_ready_thread = first_ready_thread;
- }
+static void with_locked_scheduler(
+ locked_scheduler_action *action,
+ void *action_parameter)
+{
+ lock_scheduler();
+ action(action_parameter);
+ unlock_scheduler();
}
-static void ready_thread_push_back(struct kc_thread *thread)
+static void terminate_action(void *result)
{
- if (last_ready_thread)
- {
- last_ready_thread->next = thread;
- }
- else
- {
- first_ready_thread = thread;
- }
- last_ready_thread = thread;
+ union kc_thread_result *result_value = result;
+ current_thread->result = *result_value;
+ current_thread->kernel_stack_pointer = current_thread->kernel_stack_head;
+
+ struct thread_queue queue = wait_queue;
+
+ lock_preempt();
+
+ wait_queue = (struct thread_queue) { nullptr, nullptr };
+
+ {
+ struct kc_thread *t;
+ while((t = thread_queue_pop(&queue)) != nullptr)
+ {
+ if (t->wait_target == current_thread)
+ {
+ t->wait_target = nullptr;
+ t->status = READY;
+ thread_queue_push_back(&ready_queue, t);
+ }
+ else
+ {
+ thread_queue_push(&wait_queue, t);
+ }
+ }
+ }
+
+ unlock_preempt();
+
+ block_thread(TERMINATED);
}
-static int sleeping_thread_callback(uint64_t nanoseconds)
+void kct_terminate(union kc_thread_result result)
{
- lock_preempt();
+ with_locked_scheduler(terminate_action, &result);
+}
- struct kc_thread *sleeping = sleeping_threads;
- sleeping_threads = NULL;
+union kc_thread_result kct_wait(struct kc_thread *target)
+{
+ current_thread->wait_target = target;
+ thread_queue_push_back(&wait_queue, current_thread);
+ block_thread(WAITING);
+ return target->result;
+}
- while (sleeping != NULL)
- {
- struct kc_thread *this_thread = sleeping;
- sleeping = sleeping->next;
+static void *waited_thread_test(void *)
+{
+ printf("worker thread, sleeping for some time...\n");
+ sleep_thread(30000000000);
+ return (void *)1;
+}
- if (this_thread->sleep_expiration <= nanoseconds)
- {
- //kprintf("thread awakened: %p\n", this_thread);
- this_thread->sleep_expiration = 0;
- unblock_thread(this_thread);
- }
- else
- {
- this_thread->next = sleeping_threads;
- sleeping_threads = this_thread;
- }
- }
+static void *waiting_thread_test(void *)
+{
+ printf("waiting thread\n");
+ struct kc_thread *t = create_thread(waited_thread_test, nullptr);
+ t->status = READY;
+ thread_queue_push_back(&ready_queue, t);
+ union kc_thread_result r = kct_wait(t);
+ printf("waited thread terminated result: %d\n", r);
+ return nullptr;
+}
- unlock_preempt();
+noreturn void task_init(void)
+{
+ struct kc_thread boot_thread;
+ boot_thread.status = RUNNING;
+ current_thread = &boot_thread;
- lock_scheduler();
- task_schedule();
- unlock_scheduler();
+ timesource = &pit8253_timer_source;
+ timesource->append_callback(sleeping_thread_callback);
+ timesource->start();
+ printf(
+ "starting task management, timesource delta %luns\n",
+ timesource->nanoseconds_delta());
- return 0;
+ idle_thread = create_thread(idle_thread_entry, nullptr);
+ struct kc_thread *sleepy_thread = create_thread(sleepy_thread_entry, (void *)3000000000);
+ struct kc_thread *sleepy_thread2 = create_thread(sleepy_thread_entry, (void *)5000000000);
+ struct kc_thread *waiting_thread = create_thread(waiting_thread_test, nullptr);
+ thread_queue_push(&ready_queue, sleepy_thread);
+ thread_queue_push(&ready_queue, sleepy_thread2);
+ thread_queue_push_back(&ready_queue, waiting_thread);
+ __asm__ volatile ("movq %%rsp, %0" : "=g"(boot_thread.kernel_stack_pointer) :);
+ thread_queue_push(&ready_queue, idle_thread);
+ block_thread(BLOCKED);
+ // shouldn't ever get here
+ printf("the idle thread exited somehow. we're back in the boot thread. this is not good.\n");
+ PANIC(DEAD_END);
}
+
diff --git a/kc/core/task.h b/kc/core/task.h
index bea4756..5d9f39f 100644
--- a/kc/core/task.h
+++ b/kc/core/task.h
@@ -4,34 +4,39 @@
enum kc_thread_status
{
+ AVAILABLE,
+ CREATED,
READY,
RUNNING,
SLEEPING,
BLOCKED,
+ WAITING,
TERMINATED
};
-struct kc_thread_state
+union kc_thread_result
{
- uint64_t stack;
- uint64_t stack_top;
- uint64_t page_map;
+ uint64_t scalar;
+ void *pointer;
};
struct kc_thread
{
- struct kc_thread *next;
- uint64_t time_elapsed;
- uint64_t sleep_expiration;
- enum kc_thread_status status;
- struct kc_thread_state state;
+ void *kernel_stack_head;
+ void *kernel_stack_pointer;
+ uint64_t time_elapsed;
+ union kc_thread_result result;
+ enum kc_thread_status status;
+ struct kc_thread *next;
+ union
+ {
+ uint64_t sleep_expiration;
+ struct kc_thread *wait_target;
+ };
};
-extern void cpu_set_thread(
- struct kc_thread_state *current,
- struct kc_thread_state *next,
- uint64_t *cpu_tss_rsp0);
-
void task_init(void);
-void task_schedule(void);
+
+void kct_terminate(union kc_thread_result result);
+union kc_thread_result kct_wait(struct kc_thread *target);
diff --git a/kc/core/video.c b/kc/core/video.c
index 6d89c08..a3bdce2 100644
--- a/kc/core/video.c
+++ b/kc/core/video.c
@@ -46,8 +46,8 @@
#include <stdbool.h>
-#include <lib/kstring.h>
-#include <lib/kstdio.h>
+#include <libc/string.h>
+#include <libc/stdio.h>
#include <lib/numeric.h>
#include <kernel/entry.h>
@@ -227,7 +227,7 @@ int video_init(void)
}
}
- kprintf("video output %ix%i pixels, %i bytes per line, %s 32 bytes per pixel\n",
+ printf("video output %ix%i pixels, %i bytes per line, %s 32 bytes per pixel\n",
boot_data->width, boot_data->height, boot_data->pitch, video_format_name);
diff --git a/kc/core/vm_tree.c b/kc/core/vm_tree.c
index dd3667e..72affe8 100644
--- a/kc/core/vm_tree.c
+++ b/kc/core/vm_tree.c
@@ -31,8 +31,8 @@
#include "vm_tree.h"
#include "panic.h"
-#include <lib/kstdio.h>
-#include <lib/kstring.h>
+#include <libc/stdio.h>
+#include <libc/string.h>
#define assert(expr)
@@ -44,92 +44,92 @@
static int compare(uintptr_t a1, size_t s1, uintptr_t a2, size_t s2)
{
- // case 1: a1:a1+s1 occupies a region entirely below a2
- // and is therefore less than.
- if ((a1 + s1) <= a2)
- {
- return -1;
- }
- // case 2: a1:a1+s1 occupies a region entirely above (a2+s2)
- // and is therefore greater than.
- else if (a1 >= (a2 + s2))
- {
- return 1;
- }
- // case 3: the above conditions are not satisfied and therefore
- // the regions overlap and are considered equivalent.
- return 0;
+ // case 1: a1:a1+s1 occupies a region entirely below a2
+ // and is therefore less than.
+ if ((a1 + s1) <= a2)
+ {
+ return -1;
+ }
+ // case 2: a1:a1+s1 occupies a region entirely above (a2+s2)
+ // and is therefore greater than.
+ else if (a1 >= (a2 + s2))
+ {
+ return 1;
+ }
+ // case 3: the above conditions are not satisfied and therefore
+ // the regions overlap and are considered equivalent.
+ return 0;
}
static int compare_key(struct vm_tree_key const * const k1,
- struct vm_tree_key const * const k2)
+ struct vm_tree_key const * const k2)
{
- return compare(k1->address, k1->size, k2->address, k2->size);
+ return compare(k1->address, k1->size, k2->address, k2->size);
}
void vmt_init_node(
- struct vm_tree *tree,
- struct vm_tree_node *node,
- struct vm_object *object,
- void *base,
- void *head)
+ struct vm_tree *tree,
+ struct vm_tree_node *node,
+ struct vm_object *object,
+ void *base,
+ void *head)
{
- memset(node, 0, sizeof(*node));
- node->key =
- (struct vm_tree_key)
- {
- (uintptr_t)base,
- (uintptr_t)head - (uintptr_t)base
- };
+ memset(node, 0, sizeof(*node));
+ node->key =
+ (struct vm_tree_key)
+ {
+ (uintptr_t)base,
+ (uintptr_t)head - (uintptr_t)base
+ };
- struct vm_tree_node *ek = NULL;
- if (!(ek = vmt_search_key(tree, &node->key)))
- {
- struct vm_tree_node *p = vmn_predecessor_key(
- tree->root,
- &node->key);
- if (!p)
- {
- // the tree root should be in place of a missing predecessor
- p = tree->root;
- }
- vmt_insert(
- tree,
- node,
- p,
- vmn_child_direction(node, p));
- node->object = object;
- }
- else
- {
- kprintf("fatal: attempt to insert overlapping vm node\n"
- "node 1: %p: %p @ %zu bytes\n"
- "node 2: %p: %p @ %zu bytes\n",
- node->key.address, node->key.size,
- ek->key.address, ek->key.size);
-
- PANIC(GENERAL_PANIC);
- }
+ struct vm_tree_node *ek = NULL;
+ if (!(ek = vmt_search_key(tree, &node->key)))
+ {
+ struct vm_tree_node *p = vmn_predecessor_key(
+ tree->root,
+ &node->key);
+ if (!p)
+ {
+ // the tree root should be in place of a missing predecessor
+ p = tree->root;
+ }
+ vmt_insert(
+ tree,
+ node,
+ p,
+ vmn_child_direction(node, p));
+ node->object = object;
+ }
+ else
+ {
+ printf("fatal: attempt to insert overlapping vm node\n"
+ "node 1: %p: %p @ %zu bytes\n"
+ "node 2: %p: %p @ %zu bytes\n",
+ node->key.address, node->key.size,
+ ek->key.address, ek->key.size);
+
+ PANIC(GENERAL_PANIC);
+ }
}
static struct vm_tree_node* RotateDirRoot(
- struct vm_tree* T, // red–black tree
- struct vm_tree_node* P, // root of subtree (may be the root of T)
- enum vm_tree_direction dir) { // dir ∈ { LEFT, RIGHT }
- struct vm_tree_node* G = P->parent;
- struct vm_tree_node* S = P->child[1-dir];
- struct vm_tree_node* C;
- assert(S != NIL); // pointer to true node required
- C = S->child[dir];
- P->child[1-dir] = C; if (C != NIL) C->parent = P;
- S->child[ dir] = P; P->parent = S;
- S->parent = G;
- if (G != NULL)
- G->child[ P == G->right ? RIGHT : LEFT ] = S;
- else
- T->root = S;
- return S; // new root of subtree
+ struct vm_tree* T, // red–black tree
+ struct vm_tree_node* P, // root of subtree (may be the root of T)
+ enum vm_tree_direction dir) { // dir ∈ { LEFT, RIGHT }
+ struct vm_tree_node* G = P->parent;
+ struct vm_tree_node* S = P->child[1-dir];
+ struct vm_tree_node* C;
+ assert(S != NIL); // pointer to true node required
+ C = S->child[dir];
+ P->child[1-dir] = C; if (C != NIL) C->parent = P;
+ S->child[ dir] = P; P->parent = S;
+ S->parent = G;
+ if (G != NULL)
+ G->child[ P == G->right ? RIGHT : LEFT ] = S;
+ else
+ T->root = S;
+ return S; // new root of subtree
}
#define RotateDir(N,dir) RotateDirRoot(T,N,dir)
@@ -137,251 +137,251 @@ static struct vm_tree_node* RotateDirRoot(
#define RotateRight(N) RotateDirRoot(T,N,RIGHT)
void vmt_insert(
- struct vm_tree* T, // -> red–black tree
- struct vm_tree_node* N, // -> node to be inserted
- struct vm_tree_node* P, // -> parent node of N ( may be NULL )
- enum vm_tree_direction dir) // side ( LEFT or RIGHT ) of P where to insert N
+ struct vm_tree* T, // -> red–black tree
+ struct vm_tree_node* N, // -> node to be inserted
+ struct vm_tree_node* P, // -> parent node of N ( may be NULL )
+ enum vm_tree_direction dir) // side ( LEFT or RIGHT ) of P where to insert N
{
- struct vm_tree_node* G; // -> parent node of P
- struct vm_tree_node* U; // -> uncle of N
+ struct vm_tree_node* G; // -> parent node of P
+ struct vm_tree_node* U; // -> uncle of N
- N->color = RED;
- N->left = NIL;
- N->right = NIL;
- N->parent = P;
- if (P == NULL) { // There is no parent
- T->root = N; // N is the new root of the tree T.
- return; // insertion complete
- }
- P->child[dir] = N; // insert N as dir-child of P
- // start of the (do while)-loop:
- do {
- if (P->color == BLACK) {
- // Case_I1 (P black):
- return; // insertion complete
- }
- // From now on P is red.
- if ((G = P->parent) == NULL)
- goto Case_I4; // P red and root
- // else: P red and G!=NULL.
- dir = childDir(P); // the side of parent G on which node P is located
- U = G->child[1-dir]; // uncle
- if (U == NIL || U->color == BLACK) // considered black
- goto Case_I56; // P red && U black
- // Case_I2 (P+U red):
- P->color = BLACK;
- U->color = BLACK;
- G->color = RED;
- N = G; // new current node
- // iterate 1 black level higher
- // (= 2 tree levels)
- } while ((P = N->parent) != NULL);
- // end of the (do while)-loop
- // Leaving the (do while)-loop (after having fallen through from Case_I2).
- // Case_I3: N is the root and red.
- return; // insertion complete
+ N->color = RED;
+ N->left = NIL;
+ N->right = NIL;
+ N->parent = P;
+ if (P == NULL) { // There is no parent
+ T->root = N; // N is the new root of the tree T.
+ return; // insertion complete
+ }
+ P->child[dir] = N; // insert N as dir-child of P
+ // start of the (do while)-loop:
+ do {
+ if (P->color == BLACK) {
+ // Case_I1 (P black):
+ return; // insertion complete
+ }
+ // From now on P is red.
+ if ((G = P->parent) == NULL)
+ goto Case_I4; // P red and root
+ // else: P red and G!=NULL.
+ dir = childDir(P); // the side of parent G on which node P is located
+ U = G->child[1-dir]; // uncle
+ if (U == NIL || U->color == BLACK) // considered black
+ goto Case_I56; // P red && U black
+ // Case_I2 (P+U red):
+ P->color = BLACK;
+ U->color = BLACK;
+ G->color = RED;
+ N = G; // new current node
+ // iterate 1 black level higher
+ // (= 2 tree levels)
+ } while ((P = N->parent) != NULL);
+ // end of the (do while)-loop
+ // Leaving the (do while)-loop (after having fallen through from Case_I2).
+ // Case_I3: N is the root and red.
+ return; // insertion complete
Case_I4: // P is the root and red:
- P->color = BLACK;
- return; // insertion complete
+ P->color = BLACK;
+ return; // insertion complete
Case_I56: // P red && U black:
- if (N == P->child[1-dir])
- { // Case_I5 (P red && U black && N inner grandchild of G):
- RotateDir(P,dir); // P is never the root
- N = P; // new current node
- P = G->child[dir]; // new parent of N
- // fall through to Case_I6
- }
- // Case_I6 (P red && U black && N outer grandchild of G):
- RotateDirRoot(T,G,1-dir); // G may be the root
- P->color = BLACK;
- G->color = RED;
- return; // insertion complete
+ if (N == P->child[1-dir])
+ { // Case_I5 (P red && U black && N inner grandchild of G):
+ RotateDir(P,dir); // P is never the root
+ N = P; // new current node
+ P = G->child[dir]; // new parent of N
+ // fall through to Case_I6
+ }
+ // Case_I6 (P red && U black && N outer grandchild of G):
+ RotateDirRoot(T,G,1-dir); // G may be the root
+ P->color = BLACK;
+ G->color = RED;
+ return; // insertion complete
} // end of RBinsert1
void vmt_delete(
- struct vm_tree* T, // -> red–black tree
- struct vm_tree_node* N) // -> node to be deleted
+ struct vm_tree* T, // -> red–black tree
+ struct vm_tree_node* N) // -> node to be deleted
{
- struct vm_tree_node* P = N->parent; // -> parent node of N
- enum vm_tree_direction dir; // side of P on which N is located (∈ { LEFT, RIGHT })
- struct vm_tree_node* S; // -> sibling of N
- struct vm_tree_node* C; // -> close nephew
- struct vm_tree_node* D; // -> distant nephew
+ struct vm_tree_node* P = N->parent; // -> parent node of N
+ enum vm_tree_direction dir; // side of P on which N is located (∈ { LEFT, RIGHT })
+ struct vm_tree_node* S; // -> sibling of N
+ struct vm_tree_node* C; // -> close nephew
+ struct vm_tree_node* D; // -> distant nephew
- // P != NULL, since N is not the root.
- dir = childDir(N); // side of parent P on which the node N is located
- // Replace N at its parent P by NIL:
- P->child[dir] = NIL;
- goto Start_D; // jump into the loop
+ // P != NULL, since N is not the root.
+ dir = childDir(N); // side of parent P on which the node N is located
+ // Replace N at its parent P by NIL:
+ P->child[dir] = NIL;
+ goto Start_D; // jump into the loop
- // start of the (do while)-loop:
- do {
- dir = childDir(N); // side of parent P on which node N is located
+ // start of the (do while)-loop:
+ do {
+ dir = childDir(N); // side of parent P on which node N is located
Start_D:
- S = P->child[1-dir]; // sibling of N (has black height >= 1)
- D = S->child[1-dir]; // distant nephew
- C = S->child[ dir]; // close nephew
- if (S->color == RED)
- goto Case_D3; // S red ===> P+C+D black
- // S is black:
- if (D != NIL && D->color == RED) // not considered black
- goto Case_D6; // D red && S black
- if (C != NIL && C->color == RED) // not considered black
- goto Case_D5; // C red && S+D black
- // Here both nephews are == NIL (first iteration) or black (later).
- if (P->color == RED)
- goto Case_D4; // P red && C+S+D black
- // Case_D1 (P+C+S+D black):
- S->color = RED;
- N = P; // new current node (maybe the root)
- // iterate 1 black level
- // (= 1 tree level) higher
- } while ((P = N->parent) != NULL);
- // end of the (do while)-loop
- // Case_D2 (P == NULL):
- return; // deletion complete
+ S = P->child[1-dir]; // sibling of N (has black height >= 1)
+ D = S->child[1-dir]; // distant nephew
+ C = S->child[ dir]; // close nephew
+ if (S->color == RED)
+ goto Case_D3; // S red ===> P+C+D black
+ // S is black:
+ if (D != NIL && D->color == RED) // not considered black
+ goto Case_D6; // D red && S black
+ if (C != NIL && C->color == RED) // not considered black
+ goto Case_D5; // C red && S+D black
+ // Here both nephews are == NIL (first iteration) or black (later).
+ if (P->color == RED)
+ goto Case_D4; // P red && C+S+D black
+ // Case_D1 (P+C+S+D black):
+ S->color = RED;
+ N = P; // new current node (maybe the root)
+ // iterate 1 black level
+ // (= 1 tree level) higher
+ } while ((P = N->parent) != NULL);
+ // end of the (do while)-loop
+ // Case_D2 (P == NULL):
+ return; // deletion complete
Case_D3: // S red && P+C+D black:
- RotateDirRoot(T,P,dir); // P may be the root
- P->color = RED;
- S->color = BLACK;
- S = C; // != NIL
- // now: P red && S black
- D = S->child[1-dir]; // distant nephew
- if (D != NIL && D->color == RED)
- goto Case_D6; // D red && S black
- C = S->child[ dir]; // close nephew
- if (C != NIL && C->color == RED)
- goto Case_D5; // C red && S+D black
- // Otherwise C+D considered black.
- // fall through to Case_D4
- // Case_D4: // P red && S+C+D black:
- S->color = RED;
- P->color = BLACK;
- return; // deletion complete
+ RotateDirRoot(T,P,dir); // P may be the root
+ P->color = RED;
+ S->color = BLACK;
+ S = C; // != NIL
+ // now: P red && S black
+ D = S->child[1-dir]; // distant nephew
+ if (D != NIL && D->color == RED)
+ goto Case_D6; // D red && S black
+ C = S->child[ dir]; // close nephew
+ if (C != NIL && C->color == RED)
+ goto Case_D5; // C red && S+D black
+ // Otherwise C+D considered black.
+ // fall through to Case_D4
+ // Case_D4: // P red && S+C+D black:
+ S->color = RED;
+ P->color = BLACK;
+ return; // deletion complete
Case_D4: // P red && S+C+D black:
- S->color = RED;
- P->color = BLACK;
- return; // deletion complete
+ S->color = RED;
+ P->color = BLACK;
+ return; // deletion complete
Case_D5: // C red && S+D black:
- RotateDir(S,1-dir); // S is never the root
- S->color = RED;
- C->color = BLACK;
- D = S;
- S = C;
- // now: D red && S black
- // fall through to Case_D6
+ RotateDir(S,1-dir); // S is never the root
+ S->color = RED;
+ C->color = BLACK;
+ D = S;
+ S = C;
+ // now: D red && S black
+ // fall through to Case_D6
Case_D6: // D red && S black:
- RotateDirRoot(T,P,dir); // P may be the root
- S->color = P->color;
- P->color = BLACK;
- D->color = BLACK;
- return; // deletion complete
+ RotateDirRoot(T,P,dir); // P may be the root
+ S->color = P->color;
+ P->color = BLACK;
+ D->color = BLACK;
+ return; // deletion complete
} // end of RBdelete2
enum vm_tree_direction vmn_child_direction(
- struct vm_tree_node *n,
- struct vm_tree_node *p
-)
+ struct vm_tree_node *n,
+ struct vm_tree_node *p
+ )
{
- if (p && (compare_key(&p->key, &n->key) > 0))
- {
- return LEFT;
- }
- return RIGHT;
+ if (p && (compare_key(&p->key, &n->key) > 0))
+ {
+ return LEFT;
+ }
+ return RIGHT;
}
struct vm_tree_node *vmt_search_key(
- struct vm_tree *tree,
- struct vm_tree_key *key)
+ struct vm_tree *tree,
+ struct vm_tree_key *key)
{
- struct vm_tree_node *N = tree->root;
-
- while (N && (compare_key(&N->key, key) != 0))
- {
- if (compare_key(&N->key, key) > 0)
- {
- N = N->left;
- }
- else
- {
- N = N->right;
- }
- }
+ struct vm_tree_node *N = tree->root;
+
+ while (N && (compare_key(&N->key, key) != 0))
+ {
+ if (compare_key(&N->key, key) > 0)
+ {
+ N = N->left;
+ }
+ else
+ {
+ N = N->right;
+ }
+ }
- return N;
+ return N;
}
// search for the predecessor node for a given key
struct vm_tree_node *vmn_predecessor_key(
- struct vm_tree_node *N,
- struct vm_tree_key *key)
+ struct vm_tree_node *N,
+ struct vm_tree_key *key)
{
- struct vm_tree_node *P = NULL;
+ struct vm_tree_node *P = NULL;
- while (N && (compare_key(&N->key, key) != 0))
- {
- if (compare_key(&N->key, key) > 0)
- {
- N = N->left;
- }
- else
- {
- P = N;
- N = N->right;
- }
- }
+ while (N && (compare_key(&N->key, key) != 0))
+ {
+ if (compare_key(&N->key, key) > 0)
+ {
+ N = N->left;
+ }
+ else
+ {
+ P = N;
+ N = N->right;
+ }
+ }
- return P;
+ return P;
}
// search for the successor node for a given key
struct vm_tree_node *vmn_successor_node(
- struct vm_tree_node *N)
+ struct vm_tree_node *N)
{
- if (N && N->right)
- {
- return vmn_min(N->right);
- }
+ if (N && N->right)
+ {
+ return vmn_min(N->right);
+ }
- struct vm_tree_node *p = N->parent;
- while (p && N == p->right)
- {
- N = p;
- p = p->parent;
- }
+ struct vm_tree_node *p = N->parent;
+ while (p && N == p->right)
+ {
+ N = p;
+ p = p->parent;
+ }
- return p;
+ return p;
}
struct vm_tree_node *vmn_min(struct vm_tree_node *node)
{
- while (node && node->left)
- {
- node = node->left;
- }
+ while (node && node->left)
+ {
+ node = node->left;
+ }
- return node;
+ return node;
}
struct vm_tree_node *vmn_max(struct vm_tree_node *node)
{
- while (node && node->right)
- {
- node = node->right;
- }
+ while (node && node->right)
+ {
+ node = node->right;
+ }
- return node;
+ return node;
}
struct vm_object *vmt_get_object(struct vm_tree *tree, void *address)
{
- // find the object for a page.
- struct vm_tree_key key = {(uintptr_t)address, 1};
- struct vm_tree_node *node = vmt_search_key(tree, &key);
- if (node)
- {
- return node->object;
- }
- return NULL;
+ // find the object for a page.
+ struct vm_tree_key key = {(uintptr_t)address, 1};
+ struct vm_tree_node *node = vmt_search_key(tree, &key);
+ if (node)
+ {
+ return node->object;
+ }
+ return NULL;
}
diff --git a/kc/defaults.mk b/kc/defaults.mk
index e44781b..ef4e397 100644
--- a/kc/defaults.mk
+++ b/kc/defaults.mk
@@ -1,4 +1,5 @@
+LDSCRIPT = ../kc.ld
CFLAGS += -fPIC -fvisibility=hidden -mgeneral-regs-only
diff --git a/api/libc/stdio.h b/lib/api/libc/stdio.h
index 63d1ad8..81ee462 100644
--- a/api/libc/stdio.h
+++ b/lib/api/libc/stdio.h
@@ -6,15 +6,15 @@
typedef struct FILE FILE;
-extern FILE *stdin;
extern FILE *stdout;
extern FILE *stderr;
-int fputc(int c, FILE *f);
-int fputs(const char *str, FILE *f);
+extern int fputc(int c, FILE *f);
int vfprintf(FILE *f, const char *restrict format, va_list arguments);
int fprintf(FILE *f, const char *restrict format, ...);
int vprintf(const char *restrict format, va_list arguments);
int printf(const char *restrict format, ...);
+int vsprintf(char *s, const char *restrict format, va_list arguments);
+int sprintf(char *s, const char *restrict format, ...);
diff --git a/api/libc/stdlib.h b/lib/api/libc/stdlib.h
index d1f3d3b..d1f3d3b 100644
--- a/api/libc/stdlib.h
+++ b/lib/api/libc/stdlib.h
diff --git a/api/lib/kstring.h b/lib/api/libc/string.h
index d1d45d5..c28e17c 100644
--- a/api/lib/kstring.h
+++ b/lib/api/libc/string.h
@@ -7,5 +7,8 @@ void *memmove(void *dest, const void *src, size_t size);
void *memset(void *dest, int val, size_t size);
int memcmp(const void *str1, const void *str2, size_t count);
size_t strlen(const char *s);
-unsigned long long strtoull(const char *restrict begin, char **restrict end, int base);
+unsigned long long strtoull(
+ const char *restrict begin,
+ char **restrict end,
+ int base);
diff --git a/api/libc/wchar.h b/lib/api/libc/wchar.h
index 350c209..350c209 100644
--- a/api/libc/wchar.h
+++ b/lib/api/libc/wchar.h
diff --git a/lib/elf64.c b/lib/elf64.c
index b5afc18..38cfc11 100644
--- a/lib/elf64.c
+++ b/lib/elf64.c
@@ -79,7 +79,7 @@ bool elf64_validate_fd(int fd, unsigned type, unsigned machine)
return elf64_validate(&ehdr, type, machine);
}
-static bool is_loadable(Elf64_Phdr const *phdr)
+static bool segment_is_loadable(Elf64_Phdr const *phdr)
{
return phdr != nullptr && phdr->p_type == PT_LOAD;
}
@@ -92,7 +92,7 @@ static size_t aligned_size(Elf64_Phdr const *phdr)
static size_t segment_memsz(Elf64_Phdr const *phdr)
{
- return is_loadable(phdr) ? aligned_size(phdr) : 0;
+ return segment_is_loadable(phdr) ? aligned_size(phdr) : 0;
}
size_t elf64_size(Elf64_Ehdr const *ehdr, Elf64_Phdr *phdrs)
@@ -168,7 +168,7 @@ uintptr_t elf64_dt_val(Elf64_Dyn *dyntab, unsigned long dt_type)
static ssize_t load_segment(int fd, Elf64_Phdr *phdr, size_t buffer_size, char buffer[buffer_size])
{
- if (!is_loadable(phdr))
+ if (!segment_is_loadable(phdr))
{
return 0;
}
diff --git a/lib/heap.c b/lib/heap.c
index 8331a17..03d5425 100644
--- a/lib/heap.c
+++ b/lib/heap.c
@@ -1,23 +1,143 @@
#include <string.h>
#include <stdlib.h>
+#include <sys/mman.h>
+
+#include "config.h"
struct heap_node
{
- struct heap_node *next;
size_t size;
+ union
+ {
+ struct
+ {
+ struct heap_node *prev;
+ struct heap_node *next;
+ };
+ struct
+ {
+ char block;
+ };
+ };
};
struct heap_head
{
- struct heap_node *first;
- size_t total_bytes;
- size_t ready_bytes;
+ size_t allocated_size;
+ size_t maximum_size;
+ size_t minimum_alloc;
+ struct heap_node *root;
};
+struct heap_head *heap;
+
+void *allocate_superblock(void)
+{
+ return mmap(nullptr, HEAP_SEGMENT_SIZE, 0, 0, -1, 0);
+}
+
+static struct heap_node *try_create_heap()
+{
+ if (heap != nullptr) return heap->root;
+
+ char *superblock = allocate_superblock();
+
+ heap = (struct heap_head *)superblock;
+ heap->root = (struct heap_node *)(superblock + sizeof(struct heap_head));
+
+ heap->allocated_size = HEAP_SEGMENT_SIZE;
+ heap->maximum_size = HEAP_MAX_SIZE;
+ heap->minimum_alloc = sizeof(heap->root);
+
+ heap->root->next = nullptr;
+ heap->root->prev = nullptr;
+ heap->root->size = HEAP_SEGMENT_SIZE - sizeof(superblock) - sizeof(heap->root->size);
+
+ return heap->root;
+}
+
+static struct heap_node *try_grow_heap(struct heap_node *prev)
+{
+ if (heap->allocated_size >= heap->maximum_size)
+ {
+ return nullptr;
+ }
+
+ struct heap_node *node = allocate_superblock();
+
+ if (node == nullptr)
+ {
+ return nullptr;
+ }
+
+ node->size = HEAP_SEGMENT_SIZE - sizeof(node->size);
+ node->prev = prev;
+ prev->next = node;
+
+ return node;
+}
+
+static inline size_t get_node_size(size_t size)
+{
+ return size + sizeof(size);
+}
+
+static inline bool can_divide_node(struct heap_node *parent)
+{
+ return parent->size <= heap->minimum_alloc + sizeof(struct heap_node);
+}
+
+static inline void *new_node_address(struct heap_node *parent, size_t size)
+{
+ return &parent->block + parent->size - get_node_size(size);
+}
+
+static inline struct heap_node *divide_node(struct heap_node *parent, size_t size)
+{
+ struct heap_node *child = new_node_address(parent, size);
+
+ parent->size -= get_node_size(size);
+ child->size = size;
+
+ return child;
+}
+
+static inline struct heap_node *try_divide_node(struct heap_node *node, size_t size)
+{
+ return can_divide_node(node) ? divide_node(node, size) : node;
+}
+
+static inline struct heap_node *allocate_node(size_t size)
+{
+ struct heap_node *node = try_create_heap();
+
+ while(node != nullptr)
+ {
+ if (node->size > size)
+ {
+ break;
+ }
+
+ node = node->next
+ ? node->next
+ : try_grow_heap(node);
+ }
+
+ return node;
+}
+
void *malloc(size_t size)
{
- (void)size;
- return nullptr;
+ // TODO: min(heap->minimum_alloc, size);
+ size = size >= heap->minimum_alloc
+ ? size
+ : heap->minimum_alloc;
+
+ struct heap_node *node = try_divide_node(allocate_node(size), size);
+
+ return node != nullptr
+ ? &node->block
+ : nullptr;
}
void *calloc(size_t count, size_t size)
@@ -32,8 +152,28 @@ void *calloc(size_t count, size_t size)
return block;
}
+static inline struct heap_node *block_to_node(char *block)
+{
+ return (struct heap_node *)(block - sizeof(size_t));
+}
+
void free(void *block)
{
- (void)block;
+ // TODO: insertion sort by address of node
+ // TODO: coalesce adjacent nodes
+ if (block == nullptr)
+ {
+ return;
+ }
+
+ struct heap_node *node = block_to_node(block);
+ node->prev = nullptr;
+ node->next = heap->root;
+ heap->root = node;
+
+ if (node->next != nullptr)
+ {
+ node->next->prev = node;
+ }
}
diff --git a/lib/kprintf.c b/lib/kprintf.c
deleted file mode 100644
index 3d803f6..0000000
--- a/lib/kprintf.c
+++ /dev/null
@@ -1,653 +0,0 @@
-#include <lib/kstdio.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <stdbool.h>
-
-enum specifier_type
-{
- INVALID_PRINT,
- CHARACTER_PRINT,
- STRING_PRINT,
- INTEGER_PRINT,
- COUNT_PRINT
-};
-
-enum specifier_flags
-{
- INVALID_FLAGS,
- LEFT_JUSTIFY_FLAG = 0x1,
- EXPLICIT_SIGN_FLAG = 0x2,
- PAD_SIGN_FLAG = 0x4,
- SIGNED_TYPE_FLAG = 0x8,
- SIGN_FLAG_MASK = 0x6,
- ALTERNATE_FORM_FLAG = 0x10,
- ZERO_PAD_FLAG = 0x20,
-};
-
-enum specifier_integer_base
-{
- INVALID_BASE,
- BIN_BASE = 2,
- OCT_BASE = 8,
- DEC_BASE = 10,
- HEX_BASE = 16
-};
-
-enum specifier_integer_width
-{
- INVALID_WIDTH,
- BYTE_WIDTH = 8,
- SHORT_WIDTH = 16,
- INT_WIDTH = 32,
- LONG_WIDTH = 64
-};
-
-struct method
-{
- int (*write_character)(struct method *m, char c);
- int (*write_wcharacter)(struct method *m, wchar_t c);
- int (*write_string)(struct method *m, const char *s);
- int (*write_wstring)(struct method *m, const wchar_t *s);
- void *output;
- int count;
-};
-
-struct specifier
-{
- enum specifier_type type;
- enum specifier_flags flags;
- enum specifier_integer_width integer_width;
- enum specifier_integer_base integer_base;
- int field_width;
- int field_precision;
- size_t length;
-};
-
-static struct specifier parse_specifier(const char *format, va_list *arguments)
-{
- struct specifier result =
- {
- INVALID_PRINT,
- INVALID_FLAGS,
- INVALID_WIDTH,
- INVALID_BASE,
- 0,
- 0,
- 0
- };
-
- // keep a pointer to the beginning of the specifier
- const char *begin = format;
-
- // step 1: scan for flags
- bool flags_parsed = false;
-
- while (!flags_parsed)
- {
- switch (*begin)
- {
- case 0:
- result.type = INVALID_PRINT;
- return result;
- case '-':
- result.flags |= LEFT_JUSTIFY_FLAG;
- begin++;
- break;
- case '+':
- result.flags |= EXPLICIT_SIGN_FLAG;
- begin++;
- break;
- case ' ':
- result.flags |= PAD_SIGN_FLAG;
- begin++;
- break;
- case '#':
- result.flags |= ALTERNATE_FORM_FLAG;
- begin++;
- break;
- case '0':
- result.flags |= ZERO_PAD_FLAG;
- begin++;
- break;
- default:
- flags_parsed = true;
- }
- }
-
- // step 2: parse field width and precision
- // TODO: parse field width and precision
- /* procedure:
- * 1. check if next character is * or .
- * a. if *, field width is the value pointed to by the next item in
- * arguments list
- * b. if ., field width will be set to 0, proceed to 3.
- * 2. if above check is false, check for numeric character
- * a. if is numeric character, parse field width via strtoul, add length
- * of numeric string to begin.
- * b. if is not a numeric character, skip check for width and precision
- * entirely
- * 3. check if next character is * or numeric
- * a. if *, field precision is the value pointed to by the next item
- * in arguments list.
- * b. if is numeric character, parse field precision via strtoul, add
- * length of numeric string to begin.
- */
- bool field_width_parsed = false;
- bool field_precision_parsed = false;
-
- while (!field_width_parsed || !field_precision_parsed)
- {
- switch (*begin)
- {
- case '.':
- if (!field_width_parsed)
- {
- result.field_width = 0;
- field_width_parsed = true;
- begin++;
- }
- else
- {
- // the specifier is invalid!
- result.type = INVALID_PRINT;
- }
- break;
- case '*':
- {
- int w = *va_arg(*arguments, int *);
- if (!field_width_parsed)
- {
- result.field_width = w;
- field_width_parsed = true;
- }
- else
- {
- result.field_precision = w;
- field_precision_parsed = true;
- }
- begin++;
- }
- break;
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- case '0':
- {
- char *next;
- unsigned long long w = strtoull(begin, &next, 10);
- if (!field_width_parsed)
- {
- result.field_width = (int)w;
- field_width_parsed = true;
- }
- else if (!field_precision_parsed)
- {
- result.field_precision = (int)w;
- field_precision_parsed = true;
- }
- if (next > begin)
- {
- begin = next;
- }
- }
- break;
- default:
- field_width_parsed = true;
- field_precision_parsed = true;
- }
- }
-
- // step 3: check for type width arguments
- switch (*begin)
- {
- case 0: // unexpected eos
- result.type = INVALID_PRINT;
- return result;
- case 'h':
- {
- if (begin[0] == begin[1])
- {
- result.integer_width = BYTE_WIDTH;
- begin += 2;
- }
- else
- {
- result.integer_width = SHORT_WIDTH;
- begin++;
- }
- break;
- }
- case 'l':
- {
- // TODO: deal with LLP64? idk.
- if (begin[0] == begin[1])
- {
- begin += 2;
- }
- else
- {
- begin++;
- }
- result.integer_width = LONG_WIDTH;
- break;
- }
- case 'j':
- // TODO: use INTMAX_T_WIDTH
- result.integer_width = 64;
- begin++;
- break;
- case 'z':
- // TODO: use SIZE_T_WIDTH?
- result.integer_width = 64;
- begin++;
- break;
- case 't':
- // TODO: use PTRDIFF_T_WIDTH?
- result.integer_width = 32;
- begin++;
- break;
- default:
- // there is no width argument to be found.
- result.integer_width = INT_WIDTH;
- break;
- }
-
- // step 4: parse field type
- switch (*begin)
- {
- // unexpected EOS
- case 0:
- result.type = INVALID_PRINT;
- return result;
- case 'c':
- result.type = CHARACTER_PRINT;
- break;
- case 's':
- result.type = STRING_PRINT;
- break;
- case 'd':
- case 'i':
- result.type = INTEGER_PRINT;
- result.flags |= SIGNED_TYPE_FLAG;
- result.integer_base = DEC_BASE;
- break;
- case 'u':
- result.type = INTEGER_PRINT;
- result.integer_base = DEC_BASE;
- break;
- case 'b':
- result.type = INTEGER_PRINT;
- result.integer_base = BIN_BASE;
- break;
- case 'o':
- result.type = INTEGER_PRINT;
- result.integer_base = OCT_BASE;
- break;
- case 'x':
- result.type = INTEGER_PRINT;
- result.integer_base = HEX_BASE;
- break;
- case 'p':
- // TODO: use UINTPTR_T_WIDTH here?
- // pointer type overrides all flags
- // i can do what i want it says "implementation-defined" in the spec
- result.field_precision = 16;
- result.type = INTEGER_PRINT;
- result.integer_base = HEX_BASE;
- result.integer_width = LONG_WIDTH;
- result.flags = ALTERNATE_FORM_FLAG|ZERO_PAD_FLAG;
- break;
- case 'n':
- // all flags are invalid/ignored and the current count will be
- // stored in the value pointed to by the argument
- result.type = COUNT_PRINT;
- result.flags = INVALID_FLAGS;
- result.integer_width = INVALID_WIDTH;
- result.field_width = 0;
- result.field_precision = 0;
- break;
- default:
- // this byte of the specifier _must_ be valid. if not,
- // the procedure to print should not proceed as it might
- // output garbage.
- // TODO: specify somehow in the output that the format is bad?
- result.type = INVALID_PRINT;
- return result;
- }
-
- begin++;
-
- result.length = begin - format;
- return result;
-}
-
-static char *convert_integer(
- uint64_t value,
- unsigned base,
- int zpadding,
- char *buffer,
- size_t bufsz)
-{
- static const char *stringdigits = "0123456789abcdef";
-
- // the string will be built from the lower-to-higher value, and the
- // result pointer will point to the first character of the string in
- // the supplied buffer
-
- // cannot currently work with a base > 16
- if (base > 16)
- {
- return NULL;
- }
-
- // make absolutely sure there are no excess bits
-
- // the string is being built backwards, so the pointer needs to be
- // at the last byte of the string
- char *result = buffer + bufsz - 1;
-
- // result >= buffer condition ensures we don't underflow
-
- do
- {
- *--result = stringdigits[value % base];
- zpadding--;
- value /= base;
- }
- while (value > 0 && result >= buffer);
-
- while (zpadding-- > 0 && result >= buffer)
- {
- *--result = '0';
- }
-
- return result;
-}
-
-static int print_character(
- struct method *m,
- struct specifier *spec,
- va_list *arguments)
-{
- (void)spec;
- // all specifier flags and etc. are ignored.
- return m->write_character(m, va_arg(*arguments, int));
-}
-
-static int print_string(
- struct method *m,
- struct specifier *spec,
- va_list *arguments)
-{
- // TODO: respect field width
- if (spec->integer_width == LONG_WIDTH)
- {
- return m->write_wstring(m, va_arg(*arguments, const wchar_t *));
- }
- return m->write_string(m, va_arg(*arguments, const char *));
-}
-
-static inline bool is_negative(uint64_t value, unsigned width)
-{
- switch (width)
- {
- case BYTE_WIDTH:
- return ((int8_t)value) < 0;
- case SHORT_WIDTH:
- return ((int16_t)value) < 0;
- case INT_WIDTH:
- return ((int32_t)value) < 0;
- case LONG_WIDTH:
- return ((int64_t)value) < 0;
- default:
- return false;
- }
-}
-
-static int print_integer(
- struct method *m,
- struct specifier *spec,
- va_list *arguments)
-{
- // 65 bytes is the maximum length that convert_integer will need
- // i.e. conversion of uintmax_t to binary plus NUL terminator
- // TODO: use UINTMAX_T_WIDTH + 1?
- char buffer[65] = {0};
- char *s;
- bool negative = false;
- uint64_t value = 0;
- int r = 0;
- unsigned zpad = 0;
-
- switch (spec->integer_width)
- {
- case BYTE_WIDTH:
- case SHORT_WIDTH:
- case INT_WIDTH:
- value = va_arg(*arguments, unsigned int);
- break;
- case LONG_WIDTH:
- value = va_arg(*arguments, uint64_t);
- break;
- default:
- return -1;
- }
-
- // check if we need to bother with signs
- if (spec->flags & SIGNED_TYPE_FLAG)
- {
- if ((negative = is_negative(value, spec->integer_width)))
- {
- value = ~value + 1;
- }
-
- if (negative)
- {
- r = m->write_character(m, '-');
- }
-
- else if (!negative && (spec->flags & SIGN_FLAG_MASK))
- {
- if (spec->flags & EXPLICIT_SIGN_FLAG)
- {
- r = m->write_character(m, '+');
- }
- else
- {
- r = m->write_character(m, ' ');
- }
- }
- }
-
- // zero all the unnecessary bits
- value &= (2ULL << (spec->integer_width - 1)) - 1;
-
- switch (spec->integer_base)
- {
- case BIN_BASE:
- if (spec->flags & ALTERNATE_FORM_FLAG)
- {
- r = m->write_string(m, "0b");
- }
- break;
- case OCT_BASE:
- if (spec->flags & ALTERNATE_FORM_FLAG)
- {
- r = m->write_character(m, '0');
- }
- break;
- case HEX_BASE:
- if (spec->flags & ALTERNATE_FORM_FLAG)
- {
- r = m->write_string(m, "0x");
- }
- break;
- default:
- break;
- }
-
- if (spec->flags & ZERO_PAD_FLAG)
- {
- zpad = spec->field_precision;
- }
- s = convert_integer(value, spec->integer_base, zpad, buffer, sizeof(buffer));
-
- if (s)
- {
- m->write_string(m, s);
- }
- else
- {
- m->write_string(m, "(INVALID)");
- r = -1;
- }
-
- return r;
-}
-
-static int printf_internal(
- struct method *m,
- const char *restrict format,
- va_list *arguments)
-{
- int r = 0;
-
- while (*format && !r)
- {
- // case 1: not a format specification
- if (*format != '%')
- {
- r = m->write_character(m, *format++);
- continue;
- }
-
- // case 2: looks like a format specification, but isn't
- else if (*format == '%' && format[0] == format[1])
- {
- r = m->write_character(m, '%');
- format += 2;
- continue;
- }
-
- // case 3: is a format specification. parse it
- struct specifier spec = parse_specifier(++format, arguments);
-
- switch (spec.type)
- {
- case CHARACTER_PRINT:
- r = print_character(m, &spec, arguments);
- break;
- case STRING_PRINT:
- r = print_string(m, &spec, arguments);
- break;
- case INTEGER_PRINT:
- r = print_integer(m, &spec, arguments);
- break;
- default:
- r = m->write_string(m, "(INVALID)");
- return -1;
- }
- format += spec.length;
- }
-
- return r;
-}
-
-static int kfp_write_character(struct method *m, char c)
-{
- kfputc((int)c, (FILE *)m->output);
- m->count++;
- return 0;
-}
-
-static int kfp_write_wcharacter(struct method *m, wchar_t c)
-{
- kfputc((int)c, (FILE *)m->output);
- m->count++;
- return 0;
-}
-
-static int kfp_write_string(struct method *m, const char *c)
-{
- while (*c)
- {
- m->write_character(m, *c++);
- }
- return 0;
-}
-
-static int kfp_write_wstring(struct method *m, const wchar_t *s)
-{
- while (*s)
- {
- m->write_wcharacter(m, *s++);
- }
- return 0;
-}
-
-int kvfprintf(FILE *f, const char *restrict format, va_list arguments)
-{
- struct method m = {
- kfp_write_character,
- kfp_write_wcharacter,
- kfp_write_string,
- kfp_write_wstring,
- (void *)f,
- 0};
- va_list acopy;
- va_copy(acopy, arguments);
- int r = printf_internal(&m, format, &acopy);
- va_end(acopy);
-
- if (!r)
- {
- return m.count;
- }
- else
- {
- return -1;
- }
-}
-
-int kfprintf(FILE *f, const char *restrict format, ...)
-{
- va_list arguments;
- va_start(arguments, format);
-
- int count = kvfprintf(f, format, arguments);
-
- va_end(arguments);
-
- return count;
-}
-
-int kvprintf(const char *restrict format, va_list arguments)
-{
- va_list acopy;
- va_copy(acopy, arguments);
-
- int count = kvfprintf(kstdout, format, arguments);
-
- va_end(acopy);
-
- return count;
-}
-
-int kprintf(const char *restrict format, ...)
-{
- va_list arguments;
- va_start(arguments, format);
-
- int count = kvprintf(format, arguments);
-
- va_end(arguments);
-
- return count;
-}
-
diff --git a/lib/memcmp.c b/lib/libc/memcmp.c
index 2348afe..2348afe 100644
--- a/lib/memcmp.c
+++ b/lib/libc/memcmp.c
diff --git a/lib/memcpy.c b/lib/libc/memcpy.c
index 58b1e40..58b1e40 100644
--- a/lib/memcpy.c
+++ b/lib/libc/memcpy.c
diff --git a/lib/memmove.c b/lib/libc/memmove.c
index fd06bb6..fd06bb6 100644
--- a/lib/memmove.c
+++ b/lib/libc/memmove.c
diff --git a/lib/memset.c b/lib/libc/memset.c
index 3e7025e..3e7025e 100644
--- a/lib/memset.c
+++ b/lib/libc/memset.c
diff --git a/lib/printf.c b/lib/libc/printf.c
index 4fd14e9..fa68bcc 100644
--- a/lib/printf.c
+++ b/lib/libc/printf.c
@@ -568,22 +568,43 @@ static int kfp_write_character(struct method *m, char c)
static int kfp_write_wcharacter(struct method *m, wchar_t c)
{
- (void)m;
- (void)c;
- return -1;
+ fputc((int)c, (FILE *)m->output);
+ m->count++;
+ return 0;
+}
+
+static int naive_write_string(struct method *m, const char *c)
+{
+ while (*c)
+ {
+ m->write_character(m, *c++);
+ }
+ return 0;
}
-static int kfp_write_string(struct method *m, const char *s)
+static int naive_write_wstring(struct method *m, const wchar_t *s)
{
- m->count += fputs(s, (FILE *)m->output);
+ while (*s)
+ {
+ m->write_wcharacter(m, *s++);
+ }
return 0;
}
-static int kfp_write_wstring(struct method *m, const wchar_t *s)
+static int ss_write_char(struct method *m, const char c)
+{
+ char *s = (char *)m->output;
+ *s++ = c;
+ m->count++;
+ return 0;
+}
+
+static int ss_write_wchar(struct method *m, const wchar_t c)
{
- (void)m;
- (void)s;
- return -1;
+ wchar_t *s = (wchar_t *)m->output;
+ *s++ = c;
+ m->count++;
+ return 0;
}
int vfprintf(FILE *f, const char *restrict format, va_list arguments)
@@ -591,8 +612,8 @@ int vfprintf(FILE *f, const char *restrict format, va_list arguments)
struct method m = {
kfp_write_character,
kfp_write_wcharacter,
- kfp_write_string,
- kfp_write_wstring,
+ naive_write_string,
+ naive_write_wstring,
(void *)f,
0};
va_list acopy;
@@ -646,3 +667,46 @@ int printf(const char *restrict format, ...)
return count;
}
+int vsprintf(char *s, const char *restrict format, va_list arguments)
+{
+ va_list acopy;
+ va_copy(acopy, arguments);
+
+ struct method m =
+ {
+ ss_write_char,
+ ss_write_wchar,
+ naive_write_string,
+ naive_write_wstring,
+ (void *)s,
+ 0
+ };
+
+ int r = printf_internal(&m, format, &acopy);
+ va_end(acopy);
+
+ if (!r)
+ {
+ return m.count;
+ }
+ else
+ {
+ return -1;
+ }
+
+ return r;
+}
+
+int sprintf(char *s, const char *restrict format, ...)
+{
+ va_list arguments;
+ va_start(arguments, format);
+
+ int count = vsprintf(s, format, arguments);
+
+ va_end(arguments);
+
+ return count;
+}
+
+
diff --git a/lib/stdio.c b/lib/libc/stdio.c
index 70cc685..70cc685 100644
--- a/lib/stdio.c
+++ b/lib/libc/stdio.c
diff --git a/lib/string.c b/lib/libc/string.c
index 2da2070..2da2070 100644
--- a/lib/string.c
+++ b/lib/libc/string.c
diff --git a/rules.mk b/rules.mk
index 756184e..87b5739 100644
--- a/rules.mk
+++ b/rules.mk
@@ -15,23 +15,24 @@ COMPILE.info = $(info $$(CC) $@)
%.os:
$(LINK.info)
- $(LINK.os)
+ @$(LINK.os)
%.debug.os: %.os
- $(OBJCOPY) --only-keep-debug $< $@
+ $(OBJCOPY.info)
+ @$(OBJCOPY) --only-keep-debug $< $@
@$(OBJCOPY) --strip-debug $<
%.o: %.c
$(COMPILE.info)
- $(COMPILE.c) -MMD -MP
+ @$(COMPILE.c) -MMD -MP
%.o: %.cpp
$(COMPILE.info)
- $(COMPILE.cpp) -MMD -MP
+ @$(COMPILE.cpp) -MMD -MP
%.o: %.S
$(COMPILE.info)
- $(COMPILE.S) -MMD -MP
+ @$(COMPILE.S) -MMD -MP
clean:
$(info $$(RM) $(CLEANLIST))
diff --git a/service/Makefile b/service/Makefile
index b78cac3..e9c74d5 100644
--- a/service/Makefile
+++ b/service/Makefile
@@ -4,12 +4,12 @@ LDFLAGS += -z max-page-size=4096 --export-dynamic -pic \
-z separate-code -pie -Bsymbolic -shared \
-z noexecstack -g
-VPATH := ../lib arch/x86_64/ lib
+VPATH := ../lib ../lib/libc arch/x86_64/ lib
TARGET := kjarna.os
.DEFAULT: $(TARGET)
-CPPFLAGS += -I../api/posix -I../api/libc -I../api -I.
+CPPFLAGS += -I../api/posix -I../lib/api -I../api -I.
CFLAGS += -fPIC -fvisibility=hidden -mgeneral-regs-only
diff --git a/service/config.h b/service/config.h
index b438f0b..8d3132e 100644
--- a/service/config.h
+++ b/service/config.h
@@ -2,5 +2,8 @@
#define KJARNA_REVISION 2
-const char * const HAL_PATH = "/service/kjarna/kernel.os";
+extern const char * const HAL_PATH;
+
+#define HEAP_SEGMENT_SIZE 0x4000
+#define HEAP_MAX_SIZE 0x80000000
diff --git a/service/main.c b/service/main.c
index e2c705b..788cffc 100644
--- a/service/main.c
+++ b/service/main.c
@@ -6,6 +6,7 @@
#include "config.h"
#include <lib/elf.h>
+const char * const HAL_PATH = "/service/kjarna/kernel.os";
static int open_kernel(void)
{
@@ -44,6 +45,8 @@ int main(int argc, char **argv)
printf("kjarna %d\n", KJARNA_REVISION);
int kernel_fd = open_kernel();
+ while (1);
+
(void)kernel_fd;
return 0;
}