summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile4
-rw-r--r--build.zig118
-rw-r--r--compile_flags.txt2
-rw-r--r--config/gdbinit (renamed from util/gdbinit)0
-rw-r--r--config/grub.cfg (renamed from grub.cfg)0
-rw-r--r--config/kernel.ld (renamed from kernel/kernel.ld)0
-rw-r--r--config/user.ld (renamed from user/user.ld)0
-rw-r--r--include/lib.h8
-rw-r--r--include/limits.h12
-rw-r--r--include/stdbool.h17
-rw-r--r--include/time.h63
-rw-r--r--kernel/cpu/idt.c90
-rw-r--r--kernel/drivers/clock.c150
-rw-r--r--kernel/drivers/drivers.c3
-rw-r--r--kernel/drivers/pci.c6
-rw-r--r--kernel/drivers/tty.c8
-rw-r--r--kernel/include/comus/drivers/tty.h2
l---------kernel/include/comus/error.h1
-rw-r--r--kernel/include/comus/fs.h5
-rw-r--r--kernel/include/comus/memory.h54
-rw-r--r--kernel/include/comus/time.h39
-rw-r--r--kernel/include/lib.h20
-rw-r--r--kernel/include/lib/kctype.h22
-rw-r--r--kernel/include/lib/kio.h91
-rw-r--r--kernel/include/lib/klib.h196
-rw-r--r--kernel/include/lib/kstring.h154
-rw-r--r--kernel/lib/atox.c29
-rw-r--r--kernel/lib/bound.c12
-rw-r--r--kernel/lib/btoa.c43
-rw-r--r--kernel/lib/ctoi.c14
-rw-r--r--kernel/lib/fputc.c10
-rw-r--r--kernel/lib/isdigit.c6
-rw-r--r--kernel/lib/isspace.c16
-rw-r--r--kernel/lib/itoc.c10
-rw-r--r--kernel/lib/kalloc.c210
-rw-r--r--kernel/lib/kprintf.c576
-rw-r--r--kernel/lib/memcmp.c9
-rw-r--r--kernel/lib/memcpy.c10
-rw-r--r--kernel/lib/memcpyv.c (renamed from lib/memcpyv.c)2
-rw-r--r--kernel/lib/memmove.c20
-rw-r--r--kernel/lib/memmovev.c (renamed from lib/memmovev.c)2
-rw-r--r--kernel/lib/memset.c10
-rw-r--r--kernel/lib/memsetv.c (renamed from lib/memsetv.c)2
-rw-r--r--kernel/lib/panic.c6
-rw-r--r--kernel/lib/stpcpy.c9
-rw-r--r--kernel/lib/stpncpy.c10
-rw-r--r--kernel/lib/strcat.c7
-rw-r--r--kernel/lib/strcpy.c9
-rw-r--r--kernel/lib/strlen.c9
-rw-r--r--kernel/lib/strncmp.c11
-rw-r--r--kernel/lib/strncpy.c10
-rw-r--r--kernel/lib/strtoux.c43
-rw-r--r--kernel/lib/strtox.c52
-rw-r--r--kernel/lib/uxtoa.c27
-rw-r--r--kernel/lib/xtoa.c31
-rw-r--r--kernel/main.c (renamed from kernel/kernel.c)11
-rw-r--r--kernel/mboot/mmap.c6
-rw-r--r--kernel/memory/paging.c15
-rw-r--r--kernel/memory/physalloc.c17
-rw-r--r--kernel/memory/virtalloc.c4
-rw-r--r--user/include/ctype.h (renamed from include/ctype.h)0
-rw-r--r--user/include/elf.h (renamed from include/elf.h)0
-rw-r--r--user/include/error.h (renamed from include/error.h)0
-rw-r--r--user/include/stdio.h (renamed from include/stdio.h)16
-rw-r--r--user/include/stdlib.h (renamed from include/stdlib.h)32
-rw-r--r--user/include/string.h (renamed from include/string.h)32
-rw-r--r--user/include/unistd.h (renamed from include/unistd.h)92
-rw-r--r--user/lib/alloc.c (renamed from lib/alloc.c)4
-rw-r--r--user/lib/atox.c (renamed from lib/atox.c)0
-rw-r--r--user/lib/bound.c (renamed from lib/bound.c)0
-rw-r--r--user/lib/btoa.c (renamed from lib/btoa.c)0
-rw-r--r--user/lib/ctoi.c (renamed from lib/ctoi.c)0
-rw-r--r--user/lib/delay.c (renamed from lib/delay.c)0
-rw-r--r--user/lib/entry.S (renamed from ulib/entry.S)0
-rw-r--r--user/lib/isdigit.c (renamed from lib/isdigit.c)0
-rw-r--r--user/lib/isspace.c (renamed from lib/isspace.c)0
-rw-r--r--user/lib/itoc.c (renamed from lib/itoc.c)0
-rw-r--r--user/lib/memcmp.c (renamed from lib/memcmp.c)0
-rw-r--r--user/lib/memcpy.c (renamed from lib/memcpy.c)0
-rw-r--r--user/lib/memmove.c (renamed from lib/memmove.c)0
-rw-r--r--user/lib/memset.c (renamed from lib/memset.c)0
-rw-r--r--user/lib/printf.c (renamed from lib/printf.c)0
-rw-r--r--user/lib/spawn.c (renamed from ulib/spawn.c)0
-rw-r--r--user/lib/stpcpy.c (renamed from lib/stpcpy.c)0
-rw-r--r--user/lib/stpncpy.c (renamed from lib/stpncpy.c)0
-rw-r--r--user/lib/strcat.c (renamed from lib/strcat.c)0
-rw-r--r--user/lib/strcpy.c (renamed from lib/strcpy.c)0
-rw-r--r--user/lib/strlen.c (renamed from lib/strlen.c)0
-rw-r--r--user/lib/strncmp.c (renamed from lib/strncmp.c)0
-rw-r--r--user/lib/strncpy.c (renamed from lib/strncpy.c)0
-rw-r--r--user/lib/strtoux.c (renamed from lib/strtoux.c)0
-rw-r--r--user/lib/strtox.c (renamed from lib/strtox.c)0
-rw-r--r--user/lib/syscall.S (renamed from ulib/syscall.S)0
-rw-r--r--user/lib/timetostr.c (renamed from lib/timetostr.c)0
-rw-r--r--user/lib/uxtoa.c (renamed from lib/uxtoa.c)0
-rw-r--r--user/lib/xtoa.c (renamed from lib/xtoa.c)0
-rw-r--r--util/BuildImage.c420
-rw-r--r--util/default.ld247
-rw-r--r--util/listblob.c240
-rw-r--r--util/mkblob.c321
100 files changed, 1954 insertions, 1773 deletions
diff --git a/Makefile b/Makefile
index 1fda095..fe068f9 100644
--- a/Makefile
+++ b/Makefile
@@ -19,7 +19,7 @@ qemu-gdb: bin/os.iso
$(QEMU) $(QEMUOPTS) -S -gdb tcp::1337
gdb:
- gdb -q -n -x util/gdbinit
+ gdb -q -n -x config/gdbinit
clean:
rm -fr .zig-cache
@@ -30,7 +30,7 @@ build:
bin/os.iso: build
mkdir -p bin/iso/boot/grub
- cp grub.cfg bin/iso/boot/grub
+ cp config/grub.cfg bin/iso/boot/grub
cp bin/kernel bin/iso/boot
grub-mkrescue -o bin/os.iso bin/iso 2>/dev/null
diff --git a/build.zig b/build.zig
index 276d6fb..2fd98c5 100644
--- a/build.zig
+++ b/build.zig
@@ -20,11 +20,9 @@ const c_flags = &[_][]const u8{
"-ggdb",
};
-const boot_src = &[_][]const u8{"boot/boot.S"};
-
const kernel_src = &[_][]const u8{
"kernel/entry.S", // must be first
- "kernel/kernel.c", // main function
+ "kernel/main.c", // main function
"kernel/cpu/cpu.c",
"kernel/cpu/fpu.c",
"kernel/cpu/idt.c",
@@ -36,8 +34,34 @@ const kernel_src = &[_][]const u8{
"kernel/drivers/tty.c",
"kernel/drivers/uart.c",
"kernel/fs/fs.c",
- "kernel/lib/fputc.c",
+ "kernel/lib/atox.c",
+ "kernel/lib/bound.c",
+ "kernel/lib/btoa.c",
+ "kernel/lib/ctoi.c",
+ "kernel/lib/isdigit.c",
+ "kernel/lib/isspace.c",
+ "kernel/lib/itoc.c",
+ "kernel/lib/kalloc.c",
+ "kernel/lib/kprintf.c",
+ "kernel/lib/memcmp.c",
+ "kernel/lib/memcpy.c",
+ "kernel/lib/memcpyv.c",
+ "kernel/lib/memmove.c",
+ "kernel/lib/memmovev.c",
+ "kernel/lib/memset.c",
+ "kernel/lib/memsetv.c",
"kernel/lib/panic.c",
+ "kernel/lib/stpcpy.c",
+ "kernel/lib/stpncpy.c",
+ "kernel/lib/strcat.c",
+ "kernel/lib/strcpy.c",
+ "kernel/lib/strlen.c",
+ "kernel/lib/strncmp.c",
+ "kernel/lib/strncpy.c",
+ "kernel/lib/strtoux.c",
+ "kernel/lib/strtox.c",
+ "kernel/lib/uxtoa.c",
+ "kernel/lib/xtoa.c",
"kernel/mboot/mboot.c",
"kernel/mboot/mmap.c",
"kernel/memory/memory.c",
@@ -46,61 +70,11 @@ const kernel_src = &[_][]const u8{
"kernel/memory/virtalloc.c",
};
-const lib_src = &[_][]const u8{
- "lib/alloc.c",
- "lib/atox.c",
- "lib/bound.c",
- "lib/btoa.c",
- "lib/ctoi.c",
- "lib/delay.c",
- "lib/isdigit.c",
- "lib/isspace.c",
- "lib/itoc.c",
- "lib/memcmp.c",
- "lib/memcpy.c",
- "lib/memcpyv.c",
- "lib/memmove.c",
- "lib/memmovev.c",
- "lib/memset.c",
- "lib/memsetv.c",
- "lib/printf.c",
- "lib/stpcpy.c",
- "lib/stpncpy.c",
- "lib/strcat.c",
- "lib/strcpy.c",
- "lib/strlen.c",
- "lib/strncmp.c",
- "lib/strncpy.c",
- "lib/strtoux.c",
- "lib/strtox.c",
- "lib/timetostr.c",
- "lib/uxtoa.c",
- "lib/xtoa.c",
-};
-
const Prog = struct {
name: []const u8,
source: []const []const u8,
};
-const util_progs = &[_]Prog{
- // mkblob
- Prog{
- .name = "mkblob",
- .source = &[_][]const u8{"util/mkblob.c"},
- },
- // listblob
- Prog{
- .name = "listblob",
- .source = &[_][]const u8{"util/listblob.c"},
- },
- // BuildImage
- Prog{
- .name = "BuildImage",
- .source = &[_][]const u8{"util/BuildImage.c"},
- },
-};
-
const AddSourcesOpts = struct { exe: *std.Build.Step.Compile, sources: []const []const []const u8, c_flags: []const []const u8 };
fn add_sources(b: *std.Build, opts: AddSourcesOpts) void {
@@ -138,8 +112,7 @@ fn build_kern_binary(b: *std.Build, opts: BuildKernBinaryOpts) void {
.strip = opts.strip,
});
- // add include paths
- exe.addIncludePath(b.path("include/"));
+ // add include path
if (opts.include != null) {
exe.addIncludePath(b.path(opts.include.?));
}
@@ -198,12 +171,6 @@ fn build_native_binary(b: *std.Build, opts: BuildNativeBinaryOpts) void {
pub fn build(b: *std.Build) !void {
// context
- const target32 = std.Build.resolveTargetQuery(b, .{
- .cpu_arch = std.Target.Cpu.Arch.x86,
- .os_tag = std.Target.Os.Tag.freestanding,
- .abi = std.Target.Abi.gnu,
- .ofmt = std.Target.ObjectFormat.elf,
- });
const target64 = std.Build.resolveTargetQuery(b, .{
.cpu_arch = std.Target.Cpu.Arch.x86_64,
.os_tag = std.Target.Os.Tag.freestanding,
@@ -212,19 +179,6 @@ pub fn build(b: *std.Build) !void {
});
const optimize = std.builtin.OptimizeMode.ReleaseFast;
- // boot
- build_kern_binary(b, .{
- .name = "boot",
- .target = target32,
- .optimize = optimize,
- .sources = &.{
- boot_src,
- },
- .linker = "boot/boot.ld",
- .entry = "bootentry",
- .include = "boot/include",
- });
-
// kernel
build_kern_binary(b, .{
.name = "kernel",
@@ -232,20 +186,8 @@ pub fn build(b: *std.Build) !void {
.optimize = optimize,
.sources = &.{
kernel_src,
- lib_src,
},
- .linker = "kernel/kernel.ld",
+ .linker = "config/kernel.ld",
.include = "kernel/include",
});
-
- // util_progs
- for (util_progs) |prog| {
- build_native_binary(b, .{
- .name = prog.name,
- .optimize = optimize,
- .sources = &.{
- prog.source,
- },
- });
- }
}
diff --git a/compile_flags.txt b/compile_flags.txt
index 18bbfbc..611c77e 100644
--- a/compile_flags.txt
+++ b/compile_flags.txt
@@ -1,7 +1,7 @@
-c
-std=c11
--Iinclude
-Ikernel/include
+-Iuser/include
-ffreestanding
-fno-builtin
-Wall
diff --git a/util/gdbinit b/config/gdbinit
index ca2c885..ca2c885 100644
--- a/util/gdbinit
+++ b/config/gdbinit
diff --git a/grub.cfg b/config/grub.cfg
index 6cedb28..6cedb28 100644
--- a/grub.cfg
+++ b/config/grub.cfg
diff --git a/kernel/kernel.ld b/config/kernel.ld
index 0806257..0806257 100644
--- a/kernel/kernel.ld
+++ b/config/kernel.ld
diff --git a/user/user.ld b/config/user.ld
index 9e31dff..9e31dff 100644
--- a/user/user.ld
+++ b/config/user.ld
diff --git a/include/lib.h b/include/lib.h
deleted file mode 100644
index e8e921d..0000000
--- a/include/lib.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#include <ctype.h>
-#include <error.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <string.h>
-#include <limits.h>
diff --git a/include/limits.h b/include/limits.h
deleted file mode 100644
index d4a3190..0000000
--- a/include/limits.h
+++ /dev/null
@@ -1,12 +0,0 @@
-/**
- * @file limits.h
- *
- * @author Freya Murphy <freya@freyacat.org>
- *
- * System limits
- */
-
-#define MAX_FILE_NAME_LEN 256
-#define MAX_OPEN_FILES 256
-
-#define MAX_DISKS 8
diff --git a/include/stdbool.h b/include/stdbool.h
deleted file mode 100644
index dddf1c9..0000000
--- a/include/stdbool.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/**
- * @file stdbool.h
- * @author Freya Murphy <freya@freyacat.org>
- * @author Warren R. Carithers
- *
- * Boolean definitions.
- */
-
-#ifndef _STDBOOL_H
-#define _STDBOOL_H
-
-// Boolean values
-typedef _Bool bool;
-#define true 1
-#define false 0
-
-#endif /* stdbool.h */
diff --git a/include/time.h b/include/time.h
deleted file mode 100644
index 4d339a0..0000000
--- a/include/time.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/**
- * @file time.h
- *
- * @author Freya Murphy <freya@freyacat.org>
- *
- * System time structure
- */
-
-#ifndef TIME_H_
-#define TIME_H_
-
-#include <stddef.h>
-
-typedef struct {
- int sec; /// Seconds [0,59]
- int min; /// Minutes [0,59]
- int hour; /// Hour [0,23]
- int mday; /// Day of month [1,31]
- int mon; /// Month of year [0,11]
- int year; /// Years since 1900
- int wday; /// Day of week [0,6] (Sunday = 0)
- int yday; /// Day of year [0,365]
- int yn; /// Year number [0,99]
- int cen; /// Century [19,20]
- int leap; /// If year is a leap year (True == 1)
-} time_t;
-
-typedef enum {
- TZ_UTC = 0,
- TZ_EST = -5,
- TZ_EDT = -4,
-} timezone_t;
-
-/**
- * Sets the current timezone
- */
-extern void set_timezone(timezone_t tz);
-
-/**
- * Returns current time in UTC
- */
-extern time_t get_utctime(void);
-
-/**
- * Returns current time from current Timezone
- */
-extern time_t get_localtime(void);
-
-/**
- * Return the time on the system clock
- */
-extern size_t get_systemtime(void);
-
-/**
- * Converts the time into a string format
- *
- * @param time - the current time
- * @param format - see manpage for date
- * @param buf - the buffer to store it in
- */
-extern void timetostr(time_t *time, char *format, char *buf, size_t n);
-
-#endif /* time.h */
diff --git a/kernel/cpu/idt.c b/kernel/cpu/idt.c
index 748826c..51fb125 100644
--- a/kernel/cpu/idt.c
+++ b/kernel/cpu/idt.c
@@ -72,63 +72,63 @@ void idt_init(void)
static void isr_print_regs(regs_t *regs)
{
- printf("rax: %#016lx (%lu)\n", regs->rax, regs->rax);
- printf("rbx: %#016lx (%lu)\n", regs->rbx, regs->rbx);
- printf("rcx: %#016lx (%lu)\n", regs->rcx, regs->rcx);
- printf("rdx: %#016lx (%lu)\n", regs->rdx, regs->rdx);
- printf("rsi: %#016lx (%lu)\n", regs->rsi, regs->rsi);
- printf("rdi: %#016lx (%lu)\n", regs->rdi, regs->rdi);
- printf("rsp: %#016lx (%lu)\n", regs->rsp, regs->rsp);
- printf("rbp: %#016lx (%lu)\n", regs->rbp, regs->rbp);
- printf("r8 : %#016lx (%lu)\n", regs->r8, regs->r8);
- printf("r9 : %#016lx (%lu)\n", regs->r9, regs->r9);
- printf("r10: %#016lx (%lu)\n", regs->r10, regs->r10);
- printf("r11: %#016lx (%lu)\n", regs->r11, regs->r11);
- printf("r12: %#016lx (%lu)\n", regs->r12, regs->r12);
- printf("r13: %#016lx (%lu)\n", regs->r13, regs->r13);
- printf("r14: %#016lx (%lu)\n", regs->r14, regs->r14);
- printf("r15: %#016lx (%lu)\n", regs->r15, regs->r15);
- printf("rip: %#016lx (%lu)\n", regs->rip, regs->rip);
- printf("rflags: %#016lx (%lu)\n", (uint64_t)regs->rflags.raw,
+ kprintf("rax: %#016lx (%lu)\n", regs->rax, regs->rax);
+ kprintf("rbx: %#016lx (%lu)\n", regs->rbx, regs->rbx);
+ kprintf("rcx: %#016lx (%lu)\n", regs->rcx, regs->rcx);
+ kprintf("rdx: %#016lx (%lu)\n", regs->rdx, regs->rdx);
+ kprintf("rsi: %#016lx (%lu)\n", regs->rsi, regs->rsi);
+ kprintf("rdi: %#016lx (%lu)\n", regs->rdi, regs->rdi);
+ kprintf("rsp: %#016lx (%lu)\n", regs->rsp, regs->rsp);
+ kprintf("rbp: %#016lx (%lu)\n", regs->rbp, regs->rbp);
+ kprintf("r8 : %#016lx (%lu)\n", regs->r8, regs->r8);
+ kprintf("r9 : %#016lx (%lu)\n", regs->r9, regs->r9);
+ kprintf("r10: %#016lx (%lu)\n", regs->r10, regs->r10);
+ kprintf("r11: %#016lx (%lu)\n", regs->r11, regs->r11);
+ kprintf("r12: %#016lx (%lu)\n", regs->r12, regs->r12);
+ kprintf("r13: %#016lx (%lu)\n", regs->r13, regs->r13);
+ kprintf("r14: %#016lx (%lu)\n", regs->r14, regs->r14);
+ kprintf("r15: %#016lx (%lu)\n", regs->r15, regs->r15);
+ kprintf("rip: %#016lx (%lu)\n", regs->rip, regs->rip);
+ kprintf("rflags: %#016lx (%lu)\n", (uint64_t)regs->rflags.raw,
(uint64_t)regs->rflags.raw);
- puts("rflags: ");
+ kputs("rflags: ");
if (regs->rflags.cf)
- puts("CF ");
+ kputs("CF ");
if (regs->rflags.pf)
- puts("PF ");
+ kputs("PF ");
if (regs->rflags.af)
- puts("AF ");
+ kputs("AF ");
if (regs->rflags.zf)
- puts("ZF ");
+ kputs("ZF ");
if (regs->rflags.sf)
- puts("SF ");
+ kputs("SF ");
if (regs->rflags.tf)
- puts("TF ");
+ kputs("TF ");
if (regs->rflags.if_)
- puts("IF ");
+ kputs("IF ");
if (regs->rflags.df)
- puts("DF ");
+ kputs("DF ");
if (regs->rflags.of)
- puts("OF ");
+ kputs("OF ");
if (regs->rflags.iopl)
- puts("IOPL ");
+ kputs("IOPL ");
if (regs->rflags.nt)
- puts("NT ");
+ kputs("NT ");
if (regs->rflags.md)
- puts("MD ");
+ kputs("MD ");
if (regs->rflags.rf)
- puts("RF ");
+ kputs("RF ");
if (regs->rflags.vm)
- puts("VM ");
+ kputs("VM ");
if (regs->rflags.ac)
- puts("AC ");
+ kputs("AC ");
if (regs->rflags.vif)
- puts("VIF ");
+ kputs("VIF ");
if (regs->rflags.vip)
- puts("VIP ");
+ kputs("VIP ");
if (regs->rflags.id)
- puts("ID ");
- puts("\n");
+ kputs("ID ");
+ kputs("\n");
}
#define EX_DEBUG 0x01
@@ -179,23 +179,23 @@ void idt_exception_handler(uint64_t exception, uint64_t code, regs_t *state)
case EX_PAGE_FAULT:
// page faults store the offending address in cr2
__asm__ volatile("mov %%cr2, %0" : "=r"(cr2));
- if (!load_page((void *)cr2))
+ if (!kload_page((void *)cr2))
return;
}
- puts("\n\n!!! EXCEPTION !!!\n");
- printf("%#02lX %s\n", exception, EXCEPTIONS[exception]);
- printf("Error code %#lX\n", code);
+ kputs("\n\n!!! EXCEPTION !!!\n");
+ kprintf("%#02lX %s\n", exception, EXCEPTIONS[exception]);
+ kprintf("Error code %#lX\n", code);
if (exception == EX_PAGE_FAULT) {
- printf("Page fault address: %#016lx\n", cr2);
+ kprintf("Page fault address: %#016lx\n", cr2);
}
- puts("\n");
+ kputs("\n");
isr_print_regs(state);
- puts("\n");
+ kputs("\n");
while (1) {
halt();
diff --git a/kernel/drivers/clock.c b/kernel/drivers/clock.c
index dd229dc..fadd938 100644
--- a/kernel/drivers/clock.c
+++ b/kernel/drivers/clock.c
@@ -1,6 +1,6 @@
#include <lib.h>
-#include <time.h>
#include <comus/asm.h>
+#include <comus/time.h>
#include <comus/drivers/clock.h>
#define CMOS_WRITE_PORT 0x70
@@ -15,18 +15,6 @@
#define CMOS_REG_YEAR 0x09
#define CMOS_REG_CEN 0x32
-// Live buffers to work on data
-static time_t time;
-static time_t localtime;
-
-// Front buffers so interupts dont request data that is half done
-static time_t curr_time;
-static time_t curr_localtime;
-
-// Current set time Zone
-static timezone_t curr_timezone = TZ_UTC;
-static timezone_t last_timezone = TZ_UTC;
-
static uint8_t cmos_read(uint8_t reg)
{
uint8_t hex, ret;
@@ -43,124 +31,40 @@ static uint8_t cmos_read(uint8_t reg)
static int mday_offset[12] = { 0, 31, 59, 90, 120, 151,
181, 212, 243, 273, 304, 334 };
-static int month_days[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
-
-static void update_localtime(void)
-{
- int change, max;
-
- // set localtime
- localtime = time;
-
- // if tz is UTC, we dont need to do anythin
- if (last_timezone == TZ_UTC)
- return;
-
- localtime.hour += last_timezone;
-
- // check if day rolled over
- change = localtime.hour < 0 ? -1 : localtime.hour >= 24 ? 1 : 0;
- if (!change)
- return;
-
- // roll over day
- localtime.hour = (localtime.hour + 24) % 24;
- localtime.wday = (localtime.wday + change + 7) % 7;
- localtime.mday += change;
- localtime.yday += change;
-
- // check if month rolled over
- max = month_days[localtime.mon];
- if (localtime.leap && localtime.mon == 1)
- max++;
- change = localtime.mday < 0 ? -1 : localtime.mday >= max ? 1 : 0;
- if (!change)
- return;
-
- // roll over month
- localtime.mon = (localtime.mon + change + 12) % 12;
-
- // check if year rolled over
- max = localtime.leap ? 366 : 365;
- change = localtime.yday < 0 ? -1 : localtime.yday >= max ? 1 : 0;
- if (!change)
- return;
-
- // roll over year
- localtime.yn += change;
-
- // check if cen rolled over
- change = localtime.yn < 0 ? -1 : localtime.yn >= 100 ? 1 : 0;
- if (!change)
- goto year;
-
- // roll over cen
- localtime.cen += change;
-
-year:
-
- localtime.year = localtime.yn + localtime.cen * 100;
- localtime.leap = localtime.year % 4 == 0 && localtime.year % 100 != 0;
-
- if (localtime.leap && localtime.yday == -1)
- localtime.yday = 365;
- else if (localtime.yday == -1)
- localtime.yday = 364;
- else
- localtime.yday = 0;
-
- localtime.year -= 1900;
-}
-
-void clock_update(void)
+void gettime(struct time *time)
{
- time.sec = cmos_read(CMOS_REG_SEC);
- time.min = cmos_read(CMOS_REG_MIN);
- time.hour = cmos_read(CMOS_REG_HOUR);
- time.wday = cmos_read(CMOS_REG_WDAY) - 1;
- time.mday = cmos_read(CMOS_REG_MDAY);
- time.mon = cmos_read(CMOS_REG_MON) - 1;
- time.yn = cmos_read(CMOS_REG_YEAR);
- time.cen = 20;
-
- time.year = time.yn + time.cen * 100;
-
- time.leap = time.year % 4 == 0 && time.year % 100 != 0;
+ time->sec = cmos_read(CMOS_REG_SEC);
+ time->min = cmos_read(CMOS_REG_MIN);
+ time->hour = cmos_read(CMOS_REG_HOUR);
+ time->wday = cmos_read(CMOS_REG_WDAY) - 1;
+ time->mday = cmos_read(CMOS_REG_MDAY);
+ time->mon = cmos_read(CMOS_REG_MON) - 1;
+ time->yn = cmos_read(CMOS_REG_YEAR);
+ time->cen = 20;
- time.yday = mday_offset[time.mon] + time.mday;
+ time->year = time->yn + time->cen * 100;
- if (time.leap && time.mon > 2)
- time.yday++;
+ time->leap = time->year % 4 == 0 && time->year % 100 != 0;
- time.year -= 1900;
+ time->yday = mday_offset[time->mon] + time->mday;
- update_localtime();
+ if (time->leap && time->mon > 2)
+ time->yday++;
- curr_time = time;
- curr_localtime = localtime;
+ time->year -= 1900;
}
-void set_timezone(timezone_t tz)
+uint64_t unixtime(void)
{
- curr_timezone = tz;
-}
-
-time_t get_utctime(void)
-{
- return curr_time;
-}
+ struct time time;
+ gettime(&time);
-time_t get_localtime(void)
-{
- if (curr_timezone != last_timezone) {
- last_timezone = curr_timezone;
- update_localtime();
- curr_localtime = localtime;
- }
- return curr_localtime;
-}
-
-size_t get_systemtime(void)
-{
- return 0;
+ // FIXME: probably wrong
+ uint64_t unix = 0;
+ unix += time.sec;
+ unix += time.min * 60;
+ unix += time.hour * 60 * 60;
+ unix += time.yday * 60 * 60 * 24;
+ unix += time.year * 60 * 60 * 24 * 365;
+ return unix;
}
diff --git a/kernel/drivers/drivers.c b/kernel/drivers/drivers.c
index 00ee247..9b90eb8 100644
--- a/kernel/drivers/drivers.c
+++ b/kernel/drivers/drivers.c
@@ -1,12 +1,9 @@
#include <comus/drivers.h>
#include <comus/drivers/uart.h>
-#include <comus/drivers/tty.h>
#include <comus/drivers/pci.h>
-#include <comus/drivers/clock.h>
void drivers_init(void)
{
uart_init();
pci_init();
- clock_update();
}
diff --git a/kernel/drivers/pci.c b/kernel/drivers/pci.c
index 83c47f1..e84ca11 100644
--- a/kernel/drivers/pci.c
+++ b/kernel/drivers/pci.c
@@ -34,7 +34,7 @@ uint32_t pci_rcfg_d(struct pci_device dev, uint8_t offset)
static void print_device(struct pci_table_entry *entry)
{
- printf(
+ kprintf(
"BUS: %#-4x DEV: %#-4x FUNC: %#-4x ID: %04x:%04x CLASS: %02x:%02x:%02x REV: %#02x\n",
entry->device.bus, entry->device.device, entry->device.function,
entry->vendor_id, entry->device_id, entry->class, entry->subclass,
@@ -134,11 +134,11 @@ void pci_init(void)
}
}
}
- printf("PCI DEVICES\n");
+ kprintf("PCI DEVICES\n");
for (size_t i = 0; i < pci_table_next; i++) {
print_device(&pci_table[i]);
}
- printf("\n");
+ kprintf("\n");
}
bool pci_findby_class(struct pci_device *dest, uint8_t class, uint8_t subclass,
diff --git a/kernel/drivers/tty.c b/kernel/drivers/tty.c
index 5a231cd..e9d3e50 100644
--- a/kernel/drivers/tty.c
+++ b/kernel/drivers/tty.c
@@ -2,8 +2,6 @@
#include <comus/drivers/tty.h>
#include <comus/asm.h>
#include <comus/memory.h>
-#include <stdint.h>
-#include <stdio.h>
#define VGA_ADDR 0xB8000
@@ -99,3 +97,9 @@ void tty_out(char c)
outb(0x3D4, 0x0E);
outb(0x3D5, (uint8_t)((pos >> 8) & 0xFF));
}
+
+void tty_out_str(const char *str)
+{
+ while (*str)
+ tty_out(*str++);
+}
diff --git a/kernel/include/comus/drivers/tty.h b/kernel/include/comus/drivers/tty.h
index 4f8a5f1..55aec64 100644
--- a/kernel/include/comus/drivers/tty.h
+++ b/kernel/include/comus/drivers/tty.h
@@ -17,6 +17,6 @@ void tty_out(char c);
/**
* Output a string to the terminal
*/
-void tty_out_str(char *str);
+void tty_out_str(const char *str);
#endif /* tty.h */
diff --git a/kernel/include/comus/error.h b/kernel/include/comus/error.h
new file mode 120000
index 0000000..9367cab
--- /dev/null
+++ b/kernel/include/comus/error.h
@@ -0,0 +1 @@
+../../../user/include/error.h \ No newline at end of file
diff --git a/kernel/include/comus/fs.h b/kernel/include/comus/fs.h
index 67c74e3..fe335ca 100644
--- a/kernel/include/comus/fs.h
+++ b/kernel/include/comus/fs.h
@@ -11,7 +11,10 @@
#include <stdint.h>
#include <stddef.h>
-#include <limits.h>
+
+// FIXME: aaaa
+#define MAX_DISKS 8
+#define MAX_FILE_NAME_LEN 256
struct disk {
/// set to 1 in array to state that fs is defined
diff --git a/kernel/include/comus/memory.h b/kernel/include/comus/memory.h
index 411c039..294c795 100644
--- a/kernel/include/comus/memory.h
+++ b/kernel/include/comus/memory.h
@@ -13,6 +13,7 @@
#include <stddef.h>
#define MMAP_MAX_ENTRY 64
+#define PAGE_SIZE 4096
struct memory_segment {
uint64_t addr;
@@ -54,14 +55,39 @@ uint64_t memory_used(void);
* @param writable - if this memory should be writable
* @param user - if this memory should be user writable
*/
-void *mapaddr(void *addr, size_t len);
+void *kmapaddr(void *addr, size_t len);
/**
* Unmaps mapped address from the mmap function
* @param addr - the address returned from mmap
* @param len - the length allocated
*/
-void unmapaddr(void *addr);
+void kunmapaddr(void *addr);
+
+/**
+ * Allocates size_t bytes in memory
+ *
+ * @param size - the amount of bytes to allocate
+ * @returns the address allocated or NULL on failure
+ */
+void *kalloc(size_t size);
+
+/**
+ * Rellocates a given allocated ptr to a new size of bytes in memory.
+ * If ptr is NULL it will allocate new memory.
+ *
+ * @param ptr - the pointer to reallocate
+ * @param size - the amount of bytes to reallocate to
+ * @returns the address allocated or NULL on failure
+ */
+void *krealloc(void *ptr, size_t size);
+
+/**
+ * Frees an allocated pointer in memory
+ *
+ * @param ptr - the pointer to free
+ */
+void kfree(void *ptr);
/**
* Attemps to load a mapped but not yet allocated page.
@@ -70,6 +96,28 @@ void unmapaddr(void *addr);
*
* @returns 0 on success and a negative error code on failure.
*/
-int load_page(void *virt_addr);
+int kload_page(void *virt_addr);
+
+/**
+ * Allocate a single page of memory
+ *
+ * @returns the address allocated or NULL on failure
+ */
+void *kalloc_page(void);
+
+/**
+ * Allocate size_t amount of contiguous virtual pages
+ *
+ * @param count - the number of pages to allocate
+ * @returns the address allocated or NULL on failure
+ */
+void *kalloc_pages(size_t count);
+
+/**
+ * Free allocated pages.
+ *
+ * @param ptr - the pointer provided by alloc_page or alloc_pages
+ */
+void kfree_pages(void *ptr);
#endif /* memory.h */
diff --git a/kernel/include/comus/time.h b/kernel/include/comus/time.h
new file mode 100644
index 0000000..6ecb2b7
--- /dev/null
+++ b/kernel/include/comus/time.h
@@ -0,0 +1,39 @@
+/**
+ * @file time.h
+ *
+ * @author Freya Murphy <freya@freyacat.org>
+ *
+ * System time structure
+ */
+
+#ifndef _TIME_H
+#define _TIME_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+struct time {
+ int sec; /// Seconds [0,59]
+ int min; /// Minutes [0,59]
+ int hour; /// Hour [0,23]
+ int mday; /// Day of month [1,31]
+ int mon; /// Month of year [0,11]
+ int year; /// Years since 1900
+ int wday; /// Day of week [0,6] (Sunday = 0)
+ int yday; /// Day of year [0,365]
+ int yn; /// Year number [0,99]
+ int cen; /// Century [19,20]
+ int leap; /// If year is a leap year (True == 1)
+};
+
+/**
+ * Return the current time in the system
+ */
+void gettime(struct time *time);
+
+/**
+ * Return current UTC time
+ */
+uint64_t unixtime(void);
+
+#endif /* time.h */
diff --git a/kernel/include/lib.h b/kernel/include/lib.h
new file mode 100644
index 0000000..be4e739
--- /dev/null
+++ b/kernel/include/lib.h
@@ -0,0 +1,20 @@
+/**
+ * @file lib.h
+ *
+ * @author Freya Murphy <freya@freyacat.org>
+ *
+ * Kernel C Library
+ */
+
+#ifndef _LIB_H
+#define _LIB_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include <lib/kctype.h>
+#include <lib/kio.h>
+#include <lib/klib.h>
+#include <lib/kstring.h>
+
+#endif /* lib.h */
diff --git a/kernel/include/lib/kctype.h b/kernel/include/lib/kctype.h
new file mode 100644
index 0000000..6d090c6
--- /dev/null
+++ b/kernel/include/lib/kctype.h
@@ -0,0 +1,22 @@
+/**
+ * @file kctype.h
+ *
+ * @author Freya Murphy <freya@freyacat.org>
+ *
+ * Kernel C type libaray functions
+ */
+
+#ifndef _KCTYPE_H
+#define _KCTYPE_H
+
+/**
+ * @returns 1 if c is a space
+ */
+int isspace(int c);
+
+/**
+ * @returns 1 if c is a digit (0 - 9)
+ */
+int isdigit(int c);
+
+#endif /* kctype.h */
diff --git a/kernel/include/lib/kio.h b/kernel/include/lib/kio.h
new file mode 100644
index 0000000..652a85b
--- /dev/null
+++ b/kernel/include/lib/kio.h
@@ -0,0 +1,91 @@
+/**
+ * @file kio.h
+ *
+ * @author Freya Murphy <freya@freyacat.org>
+ *
+ * Kernel I/O definitions.
+ */
+
+#ifndef _KIO_H
+#define _KIO_H
+
+#include <stddef.h>
+#include <stdarg.h>
+
+/**
+ * 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
+ */
+__attribute__((format(printf, 1, 2))) void kprintf(const char *format, ...);
+
+/**
+ * prints out a formatted string to a buffer
+ *
+ * @param s - the string to write to
+ * @param format - the format string
+ * @param ... - variable args for the format
+ * @returns number of bytes written
+ */
+__attribute__((format(printf, 2, 3))) size_t ksprintf(char *restrict s,
+ const char *format, ...);
+
+/**
+ * prints out a formatted string to a buffer with a given max length
+ *
+ * @param s - the string to write to
+ * @param maxlen - the max len of the buffer
+ * @param format - the format string
+ * @param ... - variable args for the format
+ * @returns number of bytes written
+ */
+__attribute__((format(printf, 3, 4))) size_t ksnprintf(char *restrict s,
+ size_t maxlen,
+ const char *format, ...);
+
+/**
+ * prints out a formatted string
+ *
+ * @param format - the format string
+ * @param args - variable arg list for the format
+ */
+void kvprintf(const char *format, va_list args);
+
+/**
+ * prints out a formatted string to a buffer
+ *
+ * @param s - the string to write to
+ * @param format - the format string
+ * @param args - variable arg list for the format
+ * @returns number of bytes written
+ */
+size_t kvsprintf(char *restrict s, const char *format, va_list args);
+
+/**
+ * prints out a formatted string to a buffer with a given max length
+ *
+ * @param s - the string to write to
+ * @param maxlen - the max len of the buffer
+ * @param format - the format string
+ * @param args - variable arg list for the format
+ * @returns number of bytes written
+ */
+size_t kvsnprintf(char *restrict s, size_t maxlen, const char *format,
+ va_list args);
+
+#endif /* kio.h */
diff --git a/kernel/include/lib/klib.h b/kernel/include/lib/klib.h
new file mode 100644
index 0000000..c67e57d
--- /dev/null
+++ b/kernel/include/lib/klib.h
@@ -0,0 +1,196 @@
+/**
+ * @file klib.h
+ *
+ * @author Freya Murphy <freya@freyacat.org>
+ *
+ * Kernel libaray functions
+ */
+
+#ifndef _KLIB_H
+#define _KLIB_H
+
+#include <stddef.h>
+
+/**
+ * converts single digit int to base 36
+ * @param i - int
+ * @returns c - base 36 char
+ */
+char itoc(int i);
+
+/**
+ * converts single base 36 chat into int
+ * @param c - base 36 char
+ * @returns i - int, or -1 if the char was invalid
+ */
+int ctoi(char c);
+
+/**
+ * Converts the initial portiion of the string pointed to by s to int.
+ * @param s - the string to convert
+ * @returns the number inside s or 0 on error
+ */
+int atoi(const char *s);
+
+/**
+ * Converts the initial portiion of the string pointed to by s to long.
+ * @param s - the string to convert
+ * @returns the number inside s or 0 on error
+ */
+long int atol(const char *s);
+
+/**
+ * Converts the initial portiion of the string pointed to by s to long long.
+ * @param s - the string to convert
+ * @returns the number inside s or 0 on error
+ */
+long long int atoll(const char *s);
+
+/**
+ * Converts a integer to asci inside a string with a given radix (base).
+ * @param n - the number to convert
+ * @param buffer - the string buffer
+ * @param radix - the base to convert
+ */
+char *itoa(int n, char *buffer, int radix);
+
+/**
+ * Converts a long to asci inside a string with a given radix (base).
+ * @param n - the number to convert
+ * @param buffer - the string buffer
+ * @param radix - the base to convert
+ */
+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).
+ * @param n - the number to convert
+ * @param buffer - the string buffer
+ * @param radix - the base to convert
+ */
+char *utoa(unsigned int n, char *buffer, int radix);
+
+/**
+ * Converts a unsigned long to asci inside a string with a given radix (base).
+ * @param n - the number to convert
+ * @param buffer - the string buffer
+ * @param radix - the base to convert
+ */
+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.
+ * The endptr is updated to where the string was no longer valid.
+ * @param str - the string buffer
+ * @param endptr - the endptr
+ * @param base - the base to convert to
+ * @returns 0 on error or success, error if endptr is still equal to str
+ */
+int strtoi(const char *str, char **endptr, int base);
+
+/**
+ * Converts the string in str to a long value based on the given base.
+ * The endptr is updated to where the string was no longer valid.
+ * @param str - the string buffer
+ * @param endptr - the endptr
+ * @param base - the base to convert to
+ * @returns 0 on error or success, error if endptr is still equal to str
+ */
+long int strtol(const char *str, char **endptr, int base);
+
+/**
+ * Converts the string in str to a long long value based on the given base.
+ * The endptr is updated to where the string was no longer valid.
+ * @param str - the string buffer
+ * @param endptr - the endptr
+ * @param base - the base to convert to
+ * @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);
+
+/**
+ * Converts the string in str to an unsigned int value based on the given base.
+ * The endptr is updated to where the string was no longer valid.
+ * @param str - the string buffer
+ * @param endptr - the endptr
+ * @param base - the base to convert to
+ * @returns 0 on error or success, error if endptr is still equal to str
+ */
+unsigned int strtoui(const char *str, char **endptr, int base);
+
+/**
+ * Converts the string in str to an unsigned long value based on the given base.
+ * The endptr is updated to where the string was no longer valid.
+ * @param str - the string buffer
+ * @param endptr - the endptr
+ * @param base - the base to convert to
+ * @returns 0 on error or success, error if endptr is still equal to str
+ */
+unsigned long int strtoul(const char *str, char **endptr, int base);
+
+/**
+ * Converts the string in str to an unsigned long long value based on the given base.
+ * The endptr is updated to where the string was no longer valid.
+ * @param str - the string buffer
+ * @param endptr - the endptr
+ * @param base - the base to convert to
+ * @returns 0 on error or success, error if endptr is still equal to str
+ */
+unsigned long long int strtoull(const char *str, char **endptr, int base);
+
+/**
+ * Converts a byte count to a human readable file size of at most four characters
+ * using binary suffixes.
+ *
+ * The following rules are applied:
+ * - If the byte count is less than 1024, the count is written in decimal
+ * and no suffix is applied
+ * - Otherwise, repeatedly divide by 1024 until the value is under 1000.
+ * - If the value has two or three decimal digits, print it followed by the
+ * approprate suffix.
+ * - If the value has one decimal digit, print it along with a single fractional
+ * digit. This also applies if the value is zero.
+ *
+ * @param bytes - the bytes to convert
+ * @param buf - a pointer to the buffer to store it in (which must be at least five
+ * bytes long)
+ * @returns - buf
+ */
+char *btoa(size_t bytes, char *buf);
+
+/**
+ * This function confines an argument within specified bounds.
+ *
+ * @param min - lower bound
+ * @param value - value to be constrained
+ * @param max - upper bound
+ *
+ * @returns the constrained value
+ */
+unsigned int bound(unsigned int min, unsigned int value, unsigned int max);
+
+/**
+ * Abort the kernel with a given message.
+ *
+ * @param format - the format string
+ * @param ... - variable args for the format
+ */
+__attribute__((noreturn)) void panic(const char *format, ...);
+
+#endif /* klib.h */
diff --git a/kernel/include/lib/kstring.h b/kernel/include/lib/kstring.h
new file mode 100644
index 0000000..50334b4
--- /dev/null
+++ b/kernel/include/lib/kstring.h
@@ -0,0 +1,154 @@
+/**
+ * @file kstring.h
+ *
+ * @author Freya Murphy <freya@freyacat.org>
+ *
+ * Kernel String libaray functions
+ */
+
+#ifndef _KSTRING_H
+#define _KSTRING_H
+
+#include <stddef.h>
+
+/**
+ * Compare the first n bytes (interpreted as unsigned char) of the memory areas s1 and s2
+ * @param s1 - the first memory area
+ * @param s2 - the second memory area
+ * @param n - the byte count
+ * @returns an interger less than, equal to, or greater than 0 if the first n bytes
+ * of s1 are less than, equal to, or greater than s2.
+ */
+int memcmp(const void *restrict s1, const void *restrict s2, size_t n);
+
+/**
+ * Copy the first n bytes from memory area src to memory area dest. The memory
+ * areas must not overlap.
+ * @param dest - the destination
+ * @param src - the source
+ * @param n - the byte count
+ * @returns a pointer to dest
+ */
+void *memcpy(void *restrict dest, const void *restrict src, size_t n);
+
+/**
+ * Copy the first n bytes from memory area src to memory area dest. The memory
+ * areas may overlap; memmove behaves as though the bytes are first copied to a
+ * temporary array.
+ * @param dest - the destination
+ * @param src - the source
+ * @param n - the byte count
+ * @returns a pointer to dest
+ */
+void *memmove(void *restrict dest, const void *restrict src, size_t n);
+
+/**
+ * Fill the first n bytes of the memory region dest with the constant byte c.
+ * @param dest - the destination
+ * @param c - the byte to write
+ * @param n - the byte count
+ * @returns a pointer to dest
+ */
+void *memset(void *restrict dest, int c, size_t n);
+
+/**
+ * Copy the first n bytes from memory area src to memory area dest. The memory
+ * areas must not overlap.
+ * @param dest - the destination
+ * @param src - the source
+ * @param n - the byte count
+ * @returns a pointer to dest
+ */
+volatile void *memcpyv(volatile void *restrict dest,
+ const volatile void *restrict src, size_t n);
+
+/**
+ * Copy the first n bytes from memory area src to memory area dest. The memory
+ * areas may overlap; memmove behaves as though the bytes are first copied to a
+ * temporary array.
+ * @param dest - the destination
+ * @param src - the source
+ * @param n - the byte count
+ * @returns a pointer to dest
+ */
+volatile void *memmovev(volatile void *restrict dest,
+ const volatile void *restrict src, size_t n);
+
+/**
+ * Fill the first n bytes of the memory region dest with the constant byte c.
+ * @param dest - the destination
+ * @param c - the byte to write
+ * @param n - the byte count
+ * @returns a pointer to dest
+ */
+volatile void *memsetv(volatile void *restrict dest, int c, size_t n);
+
+/**
+ * Calculates the length of the string pointed to by str, excluding
+ * the terminating null byte
+ * @param str - the string pointer
+ * @returns the length of the string in bytes
+ */
+size_t strlen(const char *str);
+
+/**
+ * Compare null terminated string s1 and s2. The comparison is done using
+ * unsigned characters.
+ * @param s1 - a pointer to the first string
+ * @param s2 - a pointer to the second string
+ * @returns an interger less than, equal to, or greater than 0 if s1 compares less
+ * than, equal to, or greater than s2
+ */
+int strcmp(const char *restrict s1, const char *restrict s2, size_t n);
+
+/**
+ * Compare at most the first n bytes of the strings s1 and s2. The comparison is
+ * done using unsigned characters.
+ * @param s1 - a pointer to the first string
+ * @param s2 - a pointer to the second string
+ * @param n - the maximum number of bytes
+ * @returns an interger less than, equal to, or greater than 0 if s1 compares less
+ * than, equal to, or greater than s2
+ */
+int strncmp(const char *restrict s1, const char *restrict s2, size_t n);
+
+/**
+ * Copies the string pointed to by src into the buffer pointer to by dest.
+ * The dest buffer must be long enough to hold src.
+ * @param dest - the destination
+ * @param src - the source
+ * @returns a pointer to dest
+ */
+char *strcpy(char *restrict dest, const char *restrict src);
+
+/**
+ * Copies the string pointed to by src into the buffer pointer to by dest.
+ * The dest buffer must be long enough to hold src or size n.
+ * @param dest - the destination
+ * @param src - the source
+ * @param n - the maximum number of bytes
+ * @returns a pointer to dest
+ */
+char *strncpy(char *restrict dest, const char *restrict src, size_t n);
+
+/**
+ * Copies the string pointed to by src into the buffer pointed to by dest.
+ * The dest buffer must be long enough to hold src.
+ * @param dest - the destination
+ * @param src - the source
+ * @param n - the maximum number of bytes
+ * @returns a pointer to the terminating null byte
+ */
+char *stpcpy(char *restrict dest, const char *restrict src);
+
+/**
+ * Copies the string pointed to by src into the buffer pointed to by dest.
+ * The dest buffer must be long enough to hold src or size n.
+ * @param dest - the destination
+ * @param src - the source
+ * @param n - the maximum number of bytes
+ * @returns a pointer to the byte after the last character copied
+ */
+char *stpncpy(char *restrict dest, const char *restrict src, size_t n);
+
+#endif /* kstring.h */
diff --git a/kernel/lib/atox.c b/kernel/lib/atox.c
new file mode 100644
index 0000000..6d3d4cc
--- /dev/null
+++ b/kernel/lib/atox.c
@@ -0,0 +1,29 @@
+#include <lib.h>
+
+#define ATOX(name, type) \
+ type name(const char *s) \
+ { \
+ for (; isspace(*s); s++) \
+ ; \
+ int neg = 0; \
+ switch (*s) { \
+ case '-': \
+ neg = 1; \
+ /* fallthrough */ \
+ case '+': \
+ s++; \
+ break; \
+ } \
+ type num = 0; \
+ for (; *s == '0'; s++) \
+ ; \
+ for (; isdigit(*s); s++) { \
+ num *= 10; \
+ num += *s - '0'; \
+ } \
+ return num * (neg ? -1 : 1); \
+ }
+
+ATOX(atoi, int)
+ATOX(atol, long int)
+ATOX(atoll, long long int)
diff --git a/kernel/lib/bound.c b/kernel/lib/bound.c
new file mode 100644
index 0000000..5a3c9fa
--- /dev/null
+++ b/kernel/lib/bound.c
@@ -0,0 +1,12 @@
+#include <lib.h>
+
+unsigned int bound(unsigned int min, unsigned int value, unsigned int max)
+{
+ if (value < min) {
+ value = min;
+ }
+ if (value > max) {
+ value = max;
+ }
+ return value;
+}
diff --git a/kernel/lib/btoa.c b/kernel/lib/btoa.c
new file mode 100644
index 0000000..96a60ef
--- /dev/null
+++ b/kernel/lib/btoa.c
@@ -0,0 +1,43 @@
+#include <lib.h>
+
+static char suffixes[] = { 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y', 'R', 'Q' };
+
+char *btoa(size_t bytes, char *buf)
+{
+ // no suffix if under 1K, print up to four digits
+ if (bytes < 1024) {
+ ultoa(bytes, buf, 10);
+ return buf;
+ }
+
+ // store one digit of remainder for decimal
+ unsigned int remainder;
+ // power of 1024
+ int power = 0;
+
+ // iterate until remaining bytes fits in three digits
+ while (bytes >= 1000) {
+ remainder = (bytes % 1024) * 10 / 1024;
+ bytes /= 1024;
+ power += 1;
+ }
+
+ // end of number
+ char *end;
+
+ if (bytes >= 10) {
+ // no decimal
+ end = ultoa(bytes, buf, 10);
+ } else {
+ // decimal
+ end = ultoa(bytes, buf, 10);
+ end[0] = '.';
+ end = ultoa(remainder, end + 1, 10);
+ }
+
+ // add suffix
+ end[0] = suffixes[power - 1];
+ end[1] = '\0';
+
+ return buf;
+}
diff --git a/kernel/lib/ctoi.c b/kernel/lib/ctoi.c
new file mode 100644
index 0000000..09a9f10
--- /dev/null
+++ b/kernel/lib/ctoi.c
@@ -0,0 +1,14 @@
+#include <lib.h>
+
+int ctoi(char c)
+{
+ if (c >= '0' && c <= '9') {
+ return c - '0';
+ } else if (c >= 'A' && c <= 'Z') {
+ return c - 'A' + 10;
+ } else if (c >= 'a' && c <= 'z') {
+ return c - 'a' + 10;
+ } else {
+ return -1;
+ }
+}
diff --git a/kernel/lib/fputc.c b/kernel/lib/fputc.c
deleted file mode 100644
index 0d47cb5..0000000
--- a/kernel/lib/fputc.c
+++ /dev/null
@@ -1,10 +0,0 @@
-#include <lib.h>
-#include <comus/drivers/tty.h>
-#include <comus/drivers/uart.h>
-
-void fputc(FILE *stream, char c)
-{
- (void)stream; // TODO: manage stream
- uart_out(c);
- tty_out(c);
-}
diff --git a/kernel/lib/isdigit.c b/kernel/lib/isdigit.c
new file mode 100644
index 0000000..f645093
--- /dev/null
+++ b/kernel/lib/isdigit.c
@@ -0,0 +1,6 @@
+#include <lib.h>
+
+int isdigit(int c)
+{
+ return c >= '0' && c <= '9';
+}
diff --git a/kernel/lib/isspace.c b/kernel/lib/isspace.c
new file mode 100644
index 0000000..5196d0c
--- /dev/null
+++ b/kernel/lib/isspace.c
@@ -0,0 +1,16 @@
+#include <lib.h>
+
+int isspace(int c)
+{
+ switch (c) {
+ case ' ':
+ case '\t':
+ case '\v':
+ case '\f':
+ case '\r':
+ case '\n':
+ return 1;
+ default:
+ return 0;
+ }
+}
diff --git a/kernel/lib/itoc.c b/kernel/lib/itoc.c
new file mode 100644
index 0000000..493b66e
--- /dev/null
+++ b/kernel/lib/itoc.c
@@ -0,0 +1,10 @@
+#include <lib.h>
+
+char itoc(int i)
+{
+ if (i < 10) {
+ return '0' + i;
+ } else {
+ return 'a' + (i - 10);
+ }
+}
diff --git a/kernel/lib/kalloc.c b/kernel/lib/kalloc.c
new file mode 100644
index 0000000..9845a62
--- /dev/null
+++ b/kernel/lib/kalloc.c
@@ -0,0 +1,210 @@
+#include <lib.h>
+#include <comus/memory.h>
+
+#define MAGIC 0xBEEFCAFE
+
+struct page_header {
+ struct page_header *next;
+ struct page_header *prev;
+ size_t
+ node_number; // all headers on the same page alloc have the same node number (so they can be merged)
+ size_t
+ free; // free space after the node (if its the last node in the alloc block)
+ size_t used; // how much space this allocation is using
+ uint64_t magic;
+};
+
+static const size_t header_len = sizeof(struct page_header);
+static struct page_header *start_header = NULL;
+static struct page_header *end_header = NULL;
+
+static struct page_header *get_header(void *ptr)
+{
+ struct page_header *header =
+ (struct page_header *)((uintptr_t)ptr - header_len);
+
+ // PERF: do we want to make sure this pointer is paged
+ // before reading it???
+ if (header->magic != MAGIC) {
+ return NULL; // invalid pointer
+ }
+
+ return header;
+}
+
+static void *alloc_new(size_t size)
+{
+ size_t pages = ((size + header_len) / PAGE_SIZE) + 1;
+
+ void *addr = kalloc_pages(pages);
+ void *mem = (char *)addr + header_len;
+
+ size_t total = pages * PAGE_SIZE;
+ size_t free = total - (size + header_len);
+
+ if (addr == NULL) {
+ return NULL;
+ }
+
+ size_t node;
+ if (end_header != NULL) {
+ node = end_header->node_number + 1;
+ } else {
+ node = 0;
+ }
+
+ struct page_header *header = addr;
+ header->magic = 0xBEEFCAFE;
+ header->used = size;
+ header->free = free;
+ header->prev = end_header;
+ header->next = NULL;
+ header->node_number = node;
+
+ if (start_header == NULL) {
+ start_header = header;
+ }
+
+ if (end_header != NULL) {
+ end_header->next = header;
+ } else {
+ end_header = header;
+ }
+
+ return mem;
+}
+
+static void *alloc_block(size_t size, struct page_header *block)
+{
+ struct page_header *header =
+ (struct page_header *)((char *)block + block->used + header_len);
+
+ size_t free = block->free - (size + header_len);
+ block->free = 0;
+
+ header->magic = MAGIC;
+ header->used = size;
+ header->free = free;
+ header->prev = block;
+ header->next = block->next;
+ block->next = header;
+ header->node_number = block->node_number;
+
+ void *mem = (char *)header + header_len;
+
+ return mem;
+}
+
+void *kalloc(size_t size)
+{
+ struct page_header *header = start_header;
+
+ for (; header != NULL; header = header->next) {
+ size_t free = header->free;
+ if (free < header_len)
+ continue;
+ if (size <=
+ (free - header_len)) { // we must be able to fit data + header
+ break;
+ }
+ }
+
+ if (header != NULL) {
+ return alloc_block(size, header);
+ } else {
+ return alloc_new(size);
+ }
+}
+
+void *krealloc(void *src, size_t dst_len)
+{
+ struct page_header *header;
+ size_t src_len;
+ void *dst;
+
+ // realloc of 0 means free pointer
+ if (dst_len == 0) {
+ kfree(src);
+ return NULL;
+ }
+
+ // NULL src means allocate ptr
+ if (src == NULL) {
+ dst = kalloc(dst_len);
+ return dst;
+ }
+
+ header = get_header(src);
+
+ if (header == NULL)
+ return NULL;
+
+ src_len = header->used;
+
+ if (src_len == 0)
+ return NULL;
+
+ dst = kalloc(dst_len);
+
+ if (dst == NULL)
+ return NULL; // allocation failed
+
+ if (dst_len < src_len)
+ src_len = dst_len;
+
+ memcpy(dst, src, src_len);
+ kfree(src);
+
+ return dst;
+}
+
+void kfree(void *ptr)
+{
+ struct page_header *header;
+
+ if (ptr == NULL)
+ return;
+
+ header = get_header(ptr);
+
+ if (header == NULL)
+ return;
+
+ header->free += header->used;
+ header->used = 0;
+
+ struct page_header *neighbor;
+
+ // merge left
+ for (neighbor = header->prev; neighbor != NULL; neighbor = neighbor->prev) {
+ if (neighbor->node_number != header->node_number)
+ break;
+ if (neighbor->used && header->used)
+ break;
+ neighbor->free += header->free + header_len;
+ neighbor->next = header->next;
+ header = neighbor;
+ }
+
+ // merge right
+ for (neighbor = header->next; neighbor != NULL; neighbor = neighbor->next) {
+ if (neighbor->node_number != header->node_number)
+ break;
+ if (neighbor->used)
+ break;
+ header->free += neighbor->free + header_len;
+ header->next = neighbor->next;
+ }
+
+ if ((header->next == NULL ||
+ header->next->node_number != header->node_number) &&
+ (header->prev == NULL ||
+ header->prev->node_number != header->node_number) &&
+ header->used == 0) {
+ if (header->next)
+ header->next->prev = header->prev;
+ if (header->prev)
+ header->prev->next = header->next;
+ kfree_pages(header);
+ }
+}
diff --git a/kernel/lib/kprintf.c b/kernel/lib/kprintf.c
new file mode 100644
index 0000000..a76036f
--- /dev/null
+++ b/kernel/lib/kprintf.c
@@ -0,0 +1,576 @@
+#include <lib.h>
+#include <comus/drivers/uart.h>
+#include <comus/drivers/tty.h>
+
+#define PRINTF_NUMERIC_BUF_LEN 50
+
+typedef union {
+ unsigned long long int u;
+ signed long long int i;
+ char *str;
+ char c;
+} data_t;
+
+/// options that can be set inside a specifier
+/// flags, width, precision, length, and data type
+typedef struct {
+ /* flags */
+ /// left justify content
+ uint8_t left : 1;
+ /// force sign (+/-) on numeric output
+ uint8_t sign : 1;
+ /// leave space if no printed sign on numeric output
+ uint8_t space : 1;
+ /// preceed hex/octal output with '0x'
+ uint8_t hash : 1;
+ /// left pads numeric output with zeros
+ uint8_t zero : 1;
+ uint8_t : 3;
+
+ /* width & precision */
+ /// minimum number of characters to be printed (padding if origonal is less)
+ int width;
+ /// digit precision used when printing numerical answers
+ int precision;
+ /// if a fixed minimum width has been provided
+ uint8_t width_set : 1;
+ /// if the provided minimum width is in the next variable argument
+ uint8_t width_varies : 1;
+ /// if a fixed digit precision has been provided
+ uint8_t precision_set : 1;
+ /// if the provided digit precision is in the next variable argument
+ uint8_t precision_varies : 1;
+ uint8_t : 4;
+
+ /* length */
+ /// what size to read argument as
+ enum printf_len {
+ PRINTF_LEN_CHAR,
+ PRINTF_LEN_SHORT_INT,
+ PRINTF_LEN_INT,
+ PRINTF_LEN_LONG_INT,
+ PRINTF_LEN_LONG_LONG_INT,
+ PRINTF_LEN_SIZE_T,
+ } len;
+
+ /* other */
+ /// radix to print the numerical answers as
+ uint8_t radix;
+ /// case to print hexadecimal values as
+ bool is_uppercase;
+} options_t;
+
+typedef struct {
+ /* input */
+ /// the origonal format string
+ const char *format;
+ /// maximum allowed output length
+ size_t max_len;
+ /// if a maximum output length is set
+ bool has_max_len;
+
+ /* output */
+ size_t written_len;
+ bool sprintf;
+ char *sprintf_buf;
+
+ /* pass 2 */
+ char *output;
+} context_t;
+
+static void printf_putc(context_t *ctx, char c)
+{
+ // bounds check
+ if (ctx->has_max_len)
+ if (ctx->written_len >= ctx->max_len)
+ return;
+
+ // write to correct
+ if (ctx->sprintf)
+ *(ctx->sprintf_buf++) = c;
+ else
+ kputc(c);
+
+ ctx->written_len++;
+}
+
+static int parse_flag(const char **res, options_t *opts)
+{
+ const char *fmt = *res;
+ switch (*(fmt++)) {
+ case '-':
+ opts->left = 1;
+ break;
+ case '+':
+ opts->sign = 1;
+ break;
+ case ' ':
+ opts->space = 1;
+ break;
+ case '#':
+ opts->hash = 1;
+ break;
+ case '0':
+ opts->zero = 1;
+ break;
+ default:
+ return 0;
+ }
+
+ *res = fmt;
+ return 1;
+}
+
+static void parse_width(const char **res, options_t *opts)
+{
+ const char *fmt = *res;
+ char *end = NULL;
+
+ // check varies
+ if (*fmt == '*') {
+ opts->width_varies = true;
+ *res = fmt++;
+ return;
+ }
+
+ // parse num
+ long width = strtol(fmt, &end, 10);
+ if (end != NULL) {
+ opts->width_set = 1;
+ opts->width = width;
+ *res = end;
+ return;
+ }
+}
+
+static void parse_precision(const char **res, options_t *opts)
+{
+ const char *fmt = *res;
+ char *end = NULL;
+
+ // check for dot
+ if (*(fmt++) != '.')
+ return;
+
+ // check varies
+ if (*fmt == '*') {
+ opts->precision_varies = true;
+ *res = fmt++;
+ return;
+ }
+
+ // parse num
+ long precision = strtol(fmt, &end, 10);
+ if (end != NULL) {
+ opts->precision_set = 1;
+ opts->precision = precision;
+ *res = end;
+ return;
+ }
+}
+
+static void parse_length(const char **res, options_t *opts)
+{
+ const char *fmt = *res;
+
+ switch (*(fmt++)) {
+ // half
+ case 'h':
+ if (*fmt == 'h') {
+ opts->len = PRINTF_LEN_CHAR;
+ fmt++;
+ } else {
+ opts->len = PRINTF_LEN_SHORT_INT;
+ }
+ break;
+ // long
+ case 'l':
+ if (*fmt == 'l') {
+ opts->len = PRINTF_LEN_LONG_LONG_INT;
+ fmt++;
+ } else {
+ opts->len = PRINTF_LEN_LONG_INT;
+ }
+ break;
+ // size_t
+ case 'z':
+ opts->len = PRINTF_LEN_SIZE_T;
+ break;
+ default:
+ opts->len = PRINTF_LEN_INT;
+ return;
+ }
+
+ *res = fmt;
+}
+
+static void get_radix(char spec, options_t *opts)
+{
+ switch (spec) {
+ case 'x':
+ case 'X':
+ opts->radix = 16;
+ break;
+ case 'o':
+ opts->radix = 8;
+ break;
+ default:
+ opts->radix = 10;
+ break;
+ }
+}
+
+static void get_case(char spec, options_t *opts)
+{
+ if (spec == 'X')
+ opts->is_uppercase = 1;
+}
+
+static char printf_itoc(int uppercase, int i)
+{
+ // decimal
+ if (i < 10) {
+ return i + '0';
+ }
+ // hex
+ if (uppercase) {
+ return (i - 10) + 'A';
+ } else {
+ return (i - 10) + 'a';
+ }
+}
+
+static int printf_lltoa(char *buf, options_t *opts, bool is_neg,
+ unsigned long long int num)
+{
+ int precision = 0;
+ char *start = buf;
+
+ // get width of number
+ int len = 0;
+ unsigned long long int temp = num;
+ if (temp == 0)
+ len = 1;
+ while (temp) {
+ if (opts->precision_set && precision++ >= opts->precision)
+ break;
+ temp /= opts->radix;
+ len++;
+ }
+ precision = 0;
+
+ // sign
+ if (is_neg) {
+ *(buf++) = '-';
+ } else if (opts->sign) {
+ *(buf++) = '+';
+ } else if (opts->space) {
+ *(buf++) = ' ';
+ }
+
+ // radix specifier
+ if (opts->hash) {
+ if (opts->radix == 8) {
+ *(buf++) = '0';
+ *(buf++) = 'o';
+ }
+ if (opts->radix == 16) {
+ *(buf++) = '0';
+ *(buf++) = 'x';
+ }
+ }
+
+ // print zeros if needed
+ if (opts->width_set && len < opts->width && opts->zero) {
+ while (len++ < opts->width)
+ *(buf++) = '0';
+ }
+
+ // write number
+ if (num == 0) {
+ *(buf++) = '0';
+ }
+ while (num) {
+ if (opts->precision_set && precision++ >= opts->precision)
+ break;
+ *(buf++) = printf_itoc(opts->is_uppercase, num % opts->radix);
+ num /= opts->radix;
+ }
+ *(buf++) = '\0';
+
+ return buf - start;
+}
+
+static void handle_int_specifier(context_t *ctx, options_t *const opts,
+ bool has_sign_bit, data_t num)
+{
+ bool is_neg = false;
+
+ // get sign if possible neg
+ if (has_sign_bit) {
+ if (num.i < 0) {
+ num.i = -num.i;
+ is_neg = true;
+ }
+ }
+
+ // get length of number and number
+ char buf[PRINTF_NUMERIC_BUF_LEN];
+ int buf_len = printf_lltoa(buf, opts, is_neg, num.u);
+
+ // get needed padding
+ int padding = 0;
+ if (opts->width_set && (buf_len < opts->width))
+ padding = opts->width - buf_len;
+
+ /* print */
+ // left padding
+ if (opts->left == 0) {
+ for (int i = 0; i < padding; i++)
+ printf_putc(ctx, opts->zero ? '0' : ' ');
+ }
+ // number
+ for (int i = 0; i < buf_len; i++)
+ printf_putc(ctx, buf[i]);
+ // right padding
+ if (opts->left == 1) {
+ for (int i = 0; i < padding; i++)
+ printf_putc(ctx, opts->zero ? '0' : ' ');
+ }
+}
+
+static void handle_char_specifier(context_t *ctx, data_t c)
+{
+ printf_putc(ctx, c.c);
+}
+
+static void handle_string_specifier(context_t *ctx, options_t *opts,
+ data_t data)
+{
+ char *str = data.str;
+ int str_len = 0;
+
+ // get length of string
+ if (opts->precision_set)
+ str_len = opts->precision;
+ else
+ str_len = strlen(str);
+
+ // get needed padding
+ int padding = 0;
+ if (opts->width_set && (str_len < opts->width))
+ padding = opts->width - str_len;
+
+ /* print */
+ // left padding
+ if (opts->left == 0) {
+ for (int i = 0; i < padding; i++)
+ printf_putc(ctx, ' ');
+ }
+ // string
+ for (int i = 0; i < str_len; i++)
+ printf_putc(ctx, str[i]);
+ // right padding
+ if (opts->left == 1) {
+ for (int i = 0; i < padding; i++)
+ printf_putc(ctx, ' ');
+ }
+}
+
+static void do_printf(context_t *ctx, va_list args)
+{
+ const char *fmt = ctx->format;
+
+ char c;
+ while (c = *fmt++, c != '\0') {
+ // save start of fmt for current iteration
+ const char *start = fmt - 1;
+
+ // ignore if not %
+ if (c != '%') {
+ printf_putc(ctx, c);
+ continue;
+ }
+
+ // read opts
+ options_t opts = { 0 };
+ while (parse_flag(&fmt, &opts))
+ ;
+ parse_width(&fmt, &opts);
+ parse_precision(&fmt, &opts);
+ parse_length(&fmt, &opts);
+
+ // read specifier
+ char spec = *fmt++;
+ get_radix(spec, &opts);
+ get_case(spec, &opts);
+
+ // read varied width / precision
+ if (opts.width_varies) {
+ opts.width_set = 1;
+ opts.width = va_arg(args, int);
+ }
+ if (opts.precision_varies) {
+ opts.precision_set = 1;
+ opts.precision = va_arg(args, int);
+ }
+ // read data from args
+ data_t data;
+ switch (spec) {
+ case 'p':
+ opts.len = PRINTF_LEN_SIZE_T;
+ opts.width_set = true;
+ opts.radix = 16;
+ opts.hash = true;
+ opts.zero = true;
+ case 'd':
+ case 'i':
+ case 'u':
+ case 'o':
+ case 'x':
+ case 'X':
+ // read number from arg
+ switch (opts.len) {
+ case PRINTF_LEN_CHAR:
+ data.u = va_arg(args, unsigned int); // char
+ break;
+ case PRINTF_LEN_SHORT_INT:
+ data.u = va_arg(args, unsigned int); // short int
+ break;
+ case PRINTF_LEN_INT:
+ data.u = va_arg(args, unsigned int);
+ break;
+ case PRINTF_LEN_LONG_INT:
+ data.u = va_arg(args, unsigned long int);
+ break;
+ case PRINTF_LEN_LONG_LONG_INT:
+ data.u = va_arg(args, unsigned long long int);
+ break;
+ case PRINTF_LEN_SIZE_T:
+ data.u = va_arg(args, size_t);
+ break;
+ }
+ break;
+ // end int
+ case 's':
+ // read string
+ data.str = va_arg(args, void *);
+ break;
+ // end string
+ case 'c':
+ // read char
+ data.c = va_arg(args, int);
+ break;
+ // end char
+ }
+
+ switch (spec) {
+ // signed int
+ case 'd':
+ case 'i':
+ handle_int_specifier(ctx, &opts, true, data);
+ break;
+ // unsigned int
+ case 'p':
+ case 'u':
+ case 'o':
+ case 'x':
+ case 'X':
+ handle_int_specifier(ctx, &opts, false, data);
+ break;
+ // character
+ case 'c':
+ handle_char_specifier(ctx, data);
+ break;
+ // string
+ case 's':
+ handle_string_specifier(ctx, &opts, data);
+ break;
+ // unknown
+ default:
+ // print from % to current
+ for (; start < fmt; start++)
+ printf_putc(ctx, *start);
+ break;
+ }
+ }
+}
+
+void kprintf(const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ kvprintf(format, args);
+ va_end(args);
+}
+
+size_t ksprintf(char *restrict s, const char *format, ...)
+{
+ va_list args;
+ size_t amt;
+ va_start(args, format);
+ amt = kvsprintf(s, format, args);
+ va_end(args);
+ return amt;
+}
+
+size_t snprintf(char *restrict s, size_t maxlen, const char *format, ...)
+{
+ va_list args;
+ size_t amt;
+ va_start(args, format);
+ amt = kvsnprintf(s, maxlen, format, args);
+ va_end(args);
+ return amt;
+}
+
+void kvprintf(const char *format, va_list args)
+{
+ // create context
+ context_t ctx = { 0 };
+ ctx.format = format;
+ // print
+ do_printf(&ctx, args);
+}
+
+size_t kvsprintf(char *restrict s, const char *format, va_list args)
+{
+ // create context
+ context_t ctx = { 0 };
+ ctx.format = format;
+ // sprintf buffer
+ ctx.sprintf_buf = s;
+ ctx.sprintf = 1;
+ // print
+ do_printf(&ctx, args);
+ return ctx.written_len;
+}
+
+size_t kvsnprintf(char *restrict s, size_t maxlen, const char *format,
+ va_list args)
+{
+ // create context
+ context_t ctx = { 0 };
+ ctx.format = format;
+ // sprintf buffer
+ ctx.sprintf_buf = s;
+ ctx.sprintf = 1;
+ // sprintf max_len
+ ctx.has_max_len = 1;
+ ctx.max_len = maxlen;
+ // print
+ do_printf(&ctx, args);
+ return ctx.written_len;
+}
+
+void kputc(char c)
+{
+ tty_out(c);
+ uart_out(c);
+}
+
+void kputs(const char *str)
+{
+ tty_out_str(str);
+ uart_out_str(str);
+}
diff --git a/kernel/lib/memcmp.c b/kernel/lib/memcmp.c
new file mode 100644
index 0000000..f938d0a
--- /dev/null
+++ b/kernel/lib/memcmp.c
@@ -0,0 +1,9 @@
+#include <lib.h>
+
+int memcmp(const void *restrict vl, const void *restrict vr, size_t n)
+{
+ const unsigned char *l = vl, *r = vr;
+ for (; n && *l == *r; n--, l++, r++)
+ ;
+ return n ? *l - *r : 0;
+}
diff --git a/kernel/lib/memcpy.c b/kernel/lib/memcpy.c
new file mode 100644
index 0000000..e848cef
--- /dev/null
+++ b/kernel/lib/memcpy.c
@@ -0,0 +1,10 @@
+#include <lib.h>
+
+void *memcpy(void *restrict dest, const void *restrict src, size_t n)
+{
+ char *d = dest;
+ const char *s = src;
+ for (; n; n--)
+ *d++ = *s++;
+ return dest;
+}
diff --git a/lib/memcpyv.c b/kernel/lib/memcpyv.c
index 610daf2..bc95807 100644
--- a/lib/memcpyv.c
+++ b/kernel/lib/memcpyv.c
@@ -1,4 +1,4 @@
-#include <string.h>
+#include <lib.h>
volatile void *memcpyv(volatile void *restrict dest,
const volatile void *restrict src, size_t n)
diff --git a/kernel/lib/memmove.c b/kernel/lib/memmove.c
new file mode 100644
index 0000000..55be66d
--- /dev/null
+++ b/kernel/lib/memmove.c
@@ -0,0 +1,20 @@
+#include <lib.h>
+
+void *memmove(void *dest, const void *src, size_t n)
+{
+ char *d = dest;
+ const char *s = src;
+
+ if (d == s)
+ return d;
+
+ if (d < s) {
+ for (; n; n--)
+ *d++ = *s++;
+ } else {
+ while (n)
+ n--, d[n] = s[n];
+ }
+
+ return dest;
+}
diff --git a/lib/memmovev.c b/kernel/lib/memmovev.c
index 0b21d25..56684a5 100644
--- a/lib/memmovev.c
+++ b/kernel/lib/memmovev.c
@@ -1,4 +1,4 @@
-#include <string.h>
+#include <lib.h>
volatile void *memmovev(volatile void *dest, const volatile void *src, size_t n)
{
diff --git a/kernel/lib/memset.c b/kernel/lib/memset.c
new file mode 100644
index 0000000..d1c2a5e
--- /dev/null
+++ b/kernel/lib/memset.c
@@ -0,0 +1,10 @@
+#include <lib.h>
+
+void *memset(void *dest, int c, size_t n)
+{
+ unsigned char *d = dest;
+ for (; n; n--) {
+ *d++ = c;
+ };
+ return dest;
+}
diff --git a/lib/memsetv.c b/kernel/lib/memsetv.c
index 91fe6a1..647847f 100644
--- a/lib/memsetv.c
+++ b/kernel/lib/memsetv.c
@@ -1,4 +1,4 @@
-#include <string.h>
+#include <lib.h>
volatile void *memsetv(volatile void *dest, int c, size_t n)
{
diff --git a/kernel/lib/panic.c b/kernel/lib/panic.c
index 403418f..5381041 100644
--- a/kernel/lib/panic.c
+++ b/kernel/lib/panic.c
@@ -7,9 +7,9 @@ __attribute__((noreturn)) void panic(const char *format, ...)
cli();
va_list list;
va_start(list, format);
- printf("\n\n!!! PANIC !!!\n");
- vprintf(format, list);
- printf("\n\n");
+ kprintf("\n\n!!! PANIC !!!\n");
+ kvprintf(format, list);
+ kprintf("\n\n");
while (1)
halt();
diff --git a/kernel/lib/stpcpy.c b/kernel/lib/stpcpy.c
new file mode 100644
index 0000000..1a7c5bf
--- /dev/null
+++ b/kernel/lib/stpcpy.c
@@ -0,0 +1,9 @@
+#include <lib.h>
+
+char *stpcpy(char *restrict dest, const char *restrict src)
+{
+ char *d = dest;
+ for (; (*d = *src); d++, src++)
+ ;
+ return d;
+}
diff --git a/kernel/lib/stpncpy.c b/kernel/lib/stpncpy.c
new file mode 100644
index 0000000..87f9838
--- /dev/null
+++ b/kernel/lib/stpncpy.c
@@ -0,0 +1,10 @@
+#include <lib.h>
+
+char *stpncpy(char *restrict dest, const char *restrict src, size_t n)
+{
+ char *d = dest;
+ for (; (*d = *src) && n; d++, src++, n--)
+ ;
+ memset(d, 0, n);
+ return d;
+}
diff --git a/kernel/lib/strcat.c b/kernel/lib/strcat.c
new file mode 100644
index 0000000..fcfa463
--- /dev/null
+++ b/kernel/lib/strcat.c
@@ -0,0 +1,7 @@
+#include <lib.h>
+
+char *strcat(char *restrict dest, const char *restrict src)
+{
+ strcpy(dest + strlen(dest), src);
+ return dest;
+}
diff --git a/kernel/lib/strcpy.c b/kernel/lib/strcpy.c
new file mode 100644
index 0000000..d74e68d
--- /dev/null
+++ b/kernel/lib/strcpy.c
@@ -0,0 +1,9 @@
+#include <lib.h>
+
+char *strcpy(char *restrict dest, const char *restrict src)
+{
+ char *d = dest;
+ for (; (*d = *src); d++, src++)
+ ;
+ return dest;
+}
diff --git a/kernel/lib/strlen.c b/kernel/lib/strlen.c
new file mode 100644
index 0000000..6d31f2f
--- /dev/null
+++ b/kernel/lib/strlen.c
@@ -0,0 +1,9 @@
+#include <lib.h>
+
+size_t strlen(const char *str)
+{
+ const char *p;
+ for (p = str; *p != 0; p++) {
+ }
+ return p - str;
+}
diff --git a/kernel/lib/strncmp.c b/kernel/lib/strncmp.c
new file mode 100644
index 0000000..0cf5837
--- /dev/null
+++ b/kernel/lib/strncmp.c
@@ -0,0 +1,11 @@
+#include <lib.h>
+
+int strncmp(const char *restrict lhs, const char *restrict rhs, size_t n)
+{
+ const unsigned char *l = (void *)lhs, *r = (void *)rhs;
+ if (!n--)
+ return 0;
+ for (; *l && *r && n && *l == *r; l++, r++, n--)
+ ;
+ return *l - *r;
+}
diff --git a/kernel/lib/strncpy.c b/kernel/lib/strncpy.c
new file mode 100644
index 0000000..f691191
--- /dev/null
+++ b/kernel/lib/strncpy.c
@@ -0,0 +1,10 @@
+#include <lib.h>
+
+char *strncpy(char *restrict dest, const char *restrict src, size_t n)
+{
+ char *d = dest;
+ for (; (*d = *src) && n; d++, src++, n--)
+ ;
+ memset(d, 0, n);
+ return dest;
+}
diff --git a/kernel/lib/strtoux.c b/kernel/lib/strtoux.c
new file mode 100644
index 0000000..e8f828b
--- /dev/null
+++ b/kernel/lib/strtoux.c
@@ -0,0 +1,43 @@
+#include <lib.h>
+
+#define STRTOUX(name, type) \
+ type name(const char *restrict s, char **restrict endptr, int radix) \
+ { \
+ const char *s_start = s; \
+ for (; isspace(*s); s++) \
+ ; \
+ \
+ if ((radix == 0 || radix == 16) && \
+ (s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))) { \
+ radix = 16; \
+ s += 2; \
+ } else if (radix == 0) { \
+ if (*s == '0') { \
+ radix = 8; \
+ s++; \
+ } else { \
+ radix = 10; \
+ } \
+ } \
+ \
+ type num = 0; \
+ int has_digit = 0; \
+ \
+ while (1) { \
+ int n = ctoi(*s++); \
+ if (n < 0 || n >= radix) \
+ break; \
+ has_digit = 1; \
+ num = num * radix + n; \
+ } \
+ \
+ if (endptr != NULL) { \
+ *endptr = has_digit ? (char *)(s - 1) : (char *)s_start; \
+ } \
+ \
+ return num; \
+ }
+
+STRTOUX(strtoui, unsigned int)
+STRTOUX(strtoul, unsigned long int)
+STRTOUX(strtoull, unsigned long long int)
diff --git a/kernel/lib/strtox.c b/kernel/lib/strtox.c
new file mode 100644
index 0000000..620b8d3
--- /dev/null
+++ b/kernel/lib/strtox.c
@@ -0,0 +1,52 @@
+#include <lib.h>
+
+#define STRTOX(name, type) \
+ type name(const char *restrict s, char **restrict endptr, int radix) \
+ { \
+ const char *s_start = s; \
+ for (; isspace(*s); s++) \
+ ; \
+ \
+ int sign = 0; \
+ switch (*s) { \
+ case '-': \
+ sign = 1; /* fallthrough */ \
+ case '+': \
+ s++; \
+ break; \
+ } \
+ \
+ if ((radix == 0 || radix == 16) && \
+ (s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))) { \
+ radix = 16; \
+ s += 2; \
+ } else if (radix == 0) { \
+ if (*s == '0') { \
+ radix = 8; \
+ s++; \
+ } else { \
+ radix = 10; \
+ } \
+ } \
+ \
+ type num = 0; \
+ int has_digit = 0; \
+ \
+ while (1) { \
+ int n = ctoi(*s++); \
+ if (n < 0 || n >= radix) \
+ break; \
+ has_digit = 1; \
+ num = num * radix + n; \
+ } \
+ \
+ if (endptr != NULL) { \
+ *endptr = has_digit ? (char *)(s - 1) : (char *)s_start; \
+ } \
+ \
+ return sign ? -num : num; \
+ }
+
+STRTOX(strtoi, int)
+STRTOX(strtol, long int)
+STRTOX(strtoll, long long int)
diff --git a/kernel/lib/uxtoa.c b/kernel/lib/uxtoa.c
new file mode 100644
index 0000000..9133d29
--- /dev/null
+++ b/kernel/lib/uxtoa.c
@@ -0,0 +1,27 @@
+#include <lib.h>
+
+#define UXTOA(type, name) \
+ char *name(unsigned type n, char *buffer, int radix) \
+ { \
+ if (n == 0) { \
+ buffer[0] = '0'; \
+ buffer[1] = '\0'; \
+ return buffer + 1; \
+ } \
+ char *start = buffer; \
+ for (; n; n /= radix) { \
+ *buffer++ = itoc(n % radix); \
+ } \
+ char *buf_end = buffer; \
+ *buffer-- = '\0'; \
+ while (buffer > start) { \
+ char tmp = *start; \
+ *start++ = *buffer; \
+ *buffer-- = tmp; \
+ } \
+ return buf_end; \
+ }
+
+UXTOA(int, utoa)
+UXTOA(long int, ultoa)
+UXTOA(long long int, ulltoa)
diff --git a/kernel/lib/xtoa.c b/kernel/lib/xtoa.c
new file mode 100644
index 0000000..bd3a367
--- /dev/null
+++ b/kernel/lib/xtoa.c
@@ -0,0 +1,31 @@
+#include <lib.h>
+
+#define XTOA(type, name) \
+ char *name(type n, char *buffer, int radix) \
+ { \
+ if (n == 0) { \
+ buffer[0] = '0'; \
+ buffer[1] = '\0'; \
+ return buffer + 1; \
+ } \
+ if (n < 0) { \
+ *buffer++ = '-'; \
+ n = -n; \
+ } \
+ char *start = buffer; \
+ for (; n; n /= radix) { \
+ *buffer++ = itoc(n % radix); \
+ } \
+ char *buf_end = buffer; \
+ *buffer-- = '\0'; \
+ while (buffer > start) { \
+ char tmp = *start; \
+ *start++ = *buffer; \
+ *buffer-- = tmp; \
+ } \
+ return buf_end; \
+ }
+
+XTOA(int, itoa)
+XTOA(long int, ltoa)
+XTOA(long long int, lltoa)
diff --git a/kernel/kernel.c b/kernel/main.c
index 7382a7d..5b06ae2 100644
--- a/kernel/kernel.c
+++ b/kernel/main.c
@@ -4,8 +4,6 @@
#include <comus/drivers.h>
#include <comus/fs.h>
#include <lib.h>
-#include <stdio.h>
-#include <time.h>
struct memory_map mmap;
@@ -29,13 +27,6 @@ void main(long magic, volatile void *mboot)
// load file systems
fs_init();
- // print current time
- char date[40];
- set_timezone(TZ_EDT);
- time_t time = get_localtime();
- timetostr(&time, "%a %b %d %Y %H:%M:%S", date, 40);
- printf("The date is: %s\n\n", date);
-
// halt
- printf("halting...\n");
+ kprintf("halting...\n");
}
diff --git a/kernel/mboot/mmap.c b/kernel/mboot/mmap.c
index ff38771..8a5f549 100644
--- a/kernel/mboot/mmap.c
+++ b/kernel/mboot/mmap.c
@@ -2,8 +2,6 @@
#include <comus/mboot.h>
#include "mboot.h"
-#include <stdint.h>
-#include <stdio.h>
static const char *segment_type[] = { "Reserved", "Free",
"Reserved", "ACPI Reserved",
@@ -17,7 +15,7 @@ void mboot_load_mmap(volatile void *mboot, struct memory_map *res)
int idx = 0;
uintptr_t i = (uintptr_t)mmap->entries;
- printf("MEMORY MAP\n");
+ kprintf("MEMORY MAP\n");
char buf[20];
for (; i < (uintptr_t)mmap->entries + mmap->size;
i += mmap->entry_size, idx++) {
@@ -27,7 +25,7 @@ void mboot_load_mmap(volatile void *mboot, struct memory_map *res)
type = segment_type[6];
else
type = segment_type[seg->type];
- printf("ADDR: %16p LEN: %4s TYPE: %s (%d)\n", (void *)seg->addr,
+ kprintf("ADDR: %16p LEN: %4s TYPE: %s (%d)\n", (void *)seg->addr,
btoa(seg->len, buf), type, seg->type);
if (seg->type != 1 || seg->len < 1)
continue;
diff --git a/kernel/memory/paging.c b/kernel/memory/paging.c
index d10cf6d..5c4fa5c 100644
--- a/kernel/memory/paging.c
+++ b/kernel/memory/paging.c
@@ -514,7 +514,7 @@ static inline void *page_align(void *addr)
return (void *)a;
}
-void *mapaddr(void *addr, size_t len)
+void *kmapaddr(void *addr, size_t len)
{
void *phys = page_align(addr);
ptrdiff_t error = (char *)addr - (char *)phys;
@@ -531,7 +531,7 @@ void *mapaddr(void *addr, size_t len)
return (char *)virt + error;
}
-void unmapaddr(void *addr)
+void kunmapaddr(void *addr)
{
long pages = virtaddr_free(addr);
if (pages < 1)
@@ -539,7 +539,7 @@ void unmapaddr(void *addr)
unmap_pages(kernel_pml4, addr, pages);
}
-void *alloc_pages(size_t count)
+void *kalloc_pages(size_t count)
{
void *virt = virtaddr_alloc(count);
if (virt == NULL)
@@ -559,13 +559,12 @@ void *alloc_pages(size_t count)
return virt;
}
-void free_page(void *virt)
+void *kalloc_page(void)
{
- (void)virt;
- panic("free_page is not yet implemented");
+ return kalloc_pages(1);
}
-void free_pages(void *virt)
+void kfree_pages(void *virt)
{
long pages = virtaddr_free(virt);
if (pages < 1)
@@ -573,7 +572,7 @@ void free_pages(void *virt)
unmap_pages(kernel_pml4, virt, pages);
}
-int load_page(void *virt_addr)
+int kload_page(void *virt_addr)
{
volatile struct pte *page = get_page(kernel_pml4, virt_addr);
if (page == NULL)
diff --git a/kernel/memory/physalloc.c b/kernel/memory/physalloc.c
index 53f8aaf..a907077 100644
--- a/kernel/memory/physalloc.c
+++ b/kernel/memory/physalloc.c
@@ -185,9 +185,9 @@ void physalloc_init(struct memory_map *map)
memory_start = page_align((uintptr_t)page_area_addr + page_area_size);
- bitmap = mapaddr(bitmap, bitmap_size);
+ bitmap = kmapaddr(bitmap, bitmap_size);
memset(bitmap, 0, bitmap_size);
- page_area_addr = mapaddr(page_area_addr, page_area_size);
+ page_area_addr = kmapaddr(page_area_addr, page_area_size);
memset(page_area_addr, 0, page_area_size);
page_start = (struct memory_segment *)page_area_addr;
@@ -210,15 +210,10 @@ void physalloc_init(struct memory_map *map)
free_memory = page_count * PAGE_SIZE;
char buf[20];
- printf("\nMEMORY USAGE\n");
- printf("mem total: %s\n", btoa(memory_total(), buf));
- printf("mem free: %s\n", btoa(memory_free(), buf));
- printf("mem used: %s\n\n", btoa(memory_used(), buf));
-}
-
-void *alloc_page(void)
-{
- return alloc_pages(1);
+ kprintf("\nMEMORY USAGE\n");
+ kprintf("mem total: %s\n", btoa(memory_total(), buf));
+ kprintf("mem free: %s\n", btoa(memory_free(), buf));
+ kprintf("mem used: %s\n\n", btoa(memory_used(), buf));
}
uint64_t memory_total(void)
diff --git a/kernel/memory/virtalloc.c b/kernel/memory/virtalloc.c
index 2b64b72..6b7fd20 100644
--- a/kernel/memory/virtalloc.c
+++ b/kernel/memory/virtalloc.c
@@ -64,11 +64,11 @@ static struct addr_node *get_node(void)
if (new_alloc < 8)
new_alloc = 8;
struct addr_node *new_nodes;
- new_nodes = malloc(sizeof(struct addr_node) * new_alloc);
+ new_nodes = kalloc(sizeof(struct addr_node) * new_alloc);
if (new_nodes == NULL)
panic("virt addr alloc nodes is null");
update_node_ptrs(alloc_nodes, new_nodes, alloc_node_count, new_alloc);
- free(alloc_nodes);
+ kfree(alloc_nodes);
alloc_nodes = new_nodes;
alloc_node_count = new_alloc;
is_allocating = false;
diff --git a/include/ctype.h b/user/include/ctype.h
index c5f92b4..c5f92b4 100644
--- a/include/ctype.h
+++ b/user/include/ctype.h
diff --git a/include/elf.h b/user/include/elf.h
index b7e6059..b7e6059 100644
--- a/include/elf.h
+++ b/user/include/elf.h
diff --git a/include/error.h b/user/include/error.h
index b9265b4..b9265b4 100644
--- a/include/error.h
+++ b/user/include/error.h
diff --git a/include/stdio.h b/user/include/stdio.h
index d335968..9e60f55 100644
--- a/include/stdio.h
+++ b/user/include/stdio.h
@@ -12,19 +12,13 @@
#include <stdarg.h>
#include <stddef.h>
+// TODO: implement
typedef void FILE;
-/// standard input
-#define stdin ((FILE *)1)
-/// standard output
-#define stdout ((FILE *)2)
-/// standard error
-#define stderr ((FILE *)3)
-
-/// console output
-#define stdcon ((FILE *)4)
-/// serial output
-#define stduart ((FILE *)5)
+extern FILE *stdin;
+extern FILE *stdout;
+#define stdin stdin
+#define stdout stdout
/**
* Prints out a char
diff --git a/include/stdlib.h b/user/include/stdlib.h
index 1455a1f..40bffde 100644
--- a/include/stdlib.h
+++ b/user/include/stdlib.h
@@ -11,8 +11,6 @@
#include <stddef.h>
-#define PAGE_SIZE 4096
-
/**
* converts single digit int to base 36
* @param i - int
@@ -221,34 +219,4 @@ extern void *realloc(void *ptr, size_t size);
*/
extern void free(void *ptr);
-/**
- * Allocate a single page of memory
- *
- * @returns the address allocated or NULL on failure
- */
-extern void *alloc_page(void);
-
-/**
- * Allocate size_t amount of contiguous virtual pages
- *
- * @param count - the number of pages to allocate
- * @returns the address allocated or NULL on failure
- */
-extern void *alloc_pages(size_t count);
-
-/**
- * Free allocated pages.
- *
- * @param ptr - the pointer provided by alloc_page or alloc_pages
- */
-extern void free_pages(void *ptr);
-
-/**
- * Abort the current process with a given message.
- *
- * @param format - the format string
- * @param ... - variable args for the format
- */
-__attribute__((noreturn)) extern void panic(const char *format, ...);
-
#endif /* stlib.h */
diff --git a/include/string.h b/user/include/string.h
index f966981..4d32f57 100644
--- a/include/string.h
+++ b/user/include/string.h
@@ -52,38 +52,6 @@ extern void *memmove(void *restrict dest, const void *restrict src, size_t n);
extern void *memset(void *restrict dest, int c, size_t n);
/**
- * Copy the first n bytes from memory area src to memory area dest. The memory
- * areas must not overlap.
- * @param dest - the destination
- * @param src - the source
- * @param n - the byte count
- * @returns a pointer to dest
- */
-extern volatile void *memcpyv(volatile void *restrict dest,
- const volatile void *restrict src, size_t n);
-
-/**
- * Copy the first n bytes from memory area src to memory area dest. The memory
- * areas may overlap; memmove behaves as though the bytes are first copied to a
- * temporary array.
- * @param dest - the destination
- * @param src - the source
- * @param n - the byte count
- * @returns a pointer to dest
- */
-extern volatile void *memmovev(volatile void *restrict dest,
- const volatile void *restrict src, size_t n);
-
-/**
- * Fill the first n bytes of the memory region dest with the constant byte c.
- * @param dest - the destination
- * @param c - the byte to write
- * @param n - the byte count
- * @returns a pointer to dest
- */
-extern volatile void *memsetv(volatile void *restrict dest, int c, size_t n);
-
-/**
* Calculates the length of the string pointed to by str, excluding
* the terminating null byte
* @param str - the string pointer
diff --git a/include/unistd.h b/user/include/unistd.h
index f9838f1..1f83abc 100644
--- a/include/unistd.h
+++ b/user/include/unistd.h
@@ -6,29 +6,29 @@
* Universial system definitions for userspace.
*/
-#ifndef _UNISTD_H
-#define _UNISTD_H
+#ifndef UNISTD_H_
+#define UNISTD_H_
#include <stdint.h>
#include <stddef.h>
/* System Call Definitions */
-typedef uint_t pid_t;
+typedef unsigned short pid_t;
/**
- * Terminates the calling process and does not return.
+ * terminates the calling process and does not return.
+ *
* @param status - the status code to exit with
*/
-__attribute__((noreturn)) extern void exit(int32_t status);
+__attribute__((noreturn)) extern void exit(int status);
/**
- * Sleeps current process until a child process terminates
+ * sleeps current process until a child process terminates
*
* @param pid - pid of the desired child, or 0 for any child
- * @param status - Pointer to int32_t into which the child's status is placed,
+ * @param status - pointer to int32_t into which the child's status is placed,
* or NULL
- *
* @return The pid of the terminated child, or an error code
*
* If there are no children in the system, returns an error code (*status
@@ -38,18 +38,18 @@ __attribute__((noreturn)) extern void exit(int32_t status);
* terminated but hasn't yet been cleaned up, cleans up that process and
* returns its information; otherwise, blocks until a child terminates.
*/
-extern int waitpid(pid_t pid, int32_t *status);
+extern int waitpid(pid_t pid, int *status);
/**
- * Create a duplicate of the calling process
+ * create a duplicate of the calling process
*
- * @return parent - the pid of the new child, or an error code
- * child - 0
+ * @return parent - the pid of the new child, or an error code
+ * child - 0
*/
extern int fork(void);
/**
- * Replace the memory image of the calling process
+ * replace the memory image of the calling process
*
* @param prog - program table index of the program to exec
* @param args - the command-line argument vector
@@ -57,126 +57,124 @@ extern int fork(void);
* Does not return if it succeeds; if it returns, something has
* gone wrong.
*/
-extern void exec(uint_t prog, char **args);
+extern void exec(const char *filename, char **args);
/**
- * Open a stream with a given filename
+ * open a stream with a given filename
*
* @param filename - the name of the file to open
* @return the file descriptior of the open file or a negative error code.
- * TODO: fmurphy implement
*/
-extern int open(char *filename);
+extern int open(const char *filename);
/**
- * Closes a stream with the given file descriptior
+ * closes a stream with the given file descriptior
+ *
* @param fd - the file descriptior of the open stream
- * TODO: fmurphy implement
*/
extern void close(int fd);
/**
- * Read into a buffer from a stream
+ * read into a buffer from a stream
*
* @param fd - file stream to read from
* @param buf - buffer to read into
* @param nbytes - maximum capacity of the buffer
- *
* @return - The count of bytes transferred, or an error code
- * TODO: fmurphy FD
*/
extern int read(int fd, void *buffer, size_t nbytes);
/**
- * Write from a buffer to a stream
+ * write from a buffer to a stream
*
* @param fd - file stream to write to
* @param buf - buffer to write from
* @param nbytes - maximum capacity of the buffer
- *
* @return - The count of bytes transferred, or an error code
- * TODO: fmurphy FD
*/
extern int write(int fd, const void *buffer, size_t nbytes);
/**
- * Gets the pid of the calling process
+ * gets the pid of the calling process
*
* @return the pid of this process
*/
extern pid_t getpid(void);
/**
- * Gets the parent pid of the current process
+ * gets the parent pid of the current process
*
* @return the parent pid of the current process, or 0 if init
*/
extern pid_t getppid(void);
/**
- * Gets the current system time
+ * gets the current system time
*
* @return the system time
- * TODO: CHANGE TIME TO 64bits!!
*/
-extern ulong_t gettime(void);
+extern unsigned long gettime(void);
/**
- * Gets the scheduling priority of the calling process
+ * gets the scheduling priority of the calling process
*
* @return the process' priority
*/
-extern uint_t getprio(void);
+extern unsigned int getprio(void);
/**
- * Sets the scheduling priority of the calling process
+ * sets the scheduling priority of the calling process
*
* @param new - the desired new priority
- *
* @return the old priority value
*/
-extern uint_t setprio(uint_t new);
+extern unsigned int setprio(unsigned int new);
/**
- * Terminates a process
+ * terminates a process
*
* @param pid - the pid of the process to kill
- *
* @return 0 on success, else an error code
*/
-extern int32_t kill(pid_t pid);
+extern int kill(pid_t pid);
/**
- * Put the current process to sleep for some length of time
+ * put the current process to sleep for some length of time
*
* @param ms - desired sleep time (in ms), or 0 to yield the CPU
- *
* @return the time the process spent sleeping (in ms)
*/
-extern int sleep(uint32_t ms);
+extern int sleep(unsigned long ms);
/**
* Wait for any child to exit
*
- * @param status - Pointer to int32_t into which the child's status is placed,
+ * @param status - pointer to int32_t into which the child's status is placed,
* or NULL
- *
* @return The pid of the terminated child, or an error code
*
* Analogous to waitpid(0,status)
*/
-extern int wait(int32_t *status);
+extern int wait(int *status);
/**
* Spawn a new process running a different program
*
* @param prog - program table index of the program to spawn
* @param args - the command-line argument vector for the process
- *
- * @return The pid of the child, or an error code
+ * @return the pid of the child, or an error code
*
* Analogous to calling fork and exec
*/
-extern int spawn(uint_t prog, char **args);
+extern int spawn(pid_t prog, char **args);
+
+/**
+ * Increment the program's data space by increment bytes.
+ *
+ * @param increment - the amount in bytes to increment the heap
+ * @return the previos program break on success, or NULL on failure
+ *
+ */
+extern void *sbrk(intptr_t increment);
#endif /* unistd.h */
diff --git a/lib/alloc.c b/user/lib/alloc.c
index dfa2df5..49c762b 100644
--- a/lib/alloc.c
+++ b/user/lib/alloc.c
@@ -1,8 +1,10 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
#define MAGIC 0xBEEFCAFE
+#define PAGE_SIZE 4096
struct page_header {
struct page_header *next;
@@ -37,6 +39,7 @@ static void *alloc_new(size_t size)
{
size_t pages = ((size + header_len) / PAGE_SIZE) + 1;
+ // FIXME: use brk/sbrk
void *addr = alloc_pages(pages);
void *mem = (char *)addr + header_len;
@@ -206,6 +209,7 @@ void free(void *ptr)
header->next->prev = header->prev;
if (header->prev)
header->prev->next = header->next;
+ // FIXME: use brk/sbrk
free_pages(header);
}
}
diff --git a/lib/atox.c b/user/lib/atox.c
index c4bef59..c4bef59 100644
--- a/lib/atox.c
+++ b/user/lib/atox.c
diff --git a/lib/bound.c b/user/lib/bound.c
index 072a41a..072a41a 100644
--- a/lib/bound.c
+++ b/user/lib/bound.c
diff --git a/lib/btoa.c b/user/lib/btoa.c
index fe5e275..fe5e275 100644
--- a/lib/btoa.c
+++ b/user/lib/btoa.c
diff --git a/lib/ctoi.c b/user/lib/ctoi.c
index efe4fec..efe4fec 100644
--- a/lib/ctoi.c
+++ b/user/lib/ctoi.c
diff --git a/lib/delay.c b/user/lib/delay.c
index ff5ccc4..ff5ccc4 100644
--- a/lib/delay.c
+++ b/user/lib/delay.c
diff --git a/ulib/entry.S b/user/lib/entry.S
index 87ad9c7..87ad9c7 100644
--- a/ulib/entry.S
+++ b/user/lib/entry.S
diff --git a/lib/isdigit.c b/user/lib/isdigit.c
index aa93ced..aa93ced 100644
--- a/lib/isdigit.c
+++ b/user/lib/isdigit.c
diff --git a/lib/isspace.c b/user/lib/isspace.c
index 9e89d76..9e89d76 100644
--- a/lib/isspace.c
+++ b/user/lib/isspace.c
diff --git a/lib/itoc.c b/user/lib/itoc.c
index c19d814..c19d814 100644
--- a/lib/itoc.c
+++ b/user/lib/itoc.c
diff --git a/lib/memcmp.c b/user/lib/memcmp.c
index 7f3dc01..7f3dc01 100644
--- a/lib/memcmp.c
+++ b/user/lib/memcmp.c
diff --git a/lib/memcpy.c b/user/lib/memcpy.c
index ec56537..ec56537 100644
--- a/lib/memcpy.c
+++ b/user/lib/memcpy.c
diff --git a/lib/memmove.c b/user/lib/memmove.c
index 81f00fe..81f00fe 100644
--- a/lib/memmove.c
+++ b/user/lib/memmove.c
diff --git a/lib/memset.c b/user/lib/memset.c
index ddf42f8..ddf42f8 100644
--- a/lib/memset.c
+++ b/user/lib/memset.c
diff --git a/lib/printf.c b/user/lib/printf.c
index 4a85956..4a85956 100644
--- a/lib/printf.c
+++ b/user/lib/printf.c
diff --git a/ulib/spawn.c b/user/lib/spawn.c
index 78b1a53..78b1a53 100644
--- a/ulib/spawn.c
+++ b/user/lib/spawn.c
diff --git a/lib/stpcpy.c b/user/lib/stpcpy.c
index 1586a37..1586a37 100644
--- a/lib/stpcpy.c
+++ b/user/lib/stpcpy.c
diff --git a/lib/stpncpy.c b/user/lib/stpncpy.c
index 4e0def6..4e0def6 100644
--- a/lib/stpncpy.c
+++ b/user/lib/stpncpy.c
diff --git a/lib/strcat.c b/user/lib/strcat.c
index 33f749b..33f749b 100644
--- a/lib/strcat.c
+++ b/user/lib/strcat.c
diff --git a/lib/strcpy.c b/user/lib/strcpy.c
index 70cd1ca..70cd1ca 100644
--- a/lib/strcpy.c
+++ b/user/lib/strcpy.c
diff --git a/lib/strlen.c b/user/lib/strlen.c
index 6c4cc86..6c4cc86 100644
--- a/lib/strlen.c
+++ b/user/lib/strlen.c
diff --git a/lib/strncmp.c b/user/lib/strncmp.c
index e890517..e890517 100644
--- a/lib/strncmp.c
+++ b/user/lib/strncmp.c
diff --git a/lib/strncpy.c b/user/lib/strncpy.c
index 264fd9d..264fd9d 100644
--- a/lib/strncpy.c
+++ b/user/lib/strncpy.c
diff --git a/lib/strtoux.c b/user/lib/strtoux.c
index 7c2d7ee..7c2d7ee 100644
--- a/lib/strtoux.c
+++ b/user/lib/strtoux.c
diff --git a/lib/strtox.c b/user/lib/strtox.c
index 5f786f1..5f786f1 100644
--- a/lib/strtox.c
+++ b/user/lib/strtox.c
diff --git a/ulib/syscall.S b/user/lib/syscall.S
index 46fcb89..46fcb89 100644
--- a/ulib/syscall.S
+++ b/user/lib/syscall.S
diff --git a/lib/timetostr.c b/user/lib/timetostr.c
index fa77362..fa77362 100644
--- a/lib/timetostr.c
+++ b/user/lib/timetostr.c
diff --git a/lib/uxtoa.c b/user/lib/uxtoa.c
index 8d4e0e1..8d4e0e1 100644
--- a/lib/uxtoa.c
+++ b/user/lib/uxtoa.c
diff --git a/lib/xtoa.c b/user/lib/xtoa.c
index bf02236..bf02236 100644
--- a/lib/xtoa.c
+++ b/user/lib/xtoa.c
diff --git a/util/BuildImage.c b/util/BuildImage.c
deleted file mode 100644
index f43f0b0..0000000
--- a/util/BuildImage.c
+++ /dev/null
@@ -1,420 +0,0 @@
-/**
-** SCCS ID: @(#)BuildImage.c 2.2 1/16/25
-**
-** @file BuildImage.c
-**
-** @author K. Reek
-** @author Jon Coles
-** @author Warren R. Carithers
-** @author Garrett C. Smith
-**
-** Modify the bootstrap image to include the information
-** on the programs to be loaded, and produce the file
-** that contains the concatenation of these programs.
-**
-*/
-
-#define _POSIX_C_SOURCE 200809L
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-
-#define TRUE 1
-#define FALSE 0
-
-#define DRIVE_FLOPPY 0x00
-#define DRIVE_USB 0x80
-
-#define SECT_SIZE 512
-
-char *progname; /* invocation name of this program */
-char *bootstrap_filename; /* path of file holding bootstrap program */
-char *output_filename; /* path of disk image file */
-FILE *out; /* output stream for disk image file */
-short drive = DRIVE_USB; /* boot drive */
-
-/*
-** Array into which program information will be stored, starting at the
-** end and moving back toward the front. The array is the same size as
-** a sector, which is guaranteed to be larger than the maximum possible
-** space available for this stuff in the bootstrap image. Thus, the
-** bootstrap image itself (and the amount of space available on the
-** device) are the only limiting factors on how many program sections
-** can be loaded.
-*/
-
-#define N_INFO (SECT_SIZE / sizeof(short))
-
-short info[N_INFO];
-int n_info = N_INFO;
-
-/**
-** quit with an appropriate message
-**
-** @param msg NULL, or a message to be printed to stderr
-** @param call_perror non-zero if perror() should be used; else,
-** fprintf() will be used
-**
-** does not return
-*/
-void quit(char *msg, int call_perror)
-{
- if (msg != NULL) {
- // preserve the error code in case we need it
- int err_num = errno;
- fprintf(stderr, "%s: ", progname);
- errno = err_num;
- if (call_perror) {
- perror(msg);
- } else {
- fprintf(stderr, "%s\n", msg);
- }
- }
- if (output_filename != NULL) {
- unlink(output_filename);
- }
- exit(EXIT_FAILURE);
- // NOTREACHED
-}
-
-const char usage_error_msg[] =
- "\nUsage: %s [ -d drive ] -b bootfile -o outfile { progfile loadpt } ...\n\n"
- "\t'drive' is either 'floppy' or 'usb' (default 'usb')\n\n"
- "\tThere must be at least one program file and load point.\n\n"
- "\tLoad points may be specified either as 32-bit quantities in hex,\n"
- "\tdecimal or octal (e.g. 0x10c00, 68608, 0206000 are all equivalent),\n"
- "\tor as an explicit segment:offset pair whose digits are always\n"
- "\tinterpreted as hexadecimal values (e.g. 10c0:0000, 1000:0c00 are\n"
- "\tboth equivalent to the previous examples).\n\n";
-
-/**
-** print a usage message and then call quit()
-**
-** does not return
-*/
-void usage_error(void)
-{
- fprintf(stderr, usage_error_msg, progname);
- quit(NULL, FALSE);
- // NOTREACHED
-}
-
-/**
-** copy the contents of a binary file into the output file, padding the
-** last sector with NUL bytes
-**
-** @param in open FILE to be read
-** @return the number of sectors copied from the file
-*/
-int copy_file(FILE *in)
-{
- int n_sectors = 0;
- char buf[SECT_SIZE];
- int n_bytes;
- int i;
-
- /*
- ** Copy the file to the output, being careful that the
- ** last sector is padded with null bytes out to the
- ** sector size.
- */
- n_sectors = 0;
- while ((n_bytes = fread(buf, 1, sizeof(buf), in)) > 0) {
- // pad this sector out to block size
- if (n_bytes < sizeof(buf)) {
- int i;
-
- for (i = n_bytes; i < sizeof(buf); i += 1) {
- buf[i] = '\0';
- }
- }
- if (fwrite(buf, 1, sizeof(buf), out) != sizeof(buf)) {
- quit("Write failed or was wrong size", FALSE);
- }
- n_sectors += 1;
- }
- return n_sectors;
-}
-
-/**
-** process a file whose contents should be at a specific'
-** address in memory when the program is loaded
-**
-** @param name path to the file to be copied
-** @param addr string containing the load address
-*/
-void process_file(char *name, char *addr)
-{
- long address;
- short segment, offset;
- int n_bytes;
-
- /*
- ** Open the input file.
- */
- FILE *in = fopen(name, "rb");
- if (in == NULL) {
- quit(name, TRUE);
- }
-
- /*
- ** Copy the file to the output, being careful that the
- ** last block is padded with null bytes.
- */
- int n_sectors = copy_file(in);
- fclose(in);
-
- /*
- ** Decode the address they gave us. We'll accept two forms:
- ** "nnnn:nnnn" for a segment:offset value (assumed to be hex),
- ** "nnnnnnn" for a decimal, hex, or octal value
- */
- int valid_address = FALSE;
- char *cp = strchr(addr, ':');
- if (cp != NULL) {
- // must be in nnnn:nnnn form exactly
- if (strlen(addr) == 9 && cp == addr + 4) {
- char *ep1, *ep2;
- int a1, a2;
-
- segment = strtol(addr, &ep1, 16);
- offset = strtol(addr + 5, &ep2, 16);
- address = (segment << 4) + offset;
- valid_address = *ep1 == '\0' && *ep2 == '\0';
- } else {
- fprintf(stderr, "Bad address format - '%s'\n", addr);
- quit(NULL, FALSE);
- }
- } else {
- // just a number, possibly hex or octal
- char *ep;
-
- address = strtol(addr, &ep, 0);
- segment = (short)(address >> 4);
- offset = (short)(address & 0xf);
- valid_address = *ep == '\0' && address <= 0x0009ffff;
- }
-
- if (!valid_address) {
- fprintf(stderr, "%s: Invalid address: %s\n", progname, addr);
- quit(NULL, FALSE);
- }
-
- /*
- ** Make sure the program will fit!
- */
- if (address + n_sectors * SECT_SIZE > 0x0009ffff) {
- fprintf(stderr, "Program %s too large to start at 0x%08x\n", name,
- (unsigned int)address);
- quit(NULL, FALSE);
- }
-
- if (n_info < 3) {
- quit("Too many programs!", FALSE);
- }
-
- /*
- ** Looks good: report and store the information.
- */
- fprintf(stderr, " %s: %d sectors, loaded at 0x%x\n", name, n_sectors,
- (unsigned int)address);
-
- info[--n_info] = n_sectors;
- info[--n_info] = segment;
- info[--n_info] = offset;
-}
-
-/*
-** Global variables set by getopt()
-*/
-
-extern int optind, optopt;
-extern char *optarg;
-
-/**
-** process the command-line arguments
-**
-** @param ac the count of entries in av
-** @param av the argument vector
-*/
-void process_args(int ac, char **av)
-{
- int c;
-
- while ((c = getopt(ac, av, ":d:o:b:")) != EOF) {
- switch (c) {
- case ':': /* missing arg value */
- fprintf(stderr, "missing operand after -%c\n", optopt);
- /* FALL THROUGH */
-
- case '?': /* error */
- usage_error();
- /* NOTREACHED */
-
- case 'b': /* -b bootstrap_file */
- bootstrap_filename = optarg;
- break;
-
- case 'd': /* -d drive */
- switch (*optarg) {
- case 'f':
- drive = DRIVE_FLOPPY;
- break;
- case 'u':
- drive = DRIVE_USB;
- break;
- default:
- usage_error();
- }
- break;
-
- case 'o': /* -o output_file */
- output_filename = optarg;
- break;
-
- default:
- usage_error();
- }
- }
-
- if (!bootstrap_filename) {
- fprintf(stderr, "%s: no bootstrap file specified\n", progname);
- exit(2);
- }
-
- if (!output_filename) {
- fprintf(stderr, "%s: no disk image file specified\n", progname);
- exit(2);
- }
-
- /*
- ** Must have at least two remaining arguments (file to load,
- ** address at which it should be loaded), and must have an
- ** even number of remaining arguments.
- */
- int remain = ac - optind;
- if (remain < 2 || (remain & 1) != 0) {
- usage_error();
- }
-}
-
-/**
-** build a bootable image file from one or more binary files
-**
-** usage:
-** BuildImage [ -d drive ] -b bootfile -o outfile { binfile1 loadpt1 } ... ]
-**
-** @param ac command-line argument count
-** @param av command-line argument vector
-** @return EXIT_SUCCESS or EXIT_FAILURE
-*/
-int main(int ac, char **av)
-{
- FILE *bootimage;
- int bootimage_size;
- int n_bytes, n_words;
- short existing_data[N_INFO];
- int i;
-
- /*
- ** Save the program name for error messages
- */
- progname = strrchr(av[0], '/');
- if (progname != NULL) {
- progname++;
- } else {
- progname = av[0];
- }
-
- /*
- ** Process arguments
- */
- process_args(ac, av);
-
- /*
- ** Open the output file
- */
-
- out = fopen(output_filename, "wb+");
- if (out == NULL) {
- quit(output_filename, TRUE);
- }
-
- /*
- ** Open the bootstrap file and copy it to the output image.
- */
- bootimage = fopen(bootstrap_filename, "rb");
- if (bootimage == NULL) {
- quit(bootstrap_filename, TRUE);
- }
-
- /*
- ** Remember the size of the bootstrap for later, as we
- ** need to patch some things into it
- */
- int n_sectors = copy_file(bootimage);
- fclose(bootimage);
-
- bootimage_size = n_sectors * SECT_SIZE;
- fprintf(stderr, " %s: %d sectors\n", bootstrap_filename, n_sectors);
-
- /*
- ** Process the programs one by one
- */
- ac -= optind;
- av += optind;
- while (ac >= 2) {
- process_file(av[0], av[1]);
- ac -= 2;
- av += 2;
- }
-
- /*
- ** Check for oddball leftover argument
- */
- if (ac > 0) {
- usage_error();
- }
-
- /*
- ** Seek to where the array of module data must begin and read
- ** what's already there.
- */
- n_words = (N_INFO - n_info);
- n_bytes = n_words * sizeof(info[0]);
- fseek(out, bootimage_size - n_bytes, SEEK_SET);
- if (fread(existing_data, sizeof(info[0]), n_words, out) != n_words) {
- quit("Read from boot image failed or was too short", FALSE);
- }
-
- /*
- ** If that space is non-zero, we have a problem
- */
- for (i = 0; i < n_words; i += 1) {
- if (existing_data[i] != 0) {
- quit("Too many programs to load!", FALSE);
- }
- }
-
- /*
- ** We know that we're only overwriting zeros at the end of
- ** the bootstrap image, so it is ok to go ahead and do it.
- */
- fseek(out, bootimage_size - n_bytes, SEEK_SET);
- if (fwrite(info + n_info, sizeof(info[0]), n_words, out) != n_words) {
- quit("Write to boot image failed or was too short", FALSE);
- }
-
- /*
- ** Write the drive index to the image.
- */
- fseek(out, 508, SEEK_SET);
- fwrite((void *)&drive, sizeof(drive), 1, out);
-
- fclose(out);
-
- return EXIT_SUCCESS;
-}
diff --git a/util/default.ld b/util/default.ld
deleted file mode 100644
index 0c600e4..0000000
--- a/util/default.ld
+++ /dev/null
@@ -1,247 +0,0 @@
-GNU ld (GNU Binutils for Ubuntu) 2.30
- Supported emulations:
- elf_x86_64
- elf32_x86_64
- elf_i386
- elf_iamcu
- i386linux
- elf_l1om
- elf_k1om
- i386pep
- i386pe
-using internal linker script:
-==================================================
-/* Script for -z combreloc: combine and sort reloc sections */
-/* Copyright (C) 2014-2018 Free Software Foundation, Inc.
- Copying and distribution of this script, with or without modification,
- are permitted in any medium without royalty provided the copyright
- notice and this notice are preserved. */
-OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64",
- "elf64-x86-64")
-OUTPUT_ARCH(i386:x86-64)
-ENTRY(_start)
-SEARCH_DIR("=/usr/local/lib/x86_64-linux-gnu"); SEARCH_DIR("=/lib/x86_64-linux-gnu"); SEARCH_DIR("=/usr/lib/x86_64-linux-gnu"); SEARCH_DIR("=/usr/lib/x86_64-linux-gnu64"); SEARCH_DIR("=/usr/local/lib64"); SEARCH_DIR("=/lib64"); SEARCH_DIR("=/usr/lib64"); SEARCH_DIR("=/usr/local/lib"); SEARCH_DIR("=/lib"); SEARCH_DIR("=/usr/lib"); SEARCH_DIR("=/usr/x86_64-linux-gnu/lib64"); SEARCH_DIR("=/usr/x86_64-linux-gnu/lib");
-SECTIONS
-{
- /* Read-only sections, merged into text segment: */
- PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS;
- .interp : { *(.interp) }
- .note.gnu.build-id : { *(.note.gnu.build-id) }
- .hash : { *(.hash) }
- .gnu.hash : { *(.gnu.hash) }
- .dynsym : { *(.dynsym) }
- .dynstr : { *(.dynstr) }
- .gnu.version : { *(.gnu.version) }
- .gnu.version_d : { *(.gnu.version_d) }
- .gnu.version_r : { *(.gnu.version_r) }
- .rela.dyn :
- {
- *(.rela.init)
- *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
- *(.rela.fini)
- *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
- *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
- *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
- *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
- *(.rela.ctors)
- *(.rela.dtors)
- *(.rela.got)
- *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
- *(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.*)
- *(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*)
- *(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*)
- *(.rela.ifunc)
- }
- .rela.plt :
- {
- *(.rela.plt)
- PROVIDE_HIDDEN (__rela_iplt_start = .);
- *(.rela.iplt)
- PROVIDE_HIDDEN (__rela_iplt_end = .);
- }
- .init :
- {
- KEEP (*(SORT_NONE(.init)))
- }
- .plt : { *(.plt) *(.iplt) }
-.plt.got : { *(.plt.got) }
-.plt.sec : { *(.plt.sec) }
- .text :
- {
- *(.text.unlikely .text.*_unlikely .text.unlikely.*)
- *(.text.exit .text.exit.*)
- *(.text.startup .text.startup.*)
- *(.text.hot .text.hot.*)
- *(.text .stub .text.* .gnu.linkonce.t.*)
- /* .gnu.warning sections are handled specially by elf32.em. */
- *(.gnu.warning)
- }
- .fini :
- {
- KEEP (*(SORT_NONE(.fini)))
- }
- PROVIDE (__etext = .);
- PROVIDE (_etext = .);
- PROVIDE (etext = .);
- .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
- .rodata1 : { *(.rodata1) }
- .eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) }
- .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) }
- .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table
- .gcc_except_table.*) }
- .gnu_extab : ONLY_IF_RO { *(.gnu_extab*) }
- /* These sections are generated by the Sun/Oracle C++ compiler. */
- .exception_ranges : ONLY_IF_RO { *(.exception_ranges
- .exception_ranges*) }
- /* Adjust the address for the data segment. We want to adjust up to
- the same address within the page on the next page up. */
- . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));
- /* Exception handling */
- .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) }
- .gnu_extab : ONLY_IF_RW { *(.gnu_extab) }
- .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
- .exception_ranges : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) }
- /* Thread Local Storage sections */
- .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
- .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
- .preinit_array :
- {
- PROVIDE_HIDDEN (__preinit_array_start = .);
- KEEP (*(.preinit_array))
- PROVIDE_HIDDEN (__preinit_array_end = .);
- }
- .init_array :
- {
- PROVIDE_HIDDEN (__init_array_start = .);
- KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
- KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
- PROVIDE_HIDDEN (__init_array_end = .);
- }
- .fini_array :
- {
- PROVIDE_HIDDEN (__fini_array_start = .);
- KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
- KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
- PROVIDE_HIDDEN (__fini_array_end = .);
- }
- .ctors :
- {
- /* gcc uses crtbegin.o to find the start of
- the constructors, so we make sure it is
- first. Because this is a wildcard, it
- doesn't matter if the user does not
- actually link against crtbegin.o; the
- linker won't look for a file to match a
- wildcard. The wildcard also means that it
- doesn't matter which directory crtbegin.o
- is in. */
- KEEP (*crtbegin.o(.ctors))
- KEEP (*crtbegin?.o(.ctors))
- /* We don't want to include the .ctor section from
- the crtend.o file until after the sorted ctors.
- The .ctor section from the crtend file contains the
- end of ctors marker and it must be last */
- KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
- KEEP (*(SORT(.ctors.*)))
- KEEP (*(.ctors))
- }
- .dtors :
- {
- KEEP (*crtbegin.o(.dtors))
- KEEP (*crtbegin?.o(.dtors))
- KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
- KEEP (*(SORT(.dtors.*)))
- KEEP (*(.dtors))
- }
- .jcr : { KEEP (*(.jcr)) }
- .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) }
- .dynamic : { *(.dynamic) }
- .got : { *(.got) *(.igot) }
- . = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 24 ? 24 : 0, .);
- .got.plt : { *(.got.plt) *(.igot.plt) }
- .data :
- {
- *(.data .data.* .gnu.linkonce.d.*)
- SORT(CONSTRUCTORS)
- }
- .data1 : { *(.data1) }
- _edata = .; PROVIDE (edata = .);
- . = .;
- __bss_start = .;
- .bss :
- {
- *(.dynbss)
- *(.bss .bss.* .gnu.linkonce.b.*)
- *(COMMON)
- /* Align here to ensure that the .bss section occupies space up to
- _end. Align after .bss to ensure correct alignment even if the
- .bss section disappears because there are no input sections.
- FIXME: Why do we need it? When there is no .bss section, we don't
- pad the .data section. */
- . = ALIGN(. != 0 ? 64 / 8 : 1);
- }
- .lbss :
- {
- *(.dynlbss)
- *(.lbss .lbss.* .gnu.linkonce.lb.*)
- *(LARGE_COMMON)
- }
- . = ALIGN(64 / 8);
- . = SEGMENT_START("ldata-segment", .);
- .lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
- {
- *(.lrodata .lrodata.* .gnu.linkonce.lr.*)
- }
- .ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
- {
- *(.ldata .ldata.* .gnu.linkonce.l.*)
- . = ALIGN(. != 0 ? 64 / 8 : 1);
- }
- . = ALIGN(64 / 8);
- _end = .; PROVIDE (end = .);
- . = DATA_SEGMENT_END (.);
- /* Stabs debugging sections. */
- .stab 0 : { *(.stab) }
- .stabstr 0 : { *(.stabstr) }
- .stab.excl 0 : { *(.stab.excl) }
- .stab.exclstr 0 : { *(.stab.exclstr) }
- .stab.index 0 : { *(.stab.index) }
- .stab.indexstr 0 : { *(.stab.indexstr) }
- .comment 0 : { *(.comment) }
- /* DWARF debug sections.
- Symbols in the DWARF debugging sections are relative to the beginning
- of the section so we begin them at 0. */
- /* DWARF 1 */
- .debug 0 : { *(.debug) }
- .line 0 : { *(.line) }
- /* GNU DWARF 1 extensions */
- .debug_srcinfo 0 : { *(.debug_srcinfo) }
- .debug_sfnames 0 : { *(.debug_sfnames) }
- /* DWARF 1.1 and DWARF 2 */
- .debug_aranges 0 : { *(.debug_aranges) }
- .debug_pubnames 0 : { *(.debug_pubnames) }
- /* DWARF 2 */
- .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
- .debug_abbrev 0 : { *(.debug_abbrev) }
- .debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end ) }
- .debug_frame 0 : { *(.debug_frame) }
- .debug_str 0 : { *(.debug_str) }
- .debug_loc 0 : { *(.debug_loc) }
- .debug_macinfo 0 : { *(.debug_macinfo) }
- /* SGI/MIPS DWARF 2 extensions */
- .debug_weaknames 0 : { *(.debug_weaknames) }
- .debug_funcnames 0 : { *(.debug_funcnames) }
- .debug_typenames 0 : { *(.debug_typenames) }
- .debug_varnames 0 : { *(.debug_varnames) }
- /* DWARF 3 */
- .debug_pubtypes 0 : { *(.debug_pubtypes) }
- .debug_ranges 0 : { *(.debug_ranges) }
- /* DWARF Extension. */
- .debug_macro 0 : { *(.debug_macro) }
- .debug_addr 0 : { *(.debug_addr) }
- .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
- /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }
-}
-
-
-==================================================
diff --git a/util/listblob.c b/util/listblob.c
deleted file mode 100644
index e6266a3..0000000
--- a/util/listblob.c
+++ /dev/null
@@ -1,240 +0,0 @@
-/**
-** @file listblob.c
-**
-** @author Warren R. Carithers
-**
-** Examine a binary blob of ELF files.
-*/
-#define _DEFAULT_SOURCE
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <stdbool.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <elf.h>
-#include <ctype.h>
-
-/*
-** Blob file organization
-**
-** The file begins with a four-byte magic number and a four-byte integer
-** indicating the number of ELF files contained in the blob. This is
-** followed by an array of 32-byte file entries, and then the contents
-** of the ELF files in the order they appear in the program file table.
-**
-** Bytes Contents
-** ----- ----------------------------
-** 0 - 3 File magic number ("BLB\0")
-** 4 - 7 Number of ELF files in blob ("n")
-** 8 - n*32+8 Program file table
-** n*32+9 - ? ELF file contents
-**
-** Each program file table entry contains the following information:
-**
-** name File name (up to 19 characters long)
-** offset Byte offset to the ELF header for this file
-** size Size of this ELF file, in bytes
-** flags Flags related to this file
-*/
-
-// blob header: 8 bytes
-typedef struct header_s {
- char magic[4];
- uint32_t num;
-} header_t;
-
-// The program table entry is 32 bytes long. To accomplish this, the
-// name field is 20 bytes long, which allows file names of 19 characters
-// (followed by a trailing NUL byte).
-//
-// If that field is made longer, it should be incremented in multiples
-// of four to avoid the insertion of padding bytes.
-#define NAMELEN 20
-
-// program descriptor: 32 bytes
-typedef struct prog_s {
- char name[NAMELEN]; // truncated name (19 chars plus NUL)
- uint32_t offset; // offset from the beginning of the blob
- uint32_t size; // size of this ELF module
- uint32_t flags; // miscellaneous flags
-} prog_t;
-
-// modules must be written as multiples of eight bytes
-#define FL_ROUNDUP 0x00000001
-
-// mask for mod 8 checking
-#define FSIZE_MASK 0x00000007
-
-// program list entry
-typedef struct node_s {
- prog_t *data;
- struct node_s *next;
-} node_t;
-
-node_t *progs, *last_prog; // list pointers
-uint32_t n_progs; // number of files being copied
-uint32_t offset; // current file area offset
-bool defs = false; // print CPP #defines?
-bool enums = false; // print C enums?
-
-// header string for the userids.h file
-const char header[] =
- "/**\n"
- "** @file userids.h\n"
- "**\n"
- "** @author Warren R. Carithers\n"
- "**\n"
- "** @brief IDs for user-level programs\n"
- "**\n"
- "** NOTE: this file is automatically generated when the user.img file\n"
- "** is created. Do not edit this manually!\n"
- "*/\n"
- "\n"
- "#ifndef USERIDS_H_\n"
- "#define USERIDS_H_\n"
- "\n"
- "#ifndef ASM_SRC\n"
- "/*\n"
- "** These IDs are used to identify the various user programs.\n"
- "** Each call to exec() will provide one of these as the first\n"
- "** argument.\n"
- "**\n"
- "** This list should be updated if/when the collection of\n"
- "** user processes changes.\n"
- "*/\n"
- "enum users_e {";
-
-// trailer string for the userids.h file
-const char trailer[] = "\n\t// sentinel\n\t, N_USERS\n"
- "};\n"
- "#endif /* !ASM_SRC */\n"
- "\n"
- "#endif";
-
-/**
-** Name: process
-**
-** Process a program list entry
-**
-** @param num Program list index
-** @param prog Pointer to the program list entry
-*/
-void process(uint32_t num, prog_t *prog)
-{
- if (defs || enums) {
- char *slash = strrchr(prog->name, '/');
- if (slash == NULL) {
- slash = prog->name;
- } else {
- ++slash;
- }
-
- slash[0] = toupper(slash[0]);
-
- if (defs) {
- // just printing #define statements
- printf("#define %-15s %2d\n", prog->name, num);
-
- } else {
- // printing a new userids.h file
- if (num == 0) {
- // first one, so print the file header
- puts(header);
- putchar('\t');
- } else {
- // second or later entry; limit to 8 per line
- fputs(((num & 0x7) == 0) ? ",\n\t" : ", ", stdout);
- }
- printf("%s", prog->name);
- }
-
- } else {
- // just printing information
- printf("Entry %2d: ", num);
- printf("%-s,", prog->name);
- printf(" offset 0x%x, size 0x%x, flags %08x\n", prog->offset,
- prog->size, prog->flags);
- }
-}
-
-void usage(char *name)
-{
- fprintf(stderr, "usage: %s [-d | -e] blob_name\n", name);
-}
-
-int main(int argc, char *argv[])
-{
- if (argc < 2 || argc > 3) {
- usage(argv[0]);
- exit(1);
- }
-
- int nameix = 1;
-
- // could use getopt() for this, but this is easy enough
- if (argc == 3) {
- if (strcmp(argv[1], "-d") == 0) {
- defs = true;
- } else if (strcmp(argv[1], "-e") == 0) {
- enums = true;
- } else {
- usage(argv[0]);
- exit(1);
- }
- nameix = 2;
- }
-
- char *name = argv[nameix];
-
- int fd = open(name, O_RDONLY);
- if (fd < 0) {
- perror(name);
- exit(1);
- }
-
- header_t hdr;
-
- int n = read(fd, &hdr, sizeof(header_t));
- if (n != sizeof(header_t)) {
- fprintf(stderr, "%s: header read returned only %d bytes\n", name, n);
- close(fd);
- exit(1);
- }
-
- if (strcmp(hdr.magic, "BLB") != 0) {
- fprintf(stderr, "%s: bad magic number\n", name);
- close(fd);
- exit(1);
- }
-
- if (hdr.num < 1) {
- fprintf(stderr, "%s: no programs in blob?\n", name);
- close(fd);
- exit(1);
- }
-
- prog_t progs[hdr.num];
-
- n = read(fd, progs, hdr.num * sizeof(prog_t));
- if (n != (int)(hdr.num * sizeof(prog_t))) {
- fprintf(stderr, "%s: prog table only %d bytes, expected %lu\n", name, n,
- hdr.num * sizeof(prog_t));
- close(fd);
- exit(1);
- }
-
- for (uint32_t i = 0; i < hdr.num; ++i) {
- process(i, &progs[i]);
- }
-
- if (enums) {
- // print the file trailer
- puts(trailer);
- }
-
- close(fd);
- return 0;
-}
diff --git a/util/mkblob.c b/util/mkblob.c
deleted file mode 100644
index ea6a946..0000000
--- a/util/mkblob.c
+++ /dev/null
@@ -1,321 +0,0 @@
-/**
-** @file mkblob.c
-**
-** @author Warren R. Carithers
-**
-** Create a binary blob from a collection of ELF files.
-*/
-#define _DEFAULT_SOURCE
-
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <elf.h>
-
-/*
-** Blob file organization
-**
-** The file begins with a four-byte magic number and a four-byte integer
-** indicating the number of ELF files contained in the blob. This is
-** followed by an array of 32-byte file table entries, and then the contents
-** of the ELF files in the order they appear in the program file table.
-**
-** Bytes Contents
-** ----- ----------------------------
-** 0 - 3 File magic number ("BLB\0")
-** 4 - 7 Number of ELF files in blob ("n")
-** 8 - n*32+8 Program file table
-** n*32+9 - ? ELF file contents
-**
-** Each program file table entry contains the following information:
-**
-** name File name (up to 19 characters long)
-** offset Byte offset to the ELF header for this file
-** size Size of this ELF file, in bytes
-** flags Flags related to this file
-*/
-
-// blob header
-typedef struct header_s {
- char magic[4];
- uint32_t num;
-} header_t;
-
-// length of the file name field
-#define NAMELEN 20
-
-// program descriptor
-typedef struct prog_s {
- char name[NAMELEN]; // truncated name (15 chars)
- uint32_t offset; // offset from the beginning of the blob
- uint32_t size; // size of this ELF module
- uint32_t flags; // miscellaneous flags
-} prog_t;
-
-// modules must be written as multiples of eight bytes
-#define FL_ROUNDUP 0x00000001
-
-// mask for mod 8 checking
-#define FSIZE_MASK 0x00000007
-
-// program list entry
-typedef struct node_s {
- prog_t *data;
- char *fullname;
- struct node_s *next;
-} node_t;
-
-node_t *progs, *last_prog; // list pointers
-uint32_t n_progs; // number of files being copied
-uint32_t offset; // current file area offset
-
-/**
-** Name: process
-**
-** Do the initial processing for an ELF file
-**
-** @param name The name of the file
-*/
-void process(const char *name)
-{
- struct stat info;
-
- // check the name length
- if (strlen(name) >= NAMELEN) {
- fprintf(stderr, "%s: name exceeds length limit (%d)\n", name,
- NAMELEN - 1);
- return;
- }
-
- // does it exist?
- if (stat(name, &info) < 0) {
- perror(name);
- return;
- }
-
- // is it a regular file?
- if (!S_ISREG(info.st_mode)) {
- fprintf(stderr, "%s: not a regular file\n", name);
- return;
- }
-
- // open it and check the file header
- int fd = open(name, O_RDONLY);
- if (fd < 0) {
- perror(name);
- return;
- }
-
- // read and check the ELF header
- Elf32_Ehdr hdr;
- int n = read(fd, &hdr, sizeof(Elf32_Ehdr));
- close(fd);
-
- if (n != sizeof(Elf32_Ehdr)) {
- fprintf(stderr, "%s: header read was short - only %d\n", name, n);
- return;
- }
-
- if (hdr.e_ident[EI_MAG0] != ELFMAG0 || hdr.e_ident[EI_MAG1] != ELFMAG1 ||
- hdr.e_ident[EI_MAG2] != ELFMAG2 || hdr.e_ident[EI_MAG3] != ELFMAG3) {
- fprintf(stderr, "%s: bad ELF magic number\n", name);
- return;
- }
-
- // ok, it's a valid ELF file - create the prog list entry
- prog_t *new = calloc(1, sizeof(prog_t));
- if (new == NULL) {
- fprintf(stderr, "%s: calloc prog returned NULL\n", name);
- return;
- }
-
- node_t *node = calloc(1, sizeof(node_t));
- if (node == NULL) {
- free(new);
- fprintf(stderr, "%s: calloc node returned NULL\n", name);
- return;
- }
-
- node->data = new;
- node->fullname = strdup(name);
-
- // copy in the name
-
- // only want the last component
- const char *slash = strrchr(name, '/');
- if (slash == NULL) {
- // only the file name
- slash = name;
- } else {
- // skip the slash
- ++slash;
- }
-
- strncpy(new->name, slash, sizeof(new->name) - 1);
- new->offset = offset;
- new->size = info.st_size;
-
- // bump our counters
- ++n_progs;
- offset += info.st_size;
-
- // make sure it's a multiple of eight bytes long
- if ((info.st_size & FSIZE_MASK) != 0) {
- // nope, so we must round it up when we write it out
- new->flags |= FL_ROUNDUP;
- // increases the offset to the next file
- offset += 8 - (info.st_size & FSIZE_MASK);
- }
-
- // add to the list
- if (progs == NULL) {
- // first entry
- progs = node;
- } else {
- // add to the end
- if (last_prog == NULL) {
- fprintf(stderr, "%s: progs ! NULL, last_prog is NULL\n", name);
- free(new);
- free(node->fullname);
- free(node);
- return;
- }
- last_prog->next = node;
- }
- last_prog = node;
-}
-
-/**
-** Name: copy
-**
-** Copy the contents of a program list entry into the blob
-**
-** @param ofd The output FILE* to be written
-** @param prog Pointer to the program list entry for the file
-*/
-void copy(FILE *ofd, node_t *node)
-{
- prog_t *prog = node->data;
-
- // open it so we can copy it
- int fd = open(node->fullname, O_RDONLY);
- if (fd < 0) {
- perror(node->fullname);
- return;
- }
-
- uint8_t buf[512];
-
- // copy it block-by-block
- do {
- int n = read(fd, buf, 512);
- // no bytes --> we're done
- if (n < 1) {
- break;
- }
- // copy it, and verify the copy count
- int k = fwrite(buf, 1, n, ofd);
- if (k != n) {
- fprintf(stderr, "%s: write of %d returned %d\n", prog->name, n, k);
- }
- } while (1);
-
- printf("%s: copied %d", prog->name, prog->size);
-
- // do we need to round up?
- if ((prog->flags & FL_ROUNDUP) != 0) {
- // we'll fill with NUL bytes
- uint64_t filler = 0;
-
- // how many filler bytes do we need?
- int nbytes = 8 - (prog->size & FSIZE_MASK);
-
- // do it, and check the transfer count to be sure
- int n = fwrite(&filler, 1, nbytes, ofd);
- if (n != nbytes) {
- fprintf(stderr, "%s: fill write of %d returned %d\n", prog->name,
- nbytes, n);
- }
-
- // report that we added some filler bytes
- printf("(+%d)", n);
- }
- puts(" bytes");
-
- // all done!
- close(fd);
-}
-
-int main(int argc, char *argv[])
-{
- // construct program list
- for (int i = 1; i < argc; ++i) {
- process(argv[i]);
- }
-
- if (n_progs < 1) {
- fputs("Nothing to do... exiting.", stderr);
- exit(0);
- }
-
- // create the output file
- FILE *ofd;
- ofd = fopen("user.img", "wb");
- if (ofd == NULL) {
- perror("user.img");
- exit(1);
- }
-
- printf("Processing %d ELF files\n", n_progs);
-
- // we need to adjust the offset values so they are relative to the
- // start of the blob, not relative to the start of the file area.
- // do this by adding the sum of the file header and program entries
- // to each offset field.
-
- uint32_t hlen = sizeof(header_t) + n_progs * sizeof(prog_t);
- node_t *curr = progs;
- while (curr != NULL) {
- curr->data->offset += hlen;
- curr = curr->next;
- }
-
- // write out the blob header
- header_t hdr = { "BLB", n_progs };
- if (fwrite(&hdr, sizeof(header_t), 1, ofd) != 1) {
- perror("blob header");
- fclose(ofd);
- exit(1);
- }
-
- // next, the program entries
- curr = progs;
- while (curr != NULL) {
- if (fwrite(curr->data, sizeof(prog_t), 1, ofd) != 1) {
- perror("blob prog entry write");
- fclose(ofd);
- exit(1);
- }
- curr = curr->next;
- }
-
- // finally, copy the files
- curr = progs;
- while (curr != NULL) {
- prog_t *prog = curr->data;
- copy(ofd, curr);
- node_t *tmp = curr;
- curr = curr->next;
- free(tmp->data);
- free(tmp->fullname);
- free(tmp);
- }
-
- fclose(ofd);
-
- return 0;
-}