break apart c libaray

This commit is contained in:
Murphy 2025-04-08 10:39:48 -04:00
parent 7fd3d3a1b6
commit 8a19547957
Signed by: freya
GPG key ID: 9FBC6FFD6D2DBF17
100 changed files with 1954 additions and 1773 deletions

View file

@ -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

118
build.zig
View file

@ -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,
},
});
}
}

View file

@ -1,7 +1,7 @@
-c
-std=c11
-Iinclude
-Ikernel/include
-Iuser/include
-ffreestanding
-fno-builtin
-Wall

View file

@ -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>

View file

@ -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

View file

@ -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 */

View file

@ -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 */

View file

@ -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();

View file

@ -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)
void gettime(struct time *time)
{
int change, max;
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;
// set localtime
localtime = time;
time->year = time->yn + time->cen * 100;
// if tz is UTC, we dont need to do anythin
if (last_timezone == TZ_UTC)
return;
time->leap = time->year % 4 == 0 && time->year % 100 != 0;
localtime.hour += last_timezone;
time->yday = mday_offset[time->mon] + time->mday;
// check if day rolled over
change = localtime.hour < 0 ? -1 : localtime.hour >= 24 ? 1 : 0;
if (!change)
return;
if (time->leap && time->mon > 2)
time->yday++;
// 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;
time->year -= 1900;
}
void clock_update(void)
uint64_t unixtime(void)
{
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;
struct time time;
gettime(&time);
time.year = time.yn + time.cen * 100;
time.leap = time.year % 4 == 0 && time.year % 100 != 0;
time.yday = mday_offset[time.mon] + time.mday;
if (time.leap && time.mon > 2)
time.yday++;
time.year -= 1900;
update_localtime();
curr_time = time;
curr_localtime = localtime;
}
void set_timezone(timezone_t tz)
{
curr_timezone = tz;
}
time_t get_utctime(void)
{
return curr_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;
}

View file

@ -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();
}

View file

@ -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,

View file

@ -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++);
}

View file

@ -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 */

View file

@ -0,0 +1 @@
../../../user/include/error.h

View file

@ -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

View file

@ -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 */

View file

@ -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 */

20
kernel/include/lib.h Normal file
View file

@ -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 */

View file

@ -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 */

91
kernel/include/lib/kio.h Normal file
View file

@ -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 */

196
kernel/include/lib/klib.h Normal file
View file

@ -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 */

View file

@ -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 */

29
kernel/lib/atox.c Normal file
View file

@ -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)

12
kernel/lib/bound.c Normal file
View file

@ -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;
}

43
kernel/lib/btoa.c Normal file
View file

@ -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;
}

14
kernel/lib/ctoi.c Normal file
View file

@ -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;
}
}

View file

@ -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);
}

6
kernel/lib/isdigit.c Normal file
View file

@ -0,0 +1,6 @@
#include <lib.h>
int isdigit(int c)
{
return c >= '0' && c <= '9';
}

16
kernel/lib/isspace.c Normal file
View file

@ -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;
}
}

10
kernel/lib/itoc.c Normal file
View file

@ -0,0 +1,10 @@
#include <lib.h>
char itoc(int i)
{
if (i < 10) {
return '0' + i;
} else {
return 'a' + (i - 10);
}
}

210
kernel/lib/kalloc.c Normal file
View file

@ -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);
}
}

576
kernel/lib/kprintf.c Normal file
View file

@ -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);
}

9
kernel/lib/memcmp.c Normal file
View file

@ -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;
}

10
kernel/lib/memcpy.c Normal file
View file

@ -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;
}

View file

@ -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)

20
kernel/lib/memmove.c Normal file
View file

@ -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;
}

View file

@ -1,4 +1,4 @@
#include <string.h>
#include <lib.h>
volatile void *memmovev(volatile void *dest, const volatile void *src, size_t n)
{

10
kernel/lib/memset.c Normal file
View file

@ -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;
}

View file

@ -1,4 +1,4 @@
#include <string.h>
#include <lib.h>
volatile void *memsetv(volatile void *dest, int c, size_t n)
{

View file

@ -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();

9
kernel/lib/stpcpy.c Normal file
View file

@ -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;
}

10
kernel/lib/stpncpy.c Normal file
View file

@ -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;
}

7
kernel/lib/strcat.c Normal file
View file

@ -0,0 +1,7 @@
#include <lib.h>
char *strcat(char *restrict dest, const char *restrict src)
{
strcpy(dest + strlen(dest), src);
return dest;
}

9
kernel/lib/strcpy.c Normal file
View file

@ -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;
}

9
kernel/lib/strlen.c Normal file
View file

@ -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;
}

11
kernel/lib/strncmp.c Normal file
View file

@ -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;
}

10
kernel/lib/strncpy.c Normal file
View file

@ -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;
}

43
kernel/lib/strtoux.c Normal file
View file

@ -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)

52
kernel/lib/strtox.c Normal file
View file

@ -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)

27
kernel/lib/uxtoa.c Normal file
View file

@ -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)

31
kernel/lib/xtoa.c Normal file
View file

@ -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)

View file

@ -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");
}

View file

@ -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;

View file

@ -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)

View file

@ -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)

View file

@ -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;

View file

@ -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

View file

@ -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 */

View file

@ -51,38 +51,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

View file

@ -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 */

View file

@ -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);
}
}

View file

@ -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;
}

View file

@ -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_*) }
}
==================================================

View file

@ -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;
}

View file

@ -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;
}