mirror of
https://github.com/kenshineto/kern.git
synced 2025-04-16 23:47:25 +00:00
break apart c libaray
This commit is contained in:
parent
7fd3d3a1b6
commit
8a19547957
100 changed files with 1954 additions and 1773 deletions
Makefilebuild.zigcompile_flags.txt
config
include
kernel
cpu
drivers
include
lib
atox.cbound.cbtoa.cctoi.cfputc.cisdigit.cisspace.citoc.ckalloc.ckprintf.cmemcmp.cmemcpy.cmemcpyv.cmemmove.cmemmovev.cmemset.cmemsetv.cpanic.cstpcpy.cstpncpy.cstrcat.cstrcpy.cstrlen.cstrncmp.cstrncpy.cstrtoux.cstrtox.cuxtoa.cxtoa.c
main.cmboot
memory
user
include
lib
util
4
Makefile
4
Makefile
|
@ -19,7 +19,7 @@ qemu-gdb: bin/os.iso
|
|||
$(QEMU) $(QEMUOPTS) -S -gdb tcp::1337
|
||||
|
||||
gdb:
|
||||
gdb -q -n -x util/gdbinit
|
||||
gdb -q -n -x config/gdbinit
|
||||
|
||||
clean:
|
||||
rm -fr .zig-cache
|
||||
|
@ -30,7 +30,7 @@ build:
|
|||
|
||||
bin/os.iso: build
|
||||
mkdir -p bin/iso/boot/grub
|
||||
cp grub.cfg bin/iso/boot/grub
|
||||
cp config/grub.cfg bin/iso/boot/grub
|
||||
cp bin/kernel bin/iso/boot
|
||||
grub-mkrescue -o bin/os.iso bin/iso 2>/dev/null
|
||||
|
||||
|
|
118
build.zig
118
build.zig
|
@ -20,11 +20,9 @@ const c_flags = &[_][]const u8{
|
|||
"-ggdb",
|
||||
};
|
||||
|
||||
const boot_src = &[_][]const u8{"boot/boot.S"};
|
||||
|
||||
const kernel_src = &[_][]const u8{
|
||||
"kernel/entry.S", // must be first
|
||||
"kernel/kernel.c", // main function
|
||||
"kernel/main.c", // main function
|
||||
"kernel/cpu/cpu.c",
|
||||
"kernel/cpu/fpu.c",
|
||||
"kernel/cpu/idt.c",
|
||||
|
@ -36,8 +34,34 @@ const kernel_src = &[_][]const u8{
|
|||
"kernel/drivers/tty.c",
|
||||
"kernel/drivers/uart.c",
|
||||
"kernel/fs/fs.c",
|
||||
"kernel/lib/fputc.c",
|
||||
"kernel/lib/atox.c",
|
||||
"kernel/lib/bound.c",
|
||||
"kernel/lib/btoa.c",
|
||||
"kernel/lib/ctoi.c",
|
||||
"kernel/lib/isdigit.c",
|
||||
"kernel/lib/isspace.c",
|
||||
"kernel/lib/itoc.c",
|
||||
"kernel/lib/kalloc.c",
|
||||
"kernel/lib/kprintf.c",
|
||||
"kernel/lib/memcmp.c",
|
||||
"kernel/lib/memcpy.c",
|
||||
"kernel/lib/memcpyv.c",
|
||||
"kernel/lib/memmove.c",
|
||||
"kernel/lib/memmovev.c",
|
||||
"kernel/lib/memset.c",
|
||||
"kernel/lib/memsetv.c",
|
||||
"kernel/lib/panic.c",
|
||||
"kernel/lib/stpcpy.c",
|
||||
"kernel/lib/stpncpy.c",
|
||||
"kernel/lib/strcat.c",
|
||||
"kernel/lib/strcpy.c",
|
||||
"kernel/lib/strlen.c",
|
||||
"kernel/lib/strncmp.c",
|
||||
"kernel/lib/strncpy.c",
|
||||
"kernel/lib/strtoux.c",
|
||||
"kernel/lib/strtox.c",
|
||||
"kernel/lib/uxtoa.c",
|
||||
"kernel/lib/xtoa.c",
|
||||
"kernel/mboot/mboot.c",
|
||||
"kernel/mboot/mmap.c",
|
||||
"kernel/memory/memory.c",
|
||||
|
@ -46,61 +70,11 @@ const kernel_src = &[_][]const u8{
|
|||
"kernel/memory/virtalloc.c",
|
||||
};
|
||||
|
||||
const lib_src = &[_][]const u8{
|
||||
"lib/alloc.c",
|
||||
"lib/atox.c",
|
||||
"lib/bound.c",
|
||||
"lib/btoa.c",
|
||||
"lib/ctoi.c",
|
||||
"lib/delay.c",
|
||||
"lib/isdigit.c",
|
||||
"lib/isspace.c",
|
||||
"lib/itoc.c",
|
||||
"lib/memcmp.c",
|
||||
"lib/memcpy.c",
|
||||
"lib/memcpyv.c",
|
||||
"lib/memmove.c",
|
||||
"lib/memmovev.c",
|
||||
"lib/memset.c",
|
||||
"lib/memsetv.c",
|
||||
"lib/printf.c",
|
||||
"lib/stpcpy.c",
|
||||
"lib/stpncpy.c",
|
||||
"lib/strcat.c",
|
||||
"lib/strcpy.c",
|
||||
"lib/strlen.c",
|
||||
"lib/strncmp.c",
|
||||
"lib/strncpy.c",
|
||||
"lib/strtoux.c",
|
||||
"lib/strtox.c",
|
||||
"lib/timetostr.c",
|
||||
"lib/uxtoa.c",
|
||||
"lib/xtoa.c",
|
||||
};
|
||||
|
||||
const Prog = struct {
|
||||
name: []const u8,
|
||||
source: []const []const u8,
|
||||
};
|
||||
|
||||
const util_progs = &[_]Prog{
|
||||
// mkblob
|
||||
Prog{
|
||||
.name = "mkblob",
|
||||
.source = &[_][]const u8{"util/mkblob.c"},
|
||||
},
|
||||
// listblob
|
||||
Prog{
|
||||
.name = "listblob",
|
||||
.source = &[_][]const u8{"util/listblob.c"},
|
||||
},
|
||||
// BuildImage
|
||||
Prog{
|
||||
.name = "BuildImage",
|
||||
.source = &[_][]const u8{"util/BuildImage.c"},
|
||||
},
|
||||
};
|
||||
|
||||
const AddSourcesOpts = struct { exe: *std.Build.Step.Compile, sources: []const []const []const u8, c_flags: []const []const u8 };
|
||||
|
||||
fn add_sources(b: *std.Build, opts: AddSourcesOpts) void {
|
||||
|
@ -138,8 +112,7 @@ fn build_kern_binary(b: *std.Build, opts: BuildKernBinaryOpts) void {
|
|||
.strip = opts.strip,
|
||||
});
|
||||
|
||||
// add include paths
|
||||
exe.addIncludePath(b.path("include/"));
|
||||
// add include path
|
||||
if (opts.include != null) {
|
||||
exe.addIncludePath(b.path(opts.include.?));
|
||||
}
|
||||
|
@ -198,12 +171,6 @@ fn build_native_binary(b: *std.Build, opts: BuildNativeBinaryOpts) void {
|
|||
pub fn build(b: *std.Build) !void {
|
||||
|
||||
// context
|
||||
const target32 = std.Build.resolveTargetQuery(b, .{
|
||||
.cpu_arch = std.Target.Cpu.Arch.x86,
|
||||
.os_tag = std.Target.Os.Tag.freestanding,
|
||||
.abi = std.Target.Abi.gnu,
|
||||
.ofmt = std.Target.ObjectFormat.elf,
|
||||
});
|
||||
const target64 = std.Build.resolveTargetQuery(b, .{
|
||||
.cpu_arch = std.Target.Cpu.Arch.x86_64,
|
||||
.os_tag = std.Target.Os.Tag.freestanding,
|
||||
|
@ -212,19 +179,6 @@ pub fn build(b: *std.Build) !void {
|
|||
});
|
||||
const optimize = std.builtin.OptimizeMode.ReleaseFast;
|
||||
|
||||
// boot
|
||||
build_kern_binary(b, .{
|
||||
.name = "boot",
|
||||
.target = target32,
|
||||
.optimize = optimize,
|
||||
.sources = &.{
|
||||
boot_src,
|
||||
},
|
||||
.linker = "boot/boot.ld",
|
||||
.entry = "bootentry",
|
||||
.include = "boot/include",
|
||||
});
|
||||
|
||||
// kernel
|
||||
build_kern_binary(b, .{
|
||||
.name = "kernel",
|
||||
|
@ -232,20 +186,8 @@ pub fn build(b: *std.Build) !void {
|
|||
.optimize = optimize,
|
||||
.sources = &.{
|
||||
kernel_src,
|
||||
lib_src,
|
||||
},
|
||||
.linker = "kernel/kernel.ld",
|
||||
.linker = "config/kernel.ld",
|
||||
.include = "kernel/include",
|
||||
});
|
||||
|
||||
// util_progs
|
||||
for (util_progs) |prog| {
|
||||
build_native_binary(b, .{
|
||||
.name = prog.name,
|
||||
.optimize = optimize,
|
||||
.sources = &.{
|
||||
prog.source,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
-c
|
||||
-std=c11
|
||||
-Iinclude
|
||||
-Ikernel/include
|
||||
-Iuser/include
|
||||
-ffreestanding
|
||||
-fno-builtin
|
||||
-Wall
|
||||
|
|
|
@ -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>
|
|
@ -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
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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++);
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
1
kernel/include/comus/error.h
Symbolic link
1
kernel/include/comus/error.h
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../../user/include/error.h
|
|
@ -11,7 +11,10 @@
|
|||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <limits.h>
|
||||
|
||||
// FIXME: aaaa
|
||||
#define MAX_DISKS 8
|
||||
#define MAX_FILE_NAME_LEN 256
|
||||
|
||||
struct disk {
|
||||
/// set to 1 in array to state that fs is defined
|
||||
|
|
|
@ -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 */
|
||||
|
|
39
kernel/include/comus/time.h
Normal file
39
kernel/include/comus/time.h
Normal 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
20
kernel/include/lib.h
Normal 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 */
|
22
kernel/include/lib/kctype.h
Normal file
22
kernel/include/lib/kctype.h
Normal 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
91
kernel/include/lib/kio.h
Normal 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
196
kernel/include/lib/klib.h
Normal 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 */
|
154
kernel/include/lib/kstring.h
Normal file
154
kernel/include/lib/kstring.h
Normal 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
29
kernel/lib/atox.c
Normal 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
12
kernel/lib/bound.c
Normal 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
43
kernel/lib/btoa.c
Normal 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
14
kernel/lib/ctoi.c
Normal 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;
|
||||
}
|
||||
}
|
|
@ -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
6
kernel/lib/isdigit.c
Normal file
|
@ -0,0 +1,6 @@
|
|||
#include <lib.h>
|
||||
|
||||
int isdigit(int c)
|
||||
{
|
||||
return c >= '0' && c <= '9';
|
||||
}
|
16
kernel/lib/isspace.c
Normal file
16
kernel/lib/isspace.c
Normal 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
10
kernel/lib/itoc.c
Normal 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
210
kernel/lib/kalloc.c
Normal 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
576
kernel/lib/kprintf.c
Normal 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
9
kernel/lib/memcmp.c
Normal 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
10
kernel/lib/memcpy.c
Normal 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;
|
||||
}
|
|
@ -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
20
kernel/lib/memmove.c
Normal 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;
|
||||
}
|
|
@ -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
10
kernel/lib/memset.c
Normal 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;
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
#include <string.h>
|
||||
#include <lib.h>
|
||||
|
||||
volatile void *memsetv(volatile void *dest, int c, size_t n)
|
||||
{
|
|
@ -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
9
kernel/lib/stpcpy.c
Normal 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
10
kernel/lib/stpncpy.c
Normal 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
7
kernel/lib/strcat.c
Normal 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
9
kernel/lib/strcpy.c
Normal 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
9
kernel/lib/strlen.c
Normal 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
11
kernel/lib/strncmp.c
Normal 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
10
kernel/lib/strncpy.c
Normal 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
43
kernel/lib/strtoux.c
Normal 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
52
kernel/lib/strtox.c
Normal 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
27
kernel/lib/uxtoa.c
Normal 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
31
kernel/lib/xtoa.c
Normal 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)
|
|
@ -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");
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
|
@ -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 */
|
|
@ -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
|
|
@ -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 */
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
247
util/default.ld
247
util/default.ld
|
@ -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_*) }
|
||||
}
|
||||
|
||||
|
||||
==================================================
|
240
util/listblob.c
240
util/listblob.c
|
@ -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;
|
||||
}
|
321
util/mkblob.c
321
util/mkblob.c
|
@ -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;
|
||||
}
|
Loading…
Add table
Reference in a new issue