summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlejandro Sior <aho@sior.be>2022-07-23 22:53:47 +0200
committerAlejandro Sior <aho@sior.be>2022-07-23 22:53:47 +0200
commitef805e9373fd946bf1fe667bf18a54dfed6d1045 (patch)
tree7762f9574bbd56c502d4dbba1a9d5f3535035211
kernel: add basic modules: arch, mem, rt
-rw-r--r--.gitignore1
-rw-r--r--amd64.ini36
-rw-r--r--arch/amd64/README4
-rw-r--r--arch/amd64/include/arch_stdint.h29
-rw-r--r--arch/amd64/linker.sc34
-rw-r--r--arch/amd64/meson.build13
-rw-r--r--arch/amd64/quirks.c7
-rw-r--r--arch/meson.build1
-rw-r--r--boot.ini1
-rw-r--r--docs/man.7.scd21
-rw-r--r--docs/verbs.7.scd39
-rw-r--r--kernel.c11
-rw-r--r--mem/README2
-rw-r--r--mem/allocator.c23
-rw-r--r--mem/allocator.h23
-rw-r--r--mem/framer.c63
-rw-r--r--mem/framer.h39
-rw-r--r--mem/meson.build8
-rw-r--r--meson.build57
-rw-r--r--rt/README5
-rw-r--r--rt/assert.h6
-rw-r--r--rt/meson.build1
-rw-r--r--rt/rt.h8
-rw-r--r--rt/stddef.h8
-rw-r--r--rt/stdint.h21
-rw-r--r--third/.gitignore2
-rw-r--r--third/boot.wrap3
-rw-r--r--third/bsfs.wrap3
-rw-r--r--third/scripts/README2
-rw-r--r--third/scripts/meson.build3
-rw-r--r--third/scripts/mkboot.c27
31 files changed, 501 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..016deba
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+/bochsrc.bxrc \ No newline at end of file
diff --git a/amd64.ini b/amd64.ini
new file mode 100644
index 0000000..378579c
--- /dev/null
+++ b/amd64.ini
@@ -0,0 +1,36 @@
+[constants]
+arch = 'x86_64-pc-freebsd-elf'
+common_flags = [
+ '--target=' + arch,
+ '-Wall',
+ '-Wno-incompatible-library-redeclaration',
+ '-Wno-builtin-requires-header',
+ '-mno-red-zone',
+ '-mno-sse',
+ '-mno-mmx',
+ '-I./',
+ '-nostdlib',
+ '-nostdinc'
+ ]
+
+[binaries]
+c = 'clang'
+c_ld = 'lld'
+strip = 'llvm-strip'
+
+[built-in options]
+c_args = common_flags + [ '-std=c11' ]
+c_link_args = [
+ '--target=' + arch,
+ '-L./',
+ '-nostdlib',
+ '-static',
+ '-Wl,-nostdlib',
+ '-Wl,--gc-sections']
+
+[host_machine]
+system = 'none'
+cpu_family = 'x86_64'
+cpu = 'x86_64'
+endian = 'little'
+strip = true
diff --git a/arch/amd64/README b/arch/amd64/README
new file mode 100644
index 0000000..1051958
--- /dev/null
+++ b/arch/amd64/README
@@ -0,0 +1,4 @@
+The [arch/amd64] module defines implementations and definitions
+pertaining to the amd64 (x86_64) architecture, as well as the
+entry point setting up the environment before jumping to the
+common abstracted code. \ No newline at end of file
diff --git a/arch/amd64/include/arch_stdint.h b/arch/amd64/include/arch_stdint.h
new file mode 100644
index 0000000..06040e2
--- /dev/null
+++ b/arch/amd64/include/arch_stdint.h
@@ -0,0 +1,29 @@
+#ifndef AMD64_STDINT_H
+#define AMD64_STDINT_H
+
+#include <assert.h>
+
+typedef unsigned char u8;
+typedef char i8;
+
+typedef unsigned short int u16;
+typedef short int i16;
+static_assert(sizeof(u16) == 2, "u16 is 2 bytes");
+static_assert(sizeof(i16) == 2, "i16 is 2 bytes");
+
+typedef unsigned int u32;
+typedef int i32;
+static_assert(sizeof(u32) == 4, "u16 is 4 bytes");
+static_assert(sizeof(i32) == 4, "i16 is 4 bytes");
+
+typedef unsigned long long int u64;
+typedef long long int i64;
+static_assert(sizeof(u64) == 8, "u64 is 8 bytes");
+static_assert(sizeof(i64) == 8, "i64 is 8 bytes");
+
+typedef unsigned long long int usize;
+typedef long long int isize;
+static_assert(sizeof(usize) == 8, "usize is 8 bytes");
+static_assert(sizeof(isize) == 8, "isize is 8 bytes");
+
+#endif \ No newline at end of file
diff --git a/arch/amd64/linker.sc b/arch/amd64/linker.sc
new file mode 100644
index 0000000..16d9330
--- /dev/null
+++ b/arch/amd64/linker.sc
@@ -0,0 +1,34 @@
+OUTPUT(elf64-x86-64)
+ENTRY(amd64_quirks)
+
+SECTIONS {
+ . = 0xffffffff80000000;
+
+ .stack (NOLOAD) : {
+ . = ALIGN(8);
+ . += 0x10000;
+ . = ALIGN(8);
+ kernel_stack_high = .;
+ } :stack
+
+ kernel_begin = .;
+ .text : {
+ KEEP(*(.text .text.*))
+ } :text
+
+ . += CONSTANT(MAXPAGESIZE);
+
+ .rodata : {
+ KEEP(*(.rodata .rodata.*))
+ } :rodata
+
+ .data : {
+ KEEP(*(.data .data.*))
+ } :data
+
+ .bss (NOLOAD) : {
+ KEEP(*(COMMON))
+ KEEP(*(.bss .bss.*))
+ } :data
+ kernel_end = .;
+} \ No newline at end of file
diff --git a/arch/amd64/meson.build b/arch/amd64/meson.build
new file mode 100644
index 0000000..4c64c8c
--- /dev/null
+++ b/arch/amd64/meson.build
@@ -0,0 +1,13 @@
+amd64_src = [
+ 'quirks.c'
+]
+
+amd64_linker_sc = meson.current_source_dir() / 'linker.sc'
+
+kernel_link_dep += amd64_linker_sc
+kernel_link_arg += '-T' + amd64_linker_sc
+kernel_inc += include_directories('include')
+
+amd64 = static_library('amd64', amd64_src, include_directories: kernel_inc)
+
+kernel_mod += amd64 \ No newline at end of file
diff --git a/arch/amd64/quirks.c b/arch/amd64/quirks.c
new file mode 100644
index 0000000..549f605
--- /dev/null
+++ b/arch/amd64/quirks.c
@@ -0,0 +1,7 @@
+#include <third/boot/bp.h>
+
+int boot();
+
+int amd64_quirks(BpBootinfo *info) {
+ return boot();
+} \ No newline at end of file
diff --git a/arch/meson.build b/arch/meson.build
new file mode 100644
index 0000000..d149899
--- /dev/null
+++ b/arch/meson.build
@@ -0,0 +1 @@
+subdir('amd64') \ No newline at end of file
diff --git a/boot.ini b/boot.ini
new file mode 100644
index 0000000..f6934fb
--- /dev/null
+++ b/boot.ini
@@ -0,0 +1 @@
+kernel=/boot/kernel \ No newline at end of file
diff --git a/docs/man.7.scd b/docs/man.7.scd
new file mode 100644
index 0000000..88a5d4d
--- /dev/null
+++ b/docs/man.7.scd
@@ -0,0 +1,21 @@
+MAN(7)
+
+# NAME
+
+man - user's manual
+
+# SUMMARY
+
+The operating system aims to be self documenting. As such a manual is written describing different aspects of the system in details in English. It is divided in multiple sections.
+
+# SECTIONS
+
+```
+ 1. Utilities
+ 3. Libraries
+ 7. Miscellaneous
+```
+
+# TODO
+
+In this manual page, the sections may perhaps be organized differently. \ No newline at end of file
diff --git a/docs/verbs.7.scd b/docs/verbs.7.scd
new file mode 100644
index 0000000..1598342
--- /dev/null
+++ b/docs/verbs.7.scd
@@ -0,0 +1,39 @@
+VERBS(7)
+
+# NAME
+
+verbs - an overview of the different verbs
+
+# VERBS
+
+The kernel codebase often makes use of the method pattern in order to codify logical operations on structures. This makes up for functions called x_verb where x represents the type of the object of the method. Some of these verbs, especially related to resource aquisition and initialization, are commonly used and are repertoried here.
+
+## Init
+
+The *init* verb initializes a structure; that is, upon success, it puts the object into a state for which it is safe to call other methods. The init operation may take zero or more arguments, depending on what is needed.
+
+The initialization function has the following signature:
+
+ [int] x_init(X*, ...)
+
+where the return value can be used to communicate errors. See relevant documentation for implementation's meanings.
+
+The init operation *may* allocate resources needed to initialize members of the object, in such a case, said resources are said to be _owned_. The init operation may however not allocate memory for the structure.
+
+## Drop
+
+The *drop* verb is the opposite of the init verb: it puts the object in a state for which forgetting about it doesn't cause resource leaks: as such, it releases the object's owned resources. The state of the object after the drop operation is most often invalid and using a dropped objects is undefined behavior.
+
+The drop operation has the following signature:
+
+ [int] x_drop(X*, ...)
+
+## Install
+
+The *install* verb places and initializes an object at a specified location *addr* in memory.
+
+The install operation has the following signature:
+
+ X *x_install(void *addr, ...)
+
+A notable example of a structure that gets to be installed is the MemFramer (mem/framer.h). This frame allocator is notably used for managing physical memory. Since it can be used at times when heap allocation is not yet available, the structure can be installed at the beginning of free regions. \ No newline at end of file
diff --git a/kernel.c b/kernel.c
new file mode 100644
index 0000000..860e980
--- /dev/null
+++ b/kernel.c
@@ -0,0 +1,11 @@
+#include <rt.h>
+
+volatile short *fb = (short*)0xB8000;
+
+int boot() {
+ char c = 'A';
+ for (int i = 0; i < 26; i++)
+ fb[i] = (c + i) | 0xD << 8;
+
+ return 0;
+} \ No newline at end of file
diff --git a/mem/README b/mem/README
new file mode 100644
index 0000000..bb27b25
--- /dev/null
+++ b/mem/README
@@ -0,0 +1,2 @@
+The [mem] module maintains abstraction and facilities aiming
+to manipulate memory and allocators. \ No newline at end of file
diff --git a/mem/allocator.c b/mem/allocator.c
new file mode 100644
index 0000000..b4d9068
--- /dev/null
+++ b/mem/allocator.c
@@ -0,0 +1,23 @@
+#include "allocator.h"
+
+/* Dispatches the alloc call */
+void *mem_alloc(MemAllocator *self, usize n) {
+ if (self->alloc)
+ return self->alloc(self, n);
+
+ return nil;
+}
+
+/* Dispatches the realloc call */
+void *mem_realloc(MemAllocator *self, void *ptr, usize n) {
+ if (self->realloc)
+ return self->realloc(self, ptr, n);
+
+ return nil;
+}
+
+/* Dispatches the free call */
+void mem_free(MemAllocator *self, void *ptr) {
+ if (self->free)
+ self->free(self, ptr);
+} \ No newline at end of file
diff --git a/mem/allocator.h b/mem/allocator.h
new file mode 100644
index 0000000..535965a
--- /dev/null
+++ b/mem/allocator.h
@@ -0,0 +1,23 @@
+#ifndef MEM_ALLOCATOR_H
+#define MEM_ALLOCATOR_H
+
+#include <rt.h>
+
+typedef struct mem_allocator MemAllocator;
+
+typedef void *(*MemAlloc)(MemAllocator *, usize);
+typedef void *(*MemRealloc)(MemAllocator *, void *, usize);
+typedef void (*MemFree)(MemAllocator *, void *);
+
+/* Abstract object representing an allocator */
+struct mem_allocator {
+ MemAlloc alloc;
+ MemRealloc realloc;
+ MemFree free;
+};
+
+void *mem_alloc(MemAllocator *self, usize n);
+void *mem_realloc(MemAllocator *self, void *ptr, usize n);
+void mem_free(MemAllocator *self, void *ptr);
+
+#endif \ No newline at end of file
diff --git a/mem/framer.c b/mem/framer.c
new file mode 100644
index 0000000..9a66feb
--- /dev/null
+++ b/mem/framer.c
@@ -0,0 +1,63 @@
+#include "framer.h"
+
+/* Installs a MemFramer at the specified address */
+MemFramer *mem_framer_install(void *addr, usize end, uint blksz) {
+ MemFramer *self = addr;
+ usize selfend = (usize)(self + 1);
+ usize next = ALIGN_UP(selfend, blksz);
+
+ *self = (MemFramer) {
+ .allocator = (MemAllocator) {
+ .alloc = mem_framer_alloc,
+ .free = mem_framer_free
+ },
+ .next = next,
+ .end = end,
+ .blksz = blksz
+ };
+
+ return self;
+}
+
+/* Allocates a frame */
+void *mem_framer_alloc(MemAllocator *inner, usize n) {
+ /* When allocating a frame, we have two paths:
+ 1. The freelist is not empty: give away
+ the last freed frame
+ 2. The freelist is empty: bump away the next
+ frame (pointed at by the next member)
+ The alloc must fail the freelist is empty and that
+ the next is beyond the end of the region */
+
+ MemFramer *self = (MemFramer*)inner;
+
+ /* The implementation does not support more than
+ one frame */
+ if (n == 0 || n > self->blksz)
+ return nil;
+
+ void *ptr = nil;
+
+ if (self->free) {
+ ptr = self->free;
+ self->free = self->free->next;
+ } else if (self->next + self->blksz <= self->end) {
+ ptr = (void*)self->next;
+ self->next += self->blksz;
+ }
+
+ return ptr;
+}
+
+/* Frees a frame */
+void mem_framer_free(MemAllocator *inner, void *ptr) {
+ /* NOTE: this implementation does make the assumption
+ that the given pointer is the base of the allocated
+ region without correction */
+
+ MemFramer *self = (MemFramer*)inner;
+
+ MemFramerFreed *freed = ptr;
+ freed->next = self->free;
+ self->free = freed;
+} \ No newline at end of file
diff --git a/mem/framer.h b/mem/framer.h
new file mode 100644
index 0000000..6d7034b
--- /dev/null
+++ b/mem/framer.h
@@ -0,0 +1,39 @@
+#ifndef MEM_FRAMER_H
+#define MEM_FRAMER_H
+
+#include <rt.h>
+
+#include "allocator.h"
+
+typedef struct mem_framer_freed {
+ struct mem_framer_freed *next;
+} MemFramerFreed;
+
+/* Allocator for frames: aligned regions of memory of same size */
+typedef struct mem_framer {
+ MemAllocator allocator;
+
+ /* The next frame to be given off to the caller
+ in case the freelist is empty */
+ usize next;
+
+ /* The end of the region covered by the memory allocator */
+ usize end;
+
+ /* The address of the last frame that has been added in
+ the freelist
+ NOTE: the freelist is a singly-linked list comprising
+ all frames that have been previously allocated
+ and then freed */
+ MemFramerFreed *free;
+
+ /* The size of a frame. This value also defines the alignment
+ that the frames must respect */
+ uint blksz;
+} MemFramer;
+
+MemFramer *mem_framer_install(void *addr, usize end, uint blksz);
+void *mem_framer_alloc(MemAllocator *self, usize n);
+void mem_framer_free(MemAllocator *self, void *ptr);
+
+#endif \ No newline at end of file
diff --git a/mem/meson.build b/mem/meson.build
new file mode 100644
index 0000000..ec4a984
--- /dev/null
+++ b/mem/meson.build
@@ -0,0 +1,8 @@
+mem_src = [
+ 'allocator.c',
+ 'framer.c'
+]
+
+mem = static_library('mem', mem_src, include_directories: kernel_inc)
+
+kernel_mod += mem \ No newline at end of file
diff --git a/meson.build b/meson.build
new file mode 100644
index 0000000..fd270f0
--- /dev/null
+++ b/meson.build
@@ -0,0 +1,57 @@
+project('kernel', 'c', subproject_dir: 'third')
+fs = import('fs')
+
+kernel_src = [
+ 'kernel.c'
+]
+kernel_link_dep = []
+kernel_link_arg = []
+kernel_inc = [include_directories('.')]
+kernel_mod = []
+
+# Modules
+subdir('rt')
+subdir('arch')
+subdir('mem')
+
+kernel = executable('kernel', kernel_src, link_with: kernel_mod, include_directories: kernel_inc, link_args: kernel_link_arg, link_depends: kernel_link_dep)
+
+# Create the bootable disk file
+
+boot_bin = subproject('boot').get_variable('boot_bin')
+mkboot = subproject('scripts').get_variable('mkboot')
+bsfs = subproject('bsfs').get_variable('bsfs')
+
+embed_files = [
+ meson.current_source_dir() / 'boot.ini'
+]
+
+embed_tgt = [
+ kernel
+]
+
+mkboot_cmd = [
+ mkboot,
+ bsfs,
+ '@OUTPUT@',
+ '@INPUT@'
+]
+
+foreach e : embed_files
+ mkboot_cmd += e
+ mkboot_cmd += fs.name(e)
+endforeach
+
+foreach e : embed_tgt
+ mkboot_cmd += e.full_path()
+ mkboot_cmd += fs.name(e.full_path())
+endforeach
+
+boot_fs = custom_target('boot.fs',
+ output: 'boot.fs',
+ input: boot_bin,
+ command: mkboot_cmd,
+ depend_files: embed_files,
+ depends: [mkboot, bsfs, embed_tgt],
+ install: true,
+ install_dir: 'subdir') \ No newline at end of file
diff --git a/rt/README b/rt/README
new file mode 100644
index 0000000..2cfdd3f
--- /dev/null
+++ b/rt/README
@@ -0,0 +1,5 @@
+The [rt] module contains definitions and declarations of things
+that are used very commonly throughout the codebase.
+
+The module notably exposes the rt.h header importing the most
+common files within this module for convenience. \ No newline at end of file
diff --git a/rt/assert.h b/rt/assert.h
new file mode 100644
index 0000000..f000d70
--- /dev/null
+++ b/rt/assert.h
@@ -0,0 +1,6 @@
+#ifndef RT_ASSERT_H
+#define RT_ASSERT_H
+
+#define static_assert _Static_assert
+
+#endif \ No newline at end of file
diff --git a/rt/meson.build b/rt/meson.build
new file mode 100644
index 0000000..86de68f
--- /dev/null
+++ b/rt/meson.build
@@ -0,0 +1 @@
+kernel_inc += include_directories('.') \ No newline at end of file
diff --git a/rt/rt.h b/rt/rt.h
new file mode 100644
index 0000000..c3670d5
--- /dev/null
+++ b/rt/rt.h
@@ -0,0 +1,8 @@
+#ifndef RT_RT_H
+#define RT_RT_H
+
+#include "assert.h"
+#include "stdint.h"
+#include "stddef.h"
+
+#endif \ No newline at end of file
diff --git a/rt/stddef.h b/rt/stddef.h
new file mode 100644
index 0000000..83d9957
--- /dev/null
+++ b/rt/stddef.h
@@ -0,0 +1,8 @@
+#ifndef RT_STDDEF_H
+#define RT_STDDEF_H
+
+#define nil ((void*)0)
+
+#define ALIGN_UP(X, F) ((X) - (X) % (F) + (F))
+
+#endif \ No newline at end of file
diff --git a/rt/stdint.h b/rt/stdint.h
new file mode 100644
index 0000000..f7ee056
--- /dev/null
+++ b/rt/stdint.h
@@ -0,0 +1,21 @@
+#ifndef RT_STDINT_H
+#define RT_STDINT_H
+
+#include "assert.h"
+
+typedef unsigned char uchar;
+
+typedef unsigned short int ushort;
+
+typedef unsigned int uint;
+
+typedef unsigned long int ulong;
+
+typedef long long int vlong;
+typedef unsigned long long int uvlong;
+
+// Machine specific types
+
+#include <arch_stdint.h>
+
+#endif \ No newline at end of file
diff --git a/third/.gitignore b/third/.gitignore
new file mode 100644
index 0000000..d5b2d9a
--- /dev/null
+++ b/third/.gitignore
@@ -0,0 +1,2 @@
+/boot/
+/bsfs/ \ No newline at end of file
diff --git a/third/boot.wrap b/third/boot.wrap
new file mode 100644
index 0000000..40da953
--- /dev/null
+++ b/third/boot.wrap
@@ -0,0 +1,3 @@
+[wrap-git]
+url = https://github.com/aosync/boot
+revision = master \ No newline at end of file
diff --git a/third/bsfs.wrap b/third/bsfs.wrap
new file mode 100644
index 0000000..bd998de
--- /dev/null
+++ b/third/bsfs.wrap
@@ -0,0 +1,3 @@
+[wrap-git]
+url = https://github.com/aosync/bsfs
+revision = master \ No newline at end of file
diff --git a/third/scripts/README b/third/scripts/README
new file mode 100644
index 0000000..301b8cd
--- /dev/null
+++ b/third/scripts/README
@@ -0,0 +1,2 @@
+The [scripts] module provides small cross platform scripts to assist
+in the building of the \ No newline at end of file
diff --git a/third/scripts/meson.build b/third/scripts/meson.build
new file mode 100644
index 0000000..e286242
--- /dev/null
+++ b/third/scripts/meson.build
@@ -0,0 +1,3 @@
+project('scripts', 'c')
+
+mkboot = executable('mkboot', 'mkboot.c', native: true) \ No newline at end of file
diff --git a/third/scripts/mkboot.c b/third/scripts/mkboot.c
new file mode 100644
index 0000000..864cb5e
--- /dev/null
+++ b/third/scripts/mkboot.c
@@ -0,0 +1,27 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#ifdef _WIN64
+#include <process.h>
+#endif
+
+int main(int argc, char **argv) {
+ if (argc < 4)
+ return 1;
+
+ char cmd[4097];
+
+ sprintf(cmd, "%s %s format ::%s", argv[1], argv[2], argv[3]);
+ system(cmd);
+
+ sprintf(cmd, "%s %s mkdir /boot", argv[1], argv[2]);
+ system(cmd);
+
+ for (int i = 4; i < argc; i += 2) {
+ sprintf(cmd, "%s %s cp ::%s /boot/%s", argv[1], argv[2], argv[i], argv[i + 1]);
+ system(cmd);
+ }
+
+ return 0;
+} \ No newline at end of file