summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPeter Mikkelsen <petermikkelsen10@gmail.com>2025-07-26 16:03:00 +0200
committerPeter Mikkelsen <petermikkelsen10@gmail.com>2025-07-26 16:03:00 +0200
commitf199eae0154f354c37750c8cd3037f94dbfe70db (patch)
tree90938c26bdbe388745a0c3bbd074af92fd49ae13 /src
Initial commit
Diffstat (limited to 'src')
-rw-r--r--src/aplos.h57
-rw-r--r--src/boot.c89
-rw-r--r--src/font.c134
-rw-r--r--src/main.c65
-rw-r--r--src/nasty.S7
-rw-r--r--src/screen.c116
-rw-r--r--src/utf8.c66
-rw-r--r--src/util.c33
8 files changed, 567 insertions, 0 deletions
diff --git a/src/aplos.h b/src/aplos.h
new file mode 100644
index 0000000..4e663f4
--- /dev/null
+++ b/src/aplos.h
@@ -0,0 +1,57 @@
+#include <stdint.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include <uchar.h>
+
+#define nelem(arr) (sizeof(arr)/sizeof(*(arr)))
+
+struct framebuffer
+{
+ void *addr;
+ uint64_t width;
+ uint64_t height;
+ uint64_t pitch;
+};
+
+struct memmap
+{
+ uintptr_t start;
+ uint64_t size;
+};
+
+struct boot_info
+{
+ struct framebuffer framebuffer;
+ uint64_t memmap_count;
+ struct memmap *memmaps;
+};
+
+/* boot.c */
+uint64_t cpu_count(void);
+
+/* main.c */
+void main(struct boot_info *);
+#define ASSERT(chk) do{if(!(chk)) halt();}while(0)
+
+/* screen.c */
+void screen_init(struct framebuffer *);
+void screen_draw_pixel(uint32_t, uint32_t, uint32_t);
+void print(char8_t *, ...);
+
+/* font.c */
+void font_init(void);
+void font_draw(char8_t *, uint32_t, uint32_t, uint32_t, uint32_t);
+
+/* util.c */
+uint16_t read_uint16_le(const uint8_t *);
+uint16_t read_uint16_be(const uint8_t *);
+uint32_t read_uint32_le(const uint8_t *);
+int memcmp(const void *, const void *, size_t);
+
+/* utf8.c */
+int utf8_char_length(const char8_t *);
+int utf8_cmp_n(const char8_t *, const char8_t *, uint64_t);
+uint32_t utf8_value(const char8_t *);
+
+/* nasty.S */
+extern void halt(void);
diff --git a/src/boot.c b/src/boot.c
new file mode 100644
index 0000000..4bbe771
--- /dev/null
+++ b/src/boot.c
@@ -0,0 +1,89 @@
+#include "aplos.h"
+
+#define LIMINE_API_REVISION 3
+#include "../external/limine/limine.h"
+
+#define LIMINE(sec) \
+ __attribute__((used, section(sec))) \
+ static volatile
+#define REQUEST LIMINE(".limine_requests")
+
+static void bootmain(void);
+
+REQUEST LIMINE_BASE_REVISION(3)
+
+REQUEST struct limine_framebuffer_request framebuffer_request = {
+ .id = LIMINE_FRAMEBUFFER_REQUEST,
+ .revision = 0
+};
+
+REQUEST struct limine_memmap_request memmap_request = {
+ .id = LIMINE_MEMMAP_REQUEST,
+ .revision = 0
+};
+
+REQUEST struct limine_paging_mode_request paging_request = {
+ .id = LIMINE_PAGING_MODE_REQUEST,
+ .revision = 1,
+ .mode = LIMINE_PAGING_MODE_X86_64_4LVL,
+ .min_mode = LIMINE_PAGING_MODE_X86_64_4LVL,
+ .max_mode = LIMINE_PAGING_MODE_X86_64_4LVL
+};
+
+REQUEST struct limine_mp_request mp_request = {
+ .id = LIMINE_MP_REQUEST,
+ .revision = 0
+};
+
+REQUEST struct limine_entry_point_request entry_point_request = {
+ .id = LIMINE_ENTRY_POINT_REQUEST,
+ .revision = 0,
+ .entry = bootmain
+};
+
+LIMINE(".limine_requests_start") LIMINE_REQUESTS_START_MARKER
+LIMINE(".limine_requests_end") LIMINE_REQUESTS_END_MARKER
+
+uint64_t
+cpu_count(void)
+{
+ return mp_request.response->cpu_count;
+}
+
+static void
+bootmain(void)
+{
+ struct boot_info info;
+
+ ASSERT(LIMINE_BASE_REVISION_SUPPORTED);
+ ASSERT(framebuffer_request.response);
+ ASSERT(memmap_request.response);
+ ASSERT(paging_request.response);
+ ASSERT(mp_request.response);
+
+ ASSERT(framebuffer_request.response->framebuffer_count >= 1);
+
+ struct limine_framebuffer *framebuffer = framebuffer_request.response->framebuffers[0];
+
+ info.framebuffer.addr = framebuffer->address;
+ info.framebuffer.width = framebuffer->width;
+ info.framebuffer.height = framebuffer->height;
+ info.framebuffer.pitch = framebuffer->pitch;
+
+ struct memmap memmaps[memmap_request.response->entry_count];
+ info.memmap_count = 0;
+
+ struct memmap *m = memmaps;
+ for(uint64_t i = 0; i < memmap_request.response->entry_count; i++){
+ struct limine_memmap_entry *e = memmap_request.response->entries[i];
+ if(e->type != LIMINE_MEMMAP_USABLE)
+ continue;
+ m->start = e->base;
+ m->size = e->length;
+ m++;
+ info.memmap_count++;
+ }
+ info.memmaps = memmaps;
+
+ main(&info);
+}
diff --git a/src/font.c b/src/font.c
new file mode 100644
index 0000000..33c81aa
--- /dev/null
+++ b/src/font.c
@@ -0,0 +1,134 @@
+#include "aplos.h"
+
+static const uint8_t font_data[] = {
+ #embed "../external/spleen/spleen-8x16.psfu"
+// #embed "../external/spleen/spleen-12x24.psfu"
+// #embed "../external/spleen/spleen-16x32.psfu"
+};
+
+static uint32_t header_size;
+static uint32_t glyph_count;
+static uint32_t bytes_per_glyph;
+static uint32_t char_height;
+static uint32_t char_width;
+
+static void font_init_psf1(void);
+static void font_init_psf2(void);
+
+static const uint8_t *font_bitmap(char8_t *c);
+static uint64_t lookup_psf1(char8_t *);
+static uint64_t lookup_psf2(char8_t *);
+
+static uint64_t (*lookup)(char8_t *);
+
+void
+font_init(void)
+{
+ if(read_uint16_le(font_data) == 0x0436)
+ font_init_psf1();
+ else if(read_uint32_le(font_data) == 0x864AB572)
+ font_init_psf2();
+ else
+ halt();
+}
+
+static void
+font_init_psf1(void)
+{
+ header_size = 4;
+ glyph_count = (font_data[2] & 1) ? 512 : 256;
+ bytes_per_glyph = font_data[3];
+ char_height = bytes_per_glyph;
+ char_width = 8;
+ lookup = lookup_psf1;
+}
+
+static void
+font_init_psf2(void)
+{
+ header_size = read_uint32_le(font_data+8);
+ glyph_count = read_uint32_le(font_data+16);
+ bytes_per_glyph = read_uint32_le(font_data+20);
+ char_height = read_uint32_le(font_data+24);
+ char_width = read_uint32_le(font_data+28);
+ lookup = lookup_psf2;
+}
+
+void
+font_draw(char8_t *c, uint32_t row, uint32_t col, uint32_t bg, uint32_t fg)
+{
+ uint32_t x0 = char_width * col;
+ uint32_t y0 = char_height * row;
+
+ const uint8_t *data = font_bitmap(c);
+ data--;
+
+ for(uint32_t y = 0; y < char_height; y++){
+ int shift = 0;
+ for(uint32_t x = 0; x < char_width; x++){
+ if(shift == 0){
+ shift = 8;
+ data++;
+ }
+ shift--;
+
+ uint8_t val = *data;
+ uint8_t mask = 1<<shift;
+ screen_draw_pixel(x0+x, y0+y, (val&mask) ? fg : bg);
+ }
+ }
+}
+
+static const uint8_t *
+font_bitmap(char8_t *c)
+{
+ uint64_t index = lookup(c);
+ if(index == UINT64_MAX){
+ if(*c == '?')
+ index = 0;
+ else
+ index = lookup(u8"?");
+ }
+ return font_data + header_size + bytes_per_glyph * index;
+}
+
+static uint64_t
+lookup_psf1(char8_t *c)
+{
+ uint64_t offset = 0;
+ uint32_t v = utf8_value(c);
+ if(v > UINT16_MAX)
+ return 0;
+
+ const uint8_t *p = font_data + header_size + glyph_count * bytes_per_glyph;
+ while(p < &font_data[nelem(font_data)]){
+ uint16_t x = read_uint16_le(p);
+ p += 2;
+ if(x == 0xFFFF)
+ offset++;
+ else if(x == v)
+ return offset;
+ }
+ return UINT64_MAX;
+}
+
+static uint64_t
+lookup_psf2(char8_t *c)
+{
+ int char_len = utf8_char_length(c);
+ uint64_t offset = 0;
+ const uint8_t *p = font_data + header_size + glyph_count * bytes_per_glyph;
+ while(p < &font_data[nelem(font_data)]){
+ if(*p == 0xFF){
+ offset++;
+ p++;
+ }else if(memcmp(p, c, char_len) == 0){
+ return offset;
+ }else if(*p == 0xFE){
+ p++;
+ }else{
+ p += utf8_char_length(p);
+ }
+ }
+ return UINT64_MAX;
+}
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..4721735
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,65 @@
+#include "aplos.h"
+
+static void welcome(void);
+static void print_memmap(struct boot_info *);
+static void print_size(uint64_t);
+
+void
+main(struct boot_info *info)
+{
+ screen_init(&info->framebuffer);
+ welcome();
+ print(u8"CPU count: %u64\n", cpu_count());
+ print_memmap(info);
+
+ halt();
+}
+
+static void
+welcome(void)
+{
+ print(u8"Starting ☺☻☺☻☺☻☺☻☺☻\n");
+}
+
+static void
+print_memmap(struct boot_info *info)
+{
+ print(u8"Usable memory: ");
+ uint64_t total = 0;
+ for(uint64_t i = 0; i < info->memmap_count; i++)
+ total += info->memmaps[i].size;
+ print_size(total);
+ print(u8"\n");
+
+ for(uint64_t i = 0; i < info->memmap_count; i++){
+ struct memmap *m = &info->memmaps[i];
+ print(u8"%p - %p (", m->start, m->start + m->size);
+ print_size(m->size);
+ print(u8")\n");
+ }
+}
+
+static void
+print_size(uint64_t size)
+{
+ uint64_t gb, mb, kb, b;
+ gb = size >> 30; size -= gb << 30;
+ mb = size >> 20; size -= mb << 20;
+ kb = size >> 10; size -= kb << 10;
+ b = size;
+
+ int printed = 0;
+
+#define P(what, spec, force) \
+ if(what || (force && !printed)){ \
+ if(printed) \
+ print(u8" + "); \
+ printed = 1; \
+ print(u8"%u64 " spec, what); \
+ }
+
+ P(gb, "GB", 0);
+ P(mb, "MB", 0);
+ P(kb, "KB", 0);
+ P(b, "B", 1);
+}
diff --git a/src/nasty.S b/src/nasty.S
new file mode 100644
index 0000000..26732a3
--- /dev/null
+++ b/src/nasty.S
@@ -0,0 +1,7 @@
+.intel_syntax noprefix
+
+.section .text
+.global halt
+halt:
+1: hlt
+ jmp 1b
diff --git a/src/screen.c b/src/screen.c
new file mode 100644
index 0000000..1ce4192
--- /dev/null
+++ b/src/screen.c
@@ -0,0 +1,116 @@
+#include "aplos.h"
+
+#define FOREGROUND 0x442A13
+#define BACKGROUND 0xE3DFD7
+
+static struct framebuffer *fb;
+static volatile uint32_t *fb_mem;
+
+static uint32_t row;
+static uint32_t col;
+
+static void screen_clear(void);
+static int print_fmt(char8_t *, va_list);
+
+void
+screen_init(struct framebuffer *framebuffer)
+{
+ fb = framebuffer;
+ fb_mem = fb->addr;
+ screen_clear();
+
+ font_init();
+}
+
+void
+screen_draw_pixel(uint32_t x, uint32_t y, uint32_t c)
+{
+ fb_mem[x + y * (fb->pitch/4)] = c;
+}
+
+void
+print(char8_t *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+
+ int n;
+ for(char8_t *p = fmt; *p; p += utf8_char_length(p)){
+ switch(*p){
+ default:
+print_char:
+ font_draw(p, row, col, BACKGROUND, FOREGROUND);
+ col++;
+ break;
+ case '\n':
+ row++;
+ col = 0;
+ break;
+ case '%':
+ n = print_fmt(p, args);
+ if(n == 0)
+ goto print_char;
+ while(n-- > 1)
+ p += utf8_char_length(p);
+ break;
+ }
+ }
+ va_end(args);
+}
+
+static void
+screen_clear(void)
+{
+ for(uint64_t y = 0; y < fb->height; y++){
+ for(uint64_t x = 0; x < fb->width; x++){
+ fb_mem[x + y * (fb->pitch/4)] = BACKGROUND;
+ }
+ }
+}
+
+static int
+print_fmt(char8_t *fmt, va_list args)
+{
+ char8_t digits[] = u8"0123456789ABCDEF";
+ char8_t *prefixes[17] = {0};
+ char8_t buf[65];
+ char8_t *p = &buf[nelem(buf)-1];
+
+ prefixes[2] = u8"0b";
+ prefixes[8] = u8"0o";
+ prefixes[16] = u8"0x";
+
+ *p = 0;
+
+#define UINT(spec, n, base, min, type) \
+ if(utf8_cmp_n(fmt, spec, 2+n) == 0){ \
+ type v = va_arg(args, type); \
+ int w = min; \
+ do{ \
+ p--; \
+ *p = digits[v%base]; \
+ v = v / base; \
+ if(w) \
+ w--; \
+ }while(v || w); \
+ if(prefixes[base]) \
+ print(prefixes[base]); \
+ print(p); \
+ return 2+n; \
+ }
+
+#define UINTS(bits, n, type) \
+ UINT(u8"%b" #bits, n, 2, 0, type) \
+ UINT(u8"%o" #bits, n, 8, 0, type) \
+ UINT(u8"%u" #bits, n, 10, 0, type) \
+ UINT(u8"%x" #bits, n, 16, 0, type) \
+
+ UINTS(64, 2, uint64_t);
+ UINTS(32, 2, uint32_t);
+ UINTS(16, 2, int);
+ UINTS(8, 1, int);
+
+ UINT(u8"%p", 0, 16, 16, uintptr_t);
+
+ return 0;
+}
diff --git a/src/utf8.c b/src/utf8.c
new file mode 100644
index 0000000..177f76d
--- /dev/null
+++ b/src/utf8.c
@@ -0,0 +1,66 @@
+#include "aplos.h"
+
+int
+utf8_char_length(const char8_t *p)
+{
+ uint8_t v = *p;
+ if((v >> 5) == 0b110)
+ return 2;
+ if((v >> 4) == 0b1110)
+ return 3;
+ if((v >> 3) == 0b11110)
+ return 4;
+ return 1;
+}
+
+int
+utf8_cmp_n(const char8_t *a, const char8_t *b, uint64_t n)
+{
+ uint32_t aval, bval;
+ while(*a && *b && n){
+ aval = utf8_value(a);
+ bval = utf8_value(b);
+
+ if(aval < bval)
+ return -1;
+ if(aval > bval)
+ return 1;
+ a += utf8_char_length(a);
+ b += utf8_char_length(b);
+ n--;
+ }
+ if((n == 0) || (*a == *b))
+ return 0;
+ if(*a)
+ return 1;
+ else
+ return -1;
+}
+
+uint32_t
+utf8_value(const char8_t *p)
+{
+ uint32_t v = 0;
+ int n = utf8_char_length(p);
+ switch(n){
+ case 1:
+ v = *p;
+ break;
+ case 2:
+ v = *p & 0b00011111;
+ break;
+ case 3:
+ v = *p & 0b00001111;
+ break;
+ case 4:
+ v = *p & 0b00000111;
+ break;
+ }
+
+ while(--n){
+ p++;
+ v <<= 6;
+ v |= *p & 0b00111111;
+ }
+ return v;
+}
diff --git a/src/util.c b/src/util.c
new file mode 100644
index 0000000..e77f65b
--- /dev/null
+++ b/src/util.c
@@ -0,0 +1,33 @@
+#include "aplos.h"
+
+uint16_t
+read_uint16_le(const uint8_t *p)
+{
+ return p[0] | (p[1] << 8);
+}
+
+uint16_t
+read_uint16_be(const uint8_t *p)
+{
+ return p[1] | (p[0] << 8);
+}
+
+uint32_t
+read_uint32_le(const uint8_t *p)
+{
+ return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
+}
+
+int
+memcmp(const void *p1, const void *p2, size_t n)
+{
+ const uint8_t *a = p1;
+ const uint8_t *b = p2;
+ for(size_t i = 0; i < n; i++){
+ if(a[i] < b[i])
+ return -1;
+ else if(a[i] > b[i])
+ return 1;
+ }
+ return 0;
+}