From f199eae0154f354c37750c8cd3037f94dbfe70db Mon Sep 17 00:00:00 2001 From: Peter Mikkelsen Date: Sat, 26 Jul 2025 16:03:00 +0200 Subject: Initial commit --- src/aplos.h | 57 +++++++++++++++++++++++++ src/boot.c | 89 +++++++++++++++++++++++++++++++++++++++ src/font.c | 134 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.c | 65 +++++++++++++++++++++++++++++ src/nasty.S | 7 ++++ src/screen.c | 116 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/utf8.c | 66 +++++++++++++++++++++++++++++ src/util.c | 33 +++++++++++++++ 8 files changed, 567 insertions(+) create mode 100644 src/aplos.h create mode 100644 src/boot.c create mode 100644 src/font.c create mode 100644 src/main.c create mode 100644 src/nasty.S create mode 100644 src/screen.c create mode 100644 src/utf8.c create mode 100644 src/util.c (limited to 'src') 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 +#include +#include +#include + +#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< 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; +} -- cgit v1.2.3