summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorElizabeth Alexander Hunt <me@liz.coffee>2026-10-11 14:22:26 -0700
committerElizabeth Alexander Hunt <me@liz.coffee>2026-10-11 14:27:23 -0700
commit7c870e6eabd53f7a8cb0c9b5ecb477797b4de09a (patch)
tree9c52c9ffb4f036ffcbeb785b8ed2b8bd0dfbf61a
parentc74bd1baa844eac1fcb17a266ef720ed0c1ae616 (diff)
downloadmacaroni-7c870e6eabd53f7a8cb0c9b5ecb477797b4de09a.tar.gz
macaroni-7c870e6eabd53f7a8cb0c9b5ecb477797b4de09a.zip
Scroll some pixels on the fuckin screenHEADmain
-rw-r--r--Makefile2
-rw-r--r--compile_flags.txt6
-rw-r--r--include/io.h13
-rw-r--r--include/utils.h8
-rw-r--r--include/video.h23
-rw-r--r--src/boot.asm6
-rw-r--r--src/io.c46
-rw-r--r--src/kernel.c43
-rw-r--r--src/utils.c13
-rw-r--r--src/video.c33
10 files changed, 161 insertions, 32 deletions
diff --git a/Makefile b/Makefile
index e44eb1b..74a84eb 100644
--- a/Makefile
+++ b/Makefile
@@ -24,7 +24,7 @@ all: $(IMAGE)
bin: $(BIN)
demo: $(IMAGE)
- $(QEMU) -cdrom $<
+ $(QEMU) -chardev file,id=char0,path=/tmp/serial.log,signal=off -serial chardev:char0 -cdrom $<
clean:
rm -rf $(OBJ) $(ISO) $(BIN) $(IMAGE)
diff --git a/compile_flags.txt b/compile_flags.txt
new file mode 100644
index 0000000..2c3cb1d
--- /dev/null
+++ b/compile_flags.txt
@@ -0,0 +1,6 @@
+--target=i686-elf
+-std=c11
+-ffreestanding
+-Wall
+-Wextra
+-Iinclude
diff --git a/include/io.h b/include/io.h
new file mode 100644
index 0000000..ed71e6f
--- /dev/null
+++ b/include/io.h
@@ -0,0 +1,13 @@
+#include <stdint.h>
+
+#ifndef IO_H
+#define IO_H
+
+uint8_t inportb(uint16_t port);
+void outportb(uint16_t port, uint8_t data);
+void init_serial();
+void serial_putc(char c);
+void serial_puts(const char* s);
+void serial_puthex(uint32_t h);
+
+#endif // IO_H \ No newline at end of file
diff --git a/include/utils.h b/include/utils.h
index 9ea1f09..beed3cc 100644
--- a/include/utils.h
+++ b/include/utils.h
@@ -1,5 +1,7 @@
#include <stdbool.h>
+#define DEBUG 0
+
#ifndef UTILS_H
#define UTILS_H
@@ -7,7 +9,7 @@
#define asm __asm__ volatile
#endif
-void macaroni_panic(char* msg);
-void macaroni_assert(bool condition, char* msg);
+void macaroni_panic(const char* msg);
+void macaroni_assert(bool condition, const char* msg);
-#endif // UTILS_H \ No newline at end of file
+#endif // UTILS_H
diff --git a/include/video.h b/include/video.h
new file mode 100644
index 0000000..85a670c
--- /dev/null
+++ b/include/video.h
@@ -0,0 +1,23 @@
+#include <stdint.h>
+#include "multiboot.h"
+
+#ifndef VIDEO_H
+#define VIDEO_H
+
+#define MULTIBOOT_GODS_WIDTH 640
+#define MULTIBOOT_GODS_HEIGHT 480
+#define MULTIBOOT_VIDEO_BPP 24
+
+typedef uint32_t macaroni_color;
+static macaroni_color RED = 0xFF0000;
+static macaroni_color GREEN = 0x00FF00;
+static macaroni_color BLUE = 0x0000FF;
+
+static uint8_t* video_framebuffer;
+static uint32_t pitch;
+static uint32_t pixel_width;
+
+void init_video(multiboot_info_t* p_multiboot_info);
+void put_pixel(macaroni_color color, uint16_t x, uint16_t y);
+
+#endif // VIDEO_H
diff --git a/src/boot.asm b/src/boot.asm
index e723d61..3d25240 100644
--- a/src/boot.asm
+++ b/src/boot.asm
@@ -1,4 +1,4 @@
-;> The Multiboot header must be contained completely within the first 8192 bytes of the OS
+;> The Multiboot header must be contained completely within the first 8192 bytes of the OS
;> image, and must be longword (32-bit) aligned.
MULTIBOOT_ALIGN_TO_PAGE: equ 1 << 0
MULTIBOOT_MEMORY_DESCRIBE: equ 1 << 1
@@ -9,7 +9,7 @@ MULTIBOOT_CHECKSUM: equ -(MULTIBOOT_MAGIC + MULTIBOOT_FLAGS)
MULTIBOOT_VIDEO_TYPE: equ 0
MULTIBOOT_GODS_WIDTH: equ 640
MULTIBOOT_GODS_HEIGHT: equ 480
-MULTIBOOT_VIDEO_BPP: equ 16
+MULTIBOOT_VIDEO_BPP: equ 24
; We don't set flags[16] because we assemble to ELF32 so header_addr, etc is useless to us
; (at least at the moment).
@@ -39,6 +39,8 @@ section .text
global _start:function (_start.end - _start)
_start:
mov esp, stack_top
+ push ebx
+ push eax
extern cmain
call cmain
cli
diff --git a/src/io.c b/src/io.c
index 1d9db60..d1206c3 100644
--- a/src/io.c
+++ b/src/io.c
@@ -1,6 +1,10 @@
#include <stdint.h>
#include "utils.h"
+#define PORT 0x3f8 // COM1
+#define LINE_STATUS_REGISTER PORT + 5
+#define TRANSMITTER_EMPTY_BITMASK 0b00100000
+
uint8_t inportb(uint16_t port) {
uint8_t r;
asm("inb %1, %0" : "=a" (r) : "dN" (port));
@@ -9,4 +13,44 @@ uint8_t inportb(uint16_t port) {
void outportb(uint16_t port, uint8_t data) {
asm("outb %1, %0" : : "dN" (port), "a" (data));
-} \ No newline at end of file
+}
+
+void init_serial() {
+ outportb(PORT + 1, 0x00); // Disable all interrupts
+ outportb(PORT + 3, 0x80); // Enable DLAB (set baud rate divisor)
+
+ // Set divisor to 3 -> (115200 / 3) = 38400
+ outportb(PORT + 0, 0x03); // LSB
+ outportb(PORT + 1, 0x00); // MSB
+
+ outportb(PORT + 3, 0x03); // Character length is 8 bits, no parity, one stop bit
+ outportb(PORT + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold
+
+// TODO: GDT and IDT in order to setup COM1 interrupts.
+// For now, though, we POLLLLL that mf.
+// outportb(PORT + 4, 0x0B); // IRQs enabled, RTS/DSR set
+
+ outportb(PORT + 4, 0x1E); // Set in loopback mode, test the serial chip
+ outportb(PORT + 0, 0xAE); // Test serial chip (send byte 0xAE and check if serial returns same byte)
+ macaroni_assert(inportb(PORT + 0) == 0xAE, "0xAE expected from serial initizliation");
+ outportb(PORT + 4, 0x0F);
+}
+
+int serial_tx_empty(void) {
+ return inportb(LINE_STATUS_REGISTER) & TRANSMITTER_EMPTY_BITMASK;
+}
+
+void serial_putc(char c) {
+ while (!serial_tx_empty());
+ outportb(PORT, c);
+}
+
+void serial_puts(const char* s) {
+ while (*s) serial_putc(*s++);
+}
+
+void serial_puthex(uint32_t h) {
+ serial_puts("0x");
+ for (int i = 28; i >= 0; i -= 4)
+ serial_putc("0123456789abcdef"[(h >> i) & 0xF]);
+}
diff --git a/src/kernel.c b/src/kernel.c
index 2c2afcc..dacc47e 100644
--- a/src/kernel.c
+++ b/src/kernel.c
@@ -1,28 +1,33 @@
-#include "utils.h"
-#include "multiboot.h"
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
+#include "utils.h"
+#include "multiboot.h"
+#include "io.h"
+#include "video.h"
-void validate_multiboot
+void validate_multiboot(multiboot_info_t* p_multiboot_info, uint32_t magic_response) {
+ macaroni_assert(magic_response == 0x2BADB002, "im not a bad boo twooo");
+ macaroni_assert(p_multiboot_info->flags != 0, "version flag being zero is not a good sign");
+}
-void cmain(void) {
- uint32_t magic_response;
- multiboot_info_t* p_multiboot_info;
- asm("\t movl %%eax,%0" : "=r"(magic_response));
- asm("\t movl %%ebx,%0" : "=r"(p_multiboot_info));
+// Stack: [...Bottom] (%ebx, %eax) [...Top]
+void cmain(uint32_t magic_response, multiboot_info_t* p_multiboot_info) {
+ validate_multiboot(p_multiboot_info, magic_response);
- macaroni_assert(magic_response == 0x2BADB002, "im not a bad boo twooo");
- macaroni_assert(p_multiboot_info->framebuffer_width == 640, "not gods width");
- macaroni_assert(p_multiboot_info->framebuffer_height == 480, "not gods height");
- macaroni_assert(p_multiboot_info->framebuffer_bpp == 16, "not gods bpp");
- macaroni_assert(p_multiboot_info->framebuffer_type == MULTIBOOT_FRAMEBUFFER_TYPE_RGB, "not gods fbtype");
- macaroni_assert(p_multiboot_info->framebuffer_red_field_position == 1, "bpp not formatted correctly");
+ init_serial();
+ init_video(p_multiboot_info);
- void *fb = (void *) (unsigned long) p_multiboot_info->framebuffer_addr;
- uint8_t* pixel = fb;
- for (int i = 0; i < 10000; i++) {
- *(pixel + i) = i * 2;
+ macaroni_color colors[] = { RED, GREEN, BLUE };
+ uint32_t i = 0;
+ while(true) {
+ for (uint32_t y = 0; y < MULTIBOOT_GODS_HEIGHT; y++) {
+ for (uint32_t x = 0; x < MULTIBOOT_GODS_WIDTH; x++) {
+ put_pixel(colors[(i + y / 10) % 3], x, y);
+ }
+ }
+ // "sleep"
+ for (int _k = 0; _k < 10000000; _k++) {}
+ i++;
}
-
}
diff --git a/src/utils.c b/src/utils.c
index 63b0b56..bf1ff13 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -1,14 +1,15 @@
#include "utils.h"
+#include "io.h"
-void macaroni_panic(char* msg) {
+void macaroni_panic(const char* msg) {
// we'll do something with msg later.
// while(true){ asm("nop\n\t"); }
+ serial_puts(msg);
asm("int $0x13");
}
-void macaroni_assert(bool condition, char* msg) {
- if (condition) {
- return;
+void macaroni_assert(bool condition, const char* msg) {
+ if (!condition) {
+ macaroni_panic(msg);
}
- macaroni_panic("thisisatest");
-} \ No newline at end of file
+}
diff --git a/src/video.c b/src/video.c
new file mode 100644
index 0000000..be01f6d
--- /dev/null
+++ b/src/video.c
@@ -0,0 +1,33 @@
+#include "video.h"
+#include "utils.h"
+#include "io.h"
+
+void init_video(multiboot_info_t* p_multiboot_info) {
+ #ifdef DEBUG
+ macaroni_assert(p_multiboot_info->framebuffer_width == MULTIBOOT_GODS_WIDTH, "not gods width");
+ macaroni_assert(p_multiboot_info->framebuffer_height == MULTIBOOT_GODS_HEIGHT, "not gods height");
+ macaroni_assert(p_multiboot_info->framebuffer_bpp == MULTIBOOT_VIDEO_BPP, "not gods bpp");
+ macaroni_assert(p_multiboot_info->framebuffer_type == MULTIBOOT_FRAMEBUFFER_TYPE_RGB, "not video fbtype");
+ #endif
+
+ #ifdef DEBUG
+ serial_puthex((uint32_t) p_multiboot_info->framebuffer_red_field_position);
+ serial_puthex((uint32_t) p_multiboot_info->framebuffer_red_mask_size);
+ serial_puthex((uint32_t) p_multiboot_info->framebuffer_green_field_position);
+ serial_puthex((uint32_t) p_multiboot_info->framebuffer_green_mask_size);
+ serial_puthex((uint32_t) p_multiboot_info->framebuffer_blue_field_position);
+ serial_puthex((uint32_t) p_multiboot_info->framebuffer_blue_mask_size);
+ serial_puthex((uint32_t) p_multiboot_info->framebuffer_bpp);
+ serial_puthex((uint32_t) p_multiboot_info->framebuffer_pitch);
+ #endif // DEBUG
+
+ video_framebuffer = (uint8_t*) (uint32_t) p_multiboot_info->framebuffer_addr;
+ pixel_width = (p_multiboot_info->framebuffer_bpp / 8);
+ pitch = p_multiboot_info->framebuffer_pitch;
+}
+
+void put_pixel(macaroni_color color, uint16_t x, uint16_t y) {
+ video_framebuffer[x * pixel_width + y * pitch] = color & 0xFF;
+ video_framebuffer[x * pixel_width + y * pitch + 1] = (color >> 8) & 0xFF;
+ video_framebuffer[x * pixel_width + y * pitch + 2] = (color >> 16) & 0xFF;
+}