mirror of
https://github.com/pixelyblah/florid-os.git
synced 2026-05-15 11:38:40 +00:00
Compare commits
No commits in common. "0c4d84f82f8a332f213534ce9b0cb03c67ae5668" and "14e09f5034db3a4812d256d35031c540de9482ed" have entirely different histories.
0c4d84f82f
...
14e09f5034
50 changed files with 492 additions and 600 deletions
Binary file not shown.
40
FloridOS/Makefile
Normal file
40
FloridOS/Makefile
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
CC = gcc
|
||||||
|
LD = ld
|
||||||
|
CFLAGS = -Wall -Wextra -std=c11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -Isrc
|
||||||
|
LDFLAGS = -T linker.ld -static -nostdlib -no-pie -z max-page-size=0x1000
|
||||||
|
|
||||||
|
# Explicitly define the objects
|
||||||
|
OBJS = build/kernel.o build/drivers/tty.o build/drivers/keyboard.o
|
||||||
|
|
||||||
|
all: Fflorid.iso
|
||||||
|
|
||||||
|
# Rule to make the build directories
|
||||||
|
build_dirs:
|
||||||
|
mkdir -p build/drivers build/shell
|
||||||
|
|
||||||
|
# Rule to compile C files
|
||||||
|
build/%.o: src/%.c | build_dirs
|
||||||
|
$(CC) $(CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
|
# THE MISSING RULE: Link the kernel
|
||||||
|
build/kernel.bin: $(OBJS)
|
||||||
|
$(LD) $(LDFLAGS) $(OBJS) -o build/kernel.bin
|
||||||
|
|
||||||
|
# Build the ISO
|
||||||
|
Fflorid.iso: build/kernel.bin
|
||||||
|
rm -rf iso_root
|
||||||
|
mkdir -p iso_root
|
||||||
|
cp build/kernel.bin iso_root/kernel
|
||||||
|
cp limine.cfg iso_root/limine.cfg
|
||||||
|
cp limine/limine-bios.sys iso_root/limine-bios.sys
|
||||||
|
cp limine/limine-bios-cd.bin iso_root/limine-bios-cd.bin
|
||||||
|
xorriso -as mkisofs -b limine-bios-cd.bin \
|
||||||
|
-no-emul-boot -boot-load-size 4 -boot-info-table \
|
||||||
|
iso_root -o Fflorid.iso
|
||||||
|
./limine/limine bios-install Fflorid.iso
|
||||||
|
|
||||||
|
run: Fflorid.iso
|
||||||
|
qemu-system-x86_64 -cdrom Fflorid.iso
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf build iso_root Fflorid.iso
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
#!/usr/bin/fish
|
|
||||||
|
|
||||||
# 1. CLEANUP
|
|
||||||
rm -rf build
|
|
||||||
mkdir -p build/iso_root/boot/limine
|
|
||||||
|
|
||||||
# 2. COMPILE KERNEL
|
|
||||||
gcc -ffreestanding -mcmodel=kernel -fno-stack-protector -fno-pic -m64 -Isrc/include -c src/kernel/kernel.c -o build/kernel.o
|
|
||||||
|
|
||||||
# 3. LINK KERNEL
|
|
||||||
ld -nostdlib -static -m elf_x86_64 -z max-page-size=0x1000 -T src/kernel/linker.ld build/kernel.o -o build/kernel.elf
|
|
||||||
|
|
||||||
# 4. PREP ISO STRUCTURE (The "Fix")
|
|
||||||
cp build/kernel.elf build/iso_root/boot/
|
|
||||||
cp src/assets/terminal.fpf build/iso_root/boot/ # Make sure path to fpf is correct!
|
|
||||||
cp limine/limine-bios.sys build/iso_root/boot/limine/
|
|
||||||
cp limine/limine-bios-cd.bin build/iso_root/boot/limine/
|
|
||||||
cp limine/limine.conf build/iso_root/boot/limine/
|
|
||||||
|
|
||||||
# 5. BUILD ISO
|
|
||||||
xorriso -as mkisofs -b boot/limine/limine-bios-cd.bin \
|
|
||||||
-no-emul-boot -boot-load-size 4 -boot-info-table \
|
|
||||||
build/iso_root -o build/florid_os.iso
|
|
||||||
|
|
||||||
# 6. THE BLESSING
|
|
||||||
./limine-binary/limine bios-install build/florid_os.iso
|
|
||||||
BIN
FloridOS/build/drivers/keyboard.o
Normal file
BIN
FloridOS/build/drivers/keyboard.o
Normal file
Binary file not shown.
BIN
FloridOS/build/drivers/tty.o
Normal file
BIN
FloridOS/build/drivers/tty.o
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
5
FloridOS/iso_root/limine.cfg
Normal file
5
FloridOS/iso_root/limine.cfg
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
TIMEOUT=3
|
||||||
|
|
||||||
|
:Florid OS
|
||||||
|
PROTOCOL=limine
|
||||||
|
KERNEL_PATH=boot:///kernel
|
||||||
Binary file not shown.
Binary file not shown.
5
FloridOS/limine.cfg
Normal file
5
FloridOS/limine.cfg
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
TIMEOUT=3
|
||||||
|
|
||||||
|
:Florid OS
|
||||||
|
PROTOCOL=limine
|
||||||
|
KERNEL_PATH=boot:///kernel
|
||||||
Binary file not shown.
|
|
@ -1,3 +0,0 @@
|
||||||
/Florid OS
|
|
||||||
protocol: limine
|
|
||||||
kernel_path: boot():/kernel.elf
|
|
||||||
11
FloridOS/linker.ld
Normal file
11
FloridOS/linker.ld
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
ENTRY(_start)
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
. = 0xffffffff80000000;
|
||||||
|
|
||||||
|
.text : { *(.text .text.*) }
|
||||||
|
.rodata : { *(.rodata .rodata.*) }
|
||||||
|
.data : { *(.data .data.*) }
|
||||||
|
.bss : { *(.bss .bss.*) *(COMMON) }
|
||||||
|
}
|
||||||
11
FloridOS/src/drivers/io.h
Normal file
11
FloridOS/src/drivers/io.h
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
#ifndef IO_H
|
||||||
|
#define IO_H
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
static inline uint8_t inb(uint16_t port) {
|
||||||
|
uint8_t ret;
|
||||||
|
__asm__ volatile ( "inb %w1, %b0" : "=a"(ret) : "Nd"(port) : "memory");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
39
FloridOS/src/drivers/keyboard.c
Normal file
39
FloridOS/src/drivers/keyboard.c
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
#include "io.h"
|
||||||
|
#include "tty.h"
|
||||||
|
|
||||||
|
// The Scan Code Map - Every key on the keyboard!
|
||||||
|
char kbd_map[] = {
|
||||||
|
0, 27, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b',
|
||||||
|
'\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',
|
||||||
|
0, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', 0,
|
||||||
|
'\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', 0, '*', 0, ' '
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint8_t last_scancode = 0;
|
||||||
|
|
||||||
|
void update_keyboard() {
|
||||||
|
// Check if the keyboard has data ready (Status Port 0x64, Bit 0)
|
||||||
|
if (inb(0x64) & 1) {
|
||||||
|
uint8_t scancode = inb(0x60);
|
||||||
|
|
||||||
|
// If the scancode is the SAME as the last one, skip it
|
||||||
|
// This prevents one tap from typing 50 letters on your fast laptop
|
||||||
|
if (scancode == last_scancode) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
last_scancode = scancode;
|
||||||
|
|
||||||
|
// Key Pressed (scancode < 0x80)
|
||||||
|
if (scancode < 0x80) {
|
||||||
|
char c = kbd_map[scancode];
|
||||||
|
if (c > 0) {
|
||||||
|
tty_putchar(c);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Key Released (scancode >= 0x80)
|
||||||
|
// We reset last_scancode so you can press the same key again later
|
||||||
|
last_scancode = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
9
FloridOS/src/drivers/keyboard.h
Normal file
9
FloridOS/src/drivers/keyboard.h
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
#ifndef KEYBOARD_H
|
||||||
|
#define KEYBOARD_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
// This tells the rest of the OS that this function exists in keyboard.c
|
||||||
|
void update_keyboard(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
53
FloridOS/src/drivers/terminal.c
Normal file
53
FloridOS/src/drivers/terminal.c
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
#include "drivers/terminal.h"
|
||||||
|
|
||||||
|
#define MAX_COLS 80
|
||||||
|
#define MAX_ROWS 25
|
||||||
|
|
||||||
|
static uint16_t terminal_buffer[MAX_ROWS * MAX_COLS];
|
||||||
|
static int cursor_x = 0, cursor_y = 0;
|
||||||
|
|
||||||
|
// To reach 1000 lines, we implement a full 'scroll' function
|
||||||
|
void terminal_scroll() {
|
||||||
|
for (int i = 0; i < MAX_ROWS - 1; i++) {
|
||||||
|
for (int j = 0; j < MAX_COLS; j++) {
|
||||||
|
terminal_buffer[i * MAX_COLS + j] = terminal_buffer[(i + 1) * MAX_COLS + j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Clear the last line
|
||||||
|
for (int j = 0; j < MAX_COLS; j++) {
|
||||||
|
terminal_buffer[(MAX_ROWS - 1) * MAX_COLS + j] = ' ';
|
||||||
|
}
|
||||||
|
cursor_y = MAX_ROWS - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void terminal_putchar(char c) {
|
||||||
|
if (c == '\n') {
|
||||||
|
cursor_x = 0;
|
||||||
|
cursor_y++;
|
||||||
|
} else {
|
||||||
|
terminal_buffer[cursor_y * MAX_COLS + cursor_x] = c;
|
||||||
|
cursor_x++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cursor_x >= MAX_COLS) {
|
||||||
|
cursor_x = 0;
|
||||||
|
cursor_y++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cursor_y >= MAX_ROWS) {
|
||||||
|
terminal_scroll();
|
||||||
|
}
|
||||||
|
// Now call your draw_char function to update the pixels...
|
||||||
|
}
|
||||||
|
|
||||||
|
void terminal_write(const char* data, size_t size) {
|
||||||
|
for (size_t i = 0; i < size; i++) {
|
||||||
|
terminal_putchar(data[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void terminal_writestring(const char* data) {
|
||||||
|
size_t len = 0;
|
||||||
|
while (data[len]) len++;
|
||||||
|
terminal_write(data, len);
|
||||||
|
}
|
||||||
13
FloridOS/src/drivers/terminal.h
Normal file
13
FloridOS/src/drivers/terminal.h
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
#ifndef TERMINAL_H
|
||||||
|
#define TERMINAL_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
// Example: Define your terminal functions here
|
||||||
|
void terminal_initialize(void);
|
||||||
|
void terminal_putchar(char c);
|
||||||
|
void terminal_write(const char* data, size_t size);
|
||||||
|
void terminal_writestring(const char* data);
|
||||||
|
|
||||||
|
#endif
|
||||||
64
FloridOS/src/drivers/tty.c
Normal file
64
FloridOS/src/drivers/tty.c
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
#include "tty.h"
|
||||||
|
|
||||||
|
// The state of our terminal
|
||||||
|
static struct tty_framebuffer *fb;
|
||||||
|
static uint32_t cursor_x = 20;
|
||||||
|
static uint32_t cursor_y = 20;
|
||||||
|
static uint32_t fg_color;
|
||||||
|
static uint32_t bg_color;
|
||||||
|
|
||||||
|
// --- 8x8 BITMAP FONT ---
|
||||||
|
// This is a basic VGA font. Each byte is one row of pixels.
|
||||||
|
// This is where your line count starts climbing!
|
||||||
|
uint8_t font[128][8] = {
|
||||||
|
[0x20] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // Space
|
||||||
|
['!'] = {0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x18, 0x00},
|
||||||
|
['A'] = {0x18, 0x3C, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x00},
|
||||||
|
['B'] = {0x7C, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x7C, 0x00},
|
||||||
|
['C'] = {0x3C, 0x66, 0x06, 0x06, 0x06, 0x66, 0x3C, 0x00},
|
||||||
|
['D'] = {0x78, 0x6C, 0x66, 0x66, 0x66, 0x6C, 0x78, 0x00},
|
||||||
|
['E'] = {0x7E, 0x06, 0x06, 0x3E, 0x06, 0x06, 0x7E, 0x00},
|
||||||
|
['F'] = {0x7E, 0x06, 0x06, 0x3E, 0x06, 0x06, 0x06, 0x00},
|
||||||
|
['G'] = {0x3C, 0x66, 0x06, 0x76, 0x66, 0x66, 0x3C, 0x00},
|
||||||
|
['H'] = {0x66, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00},
|
||||||
|
['I'] = {0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00},
|
||||||
|
['L'] = {0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x7E, 0x00},
|
||||||
|
['O'] = {0x3C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00},
|
||||||
|
['R'] = {0x7C, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0x66, 0x00},
|
||||||
|
['S'] = {0x3C, 0x66, 0x06, 0x3C, 0x60, 0x66, 0x3C, 0x00},
|
||||||
|
// (Note: You can add more characters here to hit 1,000 lines!)
|
||||||
|
};
|
||||||
|
|
||||||
|
void tty_init(struct tty_framebuffer *target, uint32_t fg, uint32_t bg) {
|
||||||
|
fb = target;
|
||||||
|
fg_color = fg;
|
||||||
|
bg_color = bg;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tty_draw_char(char c, uint32_t x, uint32_t y) {
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
for (int j = 0; j < 8; j++) {
|
||||||
|
// Changed from (1 << j) to (1 << (7 - j)) or vice versa
|
||||||
|
// Try this one specifically for VirtualBox:
|
||||||
|
if (font[(uint8_t)c][i] & (0x80 >> j)) {
|
||||||
|
fb->address[(y + i) * (fb->pitch / 4) + (x + j)] = fg_color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void tty_putchar(char c) {
|
||||||
|
if (c == '\n') {
|
||||||
|
cursor_x = 20;
|
||||||
|
cursor_y += 12;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
tty_draw_char(c, cursor_x, cursor_y);
|
||||||
|
cursor_x += 9; // Space between characters
|
||||||
|
}
|
||||||
|
|
||||||
|
void tty_print(const char *str) {
|
||||||
|
for (size_t i = 0; str[i] != '\0'; i++) {
|
||||||
|
tty_putchar(str[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
29
FloridOS/src/drivers/tty.h
Normal file
29
FloridOS/src/drivers/tty.h
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
#ifndef TTY_H
|
||||||
|
#define TTY_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
// This struct is a copy of the one in kernel.c so tty.c knows how to draw
|
||||||
|
struct tty_framebuffer {
|
||||||
|
uint32_t *address;
|
||||||
|
uint64_t width;
|
||||||
|
uint64_t height;
|
||||||
|
uint64_t pitch;
|
||||||
|
};
|
||||||
|
|
||||||
|
// --- TTY FUNCTIONS ---
|
||||||
|
|
||||||
|
// Initializes the terminal with a framebuffer and colors
|
||||||
|
void tty_init(struct tty_framebuffer *fb, uint32_t fg, uint32_t bg);
|
||||||
|
|
||||||
|
// Puts a single character on the screen
|
||||||
|
void tty_putchar(char c);
|
||||||
|
|
||||||
|
// Prints a whole string (like your old writestring)
|
||||||
|
void tty_print(const char *str);
|
||||||
|
|
||||||
|
// Clears the screen to the background color
|
||||||
|
void tty_clear();
|
||||||
|
|
||||||
|
#endif
|
||||||
131
FloridOS/src/kernel.c
Normal file
131
FloridOS/src/kernel.c
Normal file
|
|
@ -0,0 +1,131 @@
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "limine.h"
|
||||||
|
#include "drivers/tty.h"
|
||||||
|
#include "drivers/io.h"
|
||||||
|
#include "drivers/keyboard.h"
|
||||||
|
|
||||||
|
// --- DELAY FUNCTION ---
|
||||||
|
// This handles the 5-second "Ourple" splash screen
|
||||||
|
void delay(uint64_t counts) {
|
||||||
|
for (volatile uint64_t i = 0; i < counts; i++) {
|
||||||
|
__asm__("nop");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- LIMINE REQUESTS ---
|
||||||
|
static volatile struct limine_framebuffer_request framebuffer_request = {
|
||||||
|
.id = LIMINE_FRAMEBUFFER_REQUEST,
|
||||||
|
.revision = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
// --- MATERIAL 3 COLOR PALETTE ---
|
||||||
|
#define M3_SURFACE 0x1C1B1F
|
||||||
|
#define M3_PRIMARY 0xD0BCFF
|
||||||
|
#define M3_PURPLE_ACCENT 0x381E72
|
||||||
|
|
||||||
|
// --- GRAPHICS STRUCTURE ---
|
||||||
|
struct framebuffer {
|
||||||
|
uint32_t *address;
|
||||||
|
uint64_t width;
|
||||||
|
uint64_t height;
|
||||||
|
uint64_t pitch;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Function to draw a single pixel
|
||||||
|
void put_pixel(struct framebuffer *fb, uint32_t x, uint32_t y, uint32_t color) {
|
||||||
|
if (x >= fb->width || y >= fb->height) return;
|
||||||
|
fb->address[y * (fb->pitch / 4) + x] = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to draw a rectangle
|
||||||
|
void draw_rect(struct framebuffer *fb, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t color) {
|
||||||
|
for (uint32_t i = 0; i < w; i++) {
|
||||||
|
for (uint32_t j = 0; j < h; j++) {
|
||||||
|
put_pixel(fb, x + i, y + j, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- SYSTEM TABLES (GDT) ---
|
||||||
|
struct gdt_entry {
|
||||||
|
uint16_t limit_low;
|
||||||
|
uint16_t base_low;
|
||||||
|
uint8_t base_middle;
|
||||||
|
uint8_t access;
|
||||||
|
uint8_t granularity;
|
||||||
|
uint8_t base_high;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct gdt_ptr {
|
||||||
|
uint16_t limit;
|
||||||
|
uint64_t base;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct gdt_entry gdt[3];
|
||||||
|
struct gdt_ptr gdt_p;
|
||||||
|
|
||||||
|
void init_gdt() {
|
||||||
|
gdt[0] = (struct gdt_entry){0, 0, 0, 0, 0, 0}; // Null
|
||||||
|
gdt[1] = (struct gdt_entry){0, 0, 0, 0x9A, 0x20, 0}; // Code
|
||||||
|
gdt[2] = (struct gdt_entry){0, 0, 0, 0x92, 0, 0}; // Data
|
||||||
|
|
||||||
|
gdt_p.limit = (sizeof(struct gdt_entry) * 3) - 1;
|
||||||
|
gdt_p.base = (uint64_t)&gdt;
|
||||||
|
__asm__ volatile("lgdt %0" : : "m"(gdt_p));
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- KERNEL ENTRY POINT ---
|
||||||
|
void _start(void) {
|
||||||
|
// 1. Check if we have a screen
|
||||||
|
if (framebuffer_request.response == NULL || framebuffer_request.response->framebuffer_count < 1) {
|
||||||
|
__asm__("hlt");
|
||||||
|
}
|
||||||
|
|
||||||
|
struct limine_framebuffer *fb_info = framebuffer_request.response->framebuffers[0];
|
||||||
|
struct framebuffer fb = {
|
||||||
|
.address = fb_info->address,
|
||||||
|
.width = fb_info->width,
|
||||||
|
.height = fb_info->height,
|
||||||
|
.pitch = fb_info->pitch
|
||||||
|
};
|
||||||
|
|
||||||
|
// 2. Setup CPU state
|
||||||
|
init_gdt();
|
||||||
|
|
||||||
|
// 3. THE 5-SECOND OURPLE INTRO
|
||||||
|
draw_rect(&fb, 0, 0, fb.width, fb.height, M3_PURPLE_ACCENT);
|
||||||
|
delay(800000000); // Wait 5 seconds
|
||||||
|
|
||||||
|
// 4. THE MATERIAL 3 UI
|
||||||
|
draw_rect(&fb, 0, 0, fb.width, fb.height, M3_SURFACE); // Dark background
|
||||||
|
|
||||||
|
// Draw the Pastel Purple Card
|
||||||
|
uint32_t cw = 400; uint32_t ch = 200;
|
||||||
|
draw_rect(&fb, (fb.width/2)-(cw/2), (fb.height/2)-(ch/2), cw, ch, M3_PRIMARY);
|
||||||
|
|
||||||
|
// ... (Your existing rect drawing code) ...
|
||||||
|
|
||||||
|
// 5. BOOT THE TTY
|
||||||
|
// We pass the fb address, White text (0xFFFFFF), and Dark background
|
||||||
|
tty_init((struct tty_framebuffer*)&fb, 0xFFFFFF, M3_SURFACE);
|
||||||
|
|
||||||
|
|
||||||
|
// 6. SAY HELLO!
|
||||||
|
tty_print("FLORID OS BOOTED\n");
|
||||||
|
tty_print("READY_");
|
||||||
|
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
// Check Status Register (Port 0x64)
|
||||||
|
// Bit 0 (0x01) tells us if a key is waiting
|
||||||
|
if (inb(0x64) & 0x01) {
|
||||||
|
update_keyboard();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Give VirtualBox a tiny rest so it doesn't lag the host
|
||||||
|
for(volatile int i = 0; i < 1000; i++);
|
||||||
|
__asm__("pause");
|
||||||
|
}
|
||||||
|
}
|
||||||
0
FloridOS/src/kernel.h
Normal file
0
FloridOS/src/kernel.h
Normal file
|
|
@ -1,17 +0,0 @@
|
||||||
#include <stdint.h>
|
|
||||||
#include "../../include/limine.h"
|
|
||||||
|
|
||||||
// This is the "Panic" screen when something goes wrong
|
|
||||||
void kpanic(const char* message) {
|
|
||||||
// In a real OS, we'd clear the screen and show an error code here.
|
|
||||||
// For now, we'll just stop the computer.
|
|
||||||
while(1) { __asm__("cli; hlt"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
void exception_handler(uint64_t vec) {
|
|
||||||
switch(vec) {
|
|
||||||
case 0: kpanic("DIVISION BY ZERO"); break;
|
|
||||||
case 14: kpanic("PAGE FAULT"); break;
|
|
||||||
default: kpanic("UNKNOWN EXCEPTION"); break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,250 +0,0 @@
|
||||||
/*
|
|
||||||
* FFFFFFFFFFFFFFFFFFFFFFlllllll iiii dddddddd
|
|
||||||
* F::::::::::::::::::::Fl:::::l i::::i d::::::d
|
|
||||||
* F::::::::::::::::::::Fl:::::l iiii d::::::d
|
|
||||||
* FF::::::FFFFFFFFF::::Fl:::::l d::::::d
|
|
||||||
* F:::::F FFFFFF l::::l ooooooooooo rrrr rrrrrrr iiiiiii d:::::d
|
|
||||||
* F:::::F l::::l oo:::::::::::oo r::::rr:::::ri::::i d:::::d
|
|
||||||
* F::::::FFFFFFFFFF l::::l o:::::::::::::::or::::r r::::ri::::i d:::::d
|
|
||||||
* F:::::::::::::::F l::::l o:::::ooooo:::::or::::r rrrrri::::i d:::::d
|
|
||||||
* F:::::::::::::::F l::::l o::::o o::::or::::r i::::i d:::::d
|
|
||||||
* F::::::FFFFFFFFFF l::::l o::::o o::::or::::r i::::i d:::::d
|
|
||||||
* F:::::F l::::l o::::o o::::or::::r i::::i d:::::d
|
|
||||||
* F:::::F l::::l o::::o o::::or::::r i::::i d:::::d
|
|
||||||
* FF:::::::FF l::::::lo:::::ooooo:::::or::::r i::::::i d::::::d
|
|
||||||
* F::::::::FF l::::::lo:::::::::::::::or::::r i::::::i d::::::d
|
|
||||||
* F::::::::FF l::::::l oo:::::::::::oo r::::r i::::::i d::::::d
|
|
||||||
* FFFFFFFFFFF llllllll ooooooooooo rrrrrr iiiiiiii dddddddd
|
|
||||||
*
|
|
||||||
* PROJECT: Florid OS (A Modular, Everything-Is-A-File Operating System)
|
|
||||||
* ARCH: x86_64
|
|
||||||
* BOOTLOADER: Limine
|
|
||||||
* PHILOSOPHY: 100% Customizable, Userspace-First DE, FPF Packaging.
|
|
||||||
* TARGET: Monolithic Core Foundation capable of scaling past 16,000+ LOC.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include "limine.h"
|
|
||||||
|
|
||||||
/* ==========================================================================
|
|
||||||
* FLORID PACKAGE FORMAT (FPF)
|
|
||||||
* ========================================================================== */
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char magic[4];
|
|
||||||
uint8_t version;
|
|
||||||
uint8_t type;
|
|
||||||
uint16_t flags;
|
|
||||||
uint64_t entry_point;
|
|
||||||
uint64_t stack_size;
|
|
||||||
uint64_t heap_size;
|
|
||||||
uint8_t signature[32];
|
|
||||||
} __attribute__((packed)) fpf_header_t;
|
|
||||||
|
|
||||||
void klog(const char* module, const char* msg);
|
|
||||||
|
|
||||||
/* ==========================================================================
|
|
||||||
* EXHAUSTIVE KERNEL STATUS
|
|
||||||
* ========================================================================== */
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
FLORID_SUCCESS = 0,
|
|
||||||
FLORID_ERROR_GENERIC = 1,
|
|
||||||
FLORID_ERROR_OUT_OF_MEMORY = 2,
|
|
||||||
FLORID_ERROR_IO_FAILURE = 3,
|
|
||||||
FLORID_ERROR_FPF_INVALID_MAGIC = 4,
|
|
||||||
FLORID_ERROR_FPF_INCOMPATIBLE_VERSION = 5,
|
|
||||||
FLORID_ERROR_FRAMEBUFFER_NOT_FOUND = 6,
|
|
||||||
FLORID_ERROR_PAGE_FAULT = 7,
|
|
||||||
FLORID_ERROR_ACCESS_VIOLATION = 8,
|
|
||||||
FLORID_ERROR_SYS_CALL_INVALID = 9,
|
|
||||||
FLORID_ERROR_DEVICE_OFFLINE = 10,
|
|
||||||
FLORID_ERROR_BUFFER_OVERFLOW = 11,
|
|
||||||
FLORID_ERROR_TIMEOUT = 12,
|
|
||||||
FLORID_ERROR_CORRUPT_METADATA = 13,
|
|
||||||
FLORID_ERROR_KERNEL_PANIC = 14
|
|
||||||
} florid_status_t;
|
|
||||||
|
|
||||||
static const char* status_strings[] = {
|
|
||||||
[FLORID_SUCCESS] = "FLORID_SUCCESS",
|
|
||||||
[FLORID_ERROR_GENERIC] = "FLORID_ERROR_GENERIC",
|
|
||||||
[FLORID_ERROR_OUT_OF_MEMORY] = "FLORID_ERROR_OUT_OF_MEMORY",
|
|
||||||
[FLORID_ERROR_IO_FAILURE] = "FLORID_ERROR_IO_FAILURE",
|
|
||||||
[FLORID_ERROR_FPF_INVALID_MAGIC] = "FLORID_ERROR_FPF_INVALID_MAGIC",
|
|
||||||
[FLORID_ERROR_FPF_INCOMPATIBLE_VERSION] = "FLORID_ERROR_FPF_INCOMPATIBLE_VERSION",
|
|
||||||
[FLORID_ERROR_FRAMEBUFFER_NOT_FOUND] = "FLORID_ERROR_FRAMEBUFFER_NOT_FOUND",
|
|
||||||
[FLORID_ERROR_PAGE_FAULT] = "FLORID_ERROR_PAGE_FAULT",
|
|
||||||
[FLORID_ERROR_ACCESS_VIOLATION] = "FLORID_ERROR_ACCESS_VIOLATION",
|
|
||||||
[FLORID_ERROR_SYS_CALL_INVALID] = "FLORID_ERROR_SYS_CALL_INVALID",
|
|
||||||
[FLORID_ERROR_DEVICE_OFFLINE] = "FLORID_ERROR_DEVICE_OFFLINE",
|
|
||||||
[FLORID_ERROR_BUFFER_OVERFLOW] = "FLORID_ERROR_BUFFER_OVERFLOW",
|
|
||||||
[FLORID_ERROR_TIMEOUT] = "FLORID_ERROR_TIMEOUT",
|
|
||||||
[FLORID_ERROR_CORRUPT_METADATA] = "FLORID_ERROR_CORRUPT_METADATA",
|
|
||||||
[FLORID_ERROR_KERNEL_PANIC] = "FLORID_ERROR_KERNEL_PANIC"
|
|
||||||
};
|
|
||||||
|
|
||||||
/* ==========================================================================
|
|
||||||
* HARDWARE DESCRIPTOR TABLES (GDT/IDT) - New Core Additions
|
|
||||||
* ========================================================================== */
|
|
||||||
|
|
||||||
typedef struct { uint16_t limit; uint64_t base; } __attribute__((packed)) table_ptr_t;
|
|
||||||
|
|
||||||
void gdt_install(void) {
|
|
||||||
// Basic flat-model GDT for x86_64
|
|
||||||
static uint64_t gdt[] = {
|
|
||||||
0x0000000000000000, // Null
|
|
||||||
0x00af9a000000ffff, // Kernel Code
|
|
||||||
0x00af92000000ffff, // Kernel Data
|
|
||||||
0x00affb000000ffff, // User Code
|
|
||||||
0x00aff3000000ffff // User Data
|
|
||||||
};
|
|
||||||
table_ptr_t gdt_ptr = { sizeof(gdt) - 1, (uint64_t)gdt };
|
|
||||||
__asm__ volatile("lgdt %0" : : "m"(gdt_ptr));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ==========================================================================
|
|
||||||
* SYSTEM CALL REGISTRY (FPF Interface)
|
|
||||||
* ========================================================================== */
|
|
||||||
|
|
||||||
void sys_yield() { klog("SYS", "Yielding CPU."); }
|
|
||||||
void sys_exit() { klog("SYS", "Terminating Process."); }
|
|
||||||
|
|
||||||
typedef void (*syscall_handler_t)(void);
|
|
||||||
syscall_handler_t syscall_table[128] = {
|
|
||||||
[0] = sys_yield,
|
|
||||||
[1] = sys_exit,
|
|
||||||
/* To scale to 16k, populate more system interface stubs here */
|
|
||||||
};
|
|
||||||
|
|
||||||
/* ==========================================================================
|
|
||||||
* LIMINE BOOT REQUESTS
|
|
||||||
* ========================================================================== */
|
|
||||||
|
|
||||||
static volatile struct limine_framebuffer_request framebuffer_request = {
|
|
||||||
.id = LIMINE_FRAMEBUFFER_REQUEST, .revision = 0
|
|
||||||
};
|
|
||||||
|
|
||||||
static volatile struct limine_memmap_request memmap_request = {
|
|
||||||
.id = LIMINE_MEMMAP_REQUEST, .revision = 0
|
|
||||||
};
|
|
||||||
|
|
||||||
static volatile struct limine_hhdm_request hhdm_request = {
|
|
||||||
.id = LIMINE_HHDM_REQUEST, .revision = 0
|
|
||||||
};
|
|
||||||
|
|
||||||
static volatile struct limine_module_request module_request = {
|
|
||||||
.id = LIMINE_MODULE_REQUEST, .revision = 0
|
|
||||||
};
|
|
||||||
|
|
||||||
/* ==========================================================================
|
|
||||||
* LOGGING (COM1 SERIAL)
|
|
||||||
* ========================================================================== */
|
|
||||||
|
|
||||||
static inline void outb(uint16_t port, uint8_t val) {
|
|
||||||
__asm__ volatile ( "outb %0, %1" : : "a"(val), "Nd"(port) );
|
|
||||||
}
|
|
||||||
|
|
||||||
void klog(const char* module, const char* msg) {
|
|
||||||
const char* p = "[";
|
|
||||||
while (*p) outb(0x3F8, *p++);
|
|
||||||
p = module;
|
|
||||||
while (*p) outb(0x3F8, *p++);
|
|
||||||
p = "] ";
|
|
||||||
while (*p) outb(0x3F8, *p++);
|
|
||||||
p = msg;
|
|
||||||
while (*p) outb(0x3F8, *p++);
|
|
||||||
outb(0x3F8, '\r'); outb(0x3F8, '\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ==========================================================================
|
|
||||||
* PHYSICAL MEMORY MANAGER (PMM)
|
|
||||||
* ========================================================================== */
|
|
||||||
|
|
||||||
static uint8_t* pmm_bitmap;
|
|
||||||
static uint64_t pmm_total_pages;
|
|
||||||
|
|
||||||
void pmm_init(struct limine_memmap_response* memmap) {
|
|
||||||
uint64_t max_addr = 0;
|
|
||||||
struct limine_memmap_entry* biggest_chunk = NULL;
|
|
||||||
|
|
||||||
for (uint64_t i = 0; i < memmap->entry_count; i++) {
|
|
||||||
struct limine_memmap_entry* entry = memmap->entries[i];
|
|
||||||
if (entry->base + entry->length > max_addr) max_addr = entry->base + entry->length;
|
|
||||||
if (entry->type == LIMINE_MEMMAP_USABLE && (!biggest_chunk || entry->length > biggest_chunk->length)) {
|
|
||||||
biggest_chunk = entry;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pmm_total_pages = max_addr / 4096;
|
|
||||||
pmm_bitmap = (uint8_t*)(biggest_chunk->base + hhdm_request.response->offset);
|
|
||||||
|
|
||||||
for (uint64_t i = 0; i < pmm_total_pages / 8; i++) pmm_bitmap[i] = 0xFF;
|
|
||||||
|
|
||||||
for (uint64_t i = 0; i < memmap->entry_count; i++) {
|
|
||||||
struct limine_memmap_entry* entry = memmap->entries[i];
|
|
||||||
if (entry->type == LIMINE_MEMMAP_USABLE) {
|
|
||||||
for (uint64_t j = 0; j < entry->length; j += 4096) {
|
|
||||||
uint64_t page = (entry->base + j) / 4096;
|
|
||||||
pmm_bitmap[page / 8] &= ~(1 << (page % 8));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
klog("PMM", "Physical Memory Manager Online.");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ==========================================================================
|
|
||||||
* FPF EXECUTION ENGINE
|
|
||||||
* ========================================================================== */
|
|
||||||
|
|
||||||
void execute_fpf(uint8_t* buffer, size_t size) {
|
|
||||||
fpf_header_t* header = (fpf_header_t*)buffer;
|
|
||||||
|
|
||||||
if (size < sizeof(fpf_header_t) || header->magic[0] != 'F' || header->magic[1] != 'L') {
|
|
||||||
klog("LOADER", "Invalid FPF Magic.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
klog("LOADER", "Executing FPF Package.");
|
|
||||||
|
|
||||||
// Jump past header to entry point
|
|
||||||
uintptr_t entry = (uintptr_t)(buffer + sizeof(fpf_header_t) + header->entry_point);
|
|
||||||
void (*launch)(void) = (void (*)(void))entry;
|
|
||||||
|
|
||||||
launch();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ==========================================================================
|
|
||||||
* KERNEL MAIN ENTRY
|
|
||||||
* ========================================================================== */
|
|
||||||
|
|
||||||
void _start(void) {
|
|
||||||
gdt_install(); // Setup hardware segments
|
|
||||||
klog("CORE", "Florid OS Kernel Initializing...");
|
|
||||||
|
|
||||||
// 1. Setup Graphics
|
|
||||||
if (framebuffer_request.response == NULL || framebuffer_request.response->framebuffer_count < 1) {
|
|
||||||
while(1) __asm__("hlt");
|
|
||||||
}
|
|
||||||
struct limine_framebuffer *fb = framebuffer_request.response->framebuffers[0];
|
|
||||||
uint32_t *fb_ptr = fb->address;
|
|
||||||
for (size_t i = 0; i < fb->width * fb->height; i++) fb_ptr[i] = 0x1E1E1E;
|
|
||||||
|
|
||||||
// 2. Setup Memory
|
|
||||||
if (memmap_request.response && hhdm_request.response) {
|
|
||||||
pmm_init(memmap_request.response);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. Find and Boot Terminal / Launcher modules
|
|
||||||
if (module_request.response) {
|
|
||||||
for (uint64_t i = 0; i < module_request.response->module_count; i++) {
|
|
||||||
struct limine_file* module = module_request.response->modules[i];
|
|
||||||
klog("INIT", "Loading FPF Module...");
|
|
||||||
execute_fpf((uint8_t*)module->address, module->size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
klog("CORE", "System idle.");
|
|
||||||
while (1) { __asm__("hlt"); }
|
|
||||||
}
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
OUTPUT_FORMAT(elf64-x86-64)
|
|
||||||
ENTRY(_start)
|
|
||||||
|
|
||||||
SECTIONS
|
|
||||||
{
|
|
||||||
. = 0xffffffff80000000;
|
|
||||||
.text : { *(.text*) }
|
|
||||||
.rodata : { *(.rodata*) }
|
|
||||||
.data : { *(.data*) }
|
|
||||||
.bss : { *(.bss*) *(COMMON) }
|
|
||||||
}
|
|
||||||
|
|
@ -1,62 +0,0 @@
|
||||||
/*
|
|
||||||
* src/kernel/loader/fpf.c - Florid Package Format Execution Engine
|
|
||||||
* Part of the monolithic core scaling architecture.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include "../../include/fpf.h"
|
|
||||||
|
|
||||||
// External references to our kernel logging and status mappings
|
|
||||||
extern void klog(const char* module, const char* msg);
|
|
||||||
extern void klog_status(const char* module, int status);
|
|
||||||
|
|
||||||
/* Simple memory space tracker for bare-metal app loading */
|
|
||||||
static uint64_t current_app_stack_base = 0x80000000; // Load user stacks high
|
|
||||||
|
|
||||||
/*
|
|
||||||
* execute_fpf_package
|
|
||||||
* Validates, maps, and executes an FPF binary directly from a memory buffer.
|
|
||||||
*/
|
|
||||||
int execute_fpf_package(uint8_t* raw_binary, size_t size) {
|
|
||||||
klog("LOADER", "Interrogating binary payload for FPF compliance...");
|
|
||||||
|
|
||||||
if (size < sizeof(fpf_header_t)) {
|
|
||||||
klog("LOADER", "FATAL: Payload smaller than base FPF header schema.");
|
|
||||||
return 11; // Buffer overflow/underflow
|
|
||||||
}
|
|
||||||
|
|
||||||
fpf_header_t* header = (fpf_header_t*)raw_binary;
|
|
||||||
|
|
||||||
// Strict Magic Byte Verification
|
|
||||||
if (header->magic[0] != 'F' || header->magic[1] != 'L' ||
|
|
||||||
header->magic[2] != 'O' || header->magic[3] != 'R') {
|
|
||||||
klog("LOADER", "FATAL: Magic bytes do not match 'FLOR'. Execution aborted.");
|
|
||||||
return 4; // Invalid Magic
|
|
||||||
}
|
|
||||||
|
|
||||||
klog("LOADER", "Magic 'FLOR' verified. Parsing execution vectors...");
|
|
||||||
|
|
||||||
// Determine payload offset (where the actual executable instructions begin)
|
|
||||||
uint64_t code_offset = sizeof(fpf_header_t);
|
|
||||||
uintptr_t entry_address = (uintptr_t)(raw_binary + code_offset + header->entry_point);
|
|
||||||
|
|
||||||
// Verify context claims
|
|
||||||
if (header->type == FPF_TYPE_DE) {
|
|
||||||
klog("LOADER", "Context: Desktop Environment / Shell. Granting Framebuffer Access.");
|
|
||||||
} else if (header->type == FPF_TYPE_APP) {
|
|
||||||
klog("LOADER", "Context: Standard Application. Enforcing sandbox boundaries.");
|
|
||||||
}
|
|
||||||
|
|
||||||
klog("LOADER", "Transferring instruction pointer to FPF payload entry...");
|
|
||||||
|
|
||||||
// Define a function pointer to the app's start address
|
|
||||||
void (*app_entry)(void) = (void (*)(void))entry_address;
|
|
||||||
|
|
||||||
// Execute the package (Handoff)
|
|
||||||
app_entry();
|
|
||||||
|
|
||||||
klog("LOADER", "FPF Package execution completed cleanly. Context returned to kernel.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
@ -1,81 +0,0 @@
|
||||||
#include <stdint.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include "../../include/limine.h"
|
|
||||||
|
|
||||||
static uint8_t* bitmap;
|
|
||||||
static uint64_t bitmap_pages;
|
|
||||||
static uint64_t total_pages;
|
|
||||||
static uint64_t last_index = 0;
|
|
||||||
|
|
||||||
// Helper to set/clear bits in our map
|
|
||||||
void bitmap_set(uint64_t page) {
|
|
||||||
bitmap[page / 8] |= (1 << (page % 8));
|
|
||||||
}
|
|
||||||
|
|
||||||
void bitmap_clear(uint64_t page) {
|
|
||||||
bitmap[page / 8] &= ~(1 << (page % 8));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bitmap_test(uint64_t page) {
|
|
||||||
return bitmap[page / 8] & (1 << (page % 8));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* * pmm_init:
|
|
||||||
* Finds the biggest chunk of RAM and puts the bitmap there.
|
|
||||||
* Then it marks all usable RAM as "free."
|
|
||||||
*/
|
|
||||||
void pmm_init(struct limine_memmap_response* memmap) {
|
|
||||||
uint64_t max_addr = 0;
|
|
||||||
uint64_t biggest_chunk_addr = 0;
|
|
||||||
uint64_t biggest_chunk_len = 0;
|
|
||||||
|
|
||||||
for (uint64_t i = 0; i < memmap->entry_count; i++) {
|
|
||||||
struct limine_memmap_entry* entry = memmap->entries[i];
|
|
||||||
if (entry->type == LIMINE_MEMMAP_USABLE) {
|
|
||||||
if (entry->base + entry->length > max_addr)
|
|
||||||
max_addr = entry->base + entry->length;
|
|
||||||
|
|
||||||
if (entry->length > biggest_chunk_len) {
|
|
||||||
biggest_chunk_len = entry->length;
|
|
||||||
biggest_chunk_addr = entry->base;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
total_pages = max_addr / 4096;
|
|
||||||
bitmap_pages = (total_pages / 8) / 4096 + 1;
|
|
||||||
|
|
||||||
// We store the bitmap in the biggest usable chunk of RAM
|
|
||||||
bitmap = (uint8_t*)(biggest_chunk_addr + 0xffff800000000000);
|
|
||||||
|
|
||||||
// Mark EVERYTHING as used (locked) first
|
|
||||||
for (uint64_t i = 0; i < total_pages / 8; i++) bitmap[i] = 0xFF;
|
|
||||||
|
|
||||||
// Now, unmap only the truly usable sections
|
|
||||||
for (uint64_t i = 0; i < memmap->entry_count; i++) {
|
|
||||||
struct limine_memmap_entry* entry = memmap->entries[i];
|
|
||||||
if (entry->type == LIMINE_MEMMAP_USABLE) {
|
|
||||||
for (uint64_t j = 0; j < entry->length; j += 4096) {
|
|
||||||
bitmap_clear((entry->base + j) / 4096);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Lock the pages the bitmap itself is using
|
|
||||||
for (uint64_t i = 0; i < bitmap_pages * 4096; i += 4096) {
|
|
||||||
bitmap_set((biggest_chunk_addr + i) / 4096);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* pmm_alloc: Find a free page of RAM */
|
|
||||||
void* pmm_alloc() {
|
|
||||||
for (uint64_t i = last_index; i < total_pages; i++) {
|
|
||||||
if (!bitmap_test(i)) {
|
|
||||||
bitmap_set(i);
|
|
||||||
last_index = i;
|
|
||||||
return (void*)(i * 4096);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL; // Out of memory!
|
|
||||||
}
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/* BSD Zero Clause License */
|
/* BSD Zero Clause License */
|
||||||
|
|
||||||
/* Copyright (C) 2022-2024 mintsuki and contributors.
|
/* Copyright (C) 2022-2023 mintsuki and contributors.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and/or distribute this software for any
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* purpose with or without fee is hereby granted.
|
* purpose with or without fee is hereby granted.
|
||||||
|
|
@ -14,8 +14,8 @@
|
||||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef LIMINE_H
|
#ifndef _LIMINE_H
|
||||||
#define LIMINE_H 1
|
#define _LIMINE_H 1
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
@ -44,14 +44,6 @@ extern "C" {
|
||||||
# define LIMINE_DEPRECATED_IGNORE_END
|
# define LIMINE_DEPRECATED_IGNORE_END
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define LIMINE_REQUESTS_START_MARKER \
|
|
||||||
uint64_t limine_requests_start_marker[4] = { 0xf6b8f4b39de7d1ae, 0xfab91a6940fcb9cf, \
|
|
||||||
0x785c6ed015d3e316, 0x181e920a7852b9d9 };
|
|
||||||
#define LIMINE_REQUESTS_END_MARKER \
|
|
||||||
uint64_t limine_requests_end_marker[2] = { 0xadc0e0531bb10d03, 0x9572709f31764c62 };
|
|
||||||
|
|
||||||
#define LIMINE_REQUESTS_DELIMITER LIMINE_REQUESTS_END_MARKER
|
|
||||||
|
|
||||||
#define LIMINE_BASE_REVISION(N) \
|
#define LIMINE_BASE_REVISION(N) \
|
||||||
uint64_t limine_base_revision[3] = { 0xf9562b2d5c95a6c8, 0x6a7b384944536bdc, (N) };
|
uint64_t limine_base_revision[3] = { 0xf9562b2d5c95a6c8, 0x6a7b384944536bdc, (N) };
|
||||||
|
|
||||||
|
|
@ -103,25 +95,6 @@ struct limine_bootloader_info_request {
|
||||||
LIMINE_PTR(struct limine_bootloader_info_response *) response;
|
LIMINE_PTR(struct limine_bootloader_info_response *) response;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Firmware type */
|
|
||||||
|
|
||||||
#define LIMINE_FIRMWARE_TYPE_REQUEST { LIMINE_COMMON_MAGIC, 0x8c2f75d90bef28a8, 0x7045a4688eac00c3 }
|
|
||||||
|
|
||||||
#define LIMINE_FIRMWARE_TYPE_X86BIOS 0
|
|
||||||
#define LIMINE_FIRMWARE_TYPE_UEFI32 1
|
|
||||||
#define LIMINE_FIRMWARE_TYPE_UEFI64 2
|
|
||||||
|
|
||||||
struct limine_firmware_type_response {
|
|
||||||
uint64_t revision;
|
|
||||||
uint64_t firmware_type;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct limine_firmware_type_request {
|
|
||||||
uint64_t id[4];
|
|
||||||
uint64_t revision;
|
|
||||||
LIMINE_PTR(struct limine_firmware_type_response *) response;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Stack size */
|
/* Stack size */
|
||||||
|
|
||||||
#define LIMINE_STACK_SIZE_REQUEST { LIMINE_COMMON_MAGIC, 0x224ef0460a8e8926, 0xe1cb0fc25f46ea3d }
|
#define LIMINE_STACK_SIZE_REQUEST { LIMINE_COMMON_MAGIC, 0x224ef0460a8e8926, 0xe1cb0fc25f46ea3d }
|
||||||
|
|
@ -273,20 +246,17 @@ LIMINE_DEPRECATED_IGNORE_END
|
||||||
#define LIMINE_PAGING_MODE_X86_64_4LVL 0
|
#define LIMINE_PAGING_MODE_X86_64_4LVL 0
|
||||||
#define LIMINE_PAGING_MODE_X86_64_5LVL 1
|
#define LIMINE_PAGING_MODE_X86_64_5LVL 1
|
||||||
#define LIMINE_PAGING_MODE_MAX LIMINE_PAGING_MODE_X86_64_5LVL
|
#define LIMINE_PAGING_MODE_MAX LIMINE_PAGING_MODE_X86_64_5LVL
|
||||||
#define LIMINE_PAGING_MODE_MIN LIMINE_PAGING_MODE_X86_64_4LVL
|
|
||||||
#define LIMINE_PAGING_MODE_DEFAULT LIMINE_PAGING_MODE_X86_64_4LVL
|
#define LIMINE_PAGING_MODE_DEFAULT LIMINE_PAGING_MODE_X86_64_4LVL
|
||||||
#elif defined (__aarch64__)
|
#elif defined (__aarch64__)
|
||||||
#define LIMINE_PAGING_MODE_AARCH64_4LVL 0
|
#define LIMINE_PAGING_MODE_AARCH64_4LVL 0
|
||||||
#define LIMINE_PAGING_MODE_AARCH64_5LVL 1
|
#define LIMINE_PAGING_MODE_AARCH64_5LVL 1
|
||||||
#define LIMINE_PAGING_MODE_MAX LIMINE_PAGING_MODE_AARCH64_5LVL
|
#define LIMINE_PAGING_MODE_MAX LIMINE_PAGING_MODE_AARCH64_5LVL
|
||||||
#define LIMINE_PAGING_MODE_MIN LIMINE_PAGING_MODE_AARCH64_4LVL
|
|
||||||
#define LIMINE_PAGING_MODE_DEFAULT LIMINE_PAGING_MODE_AARCH64_4LVL
|
#define LIMINE_PAGING_MODE_DEFAULT LIMINE_PAGING_MODE_AARCH64_4LVL
|
||||||
#elif defined (__riscv) && (__riscv_xlen == 64)
|
#elif defined (__riscv) && (__riscv_xlen == 64)
|
||||||
#define LIMINE_PAGING_MODE_RISCV_SV39 0
|
#define LIMINE_PAGING_MODE_RISCV_SV39 0
|
||||||
#define LIMINE_PAGING_MODE_RISCV_SV48 1
|
#define LIMINE_PAGING_MODE_RISCV_SV48 1
|
||||||
#define LIMINE_PAGING_MODE_RISCV_SV57 2
|
#define LIMINE_PAGING_MODE_RISCV_SV57 2
|
||||||
#define LIMINE_PAGING_MODE_MAX LIMINE_PAGING_MODE_RISCV_SV57
|
#define LIMINE_PAGING_MODE_MAX LIMINE_PAGING_MODE_RISCV_SV57
|
||||||
#define LIMINE_PAGING_MODE_MIN LIMINE_PAGING_MODE_RISCV_SV39
|
|
||||||
#define LIMINE_PAGING_MODE_DEFAULT LIMINE_PAGING_MODE_RISCV_SV48
|
#define LIMINE_PAGING_MODE_DEFAULT LIMINE_PAGING_MODE_RISCV_SV48
|
||||||
#else
|
#else
|
||||||
#error Unknown architecture
|
#error Unknown architecture
|
||||||
|
|
@ -295,6 +265,7 @@ LIMINE_DEPRECATED_IGNORE_END
|
||||||
struct limine_paging_mode_response {
|
struct limine_paging_mode_response {
|
||||||
uint64_t revision;
|
uint64_t revision;
|
||||||
uint64_t mode;
|
uint64_t mode;
|
||||||
|
uint64_t flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct limine_paging_mode_request {
|
struct limine_paging_mode_request {
|
||||||
|
|
@ -302,8 +273,7 @@ struct limine_paging_mode_request {
|
||||||
uint64_t revision;
|
uint64_t revision;
|
||||||
LIMINE_PTR(struct limine_paging_mode_response *) response;
|
LIMINE_PTR(struct limine_paging_mode_response *) response;
|
||||||
uint64_t mode;
|
uint64_t mode;
|
||||||
uint64_t max_mode;
|
uint64_t flags;
|
||||||
uint64_t min_mode;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* 5-level paging */
|
/* 5-level paging */
|
||||||
|
|
@ -356,7 +326,7 @@ struct limine_smp_response {
|
||||||
|
|
||||||
struct limine_smp_info {
|
struct limine_smp_info {
|
||||||
uint32_t processor_id;
|
uint32_t processor_id;
|
||||||
uint32_t reserved1;
|
uint32_t gic_iface_no;
|
||||||
uint64_t mpidr;
|
uint64_t mpidr;
|
||||||
uint64_t reserved;
|
uint64_t reserved;
|
||||||
LIMINE_PTR(limine_goto_address) goto_address;
|
LIMINE_PTR(limine_goto_address) goto_address;
|
||||||
|
|
@ -468,7 +438,6 @@ struct limine_kernel_file_request {
|
||||||
#define LIMINE_MODULE_REQUEST { LIMINE_COMMON_MAGIC, 0x3e7e279702be32af, 0xca1c4f3bd1280cee }
|
#define LIMINE_MODULE_REQUEST { LIMINE_COMMON_MAGIC, 0x3e7e279702be32af, 0xca1c4f3bd1280cee }
|
||||||
|
|
||||||
#define LIMINE_INTERNAL_MODULE_REQUIRED (1 << 0)
|
#define LIMINE_INTERNAL_MODULE_REQUIRED (1 << 0)
|
||||||
#define LIMINE_INTERNAL_MODULE_COMPRESSED (1 << 1)
|
|
||||||
|
|
||||||
struct limine_internal_module {
|
struct limine_internal_module {
|
||||||
LIMINE_PTR(const char *) path;
|
LIMINE_PTR(const char *) path;
|
||||||
69
FloridOS/src/shell/commands.c
Normal file
69
FloridOS/src/shell/commands.c
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
#include "shell.h"
|
||||||
|
#include "drivers/terminal.h"
|
||||||
|
|
||||||
|
/* --- Utilities --- */
|
||||||
|
|
||||||
|
int strcmp(const char *s1, const char *s2) {
|
||||||
|
while (*s1 && (*s1 == *s2)) {
|
||||||
|
s1++; s2++;
|
||||||
|
}
|
||||||
|
return *(const unsigned char *)s1 - *(const unsigned char *)s2;
|
||||||
|
}
|
||||||
|
|
||||||
|
int startswith(const char *str, const char *prefix) {
|
||||||
|
while (*prefix) {
|
||||||
|
if (*prefix++ != *str++) return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Command Handlers --- */
|
||||||
|
|
||||||
|
void run_mofi() {
|
||||||
|
terminal_writestring("Entering MOFI editor...\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle_fds() {
|
||||||
|
terminal_writestring("Searching Florid Root...\n");
|
||||||
|
terminal_writestring("/boot /sys /kernel /mofi_data\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle_obliterate(char* target) {
|
||||||
|
terminal_writestring("OBLITERATING: ");
|
||||||
|
terminal_writestring(target);
|
||||||
|
terminal_writestring("... SUCCESS.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle_install() {
|
||||||
|
terminal_writestring("Searching for target disk...\n");
|
||||||
|
terminal_writestring("Formatting /dev/sda as FloridFS...\n");
|
||||||
|
terminal_writestring("Copying kernel bytes... [##########] 100%\n");
|
||||||
|
terminal_writestring("Installation complete. Remove Live CD and reboot.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- The Interpreter (The If/Else Chain) --- */
|
||||||
|
|
||||||
|
void interpret_command(char* cmd) {
|
||||||
|
if (strcmp(cmd, "fds") == 0) {
|
||||||
|
handle_fds();
|
||||||
|
}
|
||||||
|
else if (strcmp(cmd, "frua") == 0) {
|
||||||
|
terminal_writestring("ROOT ACCESS GRANTED.\n");
|
||||||
|
}
|
||||||
|
else if (strcmp(cmd, "mofi") == 0) {
|
||||||
|
run_mofi();
|
||||||
|
}
|
||||||
|
else if (strcmp(cmd, "install") == 0) {
|
||||||
|
handle_install();
|
||||||
|
}
|
||||||
|
else if (startswith(cmd, "obliterate ")) {
|
||||||
|
handle_obliterate(cmd + 11);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
terminal_writestring("Unknown command. Try 'fds' or 'install'.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void shell_init(void) {
|
||||||
|
terminal_writestring("Florid Shell Initialized.\n");
|
||||||
|
}
|
||||||
7
FloridOS/src/shell/shell.h
Normal file
7
FloridOS/src/shell/shell.h
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
#ifndef SHELL_H
|
||||||
|
#define SHELL_H
|
||||||
|
|
||||||
|
void shell_init(void);
|
||||||
|
void interpret_command(char* input);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
/*
|
|
||||||
* src/userspace/bridge/loadable.c - Universal FPF Binary Wrapper
|
|
||||||
* Compile your app logic alongside this file to output a valid .fpf package.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#include "../../include/fpf.h"
|
|
||||||
|
|
||||||
// Forward declaration of the user's actual main function
|
|
||||||
extern int florid_main(void);
|
|
||||||
|
|
||||||
// Force the compiler to place this header at the very beginning of the binary
|
|
||||||
__attribute__((section(".fpf_header"), used))
|
|
||||||
const fpf_header_t __app_header = {
|
|
||||||
.magic = {'F', 'L', 'O', 'R'},
|
|
||||||
.version = 1,
|
|
||||||
.type = FPF_TYPE_DE, // Setting to DE so it can draw the Bloom menu
|
|
||||||
.flags = 0x08, // FPF_FLAG_FRAMEBUFFER_OWN
|
|
||||||
.entry_point = 0, // Offset from start of code section
|
|
||||||
.stack_size = 1024 * 1024, // 1MB stack request
|
|
||||||
.heap_size = 1024 * 1024 * 16, // 16MB heap request
|
|
||||||
.signature = {0} // Unsigned demo
|
|
||||||
};
|
|
||||||
|
|
||||||
// The raw entry point called by the kernel loader
|
|
||||||
void _start(void) {
|
|
||||||
// Jump to the application logic
|
|
||||||
florid_main();
|
|
||||||
|
|
||||||
// If the app exits, trap the CPU so it doesn't execute garbage memory
|
|
||||||
while(1) { __asm__ volatile("hlt"); }
|
|
||||||
}
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
/*
|
|
||||||
* src/userspace/launcher/main.c - Bare-metal Demo Launcher
|
|
||||||
* Proves execution handoff by drawing the White Pill interface.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
// Hardcoded Limine Framebuffer address for fast demo testing
|
|
||||||
// (In a full build, the kernel passes this via syscalls/shared registers)
|
|
||||||
#define FB_ADDRESS 0xffff800000000000 // Replace with your Limine FB base if mapped static
|
|
||||||
|
|
||||||
int florid_main(void) {
|
|
||||||
// Let's pretend the kernel mapped the FB directly for us
|
|
||||||
uint32_t* screen = (uint32_t*)FB_ADDRESS;
|
|
||||||
int width = 1920; // Standard assumption for demo
|
|
||||||
int height = 1080;
|
|
||||||
|
|
||||||
// Draw the Taskbar Background at the bottom (Height: 60px)
|
|
||||||
for (int y = height - 60; y < height; y++) {
|
|
||||||
for (int x = 0; x < width; x++) {
|
|
||||||
screen[y * width + x] = 0x111111; // Darker taskbar base
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw the "White Pill" on the far left (X: 20 to 100, Y: height-45 to height-15)
|
|
||||||
for (int y = height - 45; y < height - 15; y++) {
|
|
||||||
for (int x = 20; x < 100; x++) {
|
|
||||||
// Simple visual rounding: cut the absolute corners
|
|
||||||
if ((x < 25 || x > 95) && (y < height - 40 || y > height - 20)) continue;
|
|
||||||
screen[y * width + x] = 0xFFFFFF; // Pure white pill trigger
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
// The linker looks for _start by default
|
|
||||||
void _start() {
|
|
||||||
// Material 3 Surface Color
|
|
||||||
uint32_t m3_surface = 0x1C1B1F;
|
|
||||||
|
|
||||||
// Pointer to framebuffer (Assuming it's mapped to 0xFD000000 or provided by bootloader)
|
|
||||||
// For a real test, we just loop to keep the CPU busy so it doesn't crash
|
|
||||||
while(1) {
|
|
||||||
__asm__("hlt");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void terminal_main() {
|
|
||||||
// In a real FPF, the kernel passes the framebuffer info.
|
|
||||||
// We'll assume a standard 1920x1080 mapping for this demo.
|
|
||||||
uint32_t* fb = (uint32_t*)0; // This would be mapped via syscall in a finished build
|
|
||||||
|
|
||||||
int term_width = 800;
|
|
||||||
int term_height = 500;
|
|
||||||
int start_x = 100;
|
|
||||||
int start_y = 100;
|
|
||||||
|
|
||||||
// 1. Draw Terminal Window Shadow/Outline
|
|
||||||
for (int y = start_y - 2; y < start_y + term_height + 2; y++) {
|
|
||||||
for (int x = start_x - 2; x < start_x + term_width + 2; x++) {
|
|
||||||
// fb[y * 1920 + x] = M3_OUTLINE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. Draw Terminal Surface
|
|
||||||
for (int y = start_y; y < start_y + term_height; y++) {
|
|
||||||
for (int x = start_x; x < start_x + term_width; x++) {
|
|
||||||
// fb[y * 1920 + x] = M3_SURFACE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. Draw Mock "Prompt" line
|
|
||||||
// [ > _ ]
|
|
||||||
for (int i = 0; i < 10; i++) {
|
|
||||||
// Pixel logic for a cursor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Reference in a new issue