Attempt 2 #2

Open
seeseemelk wants to merge 56 commits from attempt-2 into master
5 changed files with 334 additions and 1 deletions
Showing only changes of commit 313aeb5872 - Show all commits

View File

@@ -48,7 +48,7 @@ Once a task is completed, it should be checked off.
- [x] Create a paging subsystem. It should allow drivers to allocate and deallocate pages at will.
- [x] Create a memory allocator. This should provide the kernel with `malloc` and `free`. Internally, it should use the paging subsystem to ensure that the address it returns have actual RAM paged to them.
- [x] Create an initial driver architecture, allowing different drivers included in the kernel to test whether they should load or not.
- [ ] Create a VGA driver. On startup, some memory statistics should be displayed, as well as boot progress.
- [x] Create a VGA driver. On startup, some memory statistics should be displayed, as well as boot progress.
- [ ] Create subsystem for loading new processes in Ring 3.
- [ ] Update the build script to generate a ramdisk containing any applications to run. This initial ramdisk is in CPIO format.
- [ ] Write a VFS subsystem.

View File

@@ -12,6 +12,7 @@ add_executable(kernel
kmalloc.c
string.c
driver.c
vga.c
interrupts.S
kernel.c
)

View File

@@ -9,6 +9,7 @@
#include "paging.h"
#include "kmalloc.h"
#include "driver.h"
#include "vga.h"
void offset_print(const char *str)
{
@@ -71,6 +72,10 @@ void kernel_main(uint32_t magic, uint32_t addr) {
init_drivers();
offset_print("Drivers initialized\n");
/* Show memory statistics and boot progress on VGA */
vga_show_mem_stats();
vga_puts("Boot complete.\n\n");
/* Test kmalloc/kfree */
uint32_t *test_alloc = (uint32_t *)kmalloc(64);
if (test_alloc) {

230
src/vga.c Normal file
View File

@@ -0,0 +1,230 @@
/**
* @file vga.c
* @brief VGA text-mode driver implementation.
*
* Drives the standard VGA text-mode framebuffer at 0xB8000. The buffer
* is an array of 80×25 16-bit values, where the low byte is the ASCII
* character and the high byte encodes foreground and background color.
*
* This driver registers itself via the REGISTER_DRIVER macro and is
* automatically discovered during boot.
*/
#include "vga.h"
#include "driver.h"
#include "port_io.h"
#include "pmm.h"
/** Base address of the VGA text-mode framebuffer. */
#define VGA_BUFFER 0xB8000
/** Pointer to the VGA framebuffer, treated as an array of uint16_t. */
static uint16_t *vga_buffer = (uint16_t *)VGA_BUFFER;
/** Current cursor row (0-based). */
static uint8_t cursor_row = 0;
/** Current cursor column (0-based). */
static uint8_t cursor_col = 0;
/** Current text attribute byte (foreground | background << 4). */
static uint8_t text_attr = 0;
/**
* Create a VGA entry (character + attribute) for the framebuffer.
*
* @param c ASCII character.
* @param attr Color attribute byte.
* @return 16-bit VGA entry.
*/
static inline uint16_t vga_entry(char c, uint8_t attr) {
return (uint16_t)c | ((uint16_t)attr << 8);
}
/**
* Create a color attribute byte from foreground and background colors.
*
* @param fg Foreground color (015).
* @param bg Background color (015).
* @return Attribute byte.
*/
static inline uint8_t vga_color(vga_color_t fg, vga_color_t bg) {
return (uint8_t)fg | ((uint8_t)bg << 4);
}
/**
* Update the hardware cursor position via VGA I/O ports.
*/
static void update_cursor(void) {
uint16_t pos = cursor_row * VGA_WIDTH + cursor_col;
outb(0x3D4, 0x0F);
outb(0x3D5, (uint8_t)(pos & 0xFF));
outb(0x3D4, 0x0E);
outb(0x3D5, (uint8_t)((pos >> 8) & 0xFF));
}
/**
* Scroll the screen up by one line.
*
* The top line is discarded, all other lines move up, and the bottom
* line is filled with spaces.
*/
static void scroll(void) {
/* Move all lines up by one */
for (int i = 0; i < (VGA_HEIGHT - 1) * VGA_WIDTH; i++) {
vga_buffer[i] = vga_buffer[i + VGA_WIDTH];
}
/* Clear the last line */
uint16_t blank = vga_entry(' ', text_attr);
for (int i = (VGA_HEIGHT - 1) * VGA_WIDTH; i < VGA_HEIGHT * VGA_WIDTH; i++) {
vga_buffer[i] = blank;
}
cursor_row = VGA_HEIGHT - 1;
}
void vga_clear(void) {
uint16_t blank = vga_entry(' ', text_attr);
for (int i = 0; i < VGA_WIDTH * VGA_HEIGHT; i++) {
vga_buffer[i] = blank;
}
cursor_row = 0;
cursor_col = 0;
update_cursor();
}
void vga_set_color(vga_color_t fg, vga_color_t bg) {
text_attr = vga_color(fg, bg);
}
void vga_putchar(char c) {
if (c == '\n') {
cursor_col = 0;
cursor_row++;
} else if (c == '\r') {
cursor_col = 0;
} else if (c == '\t') {
cursor_col = (cursor_col + 8) & ~7;
if (cursor_col >= VGA_WIDTH) {
cursor_col = 0;
cursor_row++;
}
} else if (c == '\b') {
if (cursor_col > 0) {
cursor_col--;
vga_buffer[cursor_row * VGA_WIDTH + cursor_col] = vga_entry(' ', text_attr);
}
} else {
vga_buffer[cursor_row * VGA_WIDTH + cursor_col] = vga_entry(c, text_attr);
cursor_col++;
if (cursor_col >= VGA_WIDTH) {
cursor_col = 0;
cursor_row++;
}
}
if (cursor_row >= VGA_HEIGHT) {
scroll();
}
update_cursor();
}
void vga_puts(const char *str) {
while (*str) {
vga_putchar(*str);
str++;
}
}
void vga_put_hex(uint32_t val) {
const char *hex = "0123456789ABCDEF";
vga_putchar('0');
vga_putchar('x');
for (int i = 28; i >= 0; i -= 4) {
vga_putchar(hex[(val >> i) & 0xF]);
}
}
void vga_put_dec(uint32_t val) {
if (val == 0) {
vga_putchar('0');
return;
}
char buf[12];
int pos = 0;
while (val > 0) {
buf[pos++] = '0' + (val % 10);
val /= 10;
}
/* Print in reverse */
while (pos > 0) {
vga_putchar(buf[--pos]);
}
}
void vga_show_mem_stats(void) {
uint32_t mem_kb = pmm_get_memory_size() + 1024; /* total including lower */
vga_set_color(VGA_LIGHT_CYAN, VGA_BLACK);
vga_puts("=== ClaudeOS Memory Statistics ===\n");
vga_set_color(VGA_WHITE, VGA_BLACK);
vga_puts(" Total RAM: ");
vga_put_dec(mem_kb);
vga_puts(" KiB (");
vga_put_dec(mem_kb / 1024);
vga_puts(" MiB)\n");
vga_puts(" Kernel start: ");
extern uint32_t _kernel_start;
vga_put_hex((uint32_t)&_kernel_start);
vga_puts("\n");
vga_puts(" Kernel end: ");
extern uint32_t _kernel_end;
vga_put_hex((uint32_t)&_kernel_end);
vga_puts("\n");
uint32_t kernel_size = (uint32_t)&_kernel_end - (uint32_t)&_kernel_start;
vga_puts(" Kernel size: ");
vga_put_dec(kernel_size / 1024);
vga_puts(" KiB\n");
vga_set_color(VGA_LIGHT_CYAN, VGA_BLACK);
vga_puts("==================================\n");
vga_set_color(VGA_LIGHT_GREY, VGA_BLACK);
}
/* --- Driver registration --- */
/**
* VGA probe: always succeeds since VGA text mode is always available
* on the target platform (i386).
*/
static driver_probe_result_t vga_probe(void) {
return DRIVER_PROBE_OK;
}
int vga_init(void) {
text_attr = vga_color(VGA_LIGHT_GREY, VGA_BLACK);
vga_clear();
vga_set_color(VGA_LIGHT_GREEN, VGA_BLACK);
vga_puts("ClaudeOS v0.1 booting...\n\n");
vga_set_color(VGA_LIGHT_GREY, VGA_BLACK);
return 0;
}
/** VGA driver descriptor. */
static const driver_t vga_driver = {
.name = "vga",
.probe = vga_probe,
.init = vga_init,
};
REGISTER_DRIVER(vga_driver);

97
src/vga.h Normal file
View File

@@ -0,0 +1,97 @@
/**
* @file vga.h
* @brief VGA text-mode driver interface.
*
* Provides functions to write text to the VGA text-mode framebuffer
* (typically at 0xB8000). Supports an 80x25 character display with
* 16 foreground and 16 background colors.
*/
#ifndef VGA_H
#define VGA_H
#include <stdint.h>
#include <stddef.h>
/** VGA color constants. */
typedef enum {
VGA_BLACK = 0,
VGA_BLUE = 1,
VGA_GREEN = 2,
VGA_CYAN = 3,
VGA_RED = 4,
VGA_MAGENTA = 5,
VGA_BROWN = 6,
VGA_LIGHT_GREY = 7,
VGA_DARK_GREY = 8,
VGA_LIGHT_BLUE = 9,
VGA_LIGHT_GREEN = 10,
VGA_LIGHT_CYAN = 11,
VGA_LIGHT_RED = 12,
VGA_LIGHT_MAGENTA = 13,
VGA_YELLOW = 14,
VGA_WHITE = 15,
} vga_color_t;
/** VGA screen dimensions. */
#define VGA_WIDTH 80
#define VGA_HEIGHT 25
/**
* Initialize the VGA driver.
*
* Clears the screen and sets the default colors.
*
* @return 0 on success.
*/
int vga_init(void);
/**
* Clear the VGA screen.
*/
void vga_clear(void);
/**
* Set the foreground and background color for subsequent writes.
*
* @param fg Foreground color.
* @param bg Background color.
*/
void vga_set_color(vga_color_t fg, vga_color_t bg);
/**
* Write a single character at the current cursor position.
*
* @param c Character to write.
*/
void vga_putchar(char c);
/**
* Write a null-terminated string at the current cursor position.
*
* @param str String to write.
*/
void vga_puts(const char *str);
/**
* Write a 32-bit value in hexadecimal to the VGA display.
*
* @param val Value to display.
*/
void vga_put_hex(uint32_t val);
/**
* Write a 32-bit value in decimal to the VGA display.
*
* @param val Value to display.
*/
void vga_put_dec(uint32_t val);
/**
* Display boot memory statistics on VGA.
*
* Shows detected memory, kernel size, and free pages.
*/
void vga_show_mem_stats(void);
#endif /* VGA_H */