Attempt 2 #2
@@ -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 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 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.
|
- [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.
|
- [ ] 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.
|
- [ ] Update the build script to generate a ramdisk containing any applications to run. This initial ramdisk is in CPIO format.
|
||||||
- [ ] Write a VFS subsystem.
|
- [ ] Write a VFS subsystem.
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ add_executable(kernel
|
|||||||
kmalloc.c
|
kmalloc.c
|
||||||
string.c
|
string.c
|
||||||
driver.c
|
driver.c
|
||||||
|
vga.c
|
||||||
interrupts.S
|
interrupts.S
|
||||||
kernel.c
|
kernel.c
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include "paging.h"
|
#include "paging.h"
|
||||||
#include "kmalloc.h"
|
#include "kmalloc.h"
|
||||||
#include "driver.h"
|
#include "driver.h"
|
||||||
|
#include "vga.h"
|
||||||
|
|
||||||
void offset_print(const char *str)
|
void offset_print(const char *str)
|
||||||
{
|
{
|
||||||
@@ -71,6 +72,10 @@ void kernel_main(uint32_t magic, uint32_t addr) {
|
|||||||
init_drivers();
|
init_drivers();
|
||||||
offset_print("Drivers initialized\n");
|
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 */
|
/* Test kmalloc/kfree */
|
||||||
uint32_t *test_alloc = (uint32_t *)kmalloc(64);
|
uint32_t *test_alloc = (uint32_t *)kmalloc(64);
|
||||||
if (test_alloc) {
|
if (test_alloc) {
|
||||||
|
|||||||
230
src/vga.c
Normal file
230
src/vga.c
Normal 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 (0–15).
|
||||||
|
* @param bg Background color (0–15).
|
||||||
|
* @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
97
src/vga.h
Normal 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 */
|
||||||
Reference in New Issue
Block a user