cowos attempted gdt, but at least we have vga drivers now

This commit is contained in:
cowmonk 2025-07-18 23:50:07 -07:00
parent b08b0728ae
commit 41b34d2a9d
14 changed files with 253 additions and 140 deletions

View file

@ -15,14 +15,7 @@ kernel:
make -C ./kernel/ all
limine: kernel
git clone https://github.com/limine-bootloader/limine.git --branch=v9.x-binary --depth=1
make -C limine
cp -v limine/limine-bios.sys limine/limine-bios-cd.bin \
limine/limine-uefi-cd.bin isodir/boot/limine/
cp -v limine/BOOTX64.EFI isodir/EFI/BOOT/
cp -v limine/BOOTIA32.EFI isodir/EFI/BOOT/
./scripts/limine-git.sh
clean:
rm cowos.iso

View file

@ -24,3 +24,6 @@ make
# Credits
- [Limine](https://github.com/limine-bootloader/limine): modern, advanced, portable, multiprotocol bootloader and boot manager.
## People
- micl: random guy on the interweb in the LHL discord server gave me a free vga driver to use lol

View file

@ -1,61 +1,118 @@
#include <drivers/video/vga.h>
/* #include <bootloader.h> */
#include <string.h>
/* for frame buffer
static volatile struct limine_framebuffer_request limineFBreq = {
.id = LIMINE_FRAMEBUFFER_REQUEST, .revision = 0};
*/
size_t term_row;
size_t term_col;
uint8_t term_color;
uint16_t* term_buf = (uint16_t*)VGA_MEMORY;
void
term_init(void)
// Helper functions for port IO
static inline void
outb(uint16_t port, uint8_t val)
{
term_row = 0;
term_col = 0;
term_color = vga_entry_color(VGA_COLOR_WHITE, VGA_COLOR_BLACK);
__asm__ volatile ("outb %0, %1" : : "a"(val), "Nd"(port));
}
for (size_t y = 0; y < VGA_HEIGHT; y++) {
for (size_t x = 0; x < VGA_WIDTH; x++) {
const size_t index = y * VGA_WIDTH + x;
term_buf[index] = vga_entry(' ', term_color);
}
}
static inline uint8_t
inb(uint16_t port)
{
uint8_t ret;
__asm__ volatile ("inb %1, %0" : "=a"(ret) : "Nd"(port));
return ret;
}
// Write vga registers for mode change
static void
write_regs(uint8_t *regs)
{
unsigned i;
// Write misc output register
outb(VGA_MISC_WRITE, *regs);
regs++;
// Write sequencer registers (5 registers)
for (i = 0; i < 5; i++) {
outb(VGA_SEQ_INDEX, i);
outb(VGA_SEQ_DATA, *regs);
regs++;
}
// Unlock CRTC registers 0-7 by clearing protect bit
outb(VGA_CRTC_INDEX, 0x03);
outb(VGA_CRTC_DATA, inb(VGA_CRTC_DATA) | 0x80);
outb(VGA_CRTC_INDEX, 0x11);
outb(VGA_CRTC_DATA, inb(VGA_CRTC_DATA) & ~0x80);
// Update the register values to match
regs[0x03] = regs[0x03] | 0x80;
regs[0x11] = regs[0x11] & ~0x80;
// Write CRTC registers (25 registers)
for (i = 0; i < 25; i++) {
outb(VGA_CRTC_INDEX, i);
outb(VGA_CRTC_DATA, *regs);
regs++;
}
// Write graphics controller registers (9 registers)
for (i = 0; i < 9; i++) {
outb(VGA_GC_INDEX, i);
outb(VGA_GC_DATA, *regs);
regs++;
}
// Write attribute controller registers (21 registers)
for (i = 0; i < 21; i++) {
inb(VGA_INSTAT_READ); // Reset flip-flop
outb(VGA_AC_INDEX, i);
outb(VGA_AC_WRITE, *regs);
regs++;
}
// Enable video display
inb(VGA_INSTAT_READ);
outb(VGA_AC_INDEX, 0x20);
}
void
term_setcolor(uint8_t color)
vga_set_mode_13h(void)
{
term_color = color;
// Register values for VGA mode 13h (320x200, 256 colors)
// Order: Misc, Seq[5], CRTC[25], GC[9], AC[21]
static uint8_t mode_320x200x256[] = {
// Misc output register
0x63,
// Sequencer registers
0x03, 0x01, 0x0F, 0x00, 0x0E,
// CRTC registers
0x5F, 0x4F, 0x50, 0x82, 0x54, 0x80, 0xBF, 0x1F,
0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x9C, 0x0E, 0x8F, 0x28, 0x40, 0x96, 0xB9, 0xA3,
0xFF,
// Graphics controller registers
0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
0xFF,
// Attribute controller registers
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x41, 0x00, 0x0F, 0x00, 0x00
};
write_regs(mode_320x200x256);
}
void
term_putentryat(char c, uint8_t color, size_t x, size_t y)
vga_put_pixel(uint16_t x, uint16_t y, uint8_t color)
{
const size_t index = y * VGA_HEIGHT + x;
term_buf[index] = vga_entry(c, color);
// check bounds
if (x >= VGA_WIDTH || y >= VGA_HEIGHT) return;
// Direct write to video memory: offset = y * 320 + x
uint8_t *vga = (uint8_t *)VGA_GRAPHICS_BUFFER;
vga[y * VGA_WIDTH + x] = color;
}
void
term_putchar(char c)
vga_clear_screen(uint8_t color)
{
term_putentryat(c, term_color, term_col, term_row);
if (++term_col == VGA_WIDTH) {
term_col = 0;
if (++term_row == VGA_HEIGHT) {
term_row = 0;
}
}
}
void
term_writestr(const char* data)
{
for (size_t i = 0; data[i] != '\0'; i++) {
term_putchar(data[i]);
}
uint8_t *vga = (uint8_t *)VGA_GRAPHICS_BUFFER;
// fill entire buffer (64k pixels)
for (int i = 0; i < VGA_WIDTH * VGA_HEIGHT; i++) {
vga[i] = color;
}
}

BIN
kernel/drivers/video/vga.o Normal file

Binary file not shown.

View file

@ -2,49 +2,30 @@
#define VGA_H
#include <stdint.h>
#include <stddef.h>
/* hardware text mode const */
enum vga_color {
VGA_COLOR_BLACK = 0,
VGA_COLOR_BLUE = 1,
VGA_COLOR_GREEN = 2,
VGA_COLOR_CYAN = 3,
VGA_COLOR_RED = 4,
VGA_COLOR_MAGENTA = 5,
VGA_COLOR_BROWN = 6,
VGA_COLOR_LIGHT_GREY = 7,
VGA_COLOR_DARK_GREY = 8,
VGA_COLOR_LIGHT_BLUE = 9,
VGA_COLOR_LIGHT_GREEN = 10,
VGA_COLOR_LIGHT_CYAN = 11,
VGA_COLOR_LIGHT_RED = 12,
VGA_COLOR_LIGHT_MAGENTA = 13,
VGA_COLOR_LIGHT_BROWN = 14,
VGA_COLOR_WHITE = 15,
};
// VGA mem addr
#define VGA_TEXT_BUFFER 0xB8000 // Text mode video memory
#define VGA_GRAPHICS_BUFFER 0xA0000 // Graphics mode video memory
static inline uint8_t
vga_entry_color(enum vga_color fg, enum vga_color bg)
{
return fg | bg << 4;
}
// VGA mode 13h dimensions
#define VGA_WIDTH 320
#define VGA_HEIGHT 200
static inline uint16_t
vga_entry(unsigned char uc, uint8_t color)
{
return (uint16_t) uc | (uint16_t) color << 8;
}
// VGA register IO ports
#define VGA_AC_INDEX 0x3C0 // attribute controller index
#define VGA_AC_WRITE 0x3C0 // attribute controller write
#define VGA_AC_READ 0x3C1 // attribute controller read
#define VGA_MISC_WRITE 0x3C2 // miscellaneous output register
#define VGA_SEQ_INDEX 0x3C4 // sequencer index
#define VGA_SEQ_DATA 0x3C5 // sequencer data
#define VGA_GC_INDEX 0x3CE // graphics controller index
#define VGA_GC_DATA 0x3CF // graphics controller data
#define VGA_CRTC_INDEX 0x3D4 // CRT controller index
#define VGA_CRTC_DATA 0x3D5 // CRT controller data
#define VGA_INSTAT_READ 0x3DA // input status read
/* using mode 3 of VGA 80x25 */
#define VGA_WIDTH 80
#define VGA_HEIGHT 25
#define VGA_MEMORY 0xA0000 /* VGA memory location */
void vga_set_mode_13h(void);
void vga_put_pixel(uint16_t x, uint16_t y, uint8_t color);
void vga_clear_screen(uint8_t color);
void term_init(void);
void term_setcolor(uint8_t color);
void term_putentryat(char c, uint8_t color, size_t x, size_t y);
void term_putchar(char c);
void term_writestr(const char* data);
#endif // VGA_H
#endif

View file

@ -1,22 +0,0 @@
#ifndef FB_H
#define FB_H
/* *pixel = vram + y*pitch + x*pixelwidth */
/*
| width | how many pixels you have on a horizontal line |
|===========================================================================|
| height | how many horizontal lines of pixels are present |
|===========================================================================|
| pitch | how many bytes of VRAM you should skip to go one pixel down |
|===========================================================================|
| depth | how many bits of color you have |
|===========================================================================|
| pixelwidth | how many bytes of VRAM you should skip to go one pixel right |
*/
#include <klibc/types.h>
void putpixel(int pos_x, int pos_y, unsigned char VGA_COLOR);
#endif /* FB_H */

28
kernel/include/gdt.h Normal file
View file

@ -0,0 +1,28 @@
#include <stdint.h>
#ifndef GDT_H
#define GDT_H
typedef struct GDTEntry {
uint16_t limit;
uint16_t base_low;
uint16_t base_mid;
uint8_t base_high;
uint8_t access;
uint8_t granularity;
} __attribute__((packed)) GDTEntry;
typedef struct GDTPtr {
uint16_t limit;
uint64_t base;
} __attribute__((packed)) GDTPtr;
#define GDT_NUM_ENTRIES 5 /* including null descriptor */
#define GDT_KERNEL_CODE 0x08
#define GDT_KERNEL_DATA 0x10
#define GDT_USER_CODE 0x18
#define GDT_USER_DATA 0x20
void initGDT();
#endif /* GDT_H */

View file

@ -1,12 +1,15 @@
#include <gdt.h>
#include <klibc/string.h>
/* #include <drivers/video/vga.h> */
#include <drivers/video/vga.h>
#include <stddef.h>
#include <bootloader.h>
static void hcf(void) {
for (;;) {
__asm__("hlt");
}
static void
hcf(void)
{
for (;;) {
__asm__("hlt");
}
}
void
@ -15,26 +18,9 @@ kernel_main(void)
/* Make sure the bootloader understands our base revision */
if (LIMINE_BASE_REVISION_SUPPORTED == 0) hcf();
/* ensure a framebuffer */
if (framebuffer_request.response == NULL
|| framebuffer_request.response->framebuffer_count < 1) hcf();
vga_set_mode_13h();
/* fetch the first framebuffer */
struct limine_framebuffer *framebuffer = framebuffer_request.response->framebuffers[0];
/* assume framebuffer model is RGB w/32-bit pixels */
for (size_t i = 0; i < 100; i++) {
volatile uint32_t *fb_ptr = framebuffer->address;
fb_ptr[i * (framebuffer->pitch / 4) + i] = 0xffffff;
}
/* need to get an actual framebuffer driver working before we can use vga */
/*
term_init();
term_writestr("Hello World!");
*/
/* initGDT(); */
/* done so now hang */
hcf();

BIN
kernel/init/kernel.o Normal file

Binary file not shown.

BIN
kernel/klibc/stdio.o Normal file

Binary file not shown.

BIN
kernel/klibc/string.o Normal file

Binary file not shown.

73
kernel/x86/gdt.c Normal file
View file

@ -0,0 +1,73 @@
#include <gdt.h>
static GDTEntry descriptors[5];
static GDTPtr gdtptr;
void
gdt_reload()
{
asm volatile("lgdt %0\n\t"
"push $0x28\n\t"
"lea 1f(%%rip), %%rax\n\t"
"push %%rax\n\t"
"lretq\n\t"
"1:\n\t"
"mov $0x30, %%eax\n\t"
"mov %%eax, %%ds\n\t"
"mov %%eax, %%es\n\t"
"mov %%eax, %%fs\n\t"
"mov %%eax, %%gs\n\t"
"mov %%eax, %%ss\n\t"
:
: "m"(gdtptr)
: "rax", "memory");
}
void
initGDT()
{
/* null descriptor (0) */
descriptors[0].limit = 0;
descriptors[0].base_low = 0;
descriptors[0].base_mid = 0;
descriptors[0].access = 0;
descriptors[0].granularity = 0;
descriptors[0].base_high = 0;
/* kernel code 64 (40) */
descriptors[1].limit = 0;
descriptors[1].base_low = 0;
descriptors[1].base_mid = 0;
descriptors[1].access = 0b10011010;
descriptors[1].granularity = 0b00100000;
descriptors[1].base_high = 0;
/* kernel data 64 (48) */
descriptors[2].limit = 0;
descriptors[2].base_low = 0;
descriptors[2].base_mid = 0;
descriptors[2].access = 0b10010010;
descriptors[2].granularity = 0;
descriptors[2].base_high = 0;
// user code 64 (72)
descriptors[3].limit = 0;
descriptors[3].base_low = 0;
descriptors[3].base_mid = 0;
descriptors[3].access = 0b11111010;
descriptors[3].granularity = 0b00100000;
descriptors[3].base_high = 0;
// user data 64. (80)
descriptors[4].limit = 0;
descriptors[4].base_low = 0;
descriptors[4].base_mid = 0;
descriptors[4].access = 0b11110010;
descriptors[4].granularity = 0;
descriptors[4].base_high = 0;
gdtptr.limit = sizeof(descriptors) - 1;
gdtptr.base = (uint64_t)&descriptors;
gdt_reload();
}

BIN
kernel/x86/gdt.o Normal file

Binary file not shown.

14
scripts/limine-git.sh Executable file
View file

@ -0,0 +1,14 @@
#!/bin/sh
if [ ! -d ./limine/ ]; then
git clone https://github.com/limine-bootloader/limine.git --branch=v9.x-binary --depth=1
make -C limine
cp -v limine/limine-bios.sys limine/limine-bios-cd.bin \
limine/limine-uefi-cd.bin isodir/boot/limine/
mkdir -p isodir/EFI/BOOT
cp -v limine/BOOTX64.EFI isodir/EFI/BOOT/
cp -v limine/BOOTIA32.EFI isodir/EFI/BOOT/
fi