first commit

This commit is contained in:
sam 2024-02-24 20:24:22 +13:00
commit a42aab7667
26 changed files with 892 additions and 0 deletions

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
obj/*
radix.iso

34
Makefile Normal file
View file

@ -0,0 +1,34 @@
KERNEL=obj/radix.bin
ISO=radix.iso
CC=gcc
LD=ld
CFLAGS=-ffreestanding -fno-stack-protector -fno-stack-check -O3 -Wall -Wextra -Werror -m32 -Isrc
LDFLAGS=-T linker.ld -m elf_i386
NASMFLAGS=-f elf32
CFILES=$(shell cd src && find -L * -type f -name '*.c')
ASMFILES=$(shell cd src && find -L * -type f -name '*.asm')
OBJ=$(addprefix obj/,$(CFILES:.c=.c.o) $(ASMFILES:.asm=.asm.o))
$(ISO): $(KERNEL) isolinux.cfg
cp isolinux.cfg cdroot/isolinux/
cp $(KERNEL) cdroot/
mkisofs -o $(ISO) -b isolinux/isolinux.bin -c isolinux/boot.cat -no-emul-boot -boot-load-size 4 -boot-info-table cdroot/
$(KERNEL): makedir linker.ld $(OBJ)
$(LD) $(LDFLAGS) $(OBJ) -o $@
obj/%.c.o: src/%.c
$(CC) $(CFLAGS) -c $< -o $@
obj/%.asm.o: src/%.asm
nasm $(NASMFLAGS) $< -o $@
makedir:
mkdir -p obj
run: $(ISO)
qemu-system-i386 -boot d -cdrom $(ISO) -m 1G -enable-kvm -cpu host -serial stdio
clean:
rm -rf $(OBJ) $(KERNEL)

0
README.md Normal file
View file

Binary file not shown.

View file

@ -0,0 +1,4 @@
DEFAULT radix
LABEL radix
KERNEL mboot.c32
APPEND /radix.bin

BIN
cdroot/isolinux/ldlinux.c32 Normal file

Binary file not shown.

Binary file not shown.

BIN
cdroot/isolinux/mboot.c32 Normal file

Binary file not shown.

BIN
cdroot/radix.bin Executable file

Binary file not shown.

4
isolinux.cfg Normal file
View file

@ -0,0 +1,4 @@
DEFAULT radix
LABEL radix
KERNEL mboot.c32
APPEND /radix.bin

28
linker.ld Normal file
View file

@ -0,0 +1,28 @@
ENTRY(_start)
SECTIONS
{
. = 1M;
.text BLOCK(4K) : ALIGN(4K)
{
*(.multiboot)
*(.text)
}
.rodata BLOCK(4K) : ALIGN(4K)
{
*(.rodata)
}
.data BLOCK(4K) : ALIGN(4K)
{
*(.data)
}
.bss BLOCK(4K) : ALIGN(4K)
{
*(COMMON)
*(.bss)
}
}

36
src/boot.asm Normal file
View file

@ -0,0 +1,36 @@
extern kernel_main
MBALIGN equ 1 << 0
MEMINFO equ 1 << 1
VIDINFO equ 1 << 2
MBFLAGS equ MBALIGN | MEMINFO | VIDINFO
MAGIC equ 0x1BADB002
CHECKSUM equ -(MAGIC + MBFLAGS)
section .multiboot
align 4
dd MAGIC
dd MBFLAGS
dd CHECKSUM
dd 0, 0, 0, 0, 0
dd 0
dd 320, 200, 8
section .bss
align 16
stack_bottom:
resb 16384
stack_top:
section .text
global _start:function (_start.end - _start)
_start:
mov esp, stack_top
push ebx
push eax
call kernel_main
cli
.hang:
jmp .hang
.end:

5
src/ctype.c Normal file
View file

@ -0,0 +1,5 @@
#include <ctype.h>
int isdigit(char c) {
return c >= '0' && c <= '9';
}

6
src/ctype.h Normal file
View file

@ -0,0 +1,6 @@
#ifndef __CTYPE_H__
#define __CTYPE_H__
int isdigit(char arg);
#endif

7
src/hcf.asm Normal file
View file

@ -0,0 +1,7 @@
global hcf
hcf:
cli
.loop:
hlt
jmp .loop

6
src/hcf.h Normal file
View file

@ -0,0 +1,6 @@
#ifndef __HCF_H__
#define __HCF_H__
void hcf();
#endif

241
src/kernel.c Normal file
View file

@ -0,0 +1,241 @@
#include <multiboot.h>
#include <stdio.h>
#include <hcf.h>
#include <vga.h>
#include <string.h>
#include <stddef.h>
#include <stdarg.h>
#include <stdlib.h>
#include <ctype.h>
void putpixel(unsigned char* addr, int pos_x, int pos_y, unsigned char VGA_COLOR)
{
unsigned char* location = addr + 320 * pos_y + pos_x;
*location = VGA_COLOR;
}
static inline void outb(uint16_t port, uint8_t val)
{
__asm__ volatile ( "outb %b0, %w1" : : "a"(val), "Nd"(port) : "memory");
/* There's an outb %al, $imm8 encoding, for compile-time constant port numbers that fit in 8b. (N constraint).
* Wider immediate constants would be truncated at assemble-time (e.g. "i" constraint).
* The outb %al, %dx encoding is the only option for all other cases.
* %1 expands to %dx because port is a uint16_t. %w1 could be used if we had the port number a wider C type */
}
static inline uint8_t inb(uint16_t port)
{
uint8_t ret;
__asm__ volatile ( "inb %w1, %b0"
: "=a"(ret)
: "Nd"(port)
: "memory");
return ret;
}
#define PORT 0x3f8 // COM1
static int init_serial() {
outb(PORT + 1, 0x00); // Disable all interrupts
outb(PORT + 3, 0x80); // Enable DLAB (set baud rate divisor)
outb(PORT + 0, 0x03); // Set divisor to 3 (lo byte) 38400 baud
outb(PORT + 1, 0x00); // (hi byte)
outb(PORT + 3, 0x03); // 8 bits, no parity, one stop bit
outb(PORT + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold
outb(PORT + 4, 0x0B); // IRQs enabled, RTS/DSR set
outb(PORT + 4, 0x1E); // Set in loopback mode, test the serial chip
outb(PORT + 0, 0xAE); // Test serial chip (send byte 0xAE and check if serial returns same byte)
// Check if serial is faulty (i.e: not same byte as sent)
if(inb(PORT + 0) != 0xAE) {
return 1;
}
// If serial is not faulty set it in normal operation mode
// (not-loopback with IRQs enabled and OUT#1 and OUT#2 bits enabled)
outb(PORT + 4, 0x0F);
return 0;
}
int is_transmit_empty() {
return inb(PORT + 5) & 0x20;
}
void write_serial(char a) {
while (is_transmit_empty() == 0);
outb(PORT,a);
}
void serial_puts(const char* s) {
do {
write_serial(*s);
} while(*++s != '\0');
}
void sprintf(const char* fmt, ...) {
va_list args;
va_start(args, fmt);
for(int i = 0; fmt[i] != '\0'; i++)
{
switch(fmt[i])
{
case '%':
i++;
char buf[512];
size_t width = 0;
char padding_char = fmt[i];
if(isdigit(fmt[i]) || fmt[i] == ' ') {
i++;
int pos = 0;
while(isdigit(fmt[i])) {
buf[pos++] = fmt[i++];
}
buf[pos] = '\0';
width = atoi(buf);
}
const char* out = 0;
if(fmt[i] == 's')
out = va_arg(args, const char*);
if(fmt[i] == 'd')
out = itoa(va_arg(args, int), buf, 10);
if(fmt[i] == 'u')
out = ultoa(va_arg(args, uint32_t), buf, 10);
if(fmt[i] == 'x')
out = ultoa(va_arg(args, uint32_t), buf, 16);
if(fmt[i] == 'c')
write_serial(va_arg(args, int));
size_t len = strlen(out);
if(width > len) {
char padding[256];
size_t j = 0;
for(; j < width - len; j++)
padding[j] = padding_char;
padding[j] = '\0';
serial_puts(padding);
}
serial_puts(out);
break;
default:
write_serial(fmt[i]);
break;
}
}
va_end(args);
}
#define CHECK_FLAG(flags,bit) ((flags) & (1 << (bit)))
void kernel_main(uint32_t magic, multiboot_info_t* mbi) {
init_vga();
init_serial();
if(magic != MULTIBOOT_BOOTLOADER_MAGIC) {
printf("Invalid bootloader magic: %x", magic);
hcf();
}
printf("flags: 0x%x\n", mbi->flags);
uint32_t mem_total = mbi->mem_upper - mbi->mem_lower;
printf("mem_lower: %uKB, mem_upper: %uKB, mem_total: %uKB\n", mbi->mem_lower, mbi->mem_upper, mem_total);
//sprintf("checking for flag");
//if (CHECK_FLAG (mbi->flags, 12))
//{
//sprintf("flag present");
multiboot_uint32_t color;
unsigned i;
void *fb = (void *) (unsigned long) mbi->framebuffer_addr;
sprintf("fb_addr: %x, fb_width: %u, fb_height: %u", fb, mbi->framebuffer_width, mbi->framebuffer_height);
switch (mbi->framebuffer_type)
{
case MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED:
{
//sprintf("indexed");
unsigned best_distance, distance;
struct multiboot_color *palette;
palette = (struct multiboot_color *) mbi->framebuffer_palette_addr;
color = 0;
best_distance = 4*256*256;
for (i = 0; i < mbi->framebuffer_palette_num_colors; i++)
{
distance = (0xff - palette[i].blue) * (0xff - palette[i].blue)
+ palette[i].red * palette[i].red
+ palette[i].green * palette[i].green;
if (distance < best_distance)
{
color = i;
best_distance = distance;
}
}
}
break;
case MULTIBOOT_FRAMEBUFFER_TYPE_RGB:
color = ((1 << mbi->framebuffer_blue_mask_size) - 1)
<< mbi->framebuffer_blue_field_position;
break;
case MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT:
color = '\\' | 0x0100;
break;
default:
color = 0xffffffff;
break;
}
for (i = 0; i < mbi->framebuffer_width
&& i < mbi->framebuffer_height; i++)
{
switch (mbi->framebuffer_bpp)
{
case 8:
{
multiboot_uint8_t *pixel = fb + mbi->framebuffer_pitch * i + i;
*pixel = color;
}
break;
case 15:
case 16:
{
multiboot_uint16_t *pixel
= fb + mbi->framebuffer_pitch * i + 2 * i;
*pixel = color;
}
break;
case 24:
{
multiboot_uint32_t *pixel
= fb + mbi->framebuffer_pitch * i + 3 * i;
*pixel = (color & 0xffffff) | (*pixel & 0xff000000);
}
break;
case 32:
{
multiboot_uint32_t *pixel
= fb + mbi->framebuffer_pitch * i + 4 * i;
*pixel = color;
}
break;
}
}
//}
hcf();
}

274
src/multiboot.h Normal file
View file

@ -0,0 +1,274 @@
/* multiboot.h - Multiboot header file. */
/* Copyright (C) 1999,2003,2007,2008,2009,2010 Free Software Foundation, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ANY
* DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
* IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef MULTIBOOT_HEADER
#define MULTIBOOT_HEADER 1
/* How many bytes from the start of the file we search for the header. */
#define MULTIBOOT_SEARCH 8192
#define MULTIBOOT_HEADER_ALIGN 4
/* The magic field should contain this. */
#define MULTIBOOT_HEADER_MAGIC 0x1BADB002
/* This should be in %eax. */
#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002
/* Alignment of multiboot modules. */
#define MULTIBOOT_MOD_ALIGN 0x00001000
/* Alignment of the multiboot info structure. */
#define MULTIBOOT_INFO_ALIGN 0x00000004
/* Flags set in the 'flags' member of the multiboot header. */
/* Align all boot modules on i386 page (4KB) boundaries. */
#define MULTIBOOT_PAGE_ALIGN 0x00000001
/* Must pass memory information to OS. */
#define MULTIBOOT_MEMORY_INFO 0x00000002
/* Must pass video information to OS. */
#define MULTIBOOT_VIDEO_MODE 0x00000004
/* This flag indicates the use of the address fields in the header. */
#define MULTIBOOT_AOUT_KLUDGE 0x00010000
/* Flags to be set in the 'flags' member of the multiboot info structure. */
/* is there basic lower/upper memory information? */
#define MULTIBOOT_INFO_MEMORY 0x00000001
/* is there a boot device set? */
#define MULTIBOOT_INFO_BOOTDEV 0x00000002
/* is the command-line defined? */
#define MULTIBOOT_INFO_CMDLINE 0x00000004
/* are there modules to do something with? */
#define MULTIBOOT_INFO_MODS 0x00000008
/* These next two are mutually exclusive */
/* is there a symbol table loaded? */
#define MULTIBOOT_INFO_AOUT_SYMS 0x00000010
/* is there an ELF section header table? */
#define MULTIBOOT_INFO_ELF_SHDR 0X00000020
/* is there a full memory map? */
#define MULTIBOOT_INFO_MEM_MAP 0x00000040
/* Is there drive info? */
#define MULTIBOOT_INFO_DRIVE_INFO 0x00000080
/* Is there a config table? */
#define MULTIBOOT_INFO_CONFIG_TABLE 0x00000100
/* Is there a boot loader name? */
#define MULTIBOOT_INFO_BOOT_LOADER_NAME 0x00000200
/* Is there a APM table? */
#define MULTIBOOT_INFO_APM_TABLE 0x00000400
/* Is there video information? */
#define MULTIBOOT_INFO_VBE_INFO 0x00000800
#define MULTIBOOT_INFO_FRAMEBUFFER_INFO 0x00001000
#ifndef ASM_FILE
typedef unsigned char multiboot_uint8_t;
typedef unsigned short multiboot_uint16_t;
typedef unsigned int multiboot_uint32_t;
typedef unsigned long long multiboot_uint64_t;
struct multiboot_header
{
/* Must be MULTIBOOT_MAGIC - see above. */
multiboot_uint32_t magic;
/* Feature flags. */
multiboot_uint32_t flags;
/* The above fields plus this one must equal 0 mod 2^32. */
multiboot_uint32_t checksum;
/* These are only valid if MULTIBOOT_AOUT_KLUDGE is set. */
multiboot_uint32_t header_addr;
multiboot_uint32_t load_addr;
multiboot_uint32_t load_end_addr;
multiboot_uint32_t bss_end_addr;
multiboot_uint32_t entry_addr;
/* These are only valid if MULTIBOOT_VIDEO_MODE is set. */
multiboot_uint32_t mode_type;
multiboot_uint32_t width;
multiboot_uint32_t height;
multiboot_uint32_t depth;
};
/* The symbol table for a.out. */
struct multiboot_aout_symbol_table
{
multiboot_uint32_t tabsize;
multiboot_uint32_t strsize;
multiboot_uint32_t addr;
multiboot_uint32_t reserved;
};
typedef struct multiboot_aout_symbol_table multiboot_aout_symbol_table_t;
/* The section header table for ELF. */
struct multiboot_elf_section_header_table
{
multiboot_uint32_t num;
multiboot_uint32_t size;
multiboot_uint32_t addr;
multiboot_uint32_t shndx;
};
typedef struct multiboot_elf_section_header_table multiboot_elf_section_header_table_t;
struct multiboot_info
{
/* Multiboot info version number */
multiboot_uint32_t flags;
/* Available memory from BIOS */
multiboot_uint32_t mem_lower;
multiboot_uint32_t mem_upper;
/* "root" partition */
multiboot_uint32_t boot_device;
/* Kernel command line */
multiboot_uint32_t cmdline;
/* Boot-Module list */
multiboot_uint32_t mods_count;
multiboot_uint32_t mods_addr;
union
{
multiboot_aout_symbol_table_t aout_sym;
multiboot_elf_section_header_table_t elf_sec;
} u;
/* Memory Mapping buffer */
multiboot_uint32_t mmap_length;
multiboot_uint32_t mmap_addr;
/* Drive Info buffer */
multiboot_uint32_t drives_length;
multiboot_uint32_t drives_addr;
/* ROM configuration table */
multiboot_uint32_t config_table;
/* Boot Loader Name */
multiboot_uint32_t boot_loader_name;
/* APM table */
multiboot_uint32_t apm_table;
/* Video */
multiboot_uint32_t vbe_control_info;
multiboot_uint32_t vbe_mode_info;
multiboot_uint16_t vbe_mode;
multiboot_uint16_t vbe_interface_seg;
multiboot_uint16_t vbe_interface_off;
multiboot_uint16_t vbe_interface_len;
multiboot_uint64_t framebuffer_addr;
multiboot_uint32_t framebuffer_pitch;
multiboot_uint32_t framebuffer_width;
multiboot_uint32_t framebuffer_height;
multiboot_uint8_t framebuffer_bpp;
#define MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED 0
#define MULTIBOOT_FRAMEBUFFER_TYPE_RGB 1
#define MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT 2
multiboot_uint8_t framebuffer_type;
union
{
struct
{
multiboot_uint32_t framebuffer_palette_addr;
multiboot_uint16_t framebuffer_palette_num_colors;
};
struct
{
multiboot_uint8_t framebuffer_red_field_position;
multiboot_uint8_t framebuffer_red_mask_size;
multiboot_uint8_t framebuffer_green_field_position;
multiboot_uint8_t framebuffer_green_mask_size;
multiboot_uint8_t framebuffer_blue_field_position;
multiboot_uint8_t framebuffer_blue_mask_size;
};
};
};
typedef struct multiboot_info multiboot_info_t;
struct multiboot_color
{
multiboot_uint8_t red;
multiboot_uint8_t green;
multiboot_uint8_t blue;
};
struct multiboot_mmap_entry
{
multiboot_uint32_t size;
multiboot_uint64_t addr;
multiboot_uint64_t len;
#define MULTIBOOT_MEMORY_AVAILABLE 1
#define MULTIBOOT_MEMORY_RESERVED 2
#define MULTIBOOT_MEMORY_ACPI_RECLAIMABLE 3
#define MULTIBOOT_MEMORY_NVS 4
#define MULTIBOOT_MEMORY_BADRAM 5
multiboot_uint32_t type;
} __attribute__((packed));
typedef struct multiboot_mmap_entry multiboot_memory_map_t;
struct multiboot_mod_list
{
/* the memory used goes from bytes 'mod_start' to 'mod_end-1' inclusive */
multiboot_uint32_t mod_start;
multiboot_uint32_t mod_end;
/* Module command line */
multiboot_uint32_t cmdline;
/* padding to take it to 16 bytes (must be zero) */
multiboot_uint32_t pad;
};
typedef struct multiboot_mod_list multiboot_module_t;
/* APM BIOS info. */
struct multiboot_apm_info
{
multiboot_uint16_t version;
multiboot_uint16_t cseg;
multiboot_uint32_t offset;
multiboot_uint16_t cseg_16;
multiboot_uint16_t dseg;
multiboot_uint16_t flags;
multiboot_uint16_t cseg_len;
multiboot_uint16_t cseg_16_len;
multiboot_uint16_t dseg_len;
};
#endif /* ! ASM_FILE */
#endif /* ! MULTIBOOT_HEADER */

76
src/stdio.c Normal file
View file

@ -0,0 +1,76 @@
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <stddef.h>
#include <stdlib.h>
#include <vga.h>
void putc(char ch) {
vga_putc(ch);
}
void puts(const char* str) {
do {
putc(*str);
} while(*++str != '\0');
}
void printf(const char* fmt, ...) {
va_list args;
va_start(args, fmt);
for(int i = 0; fmt[i] != '\0'; i++)
{
switch(fmt[i])
{
case '%':
i++;
char buf[512];
size_t width = 0;
char padding_char = fmt[i];
if(isdigit(fmt[i]) || fmt[i] == ' ') {
i++;
int pos = 0;
while(isdigit(fmt[i])) {
buf[pos++] = fmt[i++];
}
buf[pos] = '\0';
width = atoi(buf);
}
const char* out = 0;
if(fmt[i] == 's')
out = va_arg(args, const char*);
if(fmt[i] == 'd')
out = itoa(va_arg(args, int), buf, 10);
if(fmt[i] == 'u')
out = ultoa(va_arg(args, uint32_t), buf, 10);
if(fmt[i] == 'x')
out = ultoa(va_arg(args, uint32_t), buf, 16);
if(fmt[i] == 'c')
putc(va_arg(args, int));
size_t len = strlen(out);
if(width > len) {
char padding[256];
size_t j = 0;
for(; j < width - len; j++)
padding[j] = padding_char;
padding[j] = '\0';
puts(padding);
}
puts(out);
break;
default:
putc(fmt[i]);
break;
}
}
va_end(args);
}

9
src/stdio.h Normal file
View file

@ -0,0 +1,9 @@
#ifndef __STDIO_H__
#define __STDIO_H__
#include <stdint.h>
void putc(char ch);
void puts(const char* str);
void printf(const char* fmt, ...);
#endif

77
src/stdlib.c Normal file
View file

@ -0,0 +1,77 @@
#include <stdlib.h>
#include <ctype.h>
const char* itoa(int value, char* str, int base)
{
char* rc;
char* ptr;
char* low;
if (base < 2 || base > 36)
{
*str = '\0';
return str;
}
rc = ptr = str;
if (value < 0 && base == 10)
{
*ptr++ = '-';
}
low = ptr;
do
{
*ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz"[35 + value % base];
value /= base;
} while (value);
*ptr-- = '\0';
while (low < ptr)
{
char tmp = *low;
*low++ = *ptr;
*ptr-- = tmp;
}
return rc;
}
const char* ultoa(uint32_t value, char* str, int base)
{
char* rc;
char* ptr;
char* low;
if (base < 2 || base > 36)
{
*str = '\0';
return str;
}
rc = ptr = str;
low = ptr;
do
{
*ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz"[35 + value % base];
value /= base;
} while (value);
*ptr-- = '\0';
while (low < ptr)
{
char tmp = *low;
*low++ = *ptr;
*ptr-- = tmp;
}
return rc;
}
int atoi(const char* str) {
int value = 0;
while(isdigit(*str)) {
value *= 10;
value += (*str)-'0';
str++;
}
return value;
}

9
src/stdlib.h Normal file
View file

@ -0,0 +1,9 @@
#ifndef __STDLIB_H__
#define __STDLIB_H__
#include <stdint.h>
const char* itoa(int value, char* str, int base);
const char* ultoa(uint32_t value, char* str, int base);
int atoi(const char* str);
#endif

8
src/string.c Normal file
View file

@ -0,0 +1,8 @@
#include <string.h>
size_t strlen(const char* str) {
size_t len = 0;
while (str[len])
len++;
return len;
}

7
src/string.h Normal file
View file

@ -0,0 +1,7 @@
#ifndef __STRING_H__
#define __STRING_H__
#include <stddef.h>
size_t strlen(const char* str);
#endif

39
src/vga.c Normal file
View file

@ -0,0 +1,39 @@
#include <vga.h>
#include <stdio.h>
struct vga_terminal vga_term = { 0 };
uint16_t* VGA = (uint16_t*)0xb8000;
void vga_putc(char ch) {
if(ch == '\n') {
vga_term.x = 0;
vga_term.y++;
} else {
int index = vga_term.y * VGA_WIDTH + vga_term.x;
VGA[index] = ch | (vga_term.fg | vga_term.bg << 4) << 8;
vga_term.x++;
if(vga_term.x > VGA_WIDTH) {
vga_term.x = 0;
vga_term.y++;
}
}
}
void vga_clear() {
vga_term.x = 0;
vga_term.y = 0;
for(int i = 0; i < VGA_WIDTH * VGA_HEIGHT; i++)
putc(' ');
}
void init_vga(void) {
vga_term.fg = 7;
vga_term.bg = 0;
vga_clear();
vga_term.x = 0;
vga_term.y = 0;
}

20
src/vga.h Normal file
View file

@ -0,0 +1,20 @@
#ifndef __VGA_H__
#define __VGA_H__
#include <stdint.h>
#define VGA_WIDTH 80
#define VGA_HEIGHT 25
struct vga_terminal {
uint8_t bg;
uint8_t fg;
uint8_t x;
uint8_t y;
};
extern struct vga_terminal vga_term;
void init_vga(void);
void vga_putc(char ch);
#endif