Initial commit.
This commit is contained in:
commit
a3c817412e
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# ignore binary files
|
||||||
|
*.bin
|
||||||
|
*.o
|
||||||
|
*.iso
|
||||||
|
|
||||||
|
# ignore build files
|
||||||
|
isodir
|
44
Makefile
Normal file
44
Makefile
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
# General options
|
||||||
|
TARGET=i686
|
||||||
|
ARCH=$(shell echo $(TARGET) | sed s/i.86/x86/)
|
||||||
|
# Assembly options
|
||||||
|
AS=i686-elf-as
|
||||||
|
AFLAGS=
|
||||||
|
# C options
|
||||||
|
CC=i686-elf-gcc
|
||||||
|
CFLAGS?=-O0 -g
|
||||||
|
CFLAGS:=$(CFLAGS) -std=gnu99 -ffreestanding -Wall -Wextra -Isrc/
|
||||||
|
# Linker options
|
||||||
|
LDFLAGS?=-O0
|
||||||
|
LDFLAGS:=$(LDFLAGS) -ffreestanding -nostdlib
|
||||||
|
LIBS=-lgcc
|
||||||
|
|
||||||
|
# Binary variables
|
||||||
|
OBJS=src/kernel/arch/$(ARCH)/boot.o src/kernel/kernel.o src/kernel/arch/$(ARCH)/tty.o
|
||||||
|
|
||||||
|
untrue.bin: $(OBJS)
|
||||||
|
$(CC) -T src/kernel/arch/$(ARCH)/linker.ld -o $@ $(LDFLAGS) $^ $(LIBS)
|
||||||
|
|
||||||
|
%.o: %.c
|
||||||
|
$(CC) $(CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
|
%.o: %.s
|
||||||
|
$(AS) $(AFLAGS) $< -o $@
|
||||||
|
|
||||||
|
.PHONY: all build-iso clean clean-all
|
||||||
|
all: untrue.bin
|
||||||
|
|
||||||
|
build-iso: untrue.iso
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(OBJS)
|
||||||
|
rm -rf isodir
|
||||||
|
|
||||||
|
clean-all: clean
|
||||||
|
rm -f *.iso *.bin
|
||||||
|
|
||||||
|
untrue.iso: untrue.bin
|
||||||
|
mkdir -p isodir/boot/grub/
|
||||||
|
cp configs/grub.cfg isodir/boot/grub/
|
||||||
|
cp $< isodir/boot/
|
||||||
|
grub-mkrescue -o $@ isodir
|
3
configs/grub.cfg
Normal file
3
configs/grub.cfg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
menuentry "UntrueOS" {
|
||||||
|
multiboot /boot/untrue.bin
|
||||||
|
}
|
112
src/kernel/arch/x86/boot.s
Normal file
112
src/kernel/arch/x86/boot.s
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
# declare constants for the multiboot header
|
||||||
|
.set ALIGN, 1 << 0 # align loaded modules on page boundaries
|
||||||
|
.set MEMINFO, 1 << 1 # provide memory map
|
||||||
|
.set FLAGS, ALIGN | MEMINFO # the multiboot `FLAG' field
|
||||||
|
.set MAGIC, 0x1BADB002 # 'magic number' letting the boot loader know we're here
|
||||||
|
.set CHECKSUM , -(MAGIC + FLAGS) # checksum of the above to prove we're multiboot
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Declare the multiboot header marking this program as a kernel. The bootloader
|
||||||
|
* will search for these values in the first 8 KiB of the kernel file aligned at
|
||||||
|
* 32-bit boundaries (4 bytes). We put the signature in its own section to force
|
||||||
|
* it within the first 8 KiB of the kernel file.
|
||||||
|
*/
|
||||||
|
.section .multiboot
|
||||||
|
.align 4
|
||||||
|
.long MAGIC
|
||||||
|
.long FLAGS
|
||||||
|
.long CHECKSUM
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create a 16 byte aligned stack with 16 KiB of size. We create labels at the
|
||||||
|
* bottom and top of the stack.
|
||||||
|
*/
|
||||||
|
.section .bss
|
||||||
|
.align 16
|
||||||
|
stack_bottom:
|
||||||
|
.skip 16384 # 16 KiB
|
||||||
|
stack_top:
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create the GDT
|
||||||
|
*/
|
||||||
|
.section .data
|
||||||
|
gdt_start:
|
||||||
|
gdt_null:
|
||||||
|
.long 0x0
|
||||||
|
.long 0x0
|
||||||
|
|
||||||
|
gdt_kcode:
|
||||||
|
.word 0xFFFF # limit
|
||||||
|
.word 0x0 # base
|
||||||
|
.byte 0x0 # base
|
||||||
|
.byte 0b10011010 # 1st flags | type flags
|
||||||
|
.byte 0b11001111 # 2nd flags | limit
|
||||||
|
.byte 0x0 # base
|
||||||
|
|
||||||
|
gdt_kdata:
|
||||||
|
.word 0xFFFF # limit
|
||||||
|
.word 0x0 # base
|
||||||
|
.byte 0x0 # base
|
||||||
|
.byte 0b10010010 # 1st flags | type flags
|
||||||
|
.byte 0b11001111 # 2nd flags | limit
|
||||||
|
.byte 0x0 # base
|
||||||
|
|
||||||
|
gdt_ucode:
|
||||||
|
.word 0xFFFF # limit
|
||||||
|
.word 0x0 # base
|
||||||
|
.byte 0x0 # base
|
||||||
|
.byte 0b11111010 # 1st flags | type flags
|
||||||
|
.byte 0b11001111 # 2nd flags | limit
|
||||||
|
.byte 0x0 # base
|
||||||
|
|
||||||
|
gdt_udata:
|
||||||
|
.word 0xFFFF # limit
|
||||||
|
.word 0x0 # base
|
||||||
|
.byte 0x0 # base
|
||||||
|
.byte 0b11110010 # 1st flags | type flags
|
||||||
|
.byte 0b11001111 # 2nd flags | limit
|
||||||
|
.byte 0x0 # base
|
||||||
|
|
||||||
|
gdt_end:
|
||||||
|
|
||||||
|
gdtr:
|
||||||
|
.word (gdt_end - gdt_start - 1)
|
||||||
|
.long gdt_start
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The linker script specifies the `_start' label as the entry point to the kernel
|
||||||
|
* and the bootloader will jump to this position. That is, this is where the kernel
|
||||||
|
* starts.
|
||||||
|
*/
|
||||||
|
.section .text
|
||||||
|
.global _start
|
||||||
|
.type _start, @function
|
||||||
|
_start:
|
||||||
|
# set the position of `%esp' to the top of the stack
|
||||||
|
mov $stack_top, %esp
|
||||||
|
|
||||||
|
# GDT, paging, and other features
|
||||||
|
flush_gdt:
|
||||||
|
cli
|
||||||
|
lgdt (gdtr)
|
||||||
|
movw $0x10, %ax
|
||||||
|
movw %ax, %ds
|
||||||
|
movw %ax, %es
|
||||||
|
movw %ax, %fs
|
||||||
|
movw %ax, %gs
|
||||||
|
movw %ax, %ss
|
||||||
|
ljmp $0x08, $flush_end
|
||||||
|
flush_end:
|
||||||
|
|
||||||
|
boot_kernel:
|
||||||
|
# enter high-level kernel (C)
|
||||||
|
call kernel_main
|
||||||
|
|
||||||
|
# put computer into infinite loop
|
||||||
|
cli # disable interrupts by clearing the interrupt flag in `eflags'
|
||||||
|
end_loop:
|
||||||
|
hlt # wait for next interrupt
|
||||||
|
jmp end_loop # jump to the `hlt' instruction if it ever leaves it
|
||||||
|
|
||||||
|
.size _start, . - _start
|
33
src/kernel/arch/x86/linker.ld
Normal file
33
src/kernel/arch/x86/linker.ld
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
ENTRY(_start)
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
/* put sections at 1 MiB as is conventional for kernels */
|
||||||
|
. = 1M;
|
||||||
|
|
||||||
|
/* place multiboot header early for boot loader and then `.text' section */
|
||||||
|
.text BLOCK(4K) : ALIGN(4K)
|
||||||
|
{
|
||||||
|
*(.multiboot)
|
||||||
|
*(.text)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read-only data */
|
||||||
|
.rodata BLOCK(4K) : ALIGN(4K)
|
||||||
|
{
|
||||||
|
*(.rodata)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read-write data (initialized) */
|
||||||
|
.data BLOCK(4K) : ALIGN(4K)
|
||||||
|
{
|
||||||
|
*(.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read-write data (uninitialized) and stack */
|
||||||
|
.bss BLOCK(4K) : ALIGN(4K)
|
||||||
|
{
|
||||||
|
*(COMMON)
|
||||||
|
*(.bss)
|
||||||
|
}
|
||||||
|
}
|
84
src/kernel/arch/x86/tty.c
Normal file
84
src/kernel/arch/x86/tty.c
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <kernel/tty.h>
|
||||||
|
|
||||||
|
#include "vga.h"
|
||||||
|
|
||||||
|
#define VGA_WIDTH 80
|
||||||
|
#define VGA_HEIGHT 25
|
||||||
|
#define VGA_MEMORY 0xb8000
|
||||||
|
|
||||||
|
|
||||||
|
static size_t tty_row;
|
||||||
|
static size_t tty_col;
|
||||||
|
static uint8_t tty_color;
|
||||||
|
static uint16_t *tty_buffer;
|
||||||
|
|
||||||
|
void tty_init() {
|
||||||
|
tty_row = 0;
|
||||||
|
tty_col = 0;
|
||||||
|
tty_color = vga_entry_color(VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK);
|
||||||
|
tty_buffer = (uint16_t*) VGA_MEMORY;
|
||||||
|
for(size_t y = 0; y < VGA_HEIGHT; ++y)
|
||||||
|
{
|
||||||
|
for(size_t x = 0; x < VGA_WIDTH; ++x)
|
||||||
|
{
|
||||||
|
const size_t index = GET_INDEX(x, y);
|
||||||
|
tty_buffer[index] = vga_entry(' ', tty_color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void tty_setcolor(uint8_t color) {
|
||||||
|
tty_color = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tty_putentryat(unsigned char c, uint8_t color, size_t x, size_t y) {
|
||||||
|
const size_t index = GET_INDEX(x, y);
|
||||||
|
tty_buffer[index] = vga_entry(c, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tty_scroll_down() {
|
||||||
|
// clear first line
|
||||||
|
for(size_t x = 0; x < VGA_WIDTH; ++x)
|
||||||
|
{
|
||||||
|
const size_t i = GET_INDEX(x, 0);
|
||||||
|
tty_buffer[i] = vga_entry(' ', tty_color);
|
||||||
|
}
|
||||||
|
|
||||||
|
// scroll text
|
||||||
|
for(size_t y = 1; y < VGA_HEIGHT; ++y)
|
||||||
|
{
|
||||||
|
for(size_t x = 0; x < VGA_WIDTH; ++x)
|
||||||
|
{
|
||||||
|
const size_t srci = GET_INDEX(x, y);
|
||||||
|
const size_t dsti = GET_INDEX(x, y - 1);
|
||||||
|
tty_buffer[dsti] = tty_buffer[srci];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void tty_putchar(unsigned char c) {
|
||||||
|
tty_putentryat(c, tty_color, tty_col, tty_row);
|
||||||
|
if(++tty_col == VGA_WIDTH)
|
||||||
|
{
|
||||||
|
tty_col = 0;
|
||||||
|
if(tty_row + 1 == VGA_HEIGHT)
|
||||||
|
tty_scroll_down();
|
||||||
|
else
|
||||||
|
tty_row++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void tty_write(const char *data, size_t size) {
|
||||||
|
for(size_t i = 0; i < size; ++i)
|
||||||
|
tty_putchar(data[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tty_write_s(const char *str) {
|
||||||
|
size_t len = 0;
|
||||||
|
while(str[len])
|
||||||
|
len++;
|
||||||
|
tty_write(str, len);
|
||||||
|
}
|
31
src/kernel/arch/x86/vga.h
Normal file
31
src/kernel/arch/x86/vga.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#define GET_INDEX(x, y) y * VGA_WIDTH + x
|
||||||
|
|
||||||
|
enum vga_color {
|
||||||
|
VGA_COLOR_BLACK = 0x0,
|
||||||
|
VGA_COLOR_BLUE = 0x1,
|
||||||
|
VGA_COLOR_GREEN = 0x2,
|
||||||
|
VGA_COLOR_CYAN = 0x3,
|
||||||
|
VGA_COLOR_RED = 0x4,
|
||||||
|
VGA_COLOR_MAGENTA = 0x5,
|
||||||
|
VGA_COLOR_BROWN = 0x6,
|
||||||
|
VGA_COLOR_LIGHT_GREY = 0x7,
|
||||||
|
VGA_COLOR_DARK_GREY = 0x8,
|
||||||
|
VGA_COLOR_LIGHT_BLUE = 0x9,
|
||||||
|
VGA_COLOR_LIGHT_GREEN = 0xA,
|
||||||
|
VGA_COLOR_LIGHT_CYAN = 0xB,
|
||||||
|
VGA_COLOR_LIGHT_RED = 0xC,
|
||||||
|
VGA_COLOR_LIGHT_MAGENTA = 0xD,
|
||||||
|
VGA_COLOR_LIGHT_BROWN = 0xE,
|
||||||
|
VGA_COLOR_WHITE = 0xF,
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline uint8_t vga_entry_color(enum vga_color fg, enum vga_color bg) {
|
||||||
|
return fg | bg << 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint16_t vga_entry(unsigned char c, uint8_t color) {
|
||||||
|
return (uint16_t) c | (uint16_t) color << 8;
|
||||||
|
}
|
6
src/kernel/kernel.c
Normal file
6
src/kernel/kernel.c
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#include <kernel/tty.h>
|
||||||
|
|
||||||
|
void kernel_main() {
|
||||||
|
tty_init();
|
||||||
|
tty_write_s("Hello from the kernel!");
|
||||||
|
}
|
21
src/kernel/ports.h
Normal file
21
src/kernel/ports.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
static inline void outb(uint16_t port, uint8_t data) {
|
||||||
|
__asm__("outb %%al, %%dx" : : "a" (data), "d" (port));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void outw(uint16_t port, uint16_t data) {
|
||||||
|
__asm__("outw %%ax, %%dx" : : "a" (data), "d" (port));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint8_t inb(uint16_t port) {
|
||||||
|
uint8_t res;
|
||||||
|
__asm__("inb %%dx, %%al" : "=a" (res) : "d" (port));
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint16_t inw(uint16_t port) {
|
||||||
|
uint16_t res;
|
||||||
|
__asm__("inw %%dx, %%ax" : "=a" (res) : "d" (port));
|
||||||
|
return res;
|
||||||
|
}
|
3
src/kernel/system.h
Normal file
3
src/kernel/system.h
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
static inline void abort() {
|
||||||
|
while(1);
|
||||||
|
}
|
8
src/kernel/tty.h
Normal file
8
src/kernel/tty.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
void tty_init();
|
||||||
|
void tty_putchar(unsigned char c);
|
||||||
|
void tty_write(const char *data, size_t size);
|
||||||
|
void tty_write_s(const char *str);
|
Loading…
Reference in New Issue
Block a user