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