Initial commit.

This commit is contained in:
Nicolás Ortega Froysa 2018-03-08 16:53:29 +01:00
commit a3c817412e
No known key found for this signature in database
GPG Key ID: FEC70E3BAE2E69BF
11 changed files with 352 additions and 0 deletions

7
.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
# ignore binary files
*.bin
*.o
*.iso
# ignore build files
isodir

44
Makefile Normal file
View 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
View File

@ -0,0 +1,3 @@
menuentry "UntrueOS" {
multiboot /boot/untrue.bin
}

112
src/kernel/arch/x86/boot.s Normal file
View 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

View 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
View 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
View 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
View 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
View 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
View File

@ -0,0 +1,3 @@
static inline void abort() {
while(1);
}

8
src/kernel/tty.h Normal file
View 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);