Initial commit.
This commit is contained in:
		
							
								
								
									
										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;
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user