Fixed paging fully now. Kernel is loaded with virtual memory enabled. Just need to write an allocator and make kernel use virtual memory addresses for its stuff. Restructured codebase to be less messy. Updated Makefile to put binary files under build/ rather than in root directory

This commit is contained in:
Xnoe 2021-10-11 20:47:04 +01:00
parent 6328062d4f
commit 1225529708
Signed by: xnoe
GPG Key ID: 45AC398F44F0DAFE
18 changed files with 585 additions and 58 deletions

View File

@ -1,45 +1,49 @@
CFLAGS = -m32 -mgeneral-regs-only -nostdlib -fno-builtin -fno-exceptions -fno-leading-underscore -fno-pie -fno-stack-protector -Wno-pointer-to-int-cast
LDFLAGS =
DISK_IMG_FILES = kernel.bin
KERNEL32_OBJS = screenstuff.o io.o idt.o keyboard.o strings.o atapio.o c_code_entry.o kernel.o paging.o
DISK_IMG_FILES = build/kernel/kernel.bin
KERNEL_OBJS = build/c_code_entry.o build/kernel/screenstuff.o build/kernel/io.o build/kernel/idt.o build/kernel/keyboard.o build/kernel/strings.o build/kernel/atapio.o build/kernel/kernel.o build/kernel/paging.o
STAGE2_OBS = build/c_code_entry.o build/boot_stage2/io.o build/boot_stage2/atapio.o build/boot_stage2/strings.o build/boot_stage2/screenstuff.o build/boot_stage2/stage2.o build/boot_stage2/paging.o
run: disk.img
qemu-system-x86_64 disk.img
disk.img: clean boot.sector boot.stage2 $(DISK_IMG_FILES)
disk.img: clean prepare build/boot/boot.bin build/boot_stage2/boot.bin $(DISK_IMG_FILES)
dd if=/dev/zero of=disk.img count=43 bs=100k
dd if=boot.sector of=disk.img conv=notrunc
dd obs=512 seek=1 if=boot.stage2 of=disk.img conv=notrunc
dd if=build/boot/boot.bin of=disk.img conv=notrunc
dd obs=512 seek=1 if=build/boot_stage2/boot.bin of=disk.img conv=notrunc
mount disk.img img.d
cp *.bin img.d/
cp $(DISK_IMG_FILES) img.d/
cp hello.txt img.d/
umount img.d
chmod 777 disk.img
prepare:
mkdir -p img.d
mkdir -p build/boot
mkdir -p build/boot_stage2
mkdir -p build/kernel
clean:
rm $(DISK_IMG_FILES) $(KERNEL32_OBJS) boot.sector disk.img || true
rm -rf build
boot.sector: boot.asm
build/boot/boot.bin: src/boot/boot.asm
nasm $< -o $@
boot.stage2: boot_stage2.ld boot.stage2.o
ld $(LDFLAGS) -T $< boot.stage2.o
build/boot_stage2/boot.bin: src/boot_stage2/boot_stage2.ld $(STAGE2_OBS)
ld $(LDFLAGS) -T $< $(STAGE2_OBS)
boot.stage2.o: src/boot_stage2/main.c io.o atapio.o strings.o c_code_entry.o screenstuff.o paging.o
build/kernel/kernel.bin: src/kernel/kernel.ld $(KERNEL_OBJS)
ld $(LDFLAGS) -T $< $(KERNEL_OBJS)
build/boot_stage2/stage2.o: src/boot_stage2/main.c
gcc $(CFLAGS) -o $@ -c $<
%.bin: %.asm
nasm $< -o $@
kernel.bin: kernel.ld $(KERNEL32_OBJS)
ld $(LDFLAGS) -T $< $(KERNEL32_OBJS)
%.o: src/kernel/%.asm
nasm -felf32 $< -o $@
%.o: src/%.asm
nasm -felf32 $< -o $@
%.o: src/kernel/%.c
build/kernel/%.o: src/kernel/%.c
gcc $(CFLAGS) -o $@ -c $<
build/boot_stage2/%.o: src/boot_stage2/%.c
gcc $(CFLAGS) -o $@ -c $<
build/%.o: src/%.asm
nasm -felf32 $< -o $@

View File

@ -1,15 +0,0 @@
OUTPUT_FORMAT(binary)
OUTPUT_ARCH(i386:i386)
INPUT(io.o atapio.o strings.o c_code_entry.o screenstuff.o paging.o)
OUTPUT(boot.stage2)
SECTIONS {
. = 0x7E00;
.text : {
c_code_entry.o(.text)
boot.stage2.o(.text)
*(.text)
}
}

View File

@ -1,15 +0,0 @@
OUTPUT_FORMAT(binary)
OUTPUT_ARCH(i386:i386)
OUTPUT(kernel.bin)
SECTIONS {
. = 0xc0000000;
.text : {
c_code_entry.o(.text)
kernel.o(.text)
*(.text)
heap_section = .;
}
}

122
src/boot_stage2/atapio.c Normal file
View File

@ -0,0 +1,122 @@
#include "atapio.h"
// Disk code
// Primary ATA Bus: 0x1f0 to 0x1f7
// Device Control Register: 0x3f6
// Secondary ATA Bus: 0x170 to 0x177
// Device Control Register: 0x376
uint16_t identify_result[256];
uint32_t total_28_lbas = 0;
uint8_t* rootDirEntries = 0x1000000;
uint16_t* FAT1 = 0x1002000;
uint16_t countReserved;
uint8_t countFATs;
uint16_t countRDEs;
uint16_t sectorsPerFAT;
void init_atapio() {
countReserved = *(uint16_t*)0x7c0e;
countFATs = *(uint8_t*)0x7c10;
countRDEs = *(uint16_t*)0x7c11;
sectorsPerFAT = *(uint16_t*)0x7c16;
// Select Drive 0 on the Primary Bus
outb(0x1f6, 0xa0);
// Set sector count to 0 for IDENTIFY
outb(0x1f2, 0);
// Set LBAlo to 0
outb(0x1f3, 0);
// Set LBAmid to 0
outb(0x1f4, 0);
// Set LBAhi to 0
outb(0x1f5, 0);
// Send IDENTIFY command
outb(0x1f7, 0xec);
uint8_t status = inb(0x1f7);
if (status) {
while ((status = inb(0x1f7)) & 0x80);
if ( !(inb(0x1f4) || inb(0x1f5)) ) {
while ( !(status & 8 || status & 1) )
status = inb(0x1f7);
if (!(status & 1)) {
for (int index=0; index<256; index++)
identify_result[index] = inw(0x1f0);
}
}
}
total_28_lbas = *(uint32_t*)(identify_result+60);
// We've initialised now, let's load the FAT and RootDirEntries.
read_sectors(sectorsPerFAT * countFATs + countReserved, countRDEs / 16, rootDirEntries);
read_sectors(countReserved, sectorsPerFAT, FAT1);
}
void read_sector(uint32_t address, uint8_t* buffer) {
outb(0x1f6, 0xe0 | ((address>>24)&0x0f));
// Read a single sector
outb(0x1f2, 1);
// Set LBAlo, LBAmid and LBAhi
outb(0x1f3, address);
outb(0x1f4, address>>8);
outb(0x1f5, address>>16);
// Send read command
outb(0x1f7, 0x20);
// Poll
uint8_t status = inb(0x1f7);
while ( (status & 0x80) && !(status & 8) )
status = inb(0x1f7);
for (int index=0; index<256; index++)
((uint16_t*)buffer)[index] = inw(0x1f0);
}
void read_sectors(uint32_t address, int count, uint8_t* buffer) {
for (int i=0; i<count; i++) {
read_sector(address+i, buffer+512*i);
for (int i=0; i<15; i++)
inb(0x1f7);
}
}
uint16_t file_exists(char* filename) {
for (int i=0; i<countRDEs; i++) {
bool found = strcmp(rootDirEntries+(i*32), filename, 11);
if (found) {
uint16_t* correctEntry = (rootDirEntries+(i*32));
return correctEntry[13];
}
}
return 0;
}
void load_file(char* filename, uint8_t* destination) {
uint16_t location = file_exists(filename);
if (!location)
return;
int offset = 0;
bool loaded = false;
while (!loaded) {
uint16_t fromSector = location + (sectorsPerFAT * countFATs) + (countRDEs / 16) + (countReserved - 1) - 1;
read_sector(fromSector, destination+offset);
offset += 512;
location = FAT1[location++];
if (location == 0xffff)
loaded = true;
}
}

16
src/boot_stage2/atapio.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef ATA_PIO
#define ATA_PIO
#include <stdbool.h>
#include "io.h"
#include "types.h"
#include "strings.h"
void init_atapio();
void read_sector(uint32_t address, uint8_t* buffer);
void read_sectors(uint32_t address, int count, uint8_t* buffer);
uint16_t file_exists(char* filename);
void load_file(char* filename, uint8_t* location);
#endif

View File

@ -0,0 +1,14 @@
OUTPUT_FORMAT(binary)
OUTPUT_ARCH(i386:i386)
OUTPUT(build/boot_stage2/boot.bin)
SECTIONS {
. = 0x7E00;
.text : {
build/c_code_entry.o(.text)
build/boot_stage2/stage2.o(.text)
build/boot_stage2/*(.text)
}
}

19
src/boot_stage2/io.c Normal file
View File

@ -0,0 +1,19 @@
#include "io.h"
void outb(uint16_t portnumber, uint8_t data) {
asm volatile("outb %0, %1" : : "a" (data), "Nd" (portnumber));
}
uint8_t inb(uint16_t portnumber) {
uint8_t result;
asm volatile("inb %1, %0" : "=a" (result) : "Nd" (portnumber));
return result;
}
void outw(uint16_t portnumber, uint16_t data) {
asm volatile("outw %0, %1" : : "a" (data), "Nd" (portnumber));
}
uint16_t inw(uint16_t portnumber) {
uint16_t result;
asm volatile("inw %1, %0" : "=a" (result) : "Nd" (portnumber));
return result;
}

12
src/boot_stage2/io.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef IO_H
#define IO_H
#include "types.h"
void outb(uint16_t portnumber, uint8_t data);
uint8_t inb(uint16_t portnumber);
void outw(uint16_t portnumber, uint16_t data);
uint16_t inw(uint16_t portnumber);
#endif

View File

@ -1,6 +1,6 @@
#include "../kernel/atapio.h"
#include "../kernel/screenstuff.h"
#include "../kernel/paging.h"
#include "atapio.h"
#include "screenstuff.h"
#include "paging.h"
typedef struct {
uint32_t base_low;
@ -120,7 +120,8 @@ void main() {
map_many_4k_phys_to_virt(0x121000, 0xc0101000, kernel_page_directory, kernel_page_tables, 1024); // Map 1024 pages from 0x121000 to 0xc0101000
map_4k_phys_to_virt(0xb8000, 0xc0501000, kernel_page_directory, kernel_page_tables); // Map 0xb8000 (video) to 0xc0501000
map_4k_phys_to_virt(0x8000, 0x8000, kernel_page_directory, kernel_page_tables);
map_many_4k_phys_to_virt(0x7000, 0x7000, kernel_page_directory, kernel_page_tables, 2);
map_4k_phys_to_virt(0x8f000, 0x8f000, kernel_page_directory, kernel_page_tables);
load_file("KERNEL BIN", kernel_location);

46
src/boot_stage2/paging.c Normal file
View File

@ -0,0 +1,46 @@
#include "paging.h"
typedef struct {
uint32_t page_offset : 12;
uint32_t pt_index : 10;
uint32_t pd_index : 10;
}__attribute__((packed)) split_addr;
void map_4k_phys_to_virt(uint32_t physical, uint32_t virtual, PDE* page_directory, PTE** page_tables) {
split_addr* split = (split_addr*)&virtual;
page_directory[split->pd_index] = (PDE){
.address = (uint32_t)(page_tables[split->pd_index]) >> 12,
.available = 0,
.page_4mb = 0,
.accessed = 0,
.disable_cache = 0,
.write_through_cache = 0,
.privilege = 0,
.present = 1,
.read_write = 1,
.ignored = 0,
.ignored2 = 0
};
page_tables[split->pd_index][split->pt_index] = (PTE){
.address = physical >> 12,
.available = 0,
.global = 0,
.accessed = 0,
.disable_cache = 0,
.dirty = 0,
.write_through_cache = 0,
.privilege = 0,
.present = 1,
.read_write = 1,
.ignored = 0
};
}
void map_many_4k_phys_to_virt(uint32_t physical, uint32_t virtual, PDE* page_directory, PTE** page_tables, uint32_t count) {
for (int i=0; i<count; i++)
map_4k_phys_to_virt(physical + 4096*i, virtual + 4096*i, page_directory, page_tables);
}

37
src/boot_stage2/paging.h Normal file
View File

@ -0,0 +1,37 @@
#ifndef PAGING_H
#define PAGING_H
#include <stdbool.h>
#include "types.h"
typedef struct {
uint32_t present : 1;
uint32_t read_write : 1;
uint32_t privilege : 1;
uint32_t write_through_cache : 1;
uint32_t disable_cache : 1;
uint32_t accessed : 1;
uint32_t ignored2 : 1;
uint32_t page_4mb : 1;
uint32_t ignored : 1;
uint32_t available : 3;
uint32_t address : 20;
}__attribute__((packed)) PDE;
typedef struct {
uint32_t present : 1;
uint32_t read_write : 1;
uint32_t privilege : 1;
uint32_t write_through_cache : 1;
uint32_t disable_cache : 1;
uint32_t accessed : 1;
uint32_t dirty : 1;
uint32_t ignored : 1;
uint32_t global : 1;
uint32_t available : 3;
uint32_t address : 20;
}__attribute__((packed)) PTE;
void map_4k_phys_to_virt(uint32_t physical, uint32_t virtual, PDE* page_directory, PTE** page_tables);
void map_many_4k_phys_to_virt(uint32_t physical, uint32_t virtual, PDE* page_directory, PTE** page_tables, uint32_t count);
#endif

View File

@ -0,0 +1,161 @@
#include "screenstuff.h"
uint16_t* VMEM_ADDR = (uint16_t*)0xb8000;
const int TERM_WIDTH = 80;
const int TERM_HEIGHT = 25;
int cursor_x = 0;
int cursor_y = 0;
uint16_t get_curpos() {
uint16_t cursor_position = 0;
uint8_t* cursor_position_split = (uint8_t*)&cursor_position;
outb(0x3D4, 0x0F);
cursor_position_split[0] = inb(0x3D5);
outb(0x3D4, 0x0E);
cursor_position_split[1] = inb(0x3D5);
return cursor_position;
}
void init_term() {
uint16_t cursor_position = get_curpos();
cursor_y = cursor_position / TERM_WIDTH;
cursor_x = cursor_position % TERM_WIDTH;
}
void clear_screen() {
for (int i=0; i<TERM_WIDTH*TERM_HEIGHT; i++) {
VMEM_ADDR[i] = 0x0720;
}
}
void clear_line(int line) {
for (int x=0; x<TERM_WIDTH; x++) {
VMEM_ADDR[TERM_WIDTH*line + x] = 0x0720;
}
}
void set_curpos_raw(int curpos) {
uint8_t* cursor_position_split = (uint8_t*)&curpos;
outb(0x3D4, 0x0F);
outb(0x3D5, cursor_position_split[0]);
outb(0x3D4, 0x0E);
outb(0x3D5, cursor_position_split[1]);
cursor_x = (*(uint16_t*)cursor_position_split) % TERM_WIDTH;
cursor_y = (*(uint16_t*)cursor_position_split) / TERM_WIDTH;
}
void set_curpos(int x, int y) {
set_curpos_raw(y * TERM_WIDTH + x);
cursor_x = x;
cursor_y = y;
}
int int_to_decimal(unsigned int number, char* string_buffer) {
for (int i=0; i<11; i++)
string_buffer[i] = 0;
int index = 9;
unsigned int acc = number;
if (acc == 0)
string_buffer[index--] = '0';
while (acc != 0) {
string_buffer[index--] = 0x30+(acc%10);
acc /= 10;
}
return (index+1);
}
char dec_to_hex[16] = "0123456789abcdef";
int int_to_hex(unsigned int number, char* string_buffer) {
for (int i=0; i<8; i++)
string_buffer[i] = '0';
string_buffer[8] = 0;
int index = 7;
unsigned int acc = number;
if (acc == 0)
string_buffer[index--] = '0';
while (acc != 0) {
string_buffer[index--] = dec_to_hex[acc%0x10];
acc /= 0x10;
}
return (index+1);
}
void printf(const char* string, ...) {
va_list ptr;
va_start(ptr, string);
int index = 0;
int count = 0;
char current;
while (current=string[index++]) {
count++;
if (current == '\n') {
cursor_x = 0;
cursor_y++;
}
if (cursor_x == TERM_WIDTH) {
cursor_x = 0;
cursor_y++;
}
if (cursor_y == TERM_HEIGHT) {
for (int i=1; i<TERM_HEIGHT; i++) {
for (int x=0; x<TERM_WIDTH; x++) {
int from = i * TERM_WIDTH + x;
int to = (i-1) * TERM_WIDTH + x;
VMEM_ADDR[to] = VMEM_ADDR[from];
}
}
clear_line(24);
cursor_y--;
}
if (current == '%') {
int type = string[index++];
int offset;
switch (type) {
case 'd':
char decimal_buffer[11];
offset = int_to_decimal(va_arg(ptr, int), decimal_buffer);
printf(decimal_buffer + offset);
break;
case 'x':
char hex_buffer[8];
offset = int_to_hex(va_arg(ptr, int), hex_buffer);
printf(hex_buffer);
break;
case 's':
printf(va_arg(ptr, const char*));
break;
case 'c':
int mem_pos = cursor_y * TERM_WIDTH + cursor_x++;
int promoted = va_arg(ptr, int);
char charred = promoted;
VMEM_ADDR[mem_pos] = charred + (0x07<<8);
break;
}
continue;
}
if (current != '\n') {
int mem_pos = cursor_y * TERM_WIDTH + cursor_x++;
VMEM_ADDR[mem_pos] = current + (0x07<<8);
}
}
set_curpos(cursor_x, cursor_y);
va_end(ptr);
}
void non_moving_put(char chr) {
int mem_pos = cursor_y * TERM_WIDTH + cursor_x;
VMEM_ADDR[mem_pos] = chr + (0x07<<8);
}

View File

@ -0,0 +1,19 @@
#ifndef SCREENSTUFF_H
#define SCREENSTUFF_H
#include <stdarg.h>
#include "types.h"
#include "io.h"
uint16_t get_curpos();
void init_term();
void clear_screen();
void clear_line(int line);
void set_curpos_raw(int curpos);
void set_curpos(int x, int y);
int int_to_decimal(unsigned int number, char* string_buffer);
int int_to_hex(unsigned int number, char* string_buffer);
void printf(const char* string, ...);
void non_moving_put(char chr);
#endif

69
src/boot_stage2/strings.c Normal file
View File

@ -0,0 +1,69 @@
#include "strings.h"
bool strcmp(char* a, char* b, int max) {
int index = 0;
while (index < max) {
if (a[index] != b[index])
return false;
index++;
}
return true;
}
char* split_on_first(char delimeter, char* string) {
int index = 0;
char current;
while (current = string[index++]) {
if (current == delimeter) {
string[index-1] = 0;
return string+index;
}
}
return 0;
}
int string_split(char delimeter, char* string, char** pointer_array) {
int index = 0;
int last_split_index = 0;
int split_count = 0;
char current;
while (current = string[index]) {
if (current == delimeter) {
string[index] = 0;
pointer_array[split_count++] = (string+last_split_index);
last_split_index = (index+1);
}
index++;
}
// Add remaining part of the string to the pointer_array
pointer_array[split_count] = (string+last_split_index);
return split_count;
}
void decode_filename(char* nice_name, char* filenamebuffer) {
// Clear filenamebuffer
for (int i=0; i<11; i++)
filenamebuffer[i] = ' ';
filenamebuffer[11] = 0;
int fbIndex = 0;
for (int i=0; i<12; i++) {
if (nice_name[i] == 0)
return;
if (nice_name[i] == '.') {
fbIndex = 8;
continue;
}
if (nice_name[i] >= 0x61 && nice_name[i] <= 0x7f)
filenamebuffer[fbIndex++] = nice_name[i] - 32;
else
filenamebuffer[fbIndex++] = nice_name[i];
}
}

11
src/boot_stage2/strings.h Normal file
View File

@ -0,0 +1,11 @@
#ifndef STRINGS_H
#define STRINGS_H
#include <stdbool.h>
bool strcmp(char* a, char* b, int max);
char* split_on_first(char delimeter, char* string);
int string_split(char delimeter, char* string, char** pointer_array);
void decode_filename(char* nice_name, char* filenamebuffer);
#endif

11
src/boot_stage2/types.h Normal file
View File

@ -0,0 +1,11 @@
#ifndef TYPES_H
#define TYPES_H
typedef char int8_t;
typedef unsigned char uint8_t;
typedef short int16_t;
typedef unsigned short uint16_t;
typedef long int int32_t;
typedef unsigned long int uint32_t;
#endif

15
src/kernel/kernel.ld Normal file
View File

@ -0,0 +1,15 @@
OUTPUT_FORMAT(binary)
OUTPUT_ARCH(i386:i386)
OUTPUT(build/kernel/kernel.bin)
SECTIONS {
. = 0xc0000000;
.text : {
build/c_code_entry.o(.text)
build/kernel/kernel.o(.text)
build/kernel/*(.text)
heap_section = .;
}
}