Squash commits for public release

This commit is contained in:
2025-02-12 09:54:05 -05:00
commit 7118adc514
1108 changed files with 80873 additions and 0 deletions

24
boot/x86/stage2/config.h Normal file
View File

@@ -0,0 +1,24 @@
#ifndef STAGE2_CONFIG
#define STAGE2_CONFIG
#include <libboot/types.h>
#define KERNEL_BASE 0x100000
struct x86_memory_map {
uint32_t startLo;
uint32_t startHi;
uint32_t sizeLo;
uint32_t sizeHi;
uint32_t type;
uint32_t acpi_3_0;
};
typedef struct x86_memory_map x86_memory_map_t;
struct x86_mem_desc {
uint32_t memory_map_size;
uint32_t kernel_size;
};
typedef struct x86_mem_desc x86_mem_desc_t;
#endif // STAGE2_CONFIG

View File

@@ -0,0 +1,135 @@
/**
* Ata Stage2 driver. This is a lite version, since it can work with
* only one drive at time. The @active_ata_drive is a boot drive.
*/
#include "ata.h"
#include <libboot/log/log.h>
// #define DEBUG_ATA
ata_t active_ata_drive;
void init_ata(uint32_t port, char is_master)
{
active_ata_drive.is_master = is_master;
active_ata_drive.data_port = port;
active_ata_drive.error_port = port + 0x1;
active_ata_drive.sector_count_port = port + 0x2;
active_ata_drive.lba_lo_port = port + 0x3;
active_ata_drive.lba_mid_port = port + 0x4;
active_ata_drive.lba_hi_port = port + 0x5;
active_ata_drive.device_port = port + 0x6;
active_ata_drive.command_port = port + 0x7;
active_ata_drive.control_port = port + 0x206;
}
int indentify_ata_device(drive_desc_t* drive_desc)
{
port_write8(active_ata_drive.device_port, active_ata_drive.is_master ? 0xA0 : 0xB0);
port_write8(active_ata_drive.sector_count_port, 0);
port_write8(active_ata_drive.lba_lo_port, 0);
port_write8(active_ata_drive.lba_mid_port, 0);
port_write8(active_ata_drive.lba_hi_port, 0);
port_write8(active_ata_drive.command_port, 0xEC);
// check the acceptance of a command
uint8_t status = port_read8(active_ata_drive.command_port);
if (status == 0x00) {
// printf("Cmd isn't accepted");
return -1;
}
// waiting for processing
// while BSY is on
while ((status & 0x80) == 0x80) {
status = port_read8(active_ata_drive.command_port);
}
// check if drive isn't ready to transer DRQ
if ((status & 0x08) != 0x08) {
// printf("Don't ready for transport");
return -1;
}
// transfering 256 bytes of data
for (int i = 0; i < 256; i++) {
uint16_t data = port_read16(active_ata_drive.data_port);
char* text = " \0";
text[0] = (data >> 8) & 0xFF;
text[1] = data & 0xFF;
if (i == 1) {
#ifdef DEBUG_ATA
log("Logical cylindres %x", data);
#endif
}
if (i == 3) {
#ifdef DEBUG_ATA
log("Logical heads %x", data);
#endif
}
if (i == 6) {
#ifdef DEBUG_ATA
log("Logical sectors %x", data);
#endif
}
if (i == 49) {
if (((data >> 8) & 0x1) == 1) {
#ifdef DEBUG_ATA
log("Dma supported");
#endif
}
if (((data >> 9) & 0x1) == 1) {
#ifdef DEBUG_ATA
log("Lba supported");
#endif
}
}
}
drive_desc->read = ata_read;
return 0;
}
// Returning 2 head read bytes (used to get size of kernel)
int ata_read(uint32_t sector, uint8_t* read_to)
{
uint8_t dev_config = 0xA0;
// lba support
dev_config |= (1 << 6);
if (!active_ata_drive.is_master) {
dev_config |= (1 << 4);
}
port_write8(active_ata_drive.device_port, dev_config);
port_write8(active_ata_drive.sector_count_port, 1);
port_write8(active_ata_drive.lba_lo_port, sector & 0x000000FF);
port_write8(active_ata_drive.lba_mid_port, (sector & 0x0000FF00) >> 8);
port_write8(active_ata_drive.lba_hi_port, (sector & 0x00FF0000) >> 16);
port_write8(active_ata_drive.error_port, 0);
port_write8(active_ata_drive.command_port, 0x21);
// waiting for processing
// while BSY is on and no Errors
uint8_t status = port_read8(active_ata_drive.command_port);
while (((status >> 7) & 1) == 1 && ((status >> 0) & 1) != 1) {
status = port_read8(active_ata_drive.command_port);
}
// check if drive isn't ready to transer DRQ
if (((status >> 0) & 1) == 1) {
return -1;
}
if (((status >> 3) & 1) == 0) {
return -1;
}
for (int i = 0; i < 256; i++) {
uint16_t data = port_read16(active_ata_drive.data_port);
read_to[2 * i + 1] = (data >> 8) & 0xFF;
read_to[2 * i] = data & 0xFF;
}
return 0;
}

View File

@@ -0,0 +1,25 @@
#ifndef _BOOT_X86_STAGE2_DRIVERS_ATA_H
#define _BOOT_X86_STAGE2_DRIVERS_ATA_H
#include "port.h"
#include <libboot/abi/drivers.h>
#include <libboot/types.h>
typedef struct { // LBA28 | LBA48
uint32_t data_port; // 16bit | 16 bits
uint32_t error_port; // 8 bit | 16 bits
uint32_t sector_count_port; // 8 bit | 16 bits
uint32_t lba_lo_port; // 8 bit | 16 bits
uint32_t lba_mid_port; // 8 bit | 16 bits
uint32_t lba_hi_port; // 8 bit | 16 bits
uint32_t device_port; // 8 bit
uint32_t command_port; // 8 bit
uint32_t control_port; // 8 bit
char is_master;
} ata_t;
void init_ata(uint32_t port, char is_master);
int indentify_ata_device(drive_desc_t* drive_desc);
int ata_read(uint32_t sector, uint8_t* read_to);
#endif

View File

@@ -0,0 +1,56 @@
#include "port.h"
unsigned char port_read8(unsigned short port)
{
unsigned char result_data;
asm volatile("inb %%dx, %%al"
: "=a"(result_data)
: "d"(port));
return result_data;
}
void port_write8(unsigned short port, unsigned char data)
{
asm volatile("outb %%al, %%dx"
:
: "a"(data), "d"(port));
}
unsigned short port_read16(unsigned short port)
{
unsigned short result_data;
asm volatile("inw %%dx, %%ax"
: "=a"(result_data)
: "d"(port));
return result_data;
}
void port_write16(unsigned short port, unsigned short data)
{
asm volatile("outw %%ax, %%dx"
:
: "a"(data), "d"(port));
}
unsigned int port_read32(unsigned short port)
{
unsigned int result_data;
asm volatile("inl %%dx, %%eax"
: "=a"(result_data)
: "d"(port));
return result_data;
}
void port_write32(unsigned short port, unsigned int data)
{
asm volatile("outl %%eax, %%dx"
:
: "a"(data), "d"(port));
}
void port_wait_io()
{
asm volatile("out %%al, $0x80"
:
: "a"(0)); // writing to "unused" port
}

View File

@@ -0,0 +1,15 @@
#ifndef _BOOT_X86_STAGE2_DRIVERS_PORT_H
#define _BOOT_X86_STAGE2_DRIVERS_PORT_H
unsigned char port_read8(unsigned short port);
void port_write8(unsigned short port, unsigned char data);
unsigned short port_read16(unsigned short port);
void port_write16(unsigned short port, unsigned short data);
unsigned int port_read32(unsigned short port);
void port_write32(unsigned short port, unsigned int data);
void port_wait_io();
#endif // _BOOT_X86_STAGE2_DRIVERS_PORT_H

View File

@@ -0,0 +1,36 @@
#include "uart.h"
#include "port.h"
static int _uart_setup_impl(int port)
{
port_write8(port + 1, 0x00);
port_write8(port + 3, 0x80);
port_write8(port + 0, 0x03);
port_write8(port + 1, 0x00);
port_write8(port + 3, 0x03);
port_write8(port + 2, 0xC7);
port_write8(port + 4, 0x0B);
return 0;
}
void uart_init()
{
_uart_setup_impl(COM1);
}
static inline bool _uart_is_free_in(int port)
{
return port_read8(port + 5) & 0x01;
}
static inline bool _uart_is_free_out(int port)
{
return port_read8(port + 5) & 0x20;
}
int uart_write(uint8_t data)
{
while (!_uart_is_free_out(COM1)) { }
port_write8(COM1, data);
return 0;
}

View File

@@ -0,0 +1,14 @@
#ifndef _STAGE2_DRIVERS_X86_UART_H
#define _STAGE2_DRIVERS_X86_UART_H
#include <libboot/types.h>
#define COM1 0x3F8
#define COM2 0x2F8
#define COM3 0x3E8
#define COM4 0x2E8
void uart_init();
int uart_write(uint8_t data);
#endif //_STAGE2_DRIVERS_X86_UART_H

23
boot/x86/stage2/mem/pde.h Normal file
View File

@@ -0,0 +1,23 @@
#ifndef _BOOT_X86_STAGE2_MEM_PDE_H
#define _BOOT_X86_STAGE2_MEM_PDE_H
#include <libboot/types.h>
#define table_desc_t uint32_t
#define pde_t uint32_t
enum TABLE_DESC_PAGE_FLAGS {
TABLE_DESC_PRESENT = 0,
TABLE_DESC_WRITABLE,
TABLE_DESC_USER,
TABLE_DESC_PWT,
TABLE_DESC_PCD,
TABLE_DESC_ACCESSED,
TABLE_DESC_DIRTY,
TABLE_DESC_4MB,
TABLE_DESC_CPU_GLOBAL,
TABLE_DESC_LV4_GLOBAL,
TABLE_DESC_FRAME = 12
};
#endif //_BOOT_X86_STAGE2_MEM_PDE_H

23
boot/x86/stage2/mem/pte.h Normal file
View File

@@ -0,0 +1,23 @@
#ifndef _BOOT_X86_STAGE2_MEM_PTE_H
#define _BOOT_X86_STAGE2_MEM_PTE_H
#include <libboot/types.h>
#define page_desc_t uint32_t
#define pte_t uint32_t
enum PAGE_DESC_PAGE_FLAGS {
PAGE_DESC_PRESENT = 0,
PAGE_DESC_WRITABLE,
PAGE_DESC_USER,
PAGE_DESC_WRITETHOUGH,
PAGE_DESC_NOT_CACHEABLE,
PAGE_DESC_ACCESSED,
PAGE_DESC_DIRTY,
PAGE_DESC_PAT,
PAGE_DESC_CPU_GLOBAL,
PAGE_DESC_LV4_GLOBAL,
PAGE_DESC_FRAME = 12
};
#endif //_BOOT_X86_STAGE2_MEM_PTE_H

77
boot/x86/stage2/mem/vm.c Normal file
View File

@@ -0,0 +1,77 @@
#include "vm.h"
int vm_setup()
{
ptable_t* table_0mb = (ptable_t*)0x9A000;
ptable_t* table_0mbplus = (ptable_t*)0x98000;
ptable_t* table_3gb = (ptable_t*)0x9B000;
ptable_t* table_3gbplus = (ptable_t*)0x99000;
ptable_t* table_stack = (ptable_t*)0x9C000;
pdirectory_t* dir = (pdirectory_t*)0x9D000;
for (uint32_t phyz = 0, virt = 0, i = 0; i < 1024; phyz += VMM_PAGE_SIZE, virt += VMM_PAGE_SIZE, i++) {
pte_t new_page = 0;
new_page |= 3;
new_page |= ((phyz / VMM_PAGE_SIZE) << 12);
table_0mb->entities[i] = new_page;
}
for (uint32_t phyz = 0x400000, virt = 0x400000, i = 0; i < 1024; phyz += VMM_PAGE_SIZE, virt += VMM_PAGE_SIZE, i++) {
pte_t new_page = 0;
new_page |= 3;
new_page |= ((phyz / VMM_PAGE_SIZE) << 12);
table_0mbplus->entities[i] = new_page;
}
for (uint32_t phyz = 0x100000, virt = 0xc0000000, i = 0; i < 1024; phyz += VMM_PAGE_SIZE, virt += VMM_PAGE_SIZE, i++) {
pte_t new_page = 0;
new_page |= 3;
new_page |= ((phyz / VMM_PAGE_SIZE) << 12);
table_3gb->entities[i] = new_page;
}
for (uint32_t phyz = 0x500000, virt = 0xc0400000, i = 0; i < 1024; phyz += VMM_PAGE_SIZE, virt += VMM_PAGE_SIZE, i++) {
pte_t new_page = 0;
new_page |= 3;
new_page |= ((phyz / VMM_PAGE_SIZE) << 12);
table_3gbplus->entities[i] = new_page;
}
for (uint32_t phyz = 0x000000, virt = 0xffc00000, i = 0; i < 1024; phyz += VMM_PAGE_SIZE, virt += VMM_PAGE_SIZE, i++) {
pte_t new_page = 0;
new_page |= 3;
new_page |= ((phyz / VMM_PAGE_SIZE) << 12);
table_stack->entities[i] = new_page;
}
uint8_t* dir_for_memset = (uint8_t*)dir;
for (int i = 0; i < 1024; i++) {
dir->entities[i] = 0;
}
uint32_t table_0mb_int = (uint32_t)table_0mb;
dir->entities[0] |= 3;
dir->entities[0] |= ((table_0mb_int / VMM_PAGE_SIZE) << 12);
table_0mb_int = (uint32_t)table_0mbplus;
dir->entities[1] |= 3;
dir->entities[1] |= ((table_0mb_int / VMM_PAGE_SIZE) << 12);
uint32_t table_3gb_int = (uint32_t)table_3gb;
dir->entities[768] |= 3;
dir->entities[768] |= ((table_3gb_int / VMM_PAGE_SIZE) << 12);
table_3gb_int = (uint32_t)table_3gbplus;
dir->entities[769] |= 3;
dir->entities[769] |= ((table_3gb_int / VMM_PAGE_SIZE) << 12);
uint32_t table_stack_int = (uint32_t)table_stack;
dir->entities[1023] |= 3;
dir->entities[1023] |= ((table_stack_int / VMM_PAGE_SIZE) << 12);
asm volatile("mov %%eax, %%cr3"
:
: "a"(dir));
return 0;
}

28
boot/x86/stage2/mem/vm.h Normal file
View File

@@ -0,0 +1,28 @@
#ifndef _BOOT_X86_STAGE2_MEM_VM_H
#define _BOOT_X86_STAGE2_MEM_VM_H
#include "pde.h"
#include "pte.h"
#include <libboot/types.h>
#define VMM_LV0_ENTITY_COUNT (1024)
#define VMM_LV1_ENTITY_COUNT (1024)
#define VMM_PAGE_SIZE (4096)
enum VMM_ERR_CODES {
VMM_ERR_PDIR,
VMM_ERR_NO_SPACE,
VMM_ERR_BAD_ADDR,
};
typedef struct {
page_desc_t entities[VMM_LV0_ENTITY_COUNT];
} ptable_t;
typedef struct pdirectory {
table_desc_t entities[VMM_LV1_ENTITY_COUNT];
} pdirectory_t;
int vm_setup();
#endif // _BOOT_X86_STAGE2_MEM_VM_H

156
boot/x86/stage2/stage2.c Normal file
View File

@@ -0,0 +1,156 @@
/**
* Stage2 is used to load main kernel.
*/
#include "config.h"
#include "drivers/ata.h"
#include "drivers/uart.h"
#include "mem/vm.h"
#include <libboot/abi/drivers.h>
#include <libboot/abi/memory.h>
#include <libboot/crypto/validate.h>
#include <libboot/elf/elf_lite.h>
#include <libboot/fs/ext2_lite.h>
#include <libboot/log/log.h>
#include <libboot/mem/alloc.h>
#include <libboot/mem/mem.h>
#include <libboot/types.h>
// #define DEBUG_BOOT
#define KERNEL_PATH "/boot/kernel.bin"
#define LAUNCH_SERVER_PATH "/System/launch_server"
static boot_args_t boot_args;
static size_t kernel_vaddr = 0;
static size_t kernel_paddr = 0;
static size_t kernel_size = 0;
static void alloc_init(x86_mem_desc_t* mem_desc)
{
// TODO: We use manual layouting in this bootloader. Thus
// all addresses are hardcoded, no need to use allocator at all.
}
static memory_boot_desc_t memory_boot_desc_init(x86_mem_desc_t* mem_desc)
{
char dummy_data = 0x0;
size_t ram_last_addr = 0x0;
size_t next_id = 0;
memory_layout_t* mem_layout_paddr = copy_after_kernel(kernel_paddr, &dummy_data, sizeof(dummy_data), &kernel_size, VMM_PAGE_SIZE);
x86_memory_map_t* memory_map = (x86_memory_map_t*)0xA00;
for (int i = 0; i < mem_desc->memory_map_size; i++) {
if (memory_map[i].type == 0x2) {
// The region is marked as reserved, removing it.
mem_layout_paddr[next_id].base = memory_map[i].startLo;
mem_layout_paddr[next_id].size = memory_map[i].sizeLo;
mem_layout_paddr[next_id].flags = 0;
next_id++;
} else {
ram_last_addr = max(ram_last_addr, memory_map[i].startLo + memory_map[i].sizeLo);
}
}
mem_layout_paddr[next_id].flags = MEMORY_LAYOUT_FLAG_TERMINATE;
memory_layout_t* mem_layout_vaddr = paddr_to_vaddr(mem_layout_paddr, kernel_paddr, kernel_vaddr);
memory_boot_desc_t res;
res.ram_base = 0x0;
res.ram_size = ram_last_addr;
res.reserved_areas = mem_layout_vaddr;
return res;
}
int prepare_boot_disk(drive_desc_t* drive_desc)
{
init_ata(0x1F0, 1);
if (indentify_ata_device(drive_desc) == 0) {
return 0;
}
return -1;
}
int prepare_fs(drive_desc_t* drive_desc, fs_desc_t* fs_desc)
{
if (ext2_lite_init(drive_desc, fs_desc) == 0) {
return 0;
}
return -1;
}
static int validate_kernel(drive_desc_t* drive_desc, fs_desc_t* fs_desc)
{
log("Validating Kernel...");
if (!validate_elf(KERNEL_PATH, drive_desc, fs_desc)) {
log("Can't validate kernel");
while (1) { }
}
if (!validate_elf(LAUNCH_SERVER_PATH, drive_desc, fs_desc)) {
log("Can't validate launch_server");
while (1) { }
}
return 0;
}
void* bootdesc_ptr;
void load_kernel(drive_desc_t* drive_desc, fs_desc_t* fs_desc, x86_mem_desc_t* mem_desc)
{
int res = elf_load_kernel(drive_desc, fs_desc, KERNEL_PATH, &kernel_vaddr, &kernel_paddr, &kernel_size);
kernel_size = align_size(kernel_size, VMM_PAGE_SIZE);
size_t kernel_data_size = kernel_size + align_size(sizeof(boot_args_t), VMM_PAGE_SIZE) + VMM_PAGE_SIZE;
boot_args_t boot_args;
boot_args.vaddr = kernel_vaddr;
boot_args.paddr = kernel_paddr;
boot_args.kernel_data_size = kernel_data_size;
boot_args.devtree = NULL;
boot_args.mem_boot_desc = memory_boot_desc_init(mem_desc);
memcpy(boot_args.init_process, LAUNCH_SERVER_PATH, sizeof(LAUNCH_SERVER_PATH));
bootdesc_ptr = paddr_to_vaddr(copy_after_kernel(kernel_paddr, &boot_args, sizeof(boot_args), &kernel_size, VMM_PAGE_SIZE), kernel_paddr, kernel_vaddr);
}
void stage2(x86_mem_desc_t* mem_desc)
{
uart_init();
log_init(uart_write);
alloc_init(mem_desc);
#ifdef DEBUG_BOOT
log("STAGE2");
#endif
drive_desc_t drive_desc;
fs_desc_t fs_desc;
if (prepare_boot_disk(&drive_desc) != 0) {
#ifdef DEBUG_BOOT
log("STAGE2");
#endif
while (1) { }
}
if (prepare_fs(&drive_desc, &fs_desc) != 0) {
#ifdef DEBUG_BOOT
log("STAGE2");
#endif
while (1) { }
}
validate_kernel(&drive_desc, &fs_desc);
load_kernel(&drive_desc, &fs_desc, mem_desc);
vm_setup();
// enabling paging
asm volatile("mov %cr0, %eax");
asm volatile("or $0x80000000, %eax");
asm volatile("mov %eax, %cr0");
asm volatile("push %0"
:
: "r"(bootdesc_ptr));
asm volatile("mov $0xc0000000, %eax");
asm volatile("call *%eax");
while (1) { }
}

View File

@@ -0,0 +1,12 @@
section .xos_boot_text
[bits 32]
extern stage2
extern STACK_PHYZ_TOP
global _start
_start:
mov eax, esp
mov esp, STACK_PHYZ_TOP
push dword [eax+4]
call stage2
jmp $