ZealBooter: Misc progress

This commit is contained in:
mintsuki 2022-08-20 16:13:06 +02:00
parent 325160e13b
commit 344de80dab
7 changed files with 369 additions and 32 deletions

View file

@ -35,9 +35,13 @@ umount_tempdisk() {
[ ! -d $TMPMOUNT ] && mkdir -p $TMPMOUNT
set -e
echo "Building ZealBooter..."
( cd ../zealbooter && make clean all )
set +e
echo "Making temp vdisk, running auto-install..."
qemu-img create -f raw $TMPDISK 192M
qemu-system-x86_64 -machine q35,accel=kvm -drive format=raw,file=$TMPDISK -m 1G -rtc base=localtime -cdrom AUTO-VM-1.ISO -device isa-debug-exit

View file

@ -77,6 +77,10 @@ SYS_SEMAS:: DU8 SEMA_SEMAS_NUM * DEFAULT_CACHE_LINE_WIDTH DUP(0);
//************************************
ALIGN 16, OC_NOP
// Signature to find CORE0_32BIT_INIT
DU64 0xaa23c08ed10bd4d7;
DU64 0xf6ceba7d4b74179a;
CORE0_32BIT_INIT:: //Entry point for $LK,"BootRAM",A="MN:BootRAM"$.
PUSH U32 RFLAGG_START
POPFD

View file

@ -21,7 +21,7 @@ $(eval $(call DEFAULT_VAR,CC,cc))
$(eval $(call DEFAULT_VAR,LD,ld))
# User controllable CFLAGS.
CFLAGS ?= -O2 -g -Wall -Wextra -Wpedantic -pipe
CFLAGS ?= -O2 -g -Wall -Wextra -pipe
# User controllable preprocessor flags. We set none by default.
CPPFLAGS ?=
@ -35,7 +35,7 @@ LDFLAGS ?=
# Internal C flags that should not be changed by the user.
override CFLAGS += \
-I. \
-std=c11 \
-std=gnu11 \
-ffreestanding \
-fno-stack-protector \
-fno-stack-check \

105
zealbooter/lib.c Normal file
View file

@ -0,0 +1,105 @@
#include <stdint.h>
#include <stddef.h>
#include <lib.h>
void *memcpy(void *dest, const void *src, size_t n) {
uint8_t *pdest = (uint8_t *)dest;
const uint8_t *psrc = (const uint8_t *)src;
for (size_t i = 0; i < n; i++) {
pdest[i] = psrc[i];
}
return dest;
}
void *memset(void *s, int c, size_t n) {
uint8_t *p = (uint8_t *)s;
for (size_t i = 0; i < n; i++) {
p[i] = (uint8_t)c;
}
return s;
}
void *memmove(void *dest, const void *src, size_t n) {
uint8_t *pdest = (uint8_t *)dest;
const uint8_t *psrc = (const uint8_t *)src;
if (src > dest) {
for (size_t i = 0; i < n; i++) {
pdest[i] = psrc[i];
}
} else if (src < dest) {
for (size_t i = n; i > 0; i--) {
pdest[i-1] = psrc[i-1];
}
}
return dest;
}
int memcmp(const void *s1, const void *s2, size_t n) {
const uint8_t *p1 = (const uint8_t *)s1;
const uint8_t *p2 = (const uint8_t *)s2;
for (size_t i = 0; i < n; i++) {
if (p1[i] != p2[i])
return p1[i] < p2[i] ? -1 : 1;
}
return 0;
}
char *strcpy(char *dest, const char *src) {
size_t i;
for (i = 0; src[i]; i++)
dest[i] = src[i];
dest[i] = 0;
return dest;
}
char *strncpy(char *dest, const char *src, size_t n) {
size_t i;
for (i = 0; i < n && src[i]; i++)
dest[i] = src[i];
for ( ; i < n; i++)
dest[i] = 0;
return dest;
}
int strcmp(const char *s1, const char *s2) {
for (size_t i = 0; ; i++) {
char c1 = s1[i], c2 = s2[i];
if (c1 != c2)
return c1 - c2;
if (!c1)
return 0;
}
}
int strncmp(const char *s1, const char *s2, size_t n) {
for (size_t i = 0; i < n; i++) {
char c1 = s1[i], c2 = s2[i];
if (c1 != c2)
return c1 - c2;
if (!c1)
return 0;
}
return 0;
}
size_t strlen(const char *str) {
size_t len;
for (len = 0; str[len]; len++);
return len;
}

37
zealbooter/lib.h Normal file
View file

@ -0,0 +1,37 @@
#ifndef __LIB_H__
#define __LIB_H__
#include <stddef.h>
#define DIV_ROUNDUP(A, B) ({ \
typeof(A) _a_ = A; \
typeof(B) _b_ = B; \
(_a_ + (_b_ - 1)) / _b_; \
})
#define ALIGN_UP(A, B) ({ \
typeof(A) _a__ = A; \
typeof(B) _b__ = B; \
DIV_ROUNDUP(_a__, _b__) * _b__; \
})
#define ALIGN_DOWN(A, B) ({ \
typeof(A) _a_ = A; \
typeof(B) _b_ = B; \
(_a_ / _b_) * _b_; \
})
typedef char symbol[];
void *memcpy(void *dest, const void *src, size_t n);
void *memset(void *s, int c, size_t n);
void *memmove(void *dest, const void *src, size_t n);
int memcmp(const void *s1, const void *s2, size_t n);
char *strcpy(char *dest, const char *src);
char *strncpy(char *dest, const char *src, size_t n);
int strcmp(const char *s1, const char *s2);
int strncmp(const char *s1, const char *s2, size_t n);
size_t strlen(const char *str);
#endif

36
zealbooter/lower.S Normal file
View file

@ -0,0 +1,36 @@
.section .text
.global lower
lower:
pushq $0x18
addq $(1f - lower), %rax
pushq %rax
lretq
.code32
1:
mov $0x20, %eax
mov %eax, %ds
mov %eax, %es
mov %eax, %fs
mov %eax, %gs
mov %eax, %ss
lgdt (%ecx)
mov %cr0, %eax
btr $31, %eax
mov %eax, %cr0
mov $0xc0000080, %ecx
xor %eax, %eax
xor %edx, %edx
wrmsr
mov %ebx, %eax
mov $2, %ebx
mov $0x7c00, %esp
jmp *%eax

View file

@ -1,47 +1,198 @@
#include <stdint.h>
#include <stddef.h>
#include <limine.h>
// The Limine requests can be placed anywhere, but it is important that
// the compiler does not optimise them away, so, usually, they should
// be made volatile or equivalent.
#include <lib.h>
static volatile struct limine_module_request module_request = {
.id = LIMINE_MODULE_REQUEST,
.revision = 0
};
static volatile struct limine_terminal_request terminal_request = {
.id = LIMINE_TERMINAL_REQUEST,
static volatile struct limine_kernel_address_request kernel_address_request = {
.id = LIMINE_KERNEL_ADDRESS_REQUEST,
.revision = 0
};
static void done(void) {
for (;;) {
__asm__("hlt");
}
}
struct CKernel {
static volatile struct limine_memmap_request memmap_request = {
.id = LIMINE_MEMMAP_REQUEST,
.revision = 0
};
// The following will be our kernel's entry point.
void _start(void) {
// Ensure we got a terminal
if (terminal_request.response == NULL
|| terminal_request.response->terminal_count < 1) {
done();
struct CZXE {
uint16_t jmp;
uint8_t module_align_bits;
uint8_t reserved;
uint32_t signature;
int64_t org;
int64_t patch_table_offset;
int64_t file_size;
};
struct CDate {
uint32_t time;
int32_t date;
};
#define MEM_E820_ENTRIES_NUM 48
#define MEM_E820T_USABLE 1
#define MEM_E820T_RESERVED 2
#define MEM_E820T_ACPI 3
#define MEM_E820T_ACPI_NVS 4
#define MEM_E820T_BAD_MEM 5
#define MEM_E820T_PERM_MEM 7
struct CMemE820 {
uint8_t *base;
int64_t len;
uint8_t type, pad[3];
};
struct CGDTEntry {
uint64_t lo, hi;
};
#define MP_PROCESSORS_NUM 128
struct CGDT {
struct CGDTEntry null;
struct CGDTEntry boot_ds;
struct CGDTEntry boot_cs;
struct CGDTEntry cs32;
struct CGDTEntry cs64;
struct CGDTEntry cs64_ring3;
struct CGDTEntry ds;
struct CGDTEntry ds_ring3;
struct CGDTEntry tr[MP_PROCESSORS_NUM];
struct CGDTEntry tr_ring3[MP_PROCESSORS_NUM];
};
struct CKernel {
struct CZXE h;
uint32_t jmp;
uint32_t boot_src;
uint32_t boot_blk;
uint32_t boot_patch_table_base;
uint32_t sys_run_level;
struct CDate compile_time;
// start
uint32_t boot_base;
uint16_t mem_E801[2];
struct CMemE820 mem_E820[MEM_E820_ENTRIES_NUM];
uint64_t mem_physical_space;
struct {
uint16_t limit;
uint8_t *base;
} __attribute__((packed)) sys_gdt_ptr;
uint16_t sys_pci_buses;
struct CGDT sys_gdt;
uint32_t sys_font_ptr;
} __attribute__((packed));
#define BOOT_SRC_RAM 2
#define RLF_16BIT 0b01
#define RLF_VESA 0b10
void lower(void);
struct E801 {
size_t lowermem;
size_t uppermem;
};
struct E801 get_E801(void) {
struct E801 E801 = {0};
for (size_t i = 0; i < memmap_request.response->entry_count; i++) {
struct limine_memmap_entry *entry = memmap_request.response->entries[i];
if (entry->type == LIMINE_MEMMAP_USABLE) {
if (entry->base == 0x100000) {
if (entry->length > 0xf00000) {
E801.lowermem = 0x3c00;
} else {
E801.lowermem = entry->length / 1024;
}
}
if (entry->base <= 0x1000000 && entry->base + entry->length > 0x1000000) {
E801.uppermem = ((entry->length - (0x1000000 - entry->base)) / 1024) / 64;
}
}
}
// We should now be able to call the Limine terminal to print out
// a simple "Hello World" to screen.
struct limine_terminal *terminal = terminal_request.response->terminals[0];
terminal_request.response->write(terminal, "Hello World", 11);
struct limine_file *kernel = module_request.response->modules[0];
struct CKernel *CKernel = kernel->address;
// We're done, just hang...
done();
return E801;
}
void _start(void) {
struct limine_file *kernel = module_request.response->modules[0];
struct CKernel *CKernel = (void *)0x7c00;
memcpy(CKernel, kernel->address, kernel->size);
void *CORE0_32BIT_INIT;
for (uint64_t *p = (uint64_t *)CKernel; ; p++) {
if (*p != 0xaa23c08ed10bd4d7) {
continue;
}
p++;
if (*p != 0xf6ceba7d4b74179a) {
continue;
}
p++;
CORE0_32BIT_INIT = p;
break;
}
CKernel->boot_src = BOOT_SRC_RAM;
CKernel->boot_blk = 0;
CKernel->boot_patch_table_base = (uintptr_t)CKernel + CKernel->h.patch_table_offset;
CKernel->sys_run_level = RLF_VESA | RLF_16BIT;
CKernel->boot_base = (uintptr_t)&CKernel->jmp;
CKernel->sys_gdt.boot_ds.lo = 0x000093000000ffff;
CKernel->sys_gdt.boot_cs.lo = 0x00009a000000ffff;
CKernel->sys_gdt.cs32.lo = 0x00cf9a000000ffff;
CKernel->sys_gdt.cs64.lo = 0x00af9b000000ffff;
CKernel->sys_gdt.cs64_ring3.lo = 0x00affb000000ffff;
CKernel->sys_gdt.ds.lo = 0x00af93000000ffff;
CKernel->sys_gdt.ds_ring3.lo = 0x00aff3000000ffff;
CKernel->sys_gdt_ptr.limit = sizeof(CKernel->sys_gdt) - 1;
CKernel->sys_gdt_ptr.base = (void *)&CKernel->sys_gdt;
struct E801 E801 = get_E801();
CKernel->mem_E801[0] = E801.lowermem;
CKernel->mem_E801[1] = E801.uppermem;
for (size_t i = 0; i < memmap_request.response->entry_count; i++) {
struct limine_memmap_entry *entry = memmap_request.response->entries[i];
int our_type;
switch (entry->type) {
case LIMINE_MEMMAP_BOOTLOADER_RECLAIMABLE:
case LIMINE_MEMMAP_KERNEL_AND_MODULES:
case LIMINE_MEMMAP_USABLE:
our_type = MEM_E820T_USABLE; break;
case LIMINE_MEMMAP_ACPI_RECLAIMABLE:
our_type = MEM_E820T_ACPI; break;
case LIMINE_MEMMAP_ACPI_NVS:
our_type = MEM_E820T_ACPI_NVS; break;
case LIMINE_MEMMAP_BAD_MEMORY:
our_type = MEM_E820T_BAD_MEM; break;
case LIMINE_MEMMAP_RESERVED:
default:
our_type = MEM_E820T_RESERVED; break;
}
CKernel->mem_E820[i].base = (void *)entry->base;
CKernel->mem_E820[i].len = entry->length;
CKernel->mem_E820[i].type = our_type;
}
void *target_addr = (void *)lower - kernel_address_request.response->virtual_base;
target_addr += kernel_address_request.response->physical_base;
asm volatile ("jmp *%0" :: "a"(target_addr), "b"(CORE0_32BIT_INIT), "c"(&CKernel->sys_gdt_ptr) : "memory");
__builtin_unreachable();
}