Compare commits

...

12 Commits

Author SHA1 Message Date
Drew Galbraith 50201fe6df Updated PCIe walk to be recursive and dump the offset of the sata drive 2023-06-08 00:24:50 -07:00
Drew Galbraith a2fd14a9a8 Update sprintf to allow 64 bit types 2023-06-08 00:22:24 -07:00
Drew Galbraith 56789400d7 Allow mapping the PCI Config so Yellowstone can map it.
This is a temp system call. Evemtually we should probably supply the
root process with all of the system physical memory objects.
2023-06-07 22:45:42 -07:00
Drew Galbraith 71a601362d [mammoth] Update dbgln to use sprintf 2023-06-07 22:45:24 -07:00
Drew Galbraith 20dd43cdfb [libc] Add basic sprintf function 2023-06-07 22:44:11 -07:00
Drew Galbraith bd32e85164 Fix race condition in page fault handler.
We enabled interrupts before getting the value of cr2 in the handler.
If the handler was preempted, cr2 could have been overriden by a page
fault in a separate thread or process.
2023-06-07 22:24:50 -07:00
Drew Galbraith 3e1e37bf03 Probe RSDP for PCIe Config 2023-06-07 16:24:13 -07:00
Drew Galbraith 4bd7f972c1 Add additional physical memory logging 2023-06-07 16:22:39 -07:00
Drew Galbraith 53ff49b265 Add preprocessor directives to supress logs per file.
Makes the output much cleaner by default but allows for getting more
infor if debugging in the future.
2023-06-07 13:51:13 -07:00
Drew Galbraith add533071b Use APIC for interrupts rather than PIC.
Still rely on the PIT for now rather than the local APIC timer.
2023-06-07 13:40:36 -07:00
Drew Galbraith 7c9d1075eb Move sys/test to Yellowstone init process. 2023-06-07 11:18:35 -07:00
Drew Galbraith 6f81520918 Refactor compile flags 2023-06-07 11:09:27 -07:00
39 changed files with 787 additions and 95 deletions

View File

@ -9,16 +9,20 @@ set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(CMAKE_EXPORT_COMPILE_COMMANDS True)
set(BASE_COMPILE_FLAGS "-ffreestanding -fno-exceptions -mgeneral-regs-only")
set(BASE_LINK_FLAGS "-nostdlib")
add_subdirectory(zion)
add_subdirectory(lib)
add_subdirectory(sys)
set(QEMU_CMD qemu-system-x86_64 -d guest_errors -m 1G -serial stdio -hda disk.img)
# Use machine q35 to access PCI devices.
set(QEMU_CMD qemu-system-x86_64 -machine q35 -d guest_errors -m 1G -serial stdio -hda disk.img)
add_custom_command(
OUTPUT disk.img
COMMAND sudo sh ../scripts/build_image.sh disk.img
DEPENDS zion test test2
DEPENDS zion yellowstone test2
USES_TERMINAL
)

View File

@ -1,15 +1,16 @@
add_library(libc STATIC
add_library(c STATIC
src/malloc.cpp
src/stdio.cpp
)
target_include_directories(libc
target_include_directories(c
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_link_libraries(libc
target_link_libraries(c
zion_lib
)
set_target_properties(libc PROPERTIES
COMPILE_FLAGS "${CMAKE_CXX_FLAGS} -ffreestanding -mgeneral-regs-only")
set_target_properties(c PROPERTIES
COMPILE_FLAGS "${CMAKE_CXX_FLAGS} ${BASE_COMPILE_FLAGS}")

10
lib/libc/include/stdio.h Normal file
View File

@ -0,0 +1,10 @@
#pragma once
#include <stdarg.h>
// int fprintf(FILE *stream, const char *format, ...);
int printf(const char *format, ...);
int sprintf(char *str, const char *format, ...);
// int vfprintf(FILE *stream, const char *format, va_list arg);
int vprintf(const char *format, va_list arg);
int vsprintf(char *str, const char *format, va_list arg);

116
lib/libc/src/stdio.cpp Normal file
View File

@ -0,0 +1,116 @@
#include "stdio.h"
#include <stdint.h>
namespace {
uint32_t num_chars(uint64_t num, uint8_t base) {
uint32_t width = 0;
while (num > 0) {
num /= base;
width++;
}
return width;
}
int sprint_base(char *str, uint64_t num, uint32_t base) {
uint32_t width = num_chars(num, base);
if (width == 0) {
*str = '0';
return 1;
}
uint64_t place = 1;
while (num > 0) {
// FIXME: We seem to have an issue with loading globals.
const char *kHexChars = "0123456789abcdef";
str[width - place] = kHexChars[num % base];
place++;
num /= base;
}
return width;
}
} // namespace
int sprintf(char *str, const char *format, ...) {
va_list arg;
va_start(arg, format);
int ret = vsprintf(str, format, arg);
va_end(arg);
return ret;
}
int vsprintf(char *str, const char *format, va_list arg) {
uint32_t chars = 0;
while (*format != '\0') {
if (*format != '%') {
*str = *format;
chars++;
str++;
format++;
continue;
}
format++;
switch (*format) {
case '%':
*(str++) = *(format++);
chars++;
break;
case 'l': {
switch (*(++format)) {
case 'x': {
int width = sprint_base(str, va_arg(arg, uint64_t), 16);
if (width == -1) {
return -1;
}
chars += width;
str += width;
format++;
break;
}
case 'u': {
int width = sprint_base(str, va_arg(arg, uint64_t), 10);
if (width == -1) {
return -1;
}
chars += width;
str += width;
format++;
break;
}
}
break;
}
case 'x': {
int width = sprint_base(str, va_arg(arg, uint32_t), 16);
if (width == -1) {
return -1;
}
chars += width;
str += width;
format++;
break;
}
case 'u': {
int width = sprint_base(str, va_arg(arg, uint32_t), 10);
if (width == -1) {
return -1;
}
chars += width;
str += width;
format++;
break;
}
default:
*(str++) = *(format++);
chars++;
}
}
*str = '\0';
chars++;
return chars;
}

View File

@ -1,15 +1,15 @@
add_library(libcxx STATIC
add_library(cxx STATIC
src/new.cpp
)
target_include_directories(libcxx
target_include_directories(cxx
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_link_libraries(libcxx
libc
target_link_libraries(cxx
c
zion_lib
)
set_target_properties(libcxx PROPERTIES
COMPILE_FLAGS "${CMAKE_CXX_FLAGS} -ffreestanding -mgeneral-regs-only")
set_target_properties(cxx PROPERTIES
COMPILE_FLAGS "${CMAKE_CXX_FLAGS} ${BASE_COMPILE_FLAGS}")

View File

@ -10,12 +10,10 @@ target_include_directories(mammoth_lib
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_link_libraries(mammoth_lib
c
zion_lib)
set(_COMPILE_FLAGS "${CMAKE_CXX_FLAGS} -c -ffreestanding -fno-rtti -fno-exceptions -nostdlib -mabi=sysv -mgeneral-regs-only")
set(_LINK_FLAGS "-nostdlib")
set_target_properties(mammoth_lib PROPERTIES
COMPILE_FLAGS "${_COMPILE_FLAGS}"
LINK_FLAGS "${CMAKE_EXE_LINK_FLAGS} ${_LINK_FLAGS}"
COMPILE_FLAGS "${CMAKE_CXX_FLAGS} ${BASE_COMPILE_FLAGS}"
LINK_FLAGS "${CMAKE_EXE_LINK_FLAGS} ${BASE_LINK_FLAGS}"
)

View File

@ -3,7 +3,7 @@
#include <stdint.h>
#include <zerrors.h>
void dbgln(const char*);
void dbgln(const char* fmt, ...);
// Checks that the code is ok.
// if not exits the process.

View File

@ -1,13 +1,29 @@
#include "include/mammoth/debug.h"
#include <stdarg.h>
#include <stdio.h>
#include <zcall.h>
#include <zerrors.h>
void dbgln(const char* str) {
// Safe to ignore the result since right now this doesn't throw.
void dbgln_internal(const char* str) { // Safe to ignore the result since right
// now this doesn't throw.
uint64_t _ = ZDebug(str);
}
void dbgln(const char* fmt, ...) {
char str[1024];
va_list arg;
va_start(arg, fmt);
int ret = vsprintf(str, fmt, arg);
va_end(arg);
if (ret == -1 || ret > 1024) {
crash("Bad vsprintf", 1);
}
dbgln_internal(str);
}
void check(uint64_t code) {
switch (code) {
case Z_OK:

View File

@ -6,6 +6,8 @@
#include "mammoth/channel.h"
#include "mammoth/debug.h"
#define MAM_PROC_DEBUG 0
namespace {
typedef struct {
@ -63,19 +65,27 @@ uint64_t LoadElfProgram(uint64_t base, uint64_t as_cap) {
reinterpret_cast<Elf64ProgramHeader*>(base + header->phoff);
for (uint64_t i = 0; i < header->phnum; i++) {
Elf64ProgramHeader& program = programs[i];
#if MAM_PROC_DEBUG
dbgln("Create mem object");
#endif
uint64_t mem_cap;
uint64_t size = program.filesz;
check(ZMemoryObjectCreate(size, &mem_cap));
#if MAM_PROC_DEBUG
dbgln("Map Local");
#endif
uint64_t vaddr;
check(ZAddressSpaceMap(Z_INIT_VMAS_SELF, 0, mem_cap, &vaddr));
#if MAM_PROC_DEBUG
dbgln("Copy");
#endif
memcpy(base + program.offset, program.filesz, vaddr);
#if MAM_PROC_DEBUG
dbgln("Map Foreign");
#endif
check(ZAddressSpaceMap(as_cap, program.vaddr, mem_cap, &vaddr));
}
return header->entry;
@ -87,7 +97,9 @@ uint64_t SpawnProcessFromElfRegion(uint64_t program) {
Channel local, foreign;
check(CreateChannels(local, foreign));
#if MAM_PROC_DEBUG
dbgln("Spawn");
#endif
uint64_t proc_cap;
uint64_t as_cap;
uint64_t foreign_chan_id;
@ -95,11 +107,15 @@ uint64_t SpawnProcessFromElfRegion(uint64_t program) {
&as_cap, &foreign_chan_id));
uint64_t entry_point = LoadElfProgram(program, as_cap);
#if MAM_PROC_DEBUG
dbgln("Thread Create");
#endif
uint64_t thread_cap;
check(ZThreadCreate(proc_cap, &thread_cap));
#if MAM_PROC_DEBUG
dbgln("Thread start");
#endif
check(ZThreadStart(thread_cap, entry_point, foreign_chan_id, 0));
local.WriteStr("Hello!");

View File

@ -37,7 +37,7 @@ cp /usr/share/limine/limine.sys efi/
cp ../zion/boot/limine.cfg efi/
cp zion/zion efi/
mkdir -p efi/sys
cp sys/test efi/sys/test
cp sys/yellowstone/yellowstone efi/sys/yellowstone
cp sys/test2 efi/sys/test2
chown drew:drew $1

View File

@ -1,30 +1,16 @@
set(_COMPILE_FLAGS "-ffreestanding -fno-exceptions -mgeneral-regs-only")
set(_LINK_FLAGS "-nostdlib")
set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "")
add_executable(test
test.cpp
)
target_link_libraries(test
mammoth_lib)
set_target_properties(test
PROPERTIES
COMPILE_FLAGS "${CMAKE_CXX_FLAGS} ${_COMPILE_FLAGS}"
LINK_FLAGS "${CMAKE_EXE_LINK_FLAGS} ${_LINK_FLAGS}"
)
add_subdirectory(yellowstone)
add_executable(test2
test2.cpp)
target_link_libraries(test2
libcxx
cxx
mammoth_lib)
set_target_properties(test2
PROPERTIES
COMPILE_FLAGS "${CMAKE_CXX_FLAGS} ${_COMPILE_FLAGS}"
LINK_FLAGS "${CMAKE_EXE_LINK_FLAGS} ${_LINK_FLAGS}"
COMPILE_FLAGS "${CMAKE_CXX_FLAGS} ${BASE_COMPILE_FLAGS}"
LINK_FLAGS "${CMAKE_EXE_LINK_FLAGS} ${BASE_LINK_FLAGS}"
)

5
sys/README.md Normal file
View File

@ -0,0 +1,5 @@
# System Processes
Current Processes;
- **yellowstone**: System Initialization

View File

@ -0,0 +1,16 @@
add_executable(yellowstone
hw/pcie.cpp
yellowstone.cpp
)
target_include_directories(yellowstone
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(yellowstone
cxx
mammoth_lib
)
set_target_properties(yellowstone PROPERTIES
COMPILE_FLAGS "${CMAKE_CXX_FLAGS} ${BASE_COMPILE_FLAGS}"
LINK_FLAGS "${CMAKE_EXE_LINK_FLAGS} ${BASE_LINK_FLAGS}"
)

100
sys/yellowstone/hw/pcie.cpp Normal file
View File

@ -0,0 +1,100 @@
#include "hw/pcie.h"
#include <mammoth/debug.h>
#include <zcall.h>
namespace {
struct PciDeviceHeader {
uint16_t vendor_id;
uint16_t device_id;
uint16_t command_reg;
uint16_t status_reg;
uint8_t revision;
uint8_t prog_interface;
uint8_t subclass;
uint8_t class_code;
uint8_t cache_line_size;
uint8_t latency_timer;
uint8_t header_type;
uint8_t bist;
} __attribute__((packed));
PciDeviceHeader* PciHeader(uint64_t base, uint64_t bus, uint64_t dev,
uint64_t fun) {
return reinterpret_cast<PciDeviceHeader*>(base + (bus << 20) + (dev << 15) +
(fun << 12));
}
void FunctionDump(uint64_t base, uint64_t bus, uint64_t dev, uint64_t fun) {
PciDeviceHeader* hdr = PciHeader(base, bus, dev, fun);
if (hdr->vendor_id == 0xFFFF) {
return;
}
dbgln(
"[%u.%u.%u] (Vendor, Device): (%x, %x), (Type, Class, Sub, PIF): (%u, "
"%x, %x, %x)",
bus, dev, fun, hdr->vendor_id, hdr->device_id, hdr->header_type,
hdr->class_code, hdr->subclass, hdr->prog_interface);
if ((hdr->class_code == 0x6) && (hdr->subclass == 0x4)) {
dbgln("FIXME: Handle PCI to PCI bridge.");
}
if (hdr->class_code == 0x1) {
dbgln("SATA Device at: %lx", reinterpret_cast<uint64_t>(hdr) - base);
}
}
void DeviceDump(uint64_t base, uint64_t bus, uint64_t dev) {
PciDeviceHeader* hdr = PciHeader(base, bus, dev, 0);
if (hdr->vendor_id == 0xFFFF) {
return;
}
FunctionDump(base, bus, dev, 0);
// Device is multifunction.
if (hdr->header_type & 0x80) {
for (uint64_t f = 1; f < 0x8; f++) {
FunctionDump(base, bus, dev, f);
}
}
}
void BusDump(uint64_t base, uint64_t bus) {
for (uint64_t dev = 0; dev < 0x20; dev++) {
DeviceDump(base, bus, dev);
}
}
void PciDump(uint64_t base) {
PciDeviceHeader* hdr = PciHeader(base, 0, 0, 0);
if ((hdr->header_type & 0x80) == 0) {
// Single bus system.
BusDump(base, 0);
} else {
for (uint64_t f = 0; f < 8; f++) {
PciDeviceHeader* f_hdr = PciHeader(base, 0, 0, f);
if (f_hdr->vendor_id != 0xFFFF) {
BusDump(base, f);
}
}
}
}
} // namespace
void DumpPciEDevices() {
dbgln("Creating PCI obj");
uint64_t vmmo_cap, vmmo_size;
check(ZTempPcieConfigObjectCreate(&vmmo_cap, &vmmo_size));
dbgln("Creating addr space");
uint64_t vaddr;
check(ZAddressSpaceMap(Z_INIT_VMAS_SELF, 0, vmmo_cap, &vaddr));
dbgln("Addr %lx", vaddr);
dbgln("Dumping PCI");
PciDump(vaddr);
dbgln("Done");
}

View File

@ -0,0 +1,3 @@
#pragma once
void DumpPciEDevices();

View File

@ -2,11 +2,16 @@
#include <mammoth/process.h>
#include <zcall.h>
int main() {
dbgln("Testing");
#include "hw/pcie.h"
uint64_t main() {
dbgln("Yellowstone Initializing.");
uint64_t vaddr;
check(ZAddressSpaceMap(Z_INIT_VMAS_SELF, 0, Z_INIT_BOOT_VMMO, &vaddr));
check(SpawnProcessFromElfRegion(vaddr));
dbgln("Return");
DumpPciEDevices();
dbgln("Yellowstone Finished Successfully.");
return 0;
}

View File

@ -1,9 +1,12 @@
add_executable(zion
boot/acpi.cpp
boot/boot_info.cpp
capability/capability.cpp
common/gdt.cpp
common/load_gdt.s
common/msr.cpp
debug/debug.cpp
interrupt/apic.cpp
interrupt/interrupt.cpp
interrupt/interrupt_enter.s
interrupt/timer.cpp

171
zion/boot/acpi.cpp Normal file
View File

@ -0,0 +1,171 @@
#include "boot/acpi.h"
#include "boot/boot_info.h"
#include "debug/debug.h"
#define K_ACPI_DEBUG 0
namespace {
static uint64_t gPcieEcBase = 0x0;
static uint64_t gPcieEcSize = 0x0;
struct RsdpDescriptor {
char signature[8];
uint8_t checksum;
char oem_id[6];
uint8_t revision;
uint32_t rsdt_addr;
uint32_t length;
uint64_t xsdt_addr;
uint8_t ext_checksum;
uint8_t reserved[3];
} __attribute__((packed));
struct SdtHeader {
char signature[4];
uint32_t length;
uint8_t revision;
uint8_t checksum;
char oem_id[6];
char oem_table_id[8];
uint32_t oem_revision;
uint32_t creator_id;
uint32_t creator_revision;
} __attribute__((packed));
bool streq(const char* a, const char* b, uint8_t len) {
for (uint8_t i = 0; i < len; i++) {
if (a[i] != b[i]) return false;
}
return true;
}
bool checksum(uint8_t* addr, uint8_t num_bytes) {
uint8_t check_cnt = 0;
for (uint8_t i = 0; i < num_bytes; i++) {
check_cnt += addr[i];
}
return check_cnt == 0;
}
void dbgsz(const char* c, uint8_t cnt) {
char cl[cnt + 1];
for (uint8_t i = 0; i < cnt; i++) {
cl[i] = c[i];
}
cl[cnt] = '\0';
dbgln(cl);
}
uint8_t* SdtDataStart(SdtHeader* sdt) {
return reinterpret_cast<uint8_t*>(sdt) + sizeof(SdtHeader);
}
void ParseMcfg(SdtHeader* rsdt) {
#if K_ACPI_DEBUG
dbgsz(rsdt->signature, 4);
#endif
uint32_t size = (rsdt->length - sizeof(SdtHeader)) / 16;
uint64_t* entries = reinterpret_cast<uint64_t*>(SdtDataStart(rsdt));
// There are 8 reserved bytes at the end of the table.
entries++;
for (uint32_t i = 0; i < size; i++) {
uint64_t base_ecm_addr = entries[2 * i];
uint64_t bus_info = entries[2 * i + 1];
if (bus_info != 0xff000000) {
#if K_ACPI_DEBUG
dbgln("WARN: Unexpected bus-info for PCI EC. Mem region will be wrong.")
#endif
}
gPcieEcBase = base_ecm_addr;
uint64_t num_busses = 0x100;
uint64_t dev_per_bus = 0x20;
uint64_t fns_per_dev = 0x8;
uint64_t bytes_per_fn = 0x1000;
gPcieEcSize = num_busses * dev_per_bus * fns_per_dev * bytes_per_fn;
#if K_ACPI_DEBUG
dbgln("PCI Map: %m:%x", gPcieEcBase, gPcieEcSize);
#endif
}
}
void ParseSdt(SdtHeader* rsdt) {
if (!checksum((uint8_t*)rsdt, rsdt->length)) {
dbgln("Bad RSDT checksum.");
return;
}
if (streq(rsdt->signature, "MCFG", 4)) {
ParseMcfg(rsdt);
} else {
#if K_ACPI_DEBUG
dbgln("Unhandled:");
dbgsz(rsdt->signature, 4);
#endif
}
}
void ProbeRsdt(SdtHeader* rsdt) {
if (!checksum((uint8_t*)rsdt, rsdt->length)) {
dbgln("Bad RSDT checksum.");
return;
}
#if K_ACPI_DEBUG
dbgsz(rsdt->signature, 4);
#endif
uint32_t size = (rsdt->length - sizeof(SdtHeader)) / 4;
uint32_t* entries = reinterpret_cast<uint32_t*>(SdtDataStart(rsdt));
for (uint32_t i = 0; i < size; i++) {
SdtHeader* table = reinterpret_cast<SdtHeader*>(entries[i]);
ParseSdt(table);
}
}
} // namespace
void ProbeRsdp() {
void* rsdp_addr = boot::GetRsdpAddr();
RsdpDescriptor* rsdp = static_cast<RsdpDescriptor*>(rsdp_addr);
if (!streq(rsdp->signature, "RSD PTR ", 8)) {
dbgln("Invalid Rsdp!");
return;
}
// Checks V1 up to rsdt_addr.
if (!checksum((uint8_t*)rsdp_addr, 20)) {
dbgln("Rsdp Check failed");
return;
}
#if K_ACPI_DEBUG
dbgln("ACPI Ver %u", rsdp->revision);
dbgln("RSDT Addr: %m", rsdp->rsdt_addr);
#endif
ProbeRsdt(reinterpret_cast<SdtHeader*>(rsdp->rsdt_addr));
if (rsdp->revision == 0) {
return;
}
// Checks V2 (entire structure).
if (!checksum((uint8_t*)rsdp_addr, rsdp->length)) {
dbgln("Rsdp ext checksum failed");
return;
}
#if K_ACPI_DEBUG
dbgln("XSDT Addr: %m", rsdp->xsdt_addr);
#endif
}
z_err_t GetPciExtendedConfiguration(uint64_t* base, uint64_t* offset) {
if (gPcieEcSize == 0) {
return Z_ERR_NOT_FOUND;
}
*base = gPcieEcBase;
*offset = gPcieEcSize;
return Z_OK;
}

9
zion/boot/acpi.h Normal file
View File

@ -0,0 +1,9 @@
#pragma once
#include <stdint.h>
#include "include/zerrors.h"
void ProbeRsdp();
z_err_t GetPciExtendedConfiguration(uint64_t* base, uint64_t* offset);

View File

@ -36,4 +36,15 @@ const limine_module_response& GetModules() {
return *gModuleRequest.response;
}
static volatile struct limine_rsdp_request gRsdpRequest {
.id = LIMINE_RSDP_REQUEST, .revision = 0, .response = 0,
};
void* GetRsdpAddr() {
if (!gRsdpRequest.response) {
panic("No rsdp response from limine");
}
return gRsdpRequest.response->address;
}
} // namespace boot

View File

@ -9,4 +9,6 @@ uint64_t GetHigherHalfDirectMap();
const limine_module_response& GetModules();
void* GetRsdpAddr();
} // namespace boot

View File

@ -6,5 +6,5 @@ TIMEOUT=0
PROTOCOL=limine
KERNEL_PATH=boot:///zion
MODULE_PATH=boot:///sys/test
MODULE_PATH=boot:///sys/yellowstone
MODULE_PATH=boot:///sys/test2

13
zion/common/msr.cpp Normal file
View File

@ -0,0 +1,13 @@
#include "common/msr.h"
uint64_t GetMSR(uint32_t msr) {
uint32_t lo, hi;
asm("rdmsr" : "=a"(lo), "=d"(hi) : "c"(msr));
return (static_cast<uint64_t>(hi) << 32) | lo;
}
void SetMSR(uint32_t msr, uint64_t val) {
uint32_t lo = static_cast<uint32_t>(val);
uint32_t hi = val >> 32;
asm("wrmsr" ::"a"(lo), "d"(hi), "c"(msr));
}

6
zion/common/msr.h Normal file
View File

@ -0,0 +1,6 @@
#pragma once
#include <stdint.h>
uint64_t GetMSR(uint32_t msr);
void SetMSR(uint32_t msr, uint64_t val);

View File

@ -32,6 +32,8 @@
#define Z_MEMORY_OBJECT_CREATE 0x30
#define Z_TEMP_PCIE_CONFIG_OBJECT_CREATE 0x3F
#define Z_INIT_BOOT_VMMO 0x31
// IPC Calls
@ -65,6 +67,8 @@ void ZThreadExit();
[[nodiscard]] z_err_t ZAddressSpaceMap(uint64_t vmas_cap, uint64_t vmas_offset,
uint64_t vmmo_cap, uint64_t* vaddr);
[[nodiscard]] z_err_t ZMemoryObjectCreate(uint64_t size, uint64_t* vmmo_cap);
[[nodiscard]] z_err_t ZTempPcieConfigObjectCreate(uint64_t* vmmo_cap,
uint64_t* vmmo_size);
[[nodiscard]] z_err_t ZChannelCreate(uint64_t* channel1, uint64_t* channel2);
[[nodiscard]] z_err_t ZChannelSend(uint64_t chan_cap, uint64_t type,

128
zion/interrupt/apic.cpp Normal file
View File

@ -0,0 +1,128 @@
#include "interrupt/apic.h"
#include <stdint.h>
#include "boot/boot_info.h"
#include "common/msr.h"
#include "common/port.h"
#include "debug/debug.h"
#define APIC_DEBUG 0
namespace {
#define IA32_APIC_BASE_MSR 0x1B
#define IA32_APIC_BASE_MSR_BSP 0x100 // Processor is a BSP
#define IA32_APIC_BASE_MSR_ENABLE 0x800
const uint64_t kEoiOffset = 0xB0;
constexpr uint64_t kLApicBase = 0xFEE0'0000;
constexpr uint64_t kIoApicAddr = 0xFEC0'0000;
constexpr uint64_t kIoApicData = 0xFEC0'0010;
uint32_t volatile* GetPhys(uint64_t base, uint64_t offset = 0) {
return reinterpret_cast<uint32_t*>(boot::GetHigherHalfDirectMap() + base +
offset);
}
uint32_t GetLocalReg(uint64_t offset) {
uint32_t volatile* reg = GetPhys(kLApicBase, offset);
return *reg;
}
void WriteLocalReg(uint64_t offset, uint32_t value) {
*GetPhys(kLApicBase, offset) = value;
}
uint32_t GetIoReg(uint8_t reg) {
*GetPhys(kIoApicAddr) = reg;
return *GetPhys(kIoApicData);
}
uint64_t GetIoEntry(uint8_t reg) {
*GetPhys(kIoApicAddr) = reg;
uint64_t entry = *GetPhys(kIoApicData);
*GetPhys(kIoApicAddr) = reg + 1;
entry |= ((uint64_t)*GetPhys(kIoApicData)) << 32;
return entry;
}
void SetIoEntry(uint8_t reg, uint64_t value) {
*GetPhys(kIoApicAddr) = reg;
*GetPhys(kIoApicData) = value & 0xFFFFFFFF;
*GetPhys(kIoApicAddr) = reg + 1;
*GetPhys(kIoApicData) = value >> 32;
}
#define PIC1_COMMAND 0x20
#define PIC2_COMMAND 0xA0
#define PIC1_DATA 0x21
#define PIC2_DATA 0xA1
void MaskPic() {
outb(PIC1_DATA, 0xFF);
outb(PIC2_DATA, 0xFF);
outb(PIC1_COMMAND, 0x11);
outb(PIC2_COMMAND, 0x11);
// Potential spurious interrupts at 0x87
outb(PIC1_DATA, 0x80); // PIC1 offset (high and dry).
outb(PIC2_DATA, 0x80); // PIC2 offset (high and dry).
outb(PIC1_DATA, 0x4);
outb(PIC2_DATA, 0x2);
outb(PIC1_DATA, 0x1);
outb(PIC2_DATA, 0x1);
// Mask all.
outb(PIC1_DATA, 0xFF);
outb(PIC2_DATA, 0xFF);
}
} // namespace
void InspectApic() {
#if APIC_DEBUG
dbgln("APIC:");
dbgln("ID: %x", GetLocalReg(0x20));
dbgln("VER: %x", GetLocalReg(0x30));
dbgln("TPR: %x", GetLocalReg(0x80));
dbgln("APR: %x", GetLocalReg(0x90));
dbgln("PPR: %x", GetLocalReg(0xA0));
dbgln("RRD: %x", GetLocalReg(0xC0));
dbgln("LDR: %x", GetLocalReg(0xD0));
dbgln("DFR: %x", GetLocalReg(0xE0));
dbgln("SIV: %x", GetLocalReg(0xF0));
for (uint64_t i = 0; i < 8; i++) {
dbgln("ISR(%u): %x", i, GetLocalReg(0x100 + (0x10 * i)));
}
for (uint64_t i = 0; i < 8; i++) {
dbgln("TMR(%u): %x", i, GetLocalReg(0x180 + (0x10 * i)));
}
for (uint64_t i = 0; i < 8; i++) {
dbgln("IRR(%u): %x", i, GetLocalReg(0x200 + (0x10 * i)));
}
dbgln("ESR: %x", GetLocalReg(0x280));
dbgln("IO ID: %x", GetIoReg(0x0));
dbgln("IO VER: %x", GetIoReg(0x1));
dbgln("IO ARB: %x", GetIoReg(0x2));
for (uint8_t i = 0x10; i < 0x3F; i += 2) {
dbgln("IO (%u): %x", i, GetIoEntry(i));
}
dbgln("APIC MSR: %x", GetMSR(0x1B));
#endif
}
void EnableApic() {
MaskPic();
// Map Timer.
SetIoEntry(0x14, 0x20);
// Skip Keyboard for now.
// SetIoEntry(0x12, 0x21);
InspectApic();
}
void SignalEOI() {
// Value doesn't matter.
WriteLocalReg(kEoiOffset, 0x1);
}

7
zion/interrupt/apic.h Normal file
View File

@ -0,0 +1,7 @@
#pragma once
void InspectApic();
void EnableApic();
void SignalEOI();

View File

@ -4,6 +4,7 @@
#include "common/port.h"
#include "debug/debug.h"
#include "interrupt/apic.h"
#include "memory/kernel_heap.h"
#include "scheduler/scheduler.h"
@ -42,6 +43,7 @@ InterruptDescriptor CreateDescriptor(void isr(void)) {
}
struct InterruptFrame {
uint64_t cr2;
uint64_t rax;
uint64_t rbx;
uint64_t rcx;
@ -89,16 +91,14 @@ extern "C" void interrupt_protection_fault(InterruptFrame* frame) {
extern "C" void isr_page_fault();
extern "C" void interrupt_page_fault(InterruptFrame* frame) {
dbgln("Page Fault - trying to resolve");
uint64_t cr2;
asm volatile("mov %%cr2, %0" : "=r"(cr2));
if (gScheduler->CurrentProcess().vmas()->HandlePageFault(cr2)) {
dbgln("Handled");
uint64_t err = frame->error_code;
if ((err & 0x1) == 0) {
// Page not present error may be resolveable.
if (gScheduler->CurrentProcess().vmas()->HandlePageFault(frame->cr2)) {
return;
}
dbgln("Unable to handle:");
uint64_t err = frame->error_code;
}
dbgln("Unhandled Page Fault:");
if (err & 0x1) {
dbgln("Page Protection");
} else {
@ -120,14 +120,10 @@ extern "C" void interrupt_page_fault(InterruptFrame* frame) {
}
dbgln("rip: %m", frame->rip);
dbgln("addr: %m", cr2);
dbgln("addr: %m", frame->cr2);
panic("PF");
}
#define PIC1_COMMAND 0x20
#define PIC1_DATA 0x21
#define PIC_EOI 0x20
uint64_t cnt = 0;
extern "C" void isr_timer();
extern "C" void interrupt_timer(InterruptFrame*) {
@ -138,20 +134,10 @@ extern "C" void interrupt_timer(InterruptFrame*) {
}
dbgln("timer: %us", cnt * 50 / 1000);
}
outb(PIC1_COMMAND, PIC_EOI);
SignalEOI();
gScheduler->Preempt();
}
void EnablePic() {
outb(PIC1_COMMAND, 0x11);
outb(PIC1_DATA, 0x20); // PIC1 offset.
outb(PIC1_DATA, 0x4);
outb(PIC1_DATA, 0x1);
// Mask all except the timer.
outb(PIC1_DATA, 0xE);
}
void InitIdt() {
gIdt[0] = CreateDescriptor(isr_divide_by_zero);
gIdt[13] = CreateDescriptor(isr_protection_fault);
@ -163,5 +149,5 @@ void InitIdt() {
};
asm volatile("lidt %0" ::"m"(idtp));
EnablePic();
EnableApic();
}

View File

@ -14,9 +14,12 @@
push %rcx # (Return Address)
push %rbx
push %rax
mov %cr2, %rax
push %rax
.endm
.macro interrupt_exit
add $8, %rsp
pop %rax
pop %rbx
pop %rcx
@ -26,11 +29,11 @@
pop %r8
pop %r9
pop %r10
pop %r10
pop %r10
pop %r10
pop %r10
pop %r10
pop %r11
pop %r12
pop %r13
pop %r14
pop %r15
pop %rbp
add $8, %rsp # Remove error code.

View File

@ -9,6 +9,8 @@
#include "object/thread.h"
#include "scheduler/process_manager.h"
#define K_INIT_DEBUG 0
namespace {
typedef struct {
@ -54,16 +56,20 @@ typedef struct {
uint64_t LoadElfProgram(Process& dest_proc, uint64_t base, uint64_t offset) {
Elf64Header* header = reinterpret_cast<Elf64Header*>(base);
#if K_INIT_DEBUG
dbgln("phoff: %u phnum: %u", header->phoff, header->phnum);
#endif
Elf64ProgramHeader* programs =
reinterpret_cast<Elf64ProgramHeader*>(base + header->phoff);
for (uint64_t i = 0; i < header->phnum; i++) {
Elf64ProgramHeader& program = programs[i];
#if K_INIT_DEBUG
dbgln(
"prog: type: %u, flags: %u, offset: %u\n vaddr: %m, paddr: %m\n "
"filesz: %x, memsz: %x, align: %x",
program.type, program.flags, program.offset, program.vaddr,
program.paddr, program.filesz, program.memsz, program.align);
#endif
auto mem_obj = MakeRefCounted<MemoryObject>(program.filesz);
mem_obj->CopyBytesToObject(base + program.offset, program.filesz);
dest_proc.vmas()->MapInMemoryObject(program.vaddr, mem_obj);
@ -86,12 +92,14 @@ bool streq(const char* a, const char* b) {
}
void DumpModules() {
#if K_INIT_DEBUG
const limine_module_response& resp = boot::GetModules();
dbgln("[boot] Dumping bootloader modules.");
for (uint64_t i = 0; i < resp.module_count; i++) {
const limine_file& file = *resp.modules[i];
dbgln(" %s,%m,%x", file.path, file.address, file.size);
}
#endif
}
const limine_file& GetInitProgram(const char* path) {
@ -107,7 +115,7 @@ const limine_file& GetInitProgram(const char* path) {
void LoadInitProgram() {
DumpModules();
const limine_file& init_prog = GetInitProgram("/sys/test");
const limine_file& init_prog = GetInitProgram("/sys/yellowstone");
RefPtr<Process> proc = Process::Create();
gProcMan->InsertProcess(proc);

View File

@ -3,6 +3,8 @@
#include "boot/boot_info.h"
#include "debug/debug.h"
#define K_PHYS_DEBUG 0
namespace phys_mem {
namespace {
@ -23,13 +25,18 @@ class PhysicalMemoryManager {
const limine_memmap_response& memmap = boot::GetMemoryMap();
for (uint64_t i = 0; i < memmap.entry_count; i++) {
const limine_memmap_entry& entry = *memmap.entries[i];
#if K_PHYS_DEBUG
dbgln("Region(%u) at %m:%x", entry.type, entry.base, entry.length);
#endif
if (entry.type == 0) {
uint64_t base = entry.base;
uint64_t size = entry.length;
if (base == gBootstrap.init_page) {
base = gBootstrap.next_page;
uint64_t bootstrap_used = gBootstrap.next_page - gBootstrap.init_page;
#if K_PHYS_DEBUG
dbgln("[PMM] Taking over from bootstrap, used: %x", bootstrap_used);
#endif
size -= bootstrap_used;
}
AddMemoryRegion(base, size);
@ -109,7 +116,9 @@ uint64_t AllocatePage() {
panic("No Bootstrap Memory Manager");
}
#if K_PHYS_DEBUG
dbgln("[PMM] Boostrap Alloc!");
#endif
uint64_t page = gBootstrap.next_page;
if (page == gBootstrap.max_page) {

View File

@ -4,6 +4,8 @@
#include "memory/paging_util.h"
#include "memory/physical_memory.h"
#define K_VMAS_DEBUG 0
extern KernelStackManager* gKernelStackManager;
RefPtr<AddressSpace> AddressSpace::ForRoot() {
@ -50,6 +52,9 @@ uint64_t* AddressSpace::AllocateKernelStack() {
}
bool AddressSpace::HandlePageFault(uint64_t vaddr) {
#if K_VMAS_DEBUG
dbgln("[VMAS] Page Fault!");
#endif
MemoryMapping* mapping = GetMemoryMappingForAddr(vaddr);
if (mapping == nullptr) {
return false;
@ -60,7 +65,9 @@ bool AddressSpace::HandlePageFault(uint64_t vaddr) {
dbgln("WARN: Memory object returned invalid physical addr.");
return false;
}
dbgln("Mapping P(%m) at V(%m)", physical_addr, vaddr);
#if K_VMAS_DEBUG
dbgln("[VMAS] Mapping P(%m) at V(%m)", physical_addr, vaddr);
#endif
MapPage(cr3_, vaddr, physical_addr);
return true;
}

View File

@ -4,10 +4,14 @@
#include "debug/debug.h"
#include "memory/physical_memory.h"
#define K_MEM_DEBUG 0
MemoryObject::MemoryObject(uint64_t size) : size_(size) {
if ((size & 0xFFF) != 0) {
size_ = (size & ~0xFFF) + 0x1000;
#if K_MEM_DEBUG
dbgln("MemoryObject: aligned %x to %x", size, size_);
#endif
}
// FIXME: Do this lazily.
uint64_t num_pages = size_ / 0x1000;
@ -56,7 +60,9 @@ uint64_t MemoryObject::PageNumberToPhysAddr(uint64_t page_num) {
}
if (*iter == 0) {
#if K_MEM_DEBUG
dbgln("Allocating page num %u for mem object", page_num);
#endif
*iter = phys_mem::AllocatePage();
}
return *iter;

View File

@ -20,11 +20,28 @@ class MemoryObject : public KernelObject {
void CopyBytesToObject(uint64_t source, uint64_t length);
protected:
// Hacky to avoid linked_list creation.
MemoryObject(uint64_t size, bool) : size_(size) {}
private:
// Always stores the full page-aligned size.
uint64_t size_;
uint64_t PageNumberToPhysAddr(uint64_t page_num);
virtual uint64_t PageNumberToPhysAddr(uint64_t page_num);
LinkedList<uint64_t> phys_page_list_;
};
class FixedMemoryObject : public MemoryObject {
public:
FixedMemoryObject(uint64_t physical_addr, uint64_t size)
: MemoryObject(size, true), physical_addr_(physical_addr) {}
private:
uint64_t physical_addr_;
uint64_t PageNumberToPhysAddr(uint64_t page_num) override {
return physical_addr_ + (0x1000 * page_num);
}
};

View File

@ -6,6 +6,8 @@
#include "object/process.h"
#include "scheduler/scheduler.h"
#define K_THREAD_DEBUG 0
namespace {
extern "C" void jump_user_space(uint64_t rip, uint64_t rsp, uint64_t arg1,
@ -53,14 +55,18 @@ void Thread::Start(uint64_t entry, uint64_t arg1, uint64_t arg2) {
}
void Thread::Init() {
#if K_THREAD_DEBUG
dbgln("Thread start.", pid(), id_);
#endif
uint64_t rsp = process_.vmas()->AllocateUserStack();
SetRsp0(rsp0_start_);
jump_user_space(rip_, rsp, arg1_, arg2_);
}
void Thread::Exit() {
dbgln("Exiting", pid(), id_);
#if K_THREAD_DEBUG
dbgln("Exiting");
#endif
state_ = FINISHED;
process_.CheckState();
gScheduler->Yield();

View File

@ -2,6 +2,8 @@
#include <stdint.h>
#include "boot/acpi.h"
#include "common/msr.h"
#include "debug/debug.h"
#include "include/zcall.h"
#include "include/zerrors.h"
@ -15,24 +17,8 @@
#define STAR 0xC0000081
#define LSTAR 0xC0000082
namespace {
uint64_t GetMSR(uint32_t msr) {
uint32_t lo, hi;
asm("rdmsr" : "=a"(lo), "=d"(hi) : "c"(msr));
return (static_cast<uint64_t>(hi) << 32) | lo;
}
void SetMSR(uint32_t msr, uint64_t val) {
uint32_t lo = static_cast<uint32_t>(val);
uint32_t hi = val >> 32;
asm("wrmsr" ::"a"(lo), "d"(hi), "c"(msr));
}
extern "C" void syscall_enter();
} // namespace
// Used by syscall_enter.s
extern "C" uint64_t GetKernelRsp() {
return gScheduler->CurrentThread().Rsp0Start();
@ -144,6 +130,20 @@ z_err_t MemoryObjectCreate(ZMemoryObjectCreateReq* req,
return Z_OK;
}
z_err_t TempPcieConfigObjectCreate(ZTempPcieConfigObjectCreateResp* resp) {
auto& curr_proc = gScheduler->CurrentProcess();
uint64_t pci_base, pci_size;
dbgln("Getting config");
RET_ERR(GetPciExtendedConfiguration(&pci_base, &pci_size));
dbgln("Making obj");
auto vmmo_ref = MakeRefCounted<FixedMemoryObject>(pci_base, pci_size);
dbgln("Adding cap");
resp->vmmo_cap =
curr_proc.AddCapability(StaticCastRefPtr<MemoryObject>(vmmo_ref));
resp->vmmo_size = pci_size;
return Z_OK;
}
z_err_t ChannelCreate(ZChannelCreateResp* resp) {
auto& proc = gScheduler->CurrentProcess();
auto chan_pair = Channel::CreateChannelPair();
@ -201,6 +201,9 @@ extern "C" z_err_t SyscallHandler(uint64_t call_id, void* req, void* resp) {
return MemoryObjectCreate(
reinterpret_cast<ZMemoryObjectCreateReq*>(req),
reinterpret_cast<ZMemoryObjectCreateResp*>(resp));
case Z_TEMP_PCIE_CONFIG_OBJECT_CREATE:
return TempPcieConfigObjectCreate(
reinterpret_cast<ZTempPcieConfigObjectCreateResp*>(resp));
case Z_CHANNEL_CREATE:
return ChannelCreate(reinterpret_cast<ZChannelCreateResp*>(resp));
case Z_CHANNEL_SEND:

View File

@ -83,6 +83,14 @@ z_err_t ZMemoryObjectCreate(uint64_t size, uint64_t* vmmo_cap) {
return ret;
}
z_err_t ZTempPcieConfigObjectCreate(uint64_t* vmmo_cap, uint64_t* vmmo_size) {
ZTempPcieConfigObjectCreateResp resp;
z_err_t ret = SysCall2(Z_TEMP_PCIE_CONFIG_OBJECT_CREATE, 0, &resp);
*vmmo_cap = resp.vmmo_cap;
*vmmo_size = resp.vmmo_size;
return ret;
}
z_err_t ZChannelCreate(uint64_t* channel1, uint64_t* channel2) {
ZChannelCreateResp resp;
z_err_t ret = SysCall2(Z_CHANNEL_CREATE, 0, &resp);

View File

@ -46,6 +46,11 @@ struct ZMemoryObjectCreateResp {
uint64_t vmmo_cap;
};
struct ZTempPcieConfigObjectCreateResp {
uint64_t vmmo_cap;
uint64_t vmmo_size;
};
struct ZChannelCreateResp {
uint64_t chan_cap1;
uint64_t chan_cap2;

View File

@ -1,5 +1,6 @@
#include <stdint.h>
#include "boot/acpi.h"
#include "common/gdt.h"
#include "debug/debug.h"
#include "interrupt/interrupt.h"
@ -25,6 +26,9 @@ extern "C" void zion() {
dbgln("[boot] Memory allocations available now.");
dbgln("[boot] Probing Hardware");
ProbeRsdp();
dbgln("[boot] Init Kernel Stack Manager.");
KernelStackManager::Init();