kernel cleanup

This commit is contained in:
nakst 2021-10-25 10:01:56 +01:00
parent e546555787
commit 6fa375a9d8
18 changed files with 268 additions and 755 deletions

View File

@ -1,404 +0,0 @@
#include <efi.h>
#include <efilib.h>
#define ENTRIES_PER_PAGE_TABLE (512)
#define ENTRIES_PER_PAGE_TABLE_BITS (9)
#define K_PAGE_SIZE (4096)
#define K_PAGE_BITS (12)
typedef struct __attribute__((packed)) GDTData {
uint16_t length;
uint64_t address;
} GDTData;
typedef struct MemoryRegion {
uintptr_t base, pages;
} MemoryRegion;
#define MAX_MEMORY_REGIONS (1024)
MemoryRegion memoryRegions[1024];
#define KERNEL_BUFFER_SIZE (1048576)
#define kernelBuffer ((char *) 0x200000)
#define IID_BUFFER_SIZE (64)
char iidBuffer[IID_BUFFER_SIZE];
#define MEMORY_MAP_BUFFER_SIZE (16384)
char memoryMapBuffer[MEMORY_MAP_BUFFER_SIZE];
#define VESA_VM_INFO_ONLY
#define ARCH_64
#include "../../kernel/graphics.cpp"
#include "../../kernel/elf.cpp"
void ZeroMemory(void *pointer, uint64_t size) {
char *d = (char *) pointer;
for (uintptr_t i = 0; i < size; i++) {
d[i] = 0;
}
}
EFI_STATUS EFIAPI efi_main(EFI_HANDLE imageHandle, EFI_SYSTEM_TABLE *systemTable) {
UINTN mapKey;
uint32_t *framebuffer, horizontalResolution, verticalResolution, pixelsPerScanline;
InitializeLib(imageHandle, systemTable);
ElfHeader *header;
Print(L"Loading OS...\n");
// Make sure 0x100000 -> 0x300000 is identity mapped.
{
EFI_PHYSICAL_ADDRESS address = 0x100000;
if (EFI_SUCCESS != uefi_call_wrapper(ST->BootServices->AllocatePages, 4, AllocateAddress, EfiLoaderData, 0x200, &address)) {
Print(L"Error: Could not map 0x100000 -> 0x180000.\n");
while (1);
}
}
// Find the RSDP.
{
for (uintptr_t i = 0; i < systemTable->NumberOfTableEntries; i++) {
EFI_CONFIGURATION_TABLE *entry = systemTable->ConfigurationTable + i;
if (entry->VendorGuid.Data1 == 0x8868E871 && entry->VendorGuid.Data2 == 0xE4F1 && entry->VendorGuid.Data3 == 0x11D3
&& entry->VendorGuid.Data4[0] == 0xBC && entry->VendorGuid.Data4[1] == 0x22 && entry->VendorGuid.Data4[2] == 0x00
&& entry->VendorGuid.Data4[3] == 0x80 && entry->VendorGuid.Data4[4] == 0xC7 && entry->VendorGuid.Data4[5] == 0x3C
&& entry->VendorGuid.Data4[6] == 0x88 && entry->VendorGuid.Data4[7] == 0x81) {
*((uint64_t *) 0x107FE8) = (uint64_t) entry->VendorTable;
Print(L"The RSDP can be found at 0x%x.\n", entry->VendorTable);
}
}
}
// Read the kernel, IID and loader files.
{
EFI_GUID loadedImageProtocolGUID = LOADED_IMAGE_PROTOCOL;
EFI_GUID simpleFilesystemProtocolGUID = SIMPLE_FILE_SYSTEM_PROTOCOL;
EFI_LOADED_IMAGE_PROTOCOL *loadedImageProtocol;
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *simpleFilesystemProtocol;
EFI_FILE *filesystemRoot, *kernelFile, *iidFile, *loaderFile;
UINTN size;
if (EFI_SUCCESS != uefi_call_wrapper(ST->BootServices->OpenProtocol, 6, imageHandle, &loadedImageProtocolGUID, &loadedImageProtocol, imageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL)) {
Print(L"Error: Could not open protocol 1.\n");
while (1);
}
EFI_HANDLE deviceHandle = loadedImageProtocol->DeviceHandle;
if (EFI_SUCCESS != uefi_call_wrapper(ST->BootServices->OpenProtocol, 6, deviceHandle, &simpleFilesystemProtocolGUID, &simpleFilesystemProtocol, imageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL)) {
Print(L"Error: Could not open procotol 2.\n");
while (1);
}
if (EFI_SUCCESS != uefi_call_wrapper(simpleFilesystemProtocol->OpenVolume, 2, simpleFilesystemProtocol, &filesystemRoot)) {
Print(L"Error: Could not open ESP volume.\n");
while (1);
}
if (EFI_SUCCESS != uefi_call_wrapper(filesystemRoot->Open, 5, filesystemRoot, &kernelFile, L"EssenceKernel.esx", EFI_FILE_MODE_READ, 0)) {
Print(L"Error: Could not open EssenceKernel.esx.\n");
while (1);
}
size = KERNEL_BUFFER_SIZE;
if (EFI_SUCCESS != uefi_call_wrapper(kernelFile->Read, 3, kernelFile, &size, kernelBuffer)) {
Print(L"Error: Could not load EssenceKernel.esx.\n");
while (1);
}
Print(L"Kernel size: %d bytes\n", size);
if (size == KERNEL_BUFFER_SIZE) {
Print(L"Kernel too large to fit into buffer.\n");
while (1);
}
if (EFI_SUCCESS != uefi_call_wrapper(filesystemRoot->Open, 5, filesystemRoot, &iidFile, L"EssenceIID.dat", EFI_FILE_MODE_READ, 0)) {
Print(L"Error: Could not open EssenceIID.dat.\n");
while (1);
}
size = IID_BUFFER_SIZE;
if (EFI_SUCCESS != uefi_call_wrapper(iidFile->Read, 3, iidFile, &size, iidBuffer)) {
Print(L"Error: Could not load EssenceIID.dat.\n");
while (1);
}
if (EFI_SUCCESS != uefi_call_wrapper(filesystemRoot->Open, 5, filesystemRoot, &loaderFile, L"EssenceLoader.bin", EFI_FILE_MODE_READ, 0)) {
Print(L"Error: Could not open EssenceLoader.bin.\n");
while (1);
}
size = 0x80000;
if (EFI_SUCCESS != uefi_call_wrapper(loaderFile->Read, 3, loaderFile, &size, (char *) 0x180000)) {
Print(L"Error: Could not load EssenceLoader.bin.\n");
while (1);
}
}
#if 0
// Print the memory map.
{
UINTN descriptorSize, descriptorVersion, size = MEMORY_MAP_BUFFER_SIZE;
if (EFI_SUCCESS != uefi_call_wrapper(ST->BootServices->GetMemoryMap, 5, &size, (EFI_MEMORY_DESCRIPTOR *) memoryMapBuffer, &mapKey, &descriptorSize, &descriptorVersion)) {
Print(L"Error: Could not get memory map.\n");
while (1);
}
WCHAR *memoryTypes[] = {
L"EfiReservedMemoryType",
L"EfiLoaderCode",
L"EfiLoaderData",
L"EfiBootServicesCode",
L"EfiBootServicesData",
L"EfiRuntimeServicesCode",
L"EfiRuntimeServicesData",
L"EfiConventionalMemory",
L"EfiUnusableMemory",
L"EfiACPIReclaimMemory",
L"EfiACPIMemoryNVS",
L"EfiMemoryMappedIO",
L"EfiMemoryMappedIOPortSpace",
L"EfiPalCode",
L"EfiMaxMemoryType",
};
for (uintptr_t i = 0; i < size / descriptorSize; i++) {
EFI_MEMORY_DESCRIPTOR *descriptor = (EFI_MEMORY_DESCRIPTOR *) (memoryMapBuffer + i * descriptorSize);
Print(L"memory %s: %llx -> %llx\n", memoryTypes[descriptor->Type], descriptor->PhysicalStart, descriptor->PhysicalStart + descriptor->NumberOfPages * 0x1000 - 1);
}
}
#endif
// Get the graphics mode information.
{
EFI_GRAPHICS_OUTPUT_PROTOCOL *graphicsOutputProtocol;
EFI_GUID graphicsOutputProtocolGUID = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
if (EFI_SUCCESS != uefi_call_wrapper(ST->BootServices->LocateProtocol, 3, &graphicsOutputProtocolGUID, NULL, &graphicsOutputProtocol)) {
Print(L"Error: Could not open protocol 3.\n");
while (1);
}
int32_t desiredMode = -1;
Print(L"Select a graphics mode:\n");
for (uint32_t i = 0; i < graphicsOutputProtocol->Mode->MaxMode; i++) {
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *modeInformation;
UINTN modeInformationSize;
uefi_call_wrapper(graphicsOutputProtocol->QueryMode, 4, graphicsOutputProtocol, i, &modeInformationSize, &modeInformation);
if (modeInformation->HorizontalResolution >= 800 && modeInformation->VerticalResolution >= 600) {
Print(L" %d: %d by %d\n", i + 1, modeInformation->HorizontalResolution, modeInformation->VerticalResolution);
}
}
Print(L"> ");
while (1) {
UINTN index;
uefi_call_wrapper(ST->BootServices->WaitForEvent, 3, 1, &systemTable->ConIn->WaitForKey, &index);
EFI_INPUT_KEY key;
uefi_call_wrapper(systemTable->ConIn->ReadKeyStroke, 2, systemTable->ConIn, &key);
if (key.UnicodeChar >= '0' && key.UnicodeChar <= '9') {
if (desiredMode == -1) desiredMode = 0;
desiredMode = (desiredMode * 10) + key.UnicodeChar - '0';
Print(L"%c", key.UnicodeChar);
} else if (key.UnicodeChar == 13) {
break;
}
}
Print(L"\n");
if (desiredMode != -1) {
Print(L"Setting mode %d...\n", desiredMode);
desiredMode--;
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *modeInformation;
UINTN modeInformationSize;
uefi_call_wrapper(graphicsOutputProtocol->QueryMode, 4, graphicsOutputProtocol, desiredMode, &modeInformationSize, &modeInformation);
horizontalResolution = modeInformation->HorizontalResolution;
verticalResolution = modeInformation->VerticalResolution;
pixelsPerScanline = modeInformation->PixelsPerScanLine;
uefi_call_wrapper(graphicsOutputProtocol->SetMode, 2, graphicsOutputProtocol, desiredMode);
} else {
horizontalResolution = graphicsOutputProtocol->Mode->Info->HorizontalResolution;
verticalResolution = graphicsOutputProtocol->Mode->Info->VerticalResolution;
pixelsPerScanline = graphicsOutputProtocol->Mode->Info->PixelsPerScanLine;
}
framebuffer = (uint32_t *) graphicsOutputProtocol->Mode->FrameBufferBase;
}
// Get the memory map.
{
UINTN descriptorSize, descriptorVersion, size = MEMORY_MAP_BUFFER_SIZE;
if (EFI_SUCCESS != uefi_call_wrapper(ST->BootServices->GetMemoryMap, 5, &size, (EFI_MEMORY_DESCRIPTOR *) memoryMapBuffer, &mapKey, &descriptorSize, &descriptorVersion)) {
Print(L"Error: Could not get memory map.\n");
while (1);
}
uintptr_t memoryRegionCount = 0;
for (uintptr_t i = 0; i < size / descriptorSize && memoryRegionCount != MAX_MEMORY_REGIONS - 1; i++) {
EFI_MEMORY_DESCRIPTOR *descriptor = (EFI_MEMORY_DESCRIPTOR *) (memoryMapBuffer + i * descriptorSize);
if (descriptor->Type == EfiConventionalMemory && descriptor->PhysicalStart >= 0x300000) {
memoryRegions[memoryRegionCount].base = descriptor->PhysicalStart;
memoryRegions[memoryRegionCount].pages = descriptor->NumberOfPages;
memoryRegionCount++;
}
}
memoryRegions[memoryRegionCount].base = 0;
}
// Exit boot services.
{
if (EFI_SUCCESS != uefi_call_wrapper(ST->BootServices->ExitBootServices, 2, imageHandle, mapKey)) {
Print(L"Error: Could not exit boot services.\n");
while (1);
}
}
// Identity map the first 3MB for the loader.
{
uint64_t *paging = (uint64_t *) 0x140000;
ZeroMemory(paging, 0x5000);
paging[0x1FE] = 0x140003;
paging[0x000] = 0x141003;
paging[0x200] = 0x142003;
paging[0x400] = 0x143003;
paging[0x401] = 0x144003;
for (uintptr_t i = 0; i < 0x400; i++) {
paging[0x600 + i] = (i * 0x1000) | 3;
}
}
// Copy the installation ID across.
{
uint8_t *destination = (uint8_t *) (0x107FF0);
for (uintptr_t i = 0; i < 16; i++) {
char c1 = iidBuffer[i * 3 + 0];
char c2 = iidBuffer[i * 3 + 1];
if (c1 >= '0' && c1 <= '9') c1 -= '0'; else c1 -= 'A' - 10;
if (c2 >= '0' && c2 <= '9') c2 -= '0'; else c2 -= 'A' - 10;
destination[i] = (c2) | ((c1) << 4);
}
}
// Copy the graphics information across.
{
struct VESAVideoModeInformation *destination = (struct VESAVideoModeInformation *) (0x107000);
destination->widthPixels = horizontalResolution;
destination->heightPixels = verticalResolution;
destination->bufferPhysical = (uintptr_t) framebuffer; // TODO 64-bit framebuffers.
destination->bytesPerScanlineLinear = pixelsPerScanline * 4;
destination->bitsPerPixel = 32;
}
// Allocate and map memory for the kernel.
{
uint64_t nextPageTable = 0x1C0000;
header = (ElfHeader *) kernelBuffer;
ElfProgramHeader *programHeaders = (ElfProgramHeader *) (kernelBuffer + header->programHeaderTable);
uintptr_t programHeaderEntrySize = header->programHeaderEntrySize;
for (uintptr_t i = 0; i < header->programHeaderEntries; i++) {
ElfProgramHeader *header = (ElfProgramHeader *) ((uint8_t *) programHeaders + programHeaderEntrySize * i);
if (header->type != 1) continue;
uintptr_t pagesToAllocate = header->segmentSize >> 12;
if (header->segmentSize & 0xFFF) pagesToAllocate++;
uintptr_t physicalAddress = 0;
for (uintptr_t j = 0; j < MAX_MEMORY_REGIONS; j++) {
MemoryRegion *region = memoryRegions + j;
if (!region->base) break;
if (region->pages < pagesToAllocate) continue;
physicalAddress = region->base;
region->pages -= pagesToAllocate;
region->base += pagesToAllocate << 12;
break;
}
if (!physicalAddress) {
// TODO Error handling.
*((uint32_t *) framebuffer + 3) = 0xFFFF00FF;
while (1);
}
for (uintptr_t j = 0; j < pagesToAllocate; j++, physicalAddress += 0x1000) {
uintptr_t virtualAddress = header->virtualAddress + j * K_PAGE_SIZE;
physicalAddress &= 0xFFFFFFFFFFFFF000;
virtualAddress &= 0x0000FFFFFFFFF000;
uintptr_t indexL4 = (virtualAddress >> (K_PAGE_BITS + ENTRIES_PER_PAGE_TABLE_BITS * 3)) & (ENTRIES_PER_PAGE_TABLE - 1);
uintptr_t indexL3 = (virtualAddress >> (K_PAGE_BITS + ENTRIES_PER_PAGE_TABLE_BITS * 2)) & (ENTRIES_PER_PAGE_TABLE - 1);
uintptr_t indexL2 = (virtualAddress >> (K_PAGE_BITS + ENTRIES_PER_PAGE_TABLE_BITS * 1)) & (ENTRIES_PER_PAGE_TABLE - 1);
uintptr_t indexL1 = (virtualAddress >> (K_PAGE_BITS + ENTRIES_PER_PAGE_TABLE_BITS * 0)) & (ENTRIES_PER_PAGE_TABLE - 1);
uint64_t *tableL4 = (uint64_t *) 0x140000;
if (!(tableL4[indexL4] & 1)) {
tableL4[indexL4] = nextPageTable | 7;
ZeroMemory((void *) nextPageTable, K_PAGE_SIZE);
nextPageTable += K_PAGE_SIZE;
}
uint64_t *tableL3 = (uint64_t *) (tableL4[indexL4] & ~(K_PAGE_SIZE - 1));
if (!(tableL3[indexL3] & 1)) {
tableL3[indexL3] = nextPageTable | 7;
ZeroMemory((void *) nextPageTable, K_PAGE_SIZE);
nextPageTable += K_PAGE_SIZE;
}
uint64_t *tableL2 = (uint64_t *) (tableL3[indexL3] & ~(K_PAGE_SIZE - 1));
if (!(tableL2[indexL2] & 1)) {
tableL2[indexL2] = nextPageTable | 7;
ZeroMemory((void *) nextPageTable, K_PAGE_SIZE);
nextPageTable += K_PAGE_SIZE;
}
uint64_t *tableL1 = (uint64_t *) (tableL2[indexL2] & ~(K_PAGE_SIZE - 1));
uintptr_t value = physicalAddress | 3;
tableL1[indexL1] = value;
}
}
}
// Copy the memory regions information across.
{
MemoryRegion *destination = (MemoryRegion *) 0x160000;
for (uintptr_t i = 0; i < MAX_MEMORY_REGIONS; i++) {
destination[i] = memoryRegions[i];
}
}
// Start the loader.
{
((void (*)()) 0x180000)();
}
while (1);
return EFI_SUCCESS;
}

View File

@ -55,13 +55,6 @@ _EsCRTlongjmp:
.return:
ret
[global ProcessorReadTimeStamp]
ProcessorReadTimeStamp:
rdtsc
shl rdx,32
or rax,rdx
ret
[global EsCRTsqrt]
EsCRTsqrt:
sqrtsd xmm0,xmm0
@ -72,6 +65,13 @@ EsCRTsqrtf:
sqrtss xmm0,xmm0
ret
[global ProcessorReadTimeStamp]
ProcessorReadTimeStamp:
rdtsc
shl rdx,32
or rax,rdx
ret
[global ProcessorCheckStackAlignment]
ProcessorCheckStackAlignment:
mov rax,rsp
@ -94,11 +94,3 @@ ProcessorTLSRead:
ProcessorTLSWrite:
mov [fs:rdi],rsi
ret
[global __cyg_profile_func_enter]
__cyg_profile_func_enter:
ret
[global __cyg_profile_func_exit]
__cyg_profile_func_exit:
ret

View File

@ -63,7 +63,7 @@ typedef struct EsElementPublic EsElementPublic;
#ifdef ARCH_X86_64
#define ES_API_BASE ((void **) 0x1000)
#define ES_SHARED_MEMORY_MAXIMUM_SIZE ((size_t) (1024) * 1024 * 1024 * 1024)
#define ES_PAGE_SIZE (4096)
#define ES_PAGE_SIZE ((uintptr_t) 4096)
#define ES_PAGE_BITS (12)
typedef struct EsCRTjmp_buf {

View File

@ -142,6 +142,10 @@ void ACPILapic::WriteRegister(uint32_t reg, uint32_t value) {
#ifdef ARCH_X86_COMMON
uint64_t ArchGetTimeMs() {
// Update the time stamp counter synchronization value.
timeStampCounterSynchronizationValue = ((timeStampCounterSynchronizationValue & 0x8000000000000000)
^ 0x8000000000000000) | ProcessorReadTimeStamp();
if (acpi.hpetBaseAddress && acpi.hpetPeriod) {
__int128 fsToMs = 1000000000000;
__int128 reading = acpi.hpetBaseAddress[30];
@ -724,7 +728,7 @@ void ACPIEnumeratePRTEntries(ACPI_HANDLE pciBus) {
} else if (table->Pin > 3) {
KernelLog(LOG_ERROR, "ACPI", "unexpected pin", "Pin %d was larger than expected.\n", table->Pin);
} else {
pciIRQLines[table->Address >> 16][table->Pin] = irq;
ArchSetPCIIRQLine(table->Address >> 16, table->Pin, irq);
}
}
}

View File

@ -214,7 +214,13 @@ bool KPCIDevice::EnableSingleInterrupt(KIRQHandler irqHandler, void *context, co
// If we booted from EFI, we need to get the interrupt line from ACPI.
// See the comment in InterruptHandler for what happens when passing -1.
if (KRegisterIRQ(KBootedFromEFI() ? -1 : interruptLine, irqHandler, context, cOwnerName, this)) {
intptr_t line = interruptLine;
#ifdef ARCH_X86_COMMON
extern uint32_t bootloaderID;
if (bootloaderID == 2) line = -1;
#endif
if (KRegisterIRQ(line, irqHandler, context, cOwnerName, this)) {
return true;
}

View File

@ -303,7 +303,7 @@ int PS2ReadKey() {
}
int KWaitKey() {
if (!ps2.channels) ProcessorHalt();
if (!ps2.channels) return -1;
int scancode;
while (!(scancode = PS2ReadKey()));
return scancode;

View File

@ -139,14 +139,9 @@ EsError KLoadELF(KNode *node, KLoadedExecutable *executable) {
}
}
#ifdef ARCH_X86_64
if (header.mapAddress > 0x8000000000000000UL || header.mapAddress < 0x1000 || fileSize > 0x1000000000000UL
|| header.mapAddress & (K_PAGE_SIZE - 1)) {
if (ArchCheckBundleHeader() || header.mapAddress & (K_PAGE_SIZE - 1)) {
return ES_ERROR_UNSUPPORTED_EXECUTABLE;
}
#else
#error Unimplemented.
#endif
if (header.version != 1) {
return ES_ERROR_UNSUPPORTED_EXECUTABLE;
@ -162,12 +157,7 @@ EsError KLoadELF(KNode *node, KLoadedExecutable *executable) {
// Look for the executable in the bundle.
#ifdef ARCH_X86_64
uint64_t name = CalculateCRC64(EsLiteral("$Executables/x86_64"));
#else
#error Unimplemented.
#endif
uint64_t name = CalculateCRC64(EsLiteral("$Executables/" K_ARCH_NAME));
BundleFile *files = (BundleFile *) ((BundleHeader *) header.mapAddress + 1);
bool found = false;
@ -214,13 +204,9 @@ EsError KLoadELF(KNode *node, KLoadedExecutable *executable) {
ElfProgramHeader *header = (ElfProgramHeader *) ((uint8_t *) programHeaders + programHeaderEntrySize * i);
if (header->type == 1 /* PT_LOAD */) {
#ifdef ARCH_X86_64
if (header->virtualAddress > 0x8000000000000000UL || header->virtualAddress < 0x1000 || header->segmentSize > 0x1000000000000UL) {
if (ArchCheckELFHeader()) {
return ES_ERROR_UNSUPPORTED_EXECUTABLE;
}
#else
#error Unimplemented.
#endif
#if 0
EsPrint("FileOffset %x VirtualAddress %x SegmentSize %x DataInFile %x\n",
@ -403,17 +389,8 @@ EsError KLoadELFModule(KModule *module) {
// EsPrint("\t%d: %z (%x), %d, %x, %x\n", i, buffer + symbol->name + strings->offset, symbol->value, type, offset, relocation->addend);
uintptr_t result = symbol->value + relocation->addend;
#ifdef ARCH_X86_64
if (type == 0) {}
else if (type == 10 /* R_X86_64_32 */) *((uint32_t *) (buffer + offset)) = result;
else if (type == 11 /* R_X86_64_32S */) *((uint32_t *) (buffer + offset)) = result;
else if (type == 1 /* R_X86_64_64 */) *((uint64_t *) (buffer + offset)) = result;
else if (type == 2 /* R_X86_64_PC32 */) *((uint32_t *) (buffer + offset)) = result - ((uint64_t) buffer + offset);
else if (type == 24 /* R_X86_64_PC64 */) *((uint64_t *) (buffer + offset)) = result - ((uint64_t) buffer + offset);
else if (type == 4 /* R_X86_64_PLT32 */) *((uint32_t *) (buffer + offset)) = result - ((uint64_t) buffer + offset);
#endif
else return ES_ERROR_UNSUPPORTED_FEATURE;
EsError error = ArchApplyRelocation(type, buffer, offset, result);
if (error != ES_SUCCESS) return error;
}
}

View File

@ -4,7 +4,9 @@
#define K_PRIVATE
#include "module.h"
//////////////////////////////////
// ---------------------------------------------------------------------------------------------------------------
// Constants.
// ---------------------------------------------------------------------------------------------------------------
// TODO Determine the best values for these constants.
@ -62,11 +64,9 @@
#define PHYSICAL_MEMORY_MANIPULATION_REGION_PAGES (16)
#define POOL_CACHE_COUNT (16)
//////////////////////////////////
#include <shared/ini.h>
#define EsAssertionFailure(file, line) KernelPanic("%z:%d - EsAssertionFailure called.\n", file, line)
// ---------------------------------------------------------------------------------------------------------------
// Core definitions.
// ---------------------------------------------------------------------------------------------------------------
#ifdef ARCH_X86_64
#include "x86_64.cpp"
@ -98,93 +98,141 @@ struct CPULocalStorage {
volatile uint8_t asyncTasksRead, asyncTasksWrite;
};
//////////////////////////////////
struct PhysicalMemoryRegion {
uint64_t baseAddress;
uint64_t pageCount;
};
void KernelInitialise();
void KernelShutdown(uintptr_t action);
void ArchInitialise();
void ArchShutdown(uintptr_t action);
extern "C" void ArchResetCPU();
extern "C" void ArchSpeakerBeep();
extern "C" void ArchNextTimer(size_t ms); // Schedule the next TIMER_INTERRUPT.
extern "C" uint64_t ArchGetTimeMs(); // Called by the scheduler on the boot processor every context switch.
InterruptContext *ArchInitialiseThread(uintptr_t kernelStack, uintptr_t kernelStackSize, struct Thread *thread,
uintptr_t startAddress, uintptr_t argument1, uintptr_t argument2,
bool userland, uintptr_t stack, uintptr_t userStackSize);
void StartDebugOutput();
uint64_t timeStampTicksPerMs;
EsUniqueIdentifier installationID; // The identifier of this OS installation, given to us by the bootloader.
struct Process *desktopProcess;
KSpinlock ipiLock;
// ---------------------------------------------------------------------------------------------------------------
// Architecture specific layer definitions.
// ---------------------------------------------------------------------------------------------------------------
//////////////////////////////////
extern "C" {
void ArchInitialise();
void ArchShutdown(uintptr_t action);
void ArchNextTimer(size_t ms); // Schedule the next TIMER_INTERRUPT.
uint64_t ArchGetTimeMs(); // Called by the scheduler on the boot processor every context switch.
InterruptContext *ArchInitialiseThread(uintptr_t kernelStack, uintptr_t kernelStackSize, struct Thread *thread,
uintptr_t startAddress, uintptr_t argument1, uintptr_t argument2,
bool userland, uintptr_t stack, uintptr_t userStackSize);
EsError ArchApplyRelocation(uintptr_t type, uint8_t *buffer, uintptr_t offset, uintptr_t result);
void ArchSwitchContext(struct InterruptContext *context, struct MMArchVAS *virtualAddressSpace, uintptr_t threadKernelStack,
struct Thread *newThread, struct MMSpace *oldAddressSpace);
void MMArchRemap(MMSpace *space, const void *virtualAddress, uintptr_t newPhysicalAddress); // Must be done with interrupts disabled; does not invalidate on other processors.
bool MMArchMapPage(MMSpace *space, uintptr_t physicalAddress, uintptr_t virtualAddress, unsigned flags); // Returns false if the page was already mapped.
void MMArchUnmapPages(MMSpace *space, uintptr_t virtualAddressStart, uintptr_t pageCount, unsigned flags, size_t unmapMaximum = 0, uintptr_t *resumePosition = nullptr);
void MMArchInvalidatePages(uintptr_t virtualAddressStart, uintptr_t pageCount);
bool MMArchHandlePageFault(uintptr_t address, uint32_t flags);
void MMArchInitialiseVAS();
bool MMArchInitialiseUserSpace(MMSpace *space);
bool MMArchCommitPageTables(MMSpace *space, struct MMRegion *region);
bool MMArchMakePageWritable(MMSpace *space, uintptr_t virtualAddress);
bool MMArchIsBufferInUserRange(uintptr_t baseAddress, size_t byteCount);
bool MMArchSafeCopy(uintptr_t destinationAddress, uintptr_t sourceAddress, size_t byteCount); // Returns false if a page fault occured during the copy.
void MMArchFreeVAS(MMSpace *space);
void MMArchFinalizeVAS(MMSpace *space);
void ProcessorDisableInterrupts();
void ProcessorEnableInterrupts();
bool ProcessorAreInterruptsEnabled();
void ArchResetCPU();
void ProcessorHalt();
void ProcessorSendYieldIPI(Thread *thread);
void ProcessorFakeTimerInterrupt();
void ProcessorInvalidatePage(uintptr_t virtualAddress);
void ProcessorInvalidateAllPages();
void ProcessorFlushCodeCache();
void ProcessorFlushCache();
void ProcessorSetLocalStorage(struct CPULocalStorage *cls);
void ProcessorSetThreadStorage(uintptr_t tls);
void ProcessorSetAddressSpace(struct MMArchVAS *virtualAddressSpace); // Need to call MMSpaceOpenReference/MMSpaceCloseReference if using this.
uint64_t ProcessorReadTimeStamp();
struct CPULocalStorage *GetLocalStorage();
struct Thread *GetCurrentThread();
extern PhysicalMemoryRegion *physicalMemoryRegions;
extern size_t physicalMemoryRegionsCount;
extern size_t physicalMemoryRegionsPagesCount;
extern size_t physicalMemoryOriginalPagesCount;
extern size_t physicalMemoryRegionsIndex;
extern uintptr_t physicalMemoryHighest;
// From module.h:
// uintptr_t MMArchTranslateAddress(MMSpace *space, uintptr_t virtualAddress, bool writeAccess);
// uint32_t KPCIReadConfig(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset, int size);
// void KPCIWriteConfig(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset, uint32_t value, int size);
// bool KRegisterIRQ(intptr_t interruptIndex, KIRQHandler handler, void *context, const char *cOwnerName, struct KPCIDevice *pciDevice);
// KMSIInformation KRegisterMSI(KIRQHandler handler, void *context, const char *cOwnerName);
// void KUnregisterMSI(uintptr_t tag);
}
#endif
// ---------------------------------------------------------------------------------------------------------------
// Kernel components.
// ---------------------------------------------------------------------------------------------------------------
#include <shared/avl_tree.cpp>
#include <shared/bitset.cpp>
#include <shared/range_set.cpp>
#include "memory.cpp"
#ifndef IMPLEMENTATION
#include <shared/heap.cpp>
#include <shared/arena.cpp>
#else
#define ARRAY_IMPLEMENTATION_ONLY
#include <shared/array.cpp>
#include <shared/partitions.cpp>
#endif
#include "objects.cpp"
#include "syscall.cpp"
#include "scheduler.cpp"
#include "synchronisation.cpp"
#include "drivers.cpp"
#include "cache.cpp"
#include "elf.cpp"
#include "graphics.cpp"
#include "cache.cpp"
#include "files.cpp"
#include "windows.cpp"
#include "networking.cpp"
#include "terminal.cpp"
#include "drivers.cpp"
#ifdef ENABLE_POSIX_SUBSYSTEM
#include "posix.cpp"
#endif
#ifndef IMPLEMENTATION
#define ARRAY_IMPLEMENTATION_ONLY
#include <shared/array.cpp>
#include <shared/heap.cpp>
#include <shared/arena.cpp>
#include <shared/partitions.cpp>
#include <shared/ini.h>
#endif
// ---------------------------------------------------------------------------------------------------------------
// Miscellaneous.
// ---------------------------------------------------------------------------------------------------------------
#ifdef IMPLEMENTATION
//////////////////////////////////
extern "C" uint64_t KGetTimeInMs() {
if (!timeStampTicksPerMs) return 0;
uint64_t KGetTimeInMs() {
return scheduler.timeMs;
}
uint64_t KGetTimeStampTicksPerMs() {
return timeStampTicksPerMs;
}
uint64_t KGetTimeStampTicksPerUs() {
return timeStampTicksPerMs / 1000;
}
bool KInIRQ() {
return GetLocalStorage()->inIRQ;
}
bool KBootedFromEFI() {
extern uint32_t bootloaderID;
return bootloaderID == 2;
}
bool KInIRQ() {
return GetLocalStorage()->inIRQ;
}
void KSwitchThreadAfterIRQ() {
GetLocalStorage()->irqSwitchThread = true;
}
@ -193,12 +241,19 @@ EsUniqueIdentifier KGetBootIdentifier() {
return installationID;
}
//////////////////////////////////
void EsAssertionFailure(const char *file, int line) {
KernelPanic("%z:%d - EsAssertionFailure called.\n", file, line);
}
#ifdef ARCH_X86_64
#endif
// ---------------------------------------------------------------------------------------------------------------
// Architecture specific layer implementation.
// ---------------------------------------------------------------------------------------------------------------
#if defined(ARCH_X86_64) && defined(IMPLEMENTATION)
#include "x86_64.h"
#include "terminal.cpp"
#include <drivers/acpi.cpp>
#include "x86_64.cpp"
#endif
#endif

View File

@ -10,7 +10,7 @@
#include "kernel.h"
extern "C" void KernelMain() {
scheduler.SpawnProcess(PROCESS_KERNEL); // Spawn the kernel process.
kernelProcess = scheduler.SpawnProcess(PROCESS_KERNEL); // Spawn the kernel process.
ArchInitialise(); // Start processors and initialise CPULocalStorage.
scheduler.started = true; // Start the pre-emptive scheduler.
// Continues in KernelInitialise.

View File

@ -66,7 +66,7 @@ struct MMRegion {
// One per process.
struct MMSpace {
VIRTUAL_ADDRESS_SPACE_DATA(); // Architecture specific data.
MMArchVAS data; // Architecture specific data.
AVLTree<MMRegion> // Key =
freeRegionsBase, // Base address
@ -173,7 +173,7 @@ struct PMM {
KSpinlock pmManipulationProcessorLock;
void *pmManipulationRegion;
Thread *zeroPageThread, *balanceThread;
Thread *zeroPageThread;
KEvent zeroPageEvent;
LinkedList<MMObjectCache> objectCacheList;
@ -191,7 +191,7 @@ struct PMM {
// These variables will be cleared if the object they point to is removed.
// See MMUnreserve and Scheduler::RemoveProcess.
Process *nextProcessToBalance;
struct Process *nextProcessToBalance;
MMRegion *nextRegionToBalance;
uintptr_t balanceResumePosition;
};
@ -247,22 +247,6 @@ extern MMSpace _kernelMMSpace, _coreMMSpace;
#define MM_SHARED_ENTRY_PRESENT (1)
// Architecture-dependent functions.
bool MMArchMapPage(MMSpace *space, uintptr_t physicalAddress, uintptr_t virtualAddress, unsigned flags); // Returns false if the page was already mapped.
void MMArchUnmapPages(MMSpace *space, uintptr_t virtualAddressStart, uintptr_t pageCount, unsigned flags, size_t unmapMaximum = 0, uintptr_t *resumePosition = nullptr);
void MMArchInvalidatePages(uintptr_t virtualAddressStart, uintptr_t pageCount);
bool MMArchHandlePageFault(uintptr_t address, uint32_t flags);
uintptr_t MMArchTranslateAddress(MMSpace *space, uintptr_t virtualAddress, bool writeAccess);
void MMArchInitialiseVAS();
bool MMArchInitialiseUserSpace(MMSpace *space);
bool MMArchCommitPageTables(MMSpace *space, MMRegion *region);
bool MMArchMakePageWritable(MMSpace *space, uintptr_t virtualAddress);
bool MMArchIsBufferInUserRange(uintptr_t baseAddress, size_t byteCount);
extern "C" bool MMArchSafeCopy(uintptr_t destinationAddress, uintptr_t sourceAddress, size_t byteCount); // Returns false if a page fault occured during the copy.
void MMFreeVAS(MMSpace *space);
void MMFinalizeVAS(MMSpace *space);
// Forward declarations.
bool MMHandlePageFault(MMSpace *space, uintptr_t address, unsigned flags);
@ -293,22 +277,6 @@ MMRegion *MMFindRegion(MMSpace *space, uintptr_t address);
void *MMMapFile(MMSpace *space, struct FSFile *node, EsFileOffset offset, size_t bytes,
int protection, void *baseAddress, size_t zeroedBytes = 0, uint32_t additionalFlags = ES_FLAGS_DEFAULT);
// Physical memory information from the bootloader.
struct PhysicalMemoryRegion {
uint64_t baseAddress;
// The memory map the BIOS provides gives the information in pages.
uint64_t pageCount;
};
extern PhysicalMemoryRegion *physicalMemoryRegions;
extern size_t physicalMemoryRegionsCount;
extern size_t physicalMemoryRegionsPagesCount;
extern size_t physicalMemoryOriginalPagesCount;
extern size_t physicalMemoryRegionsIndex;
extern uintptr_t physicalMemoryHighest;
// Physical memory manipulation.
void PMZero(uintptr_t *pages, size_t pageCount,
@ -1649,7 +1617,7 @@ void MMSpaceDestroy(MMSpace *space) {
EsHeapFree(item->thisItem, sizeof(MMRegion), K_CORE);
}
MMFreeVAS(space);
MMArchFreeVAS(space);
}
bool MMUnmapFilePage(uintptr_t frameNumber) {
@ -2301,7 +2269,7 @@ void MMSpaceCloseReference(MMSpace *space) {
KRegisterAsyncTask([] (EsGeneric _space) {
MMSpace *space = (MMSpace *) _space.p;
MMFinalizeVAS(space);
MMArchFinalizeVAS(space);
scheduler.mmSpacePool.Remove(space);
}, space);
}
@ -2374,8 +2342,7 @@ void MMInitialise() {
pmm.zeroPageEvent.autoReset = true;
MMCommit(PHYSICAL_MEMORY_MANIPULATION_REGION_PAGES * K_PAGE_SIZE, true);
pmm.zeroPageThread = scheduler.SpawnThread("MMZero", (uintptr_t) MMZeroPageThread, 0, SPAWN_THREAD_LOW_PRIORITY);
pmm.balanceThread = scheduler.SpawnThread("MMBalance", (uintptr_t) MMBalanceThread, 0, ES_FLAGS_DEFAULT);
pmm.balanceThread->isPageGenerator = true;
scheduler.SpawnThread("MMBalance", (uintptr_t) MMBalanceThread, 0, ES_FLAGS_DEFAULT)->isPageGenerator = true;
scheduler.SpawnThread("MMObjTrim", (uintptr_t) MMObjectCacheTrimThread, 0, ES_FLAGS_DEFAULT);
}

View File

@ -78,6 +78,8 @@ void KernelLog(KLogLevel level, const char *subsystem, const char *event, const
void KernelPanic(const char *format, ...);
void EsPrint(const char *format, ...);
void StartDebugOutput(); // Causes the output to be directly displayed on the screen. For debugging only.
#define EsPanic KernelPanic
// ---------------------------------------------------------------------------------------------------------------
@ -133,72 +135,33 @@ void KRegisterAsyncTask(KAsyncTaskCallback callback, EsGeneric argument, bool ne
#endif
// ---------------------------------------------------------------------------------------------------------------
// Processor instruction wrappers.
// Processor IO.
// ---------------------------------------------------------------------------------------------------------------
extern "C" struct CPULocalStorage *GetLocalStorage();
extern "C" struct Thread *GetCurrentThread();
extern "C" void ProcessorDisableInterrupts();
extern "C" void ProcessorEnableInterrupts();
extern "C" bool ProcessorAreInterruptsEnabled();
extern "C" void ProcessorHalt();
extern "C" void ProcessorIdle();
extern "C" void ProcessorOut8(uint16_t port, uint8_t value);
extern "C" uint8_t ProcessorIn8(uint16_t port);
extern "C" void ProcessorOut16(uint16_t port, uint16_t value);
extern "C" uint16_t ProcessorIn16(uint16_t port);
extern "C" void ProcessorOut32(uint16_t port, uint32_t value);
extern "C" uint32_t ProcessorIn32(uint16_t port);
extern "C" void ProcessorInvalidatePage(uintptr_t virtualAddress);
extern "C" void ProcessorInvalidateAllPages();
extern "C" void ProcessorAPStartup();
extern "C" void ProcessorMagicBreakpoint(...);
extern "C" void ProcessorBreakpointHelper(...);
extern "C" void ProcessorSetLocalStorage(struct CPULocalStorage *cls);
extern "C" void ProcessorSetThreadStorage(uintptr_t tls);
extern "C" size_t ProcessorSendIPI(uintptr_t interrupt, bool nmi = false, int processorID = -1); // Returns the number of processors the IPI was *not* sent to.
extern "C" void ProcessorDebugOutputByte(uint8_t byte);
extern "C" void ProcessorFakeTimerInterrupt();
extern "C" uint64_t ProcessorReadTimeStamp();
extern "C" void DoContextSwitch(struct InterruptContext *context, uintptr_t virtualAddressSpace, uintptr_t threadKernelStack,
struct Thread *newThread, struct MMSpace *oldAddressSpace);
extern "C" void ProcessorSetAddressSpace(uintptr_t virtualAddressSpaceIdentifier); // Need to call MMSpaceOpenReference/MMSpaceCloseReference if using this.
extern "C" uintptr_t ProcessorGetAddressSpace();
extern "C" void ProcessorFlushCodeCache();
extern "C" void ProcessorFlushCache();
#ifdef ARCH_X86_64
extern "C" uintptr_t ProcessorGetRSP();
extern "C" uintptr_t ProcessorGetRBP();
extern "C" uint64_t ProcessorReadMXCSR();
#endif
// ---------------------------------------------------------------------------------------------------------------
// Kernel core.
// ---------------------------------------------------------------------------------------------------------------
extern "C" uint64_t KGetTimeInMs(); // Scheduler time.
uint64_t KGetTimeInMs(); // Scheduler time.
EsUniqueIdentifier KGetBootIdentifier();
size_t KGetCPUCount();
CPULocalStorage *KGetCPULocal(uintptr_t index);
struct CPULocalStorage *KGetCPULocal(uintptr_t index);
uint64_t KCPUCurrentID();
uint64_t KGetTimeStampTicksPerMs();
uint64_t KGetTimeStampTicksPerUs();
bool KBootedFromEFI();
bool KInIRQ();
void KSwitchThreadAfterIRQ();
void KDebugKeyPressed();
int KWaitKey();
#ifdef ARCH_X86_COMMON
void KPS2SafeToInitialise();
#endif
EsUniqueIdentifier KGetBootIdentifier();
struct KTimeout {
uint64_t end;
inline KTimeout(int ms) { end = KGetTimeInMs() + ms; }
@ -364,15 +327,8 @@ void KTimerRemove(KTimer *timer); // Timers with callbacks cannot be removed (it
// Memory manager.
// ---------------------------------------------------------------------------------------------------------------
#ifdef ARCH_X86_64
#define K_PAGE_BITS (12)
#define K_PAGE_SIZE ((uintptr_t) 1 << K_PAGE_BITS)
#define K_USER_ADDRESS_SPACE_START (0x0000000000000000ULL)
#define K_USER_ADDRESS_SPACE_END (0x0000800000000000ULL)
#define K_KERNEL_ADDRESS_SPACE_START (0xFFFF800000000000ULL)
#define K_KERNEL_ADDRESS_SPACE_END (0xFFFFFFFFFFFFFFFFULL)
#define K_STACK_GROWS_DOWN
#endif
#define K_PAGE_BITS ES_PAGE_BITS
#define K_PAGE_SIZE ES_PAGE_SIZE
struct MMSpace;
MMSpace *MMGetKernelSpace();
@ -399,9 +355,6 @@ uint64_t MMNumberOfUsablePhysicalPages();
// Returns 0 if not mapped. Rounds address down to nearest page.
uintptr_t MMArchTranslateAddress(MMSpace *space, uintptr_t virtualAddress, bool writeAccess = false /* if true, return 0 if address not writable */);
// Must be done with interrupts disabled; does not invalidate the page on other processors.
void MMArchRemap(MMSpace *space, const void *virtualAddress, uintptr_t newPhysicalAddress);
#define MM_PHYSICAL_ALLOCATE_CAN_FAIL (1 << 0) // Don't panic if the allocation fails.
#define MM_PHYSICAL_ALLOCATE_COMMIT_NOW (1 << 1) // Commit (fixed) the allocated pages.
#define MM_PHYSICAL_ALLOCATE_ZEROED (1 << 2) // Zero the pages.

View File

@ -468,7 +468,7 @@ namespace POSIX {
// Save the state of the user's stack.
currentThread->posixData->forkStackSize = currentThread->userStackCommit;
currentThread->posixData->forkStack = (void *) EsHeapAllocate(currentThread->posixData->forkStackSize, false, K_PAGED);
#ifdef K_STACK_GROWS_DOWN
#ifdef K_ARCH_STACK_GROWS_DOWN
EsMemoryCopy(currentThread->posixData->forkStack,
(void *) (currentThread->userStackBase + currentThread->userStackReserve - currentThread->posixData->forkStackSize),
currentThread->posixData->forkStackSize);
@ -533,7 +533,7 @@ namespace POSIX {
CloseHandleToObject(process->executableMainThread, KERNEL_OBJECT_THREAD);
// Restore the state of our stack.
#ifdef K_STACK_GROWS_DOWN
#ifdef K_ARCH_STACK_GROWS_DOWN
EsMemoryCopy((void *) (currentThread->userStackBase + currentThread->userStackReserve - currentThread->posixData->forkStackSize),
currentThread->posixData->forkStack, currentThread->posixData->forkStackSize);
#else
@ -560,7 +560,7 @@ namespace POSIX {
// Are we vforking?
if (currentThread->posixData->forkStack) {
// Restore the state of our stack.
#ifdef K_STACK_GROWS_DOWN
#ifdef K_ARCH_STACK_GROWS_DOWN
EsMemoryCopy((void *) (currentThread->userStackBase + currentThread->userStackReserve - currentThread->posixData->forkStackSize),
currentThread->posixData->forkStack, currentThread->posixData->forkStackSize);
#else

View File

@ -163,9 +163,6 @@ struct Process {
#endif
};
Process _kernelProcess;
Process *kernelProcess = &_kernelProcess;
struct Scheduler {
// External API:
@ -176,7 +173,7 @@ struct Scheduler {
#define SPAWN_THREAD_LOW_PRIORITY (4)
#define SPAWN_THREAD_PAUSED (8)
Thread *SpawnThread(const char *cName, uintptr_t startAddress, uintptr_t argument1 = 0,
unsigned flags = ES_FLAGS_DEFAULT, Process *process = kernelProcess, uintptr_t argument2 = 0);
uint32_t flags = ES_FLAGS_DEFAULT, Process *process = nullptr, uintptr_t argument2 = 0);
void TerminateThread(Thread *thread, bool lockAlreadyAcquired = false);
void PauseThread(Thread *thread, bool resume /*true to resume, false to pause*/, bool lockAlreadyAcquired = false);
@ -238,6 +235,10 @@ struct Scheduler {
#endif
};
Process _kernelProcess;
Process *kernelProcess = &_kernelProcess;
Process *desktopProcess;
extern Scheduler scheduler;
#endif
@ -364,9 +365,13 @@ void Scheduler::InsertNewThread(Thread *thread, bool addToActiveList, Process *o
allThreads.InsertStart(&thread->allItem);
}
Thread *Scheduler::SpawnThread(const char *cName, uintptr_t startAddress, uintptr_t argument1, unsigned flags, Process *process, uintptr_t argument2) {
Thread *Scheduler::SpawnThread(const char *cName, uintptr_t startAddress, uintptr_t argument1, uint32_t flags, Process *process, uintptr_t argument2) {
bool userland = flags & SPAWN_THREAD_USERLAND;
if (!process) {
process = kernelProcess;
}
if (userland && process == kernelProcess) {
KernelPanic("Scheduler::SpawnThread - Cannot add userland thread to kernel process.\n");
}
@ -403,7 +408,7 @@ Thread *Scheduler::SpawnThread(const char *cName, uintptr_t startAddress, uintpt
MMRegion *region = MMFindAndPinRegion(process->vmm, stack, userStackReserve);
KMutexAcquire(&process->vmm->reserveMutex);
#ifdef K_STACK_GROWS_DOWN
#ifdef K_ARCH_STACK_GROWS_DOWN
bool success = MMCommitRange(process->vmm, region, (userStackReserve - userStackCommit) / K_PAGE_SIZE, userStackCommit / K_PAGE_SIZE);
#else
bool success = MMCommitRange(process->vmm, region, 0, userStackCommit / K_PAGE_SIZE);
@ -779,7 +784,7 @@ void Thread::SetAddressSpace(MMSpace *space) {
temporaryAddressSpace = space;
MMSpace *newSpace = space ?: kernelMMSpace;
MMSpaceOpenReference(newSpace);
ProcessorSetAddressSpace(VIRTUAL_ADDRESS_SPACE_IDENTIFIER(newSpace));
ProcessorSetAddressSpace(&newSpace->data);
KSpinlockRelease(&scheduler.lock);
MMSpaceCloseReference(oldSpace);
}
@ -1020,11 +1025,7 @@ void Scheduler::PauseThread(Thread *thread, bool resume, bool lockAlreadyAcquire
} else {
// The thread is executing, but on a different processor.
// Send them an IPI to stop.
thread->receivedYieldIPI = false;
KSpinlockAcquire(&ipiLock);
ProcessorSendIPI(YIELD_IPI, false);
KSpinlockRelease(&ipiLock);
while (!thread->receivedYieldIPI); // Spin until the thread gets the IPI.
ProcessorSendYieldIPI(thread);
// TODO The interrupt context might not be set at this point.
}
} else {
@ -1349,29 +1350,18 @@ void Scheduler::Yield(InterruptContext *context) {
else newThread->process->cpuTimeSlices++;
// Prepare the next timer interrupt.
uint64_t nextTimer = 1;
ArchNextTimer(nextTimer);
ArchNextTimer(1 /* ms */);
if (!local->processorID) {
// Update the scheduler's time.
#if 1
timeMs = ArchGetTimeMs();
globalData->schedulerTimeMs = timeMs;
#else
// This drifts by roughly a second every minute.
timeMs = ProcessorReadTimeStamp() / KGetTimeStampTicksPerMs();
#endif
// Update the time stamp counter synchronization value.
extern volatile uint64_t timeStampCounterSynchronizationValue;
timeStampCounterSynchronizationValue = ((timeStampCounterSynchronizationValue & 0x8000000000000000)
^ 0x8000000000000000) | ProcessorReadTimeStamp();
}
InterruptContext *newContext = newThread->interruptContext;
MMSpace *addressSpace = newThread->temporaryAddressSpace ?: newThread->process->vmm;
MMSpaceOpenReference(addressSpace);
DoContextSwitch(newContext, VIRTUAL_ADDRESS_SPACE_IDENTIFIER(addressSpace), newThread->kernelStack, newThread, oldAddressSpace);
ArchSwitchContext(newContext, &addressSpace->data, newThread->kernelStack, newThread, oldAddressSpace);
KernelPanic("Scheduler::Yield - DoContextSwitch unexpectedly returned.\n");
}

View File

@ -9,9 +9,7 @@ KMutex eventForwardMutex;
uintptr_t DoSyscall(EsSyscallType index,
uintptr_t argument0, uintptr_t argument1,
uintptr_t argument2, uintptr_t argument3,
uint64_t flags, bool *fatal, uintptr_t *userStackPointer);
#define DO_SYSCALL_BATCHED (2)
bool batched, bool *fatal, uintptr_t *userStackPointer);
struct MessageQueue {
bool SendMessage(void *target, EsMessage *message); // Returns false if the message queue is full.
@ -1244,7 +1242,7 @@ SYSCALL_IMPLEMENT(ES_SYSCALL_THREAD_STACK_SIZE) {
KMutexAcquire(&currentVMM->reserveMutex);
if (thread->userStackCommit <= argument3 && argument3 <= thread->userStackReserve && !(argument3 & (K_PAGE_BITS - 1)) && region) {
#ifdef K_STACK_GROWS_DOWN
#ifdef K_ARCH_STACK_GROWS_DOWN
success = MMCommitRange(currentVMM, region, (thread->userStackReserve - argument3) / K_PAGE_SIZE, argument3 / K_PAGE_SIZE);
#else
success = MMCommitRange(currentVMM, region, 0, argument3 / K_PAGE_SIZE);
@ -1293,7 +1291,7 @@ SYSCALL_IMPLEMENT(ES_SYSCALL_BATCH) {
EsBatchCall call = calls[i];
bool fatal = false;
uintptr_t _returnValue = calls[i].returnValue = DoSyscall(call.index, call.argument0, call.argument1, call.argument2, call.argument3,
DO_SYSCALL_BATCHED, &fatal, userStackPointer);
true /* batched */, &fatal, userStackPointer);
if (fatal) SYSCALL_RETURN(_returnValue, true);
if (calls[i].stopBatchIfError && ES_CHECK_ERROR(_returnValue)) break;
if (currentThread->terminating) break;
@ -1928,12 +1926,8 @@ SyscallFunction syscallFunctions[ES_SYSCALL_COUNT + 1] {
#pragma GCC diagnostic pop
uintptr_t DoSyscall(EsSyscallType index,
uintptr_t argument0, uintptr_t argument1,
uintptr_t argument2, uintptr_t argument3,
uint64_t flags, bool *fatal, uintptr_t *userStackPointer) {
bool batched = flags & DO_SYSCALL_BATCHED;
uintptr_t DoSyscall(EsSyscallType index, uintptr_t argument0, uintptr_t argument1, uintptr_t argument2, uintptr_t argument3,
bool batched, bool *fatal, uintptr_t *userStackPointer) {
// Interrupts need to be enabled during system calls,
// because many of them block on mutexes or events.
ProcessorEnableInterrupts();

View File

@ -4,7 +4,6 @@
#ifdef IMPLEMENTATION
#include <shared/vga_font.cpp>
#include "x86_64.h"
#define TERMINAL_ADDRESS ((uint16_t *) (LOW_MEMORY_MAP_START + 0xB8000))
@ -17,6 +16,8 @@ KMutex printLock;
#endif
void DebugWriteCharacter(uintptr_t character);
extern "C" void ProcessorDebugOutputByte(uint8_t byte);
int KWaitKey();
#ifdef ARCH_X86_COMMON
bool printToDebugger = false;
@ -250,7 +251,13 @@ void KernelPanic(const char *format, ...) {
#ifdef POST_PANIC_DEBUGGING
uintptr_t kernelLogEnd = kernelLogPosition;
EsPrint("Press 'D' to enter debugger.\n");
while (KWaitKey() != ES_SCANCODE_D);
while (true) {
int key = KWaitKey();
if (key == ES_SCANCODE_D) break;
if (key == -1) ProcessorHalt();
}
graphics.debuggerActive = true;
while (true) {

View File

@ -2,24 +2,6 @@
typedef struct ACPIProcessor ArchCPU;
// Interrupt vectors:
// 0x00 - 0x1F: CPU exceptions
// 0x20 - 0x2F: PIC (disabled, spurious)
// 0x30 - 0x4F: Timers and low-priority IPIs.
// 0x50 - 0x6F: APIC (standard)
// 0x70 - 0xAF: MSI
// 0xF0 - 0xFE: High-priority IPIs
// 0xFF: APIC (spurious interrupt)
#define TIMER_INTERRUPT (0x40)
#define YIELD_IPI (0x41)
#define IRQ_BASE (0x50)
#define CALL_FUNCTION_ON_ALL_PROCESSORS_IPI (0xF0)
#define KERNEL_PANIC_IPI (0) // NMIs ignore the interrupt vector.
#define INTERRUPT_VECTOR_MSI_START (0x70)
#define INTERRUPT_VECTOR_MSI_COUNT (0x40)
struct InterruptContext {
uint64_t cr2, ds;
uint8_t fxsave[512 + 16];
@ -30,7 +12,8 @@ struct InterruptContext {
uint64_t rip, cs, flags, rsp, ss;
};
struct VirtualAddressSpaceData {
struct MMArchVAS {
// NOTE Must be first in the structure. See ProcessorSetAddressSpace and ArchSwitchContext.
uintptr_t cr3;
// Each process has a 47-bit address space.
@ -57,9 +40,6 @@ struct VirtualAddressSpaceData {
KMutex mutex; // Acquire to modify the page tables.
};
#define VIRTUAL_ADDRESS_SPACE_DATA() VirtualAddressSpaceData data
#define VIRTUAL_ADDRESS_SPACE_IDENTIFIER(x) ((x)->data.cr3)
#define MM_CORE_SPACE_START (0xFFFF800100000000)
#define MM_CORE_SPACE_SIZE (0xFFFF8001F0000000 - 0xFFFF800100000000)
#define MM_CORE_REGIONS_START (0xFFFF8001F0000000)
@ -71,11 +51,12 @@ struct VirtualAddressSpaceData {
#define MM_USER_SPACE_START (0x100000000000)
#define MM_USER_SPACE_SIZE (0xF00000000000 - 0x100000000000)
#define ArchCheckBundleHeader() (header.mapAddress > 0x800000000000UL || header.mapAddress < 0x1000 || fileSize > 0x1000000000000UL)
#define ArchCheckELFHeader() (header->virtualAddress > 0x800000000000UL || header->virtualAddress < 0x1000 || header->segmentSize > 0x1000000000000UL)
#define ArchIsAddressInKernelSpace(x) ((uintptr_t) (x) >= 0xFFFF800000000000)
uint8_t coreL1Commit[(0xFFFF800200000000 - 0xFFFF800100000000) >> (/* ENTRIES_PER_PAGE_TABLE_BITS */ 9 + K_PAGE_BITS + 3)];
uint8_t pciIRQLines[0x100 /* slots */][4 /* pins */];
#define K_ARCH_STACK_GROWS_DOWN
#define K_ARCH_NAME "x86_64"
#endif
@ -94,19 +75,19 @@ struct IRQHandler {
const char *cOwnerName;
};
uint8_t pciIRQLines[0x100 /* slots */][4 /* pins */];
MSIHandler msiHandlers[INTERRUPT_VECTOR_MSI_COUNT];
IRQHandler irqHandlers[0x40];
KSpinlock irqHandlersLock; // Also for msiHandlers.
extern uintptr_t bootloaderInformationOffset;
extern "C" bool simdSSE3Support;
extern "C" bool simdSSSE3Support;
KSpinlock ipiLock;
uint8_t coreL1Commit[(0xFFFF800200000000 - 0xFFFF800100000000) >> (/* ENTRIES_PER_PAGE_TABLE_BITS */ 9 + K_PAGE_BITS + 3)];
volatile uintptr_t tlbShootdownVirtualAddress;
volatile size_t tlbShootdownPageCount;
extern "C" uintptr_t _KThreadTerminate;
typedef void (*CallFunctionOnAllProcessorsCallbackFunction)();
volatile CallFunctionOnAllProcessorsCallbackFunction callFunctionOnAllProcessorsCallback;
volatile uintptr_t callFunctionOnAllProcessorsRemaining;
@ -119,10 +100,14 @@ volatile uintptr_t callFunctionOnAllProcessorsRemaining;
#define ENTRIES_PER_PAGE_TABLE (512)
#define ENTRIES_PER_PAGE_TABLE_BITS (9)
void ArchSetPCIIRQLine(uint8_t slot, uint8_t pin, uint8_t line) {
pciIRQLines[slot][pin] = line;
}
bool MMArchCommitPageTables(MMSpace *space, MMRegion *region) {
KMutexAssertLocked(&space->reserveMutex);
VirtualAddressSpaceData *data = &space->data;
MMArchVAS *data = &space->data;
uintptr_t base = (region->baseAddress - (space == coreMMSpace ? MM_CORE_SPACE_START : 0)) & 0x7FFFFFFFF000;
uintptr_t end = base + (region->pageCount << K_PAGE_BITS);
@ -589,13 +574,7 @@ bool MMArchInitialiseUserSpace(MMSpace *space) {
return true;
}
void ArchCleanupVirtualAddressSpace(void *argument) {
KernelLog(LOG_VERBOSE, "Arch", "remove virtual address space page", "Removing virtual address space page %x...\n", argument);
MMPhysicalFree((uintptr_t) argument);
MMDecommit(K_PAGE_SIZE, true);
}
void MMFreeVAS(MMSpace *space) {
void MMArchFreeVAS(MMSpace *space) {
for (uintptr_t i = 0; i < 256; i++) {
if (!PAGE_TABLE_L4[i]) continue;
@ -617,7 +596,7 @@ void MMFreeVAS(MMSpace *space) {
}
if (space->data.pageTablesActive) {
KernelPanic("MMFreeVAS - Space %x still has %d page tables active.\n", space, space->data.pageTablesActive);
KernelPanic("MMArchFreeVAS - Space %x still has %d page tables active.\n", space, space->data.pageTablesActive);
}
KMutexAcquire(&coreMMSpace->reserveMutex);
@ -628,32 +607,16 @@ void MMFreeVAS(MMSpace *space) {
MMDecommit(space->data.pageTablesCommitted * K_PAGE_SIZE, true);
}
void MMFinalizeVAS(MMSpace *space) {
void MMArchFinalizeVAS(MMSpace *space) {
if (!space->data.cr3) return;
// Freeing the L4 page table has to be done in the kernel process, since it's the page CR3 would points to!
// Therefore, this function only is called in an async task.
if (space->data.cr3 == ProcessorReadCR3()) KernelPanic("MMFinalizeVAS - Space %x is active.\n", space);
if (space->data.cr3 == ProcessorReadCR3()) KernelPanic("MMArchFinalizeVAS - Space %x is active.\n", space);
PMZero(&space->data.cr3, 1, true); // Fail as fast as possible if someone's still using this page.
MMPhysicalFree(space->data.cr3);
MMDecommit(K_PAGE_SIZE, true);
}
void ArchCheckAddressInRange(int type, uintptr_t address) {
if (type == 1) {
if ((uintptr_t) address < 0xFFFF900000000000) {
KernelPanic("ArchCheckAddressInRange - Address out of expected range.\n");
}
} else if (type == 2) {
if ((uintptr_t) address < 0xFFFF8F8000000000 || (uintptr_t) address >= 0xFFFF900000000000) {
KernelPanic("ArchCheckAddressInRange - Address out of expected range.\n");
}
} else {
if ((uintptr_t) address >= 0xFFFF800000000000) {
KernelPanic("ArchCheckAddressInRange - Address out of expected range.\n");
}
}
}
uint64_t ArchGetTimeFromPITMs() {
// TODO This isn't working on real hardware, but ArchDelay1Ms is?
@ -884,6 +847,14 @@ size_t ProcessorSendIPI(uintptr_t interrupt, bool nmi, int processorID) {
return ignored;
}
void ProcessorSendYieldIPI(Thread *thread) {
thread->receivedYieldIPI = false;
KSpinlockAcquire(&ipiLock);
ProcessorSendIPI(YIELD_IPI, false);
KSpinlockRelease(&ipiLock);
while (!thread->receivedYieldIPI); // Spin until the thread gets the IPI.
}
void ArchNextTimer(size_t ms) {
while (!scheduler.started); // Wait until the scheduler is ready.
GetLocalStorage()->schedulerReady = true; // Make sure this CPU can be scheduled.
@ -901,7 +872,7 @@ NewProcessorStorage AllocateNewProcessorStorage(ACPIProcessor *archCPU) {
return storage;
}
extern "C" void SetupProcessor2(NewProcessorStorage *storage) {
void SetupProcessor2(NewProcessorStorage *storage) {
// Setup the local interrupts for the current processor.
for (uintptr_t i = 0; i < acpi.lapicNMICount; i++) {
@ -1299,10 +1270,6 @@ extern "C" uintptr_t Syscall(uintptr_t argument0, uintptr_t argument1, uintptr_t
return DoSyscall((EsSyscallType) argument0, argument1, argument2, argument3, argument4, false, nullptr, userStackPointer);
}
bool HasSSSE3Support() {
return simdSSSE3Support;
}
uintptr_t GetBootloaderInformationOffset() {
return bootloaderInformationOffset;
}
@ -1333,4 +1300,16 @@ void KPCIWriteConfig(uint8_t bus, uint8_t device, uint8_t function, uint8_t offs
else KernelPanic("PCIController::WriteConfig - Invalid size %d.\n", size);
}
EsError ArchApplyRelocation(uintptr_t type, uint8_t *buffer, uintptr_t offset, uintptr_t result) {
if (type == 0) {}
else if (type == 10 /* R_X86_64_32 */) *((uint32_t *) (buffer + offset)) = result;
else if (type == 11 /* R_X86_64_32S */) *((uint32_t *) (buffer + offset)) = result;
else if (type == 1 /* R_X86_64_64 */) *((uint64_t *) (buffer + offset)) = result;
else if (type == 2 /* R_X86_64_PC32 */) *((uint32_t *) (buffer + offset)) = result - ((uint64_t) buffer + offset);
else if (type == 24 /* R_X86_64_PC64 */) *((uint64_t *) (buffer + offset)) = result - ((uint64_t) buffer + offset);
else if (type == 4 /* R_X86_64_PLT32 */) *((uint32_t *) (buffer + offset)) = result - ((uint64_t) buffer + offset);
else return ES_ERROR_UNSUPPORTED_FEATURE;
return ES_SUCCESS;
}
#endif

View File

@ -46,21 +46,52 @@
#define IO_PCI_CONFIG (0x0CF8)
#define IO_PCI_DATA (0x0CFC)
// --------------------------------- Interrupt vectors.
// Interrupt vectors:
// 0x00 - 0x1F: CPU exceptions
// 0x20 - 0x2F: PIC (disabled, spurious)
// 0x30 - 0x4F: Timers and low-priority IPIs.
// 0x50 - 0x6F: APIC (standard)
// 0x70 - 0xAF: MSI
// 0xF0 - 0xFE: High-priority IPIs
// 0xFF: APIC (spurious interrupt)
#define TIMER_INTERRUPT (0x40)
#define YIELD_IPI (0x41)
#define IRQ_BASE (0x50)
#define CALL_FUNCTION_ON_ALL_PROCESSORS_IPI (0xF0)
#define KERNEL_PANIC_IPI (0) // NMIs ignore the interrupt vector.
#define INTERRUPT_VECTOR_MSI_START (0x70)
#define INTERRUPT_VECTOR_MSI_COUNT (0x40)
// --------------------------------- Forward declarations.
extern "C" uint64_t ProcessorReadCR3();
extern "C" void gdt_data();
extern "C" void processorGDTR();
extern "C" uint64_t ProcessorReadCR3();
extern "C" uintptr_t ProcessorGetRSP();
extern "C" uintptr_t ProcessorGetRBP();
extern "C" uint64_t ProcessorReadMXCSR();
extern "C" void ProcessorInstallTSS(uint32_t *gdt, uint32_t *tss);
extern "C" void ProcessorAPStartup();
extern "C" void SSSE3Framebuffer32To24Copy(volatile uint8_t *destination, volatile uint8_t *source, size_t pixelGroups);
extern "C" uintptr_t _KThreadTerminate;
extern bool pagingNXESupport;
extern bool pagingPCIDSupport;
extern bool pagingSMEPSupport;
extern bool pagingTCESupport;
extern "C" void processorGDTR();
extern "C" void SetupProcessor2(struct NewProcessorStorage *);
extern "C" void ProcessorInstallTSS(uint32_t *gdt, uint32_t *tss);
extern volatile uint64_t timeStampCounterSynchronizationValue;
extern "C" bool simdSSE3Support;
extern "C" bool simdSSSE3Support;
extern uintptr_t bootloaderInformationOffset;
struct NewProcessorStorage {
struct CPULocalStorage *local;
@ -68,11 +99,13 @@ struct NewProcessorStorage {
};
NewProcessorStorage AllocateNewProcessorStorage(struct ACPIProcessor *archCPU);
bool HasSSSE3Support();
extern "C" void SetupProcessor2(struct NewProcessorStorage *);
uintptr_t GetBootloaderInformationOffset();
void ArchDelay1Ms(); // Spin for approximately 1ms. Use only during initialisation. Not thread-safe.
uint64_t ArchGetTimeFromPITMs();
void *ACPIGetRSDP();
uint8_t ACPIGetCenturyRegisterIndex();
size_t ProcessorSendIPI(uintptr_t interrupt, bool nmi = false, int processorID = -1); // Returns the number of processors the IPI was *not* sent to.
void ArchSetPCIIRQLine(uint8_t slot, uint8_t pin, uint8_t line);
#endif

View File

@ -12,7 +12,6 @@ idt_data: resb idt_size
%define cpu_local_storage_size 8192
; Array of pointers to the CPU local states
[global cpu_local_storage]
cpu_local_storage: resb cpu_local_storage_size
[section .data]
@ -581,7 +580,6 @@ ProcessorInvalidateAllPages:
mov cr4,rax
ret
[global ProcessorIdle]
ProcessorIdle:
sti
hlt
@ -773,6 +771,7 @@ ReturnFromInterruptHandler:
[global ProcessorSetAddressSpace]
ProcessorSetAddressSpace:
mov rdi,[rdi]
mov rax,cr3
cmp rax,rdi
je .cont
@ -780,11 +779,6 @@ ProcessorSetAddressSpace:
.cont:
ret
[global ProcessorGetAddressSpace]
ProcessorGetAddressSpace:
mov rax,cr3
ret
[global ProcessorGetRSP]
ProcessorGetRSP:
mov rax,rsp
@ -796,11 +790,12 @@ ProcessorGetRBP:
ret
[extern PostContextSwitch]
[global DoContextSwitch]
DoContextSwitch:
[global ArchSwitchContext]
ArchSwitchContext:
cli
mov [gs:16],rcx
mov [gs:8],rdx
mov rsi,[rsi]
mov rax,cr3
cmp rax,rsi
je .cont
@ -811,38 +806,11 @@ DoContextSwitch:
call PostContextSwitch
jmp ReturnFromInterruptHandler
[global ProcessorMagicBreakpoint]
ProcessorMagicBreakpoint:
xchg bx,bx
[global ProcessorBreakpointHelper]
ProcessorBreakpointHelper:
ret
[global ProcessorReadCR3]
ProcessorReadCR3:
mov rax,cr3
ret
[global ArchSpeakerBeep]
ArchSpeakerBeep:
; Beep!!!
mov rdi,0x43
mov rsi,0xB6
call ProcessorOut8
mov rdi,0x42
mov rsi,0x97
call ProcessorOut8
mov rdi,0x42
mov rsi,0x0A
call ProcessorOut8
mov rdi,0x61
call ProcessorIn8
mov rsi,rax
or rsi,3
mov rdi,0x61
call ProcessorOut8
ret
[global ProcessorDebugOutputByte]
ProcessorDebugOutputByte:
%ifdef COM_OUTPUT
@ -1083,11 +1051,3 @@ CALL_REGISTER_INDIRECT r12
CALL_REGISTER_INDIRECT r13
CALL_REGISTER_INDIRECT r14
CALL_REGISTER_INDIRECT r15
[global __cyg_profile_func_enter]
__cyg_profile_func_enter:
ret
[global __cyg_profile_func_exit]
__cyg_profile_func_exit:
ret