mirror of https://gitlab.com/nakst/essence
kernel cleanup
This commit is contained in:
parent
e546555787
commit
6fa375a9d8
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -303,7 +303,7 @@ int PS2ReadKey() {
|
|||
}
|
||||
|
||||
int KWaitKey() {
|
||||
if (!ps2.channels) ProcessorHalt();
|
||||
if (!ps2.channels) return -1;
|
||||
int scancode;
|
||||
while (!(scancode = PS2ReadKey()));
|
||||
return scancode;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
169
kernel/kernel.h
169
kernel/kernel.h
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
@ -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(¤tVMM->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();
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue