KernelMain: more precise memory reporting, MmInitializePhysical: support more than ~1.1 GB of memory.
This commit is contained in:
1 parent
0e1479b168
commit
84d6265410
6 files changed
+26
-175
No files matched your search
Binary file not shown.
+4
-154
@@ -1,159 +1,9 @@
|
|||||||
// ahci.c - AHCI SATA driver (basic PRDT, 1 slot, port 0)
|
|
||||||
#include <io_driver.h>
|
|
||||||
#include <hal_api.h>
|
#include <hal_api.h>
|
||||||
#include <mm_virt.h>
|
#include <ke_status.h>
|
||||||
#include <ke_debug.h>
|
#include <ke_debug.h>
|
||||||
#include <stdint.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <intrin.h>
|
|
||||||
|
|
||||||
// AHCI generic host control registers (BAR5 offsets).
|
|
||||||
#define AHCI_GHC 0x04 // Global Host Control
|
|
||||||
#define AHCI_PI 0x0C // Ports Implemented
|
|
||||||
#define AHCI_PORT_BASE(p) (0x100 + (p) * 0x80)
|
|
||||||
|
|
||||||
// Port registers (relative to port base).
|
|
||||||
#define P_CLB 0x00 // Command List Base Address
|
|
||||||
#define P_FB 0x08 // FIS Base Address
|
|
||||||
#define P_IS 0x10 // Interrupt Status
|
|
||||||
#define P_CMD 0x18 // Command and Status
|
|
||||||
#define P_TFD 0x20 // Task File Data
|
|
||||||
#define P_SIG 0x24 // Signature
|
|
||||||
#define P_SSTS 0x28 // SATA Status
|
|
||||||
#define P_CI 0x38 // Command Issue
|
|
||||||
|
|
||||||
#define CMD_ST (1 << 0)
|
|
||||||
#define CMD_FRE (1 << 4)
|
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
|
||||||
typedef struct { uint8_t cfl:5,a:1,w:1,p:1; uint8_t pmport:4,r:1,b:1,c:1,rsvd:1; uint16_t prdtl;
|
|
||||||
uint32_t prdbc; uint64_t ctba; uint32_t rsvd2[4]; } HBA_CMD_HEADER;
|
|
||||||
typedef struct { uint64_t dba; uint32_t rsvd; uint32_t dbc:22, rsvd2:9, i:1; } HBA_PRDT;
|
|
||||||
typedef struct { uint8_t cfis[64]; uint8_t acmd[16]; uint8_t rsvd[48]; HBA_PRDT prdt[1]; } HBA_CMD_TABLE;
|
|
||||||
#pragma pack(pop)
|
|
||||||
|
|
||||||
static const HAL_API* gHal;
|
|
||||||
static volatile uint32_t* gAhci = (volatile uint32_t *)0;
|
|
||||||
static HBA_CMD_HEADER* gCmdList = (HBA_CMD_HEADER *)0;
|
|
||||||
static HBA_CMD_TABLE* gCmdTable = (HBA_CMD_TABLE *)0;
|
|
||||||
static uint8_t* gFisBuf = (uint8_t *)0;
|
|
||||||
static uint8_t gPort = 0;
|
|
||||||
static uint64_t gSectors = 0;
|
|
||||||
|
|
||||||
static inline uint32_t PRd(uint32_t off) {
|
|
||||||
return *(volatile uint32_t *)((uint8_t *)gAhci + off);
|
|
||||||
}
|
|
||||||
static inline void PWr(uint32_t off, uint32_t v) {
|
|
||||||
*(volatile uint32_t *)((uint8_t *)gAhci + off) = v;
|
|
||||||
}
|
|
||||||
static inline uint32_t PortRd(uint8_t p, uint32_t off) {
|
|
||||||
return PRd(AHCI_PORT_BASE(p) + off);
|
|
||||||
}
|
|
||||||
static inline void PortWr(uint8_t p, uint32_t off, uint32_t v) {
|
|
||||||
PWr(AHCI_PORT_BASE(p) + off, v);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void AhciIssueCmd(uint8_t fis[20], void* buf, uint32_t bytes, int write) {
|
|
||||||
// Fill FIS in command table.
|
|
||||||
memcpy(gCmdTable->cfis, fis, 20);
|
|
||||||
gCmdTable->prdt[0].dba = MmGetPhysicalAddress((uintptr_t)buf);
|
|
||||||
gCmdTable->prdt[0].dbc = bytes - 1;
|
|
||||||
gCmdTable->prdt[0].i = 1;
|
|
||||||
|
|
||||||
gCmdList[0].cfl = 5; // FIS length in DWORDs
|
|
||||||
gCmdList[0].w = write ? 1 : 0;
|
|
||||||
gCmdList[0].prdtl = 1;
|
|
||||||
gCmdList[0].prdbc = 0;
|
|
||||||
gCmdList[0].ctba = MmGetPhysicalAddress((uintptr_t)gCmdTable);
|
|
||||||
|
|
||||||
PortWr(gPort, P_CI, 1);
|
|
||||||
while (PortRd(gPort, P_CI) & 1) _mm_pause();
|
|
||||||
}
|
|
||||||
|
|
||||||
static KSTATUS AhciRead(uint64_t lba, uint32_t count, void* buf) {
|
|
||||||
uint8_t fis[20] = {0};
|
|
||||||
fis[0] = 0x27; fis[1] = 0x80; // H2D, C=1
|
|
||||||
fis[2] = 0x25; // READ DMA EXT
|
|
||||||
fis[4] = (uint8_t)lba;
|
|
||||||
fis[5] = (uint8_t)(lba >> 8);
|
|
||||||
fis[6] = (uint8_t)(lba >> 16);
|
|
||||||
fis[7] = 0x40; // LBA mode
|
|
||||||
fis[8] = (uint8_t)(lba >> 24);
|
|
||||||
fis[9] = (uint8_t)(lba >> 32);
|
|
||||||
fis[10]= (uint8_t)(lba >> 40);
|
|
||||||
fis[12]= (uint8_t)count;
|
|
||||||
fis[13]= (uint8_t)(count >> 8);
|
|
||||||
AhciIssueCmd(fis, buf, count * 512, 0);
|
|
||||||
return STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static KSTATUS AhciWrite(uint64_t lba, uint32_t count, const void* buf) {
|
|
||||||
uint8_t fis[20] = {0};
|
|
||||||
fis[0] = 0x27; fis[1] = 0x80;
|
|
||||||
fis[2] = 0x35; // WRITE DMA EXT
|
|
||||||
fis[4] = (uint8_t)lba;
|
|
||||||
fis[5] = (uint8_t)(lba >> 8);
|
|
||||||
fis[6] = (uint8_t)(lba >> 16);
|
|
||||||
fis[7] = 0x40;
|
|
||||||
fis[8] = (uint8_t)(lba >> 24);
|
|
||||||
fis[9] = (uint8_t)(lba >> 32);
|
|
||||||
fis[10]= (uint8_t)(lba >> 40);
|
|
||||||
fis[12]= (uint8_t)count;
|
|
||||||
fis[13]= (uint8_t)(count >> 8);
|
|
||||||
AhciIssueCmd(fis, (void *)buf, count * 512, 1);
|
|
||||||
return STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
KSTATUS DriverEntry(const HAL_API* hal) {
|
KSTATUS DriverEntry(const HAL_API* hal) {
|
||||||
DbgPrint("AHCI: Init\n");
|
(void)hal;
|
||||||
gHal = hal;
|
DbgPrint("AHCI: TODO.\n");
|
||||||
uint8_t bus, dev, fn;
|
return STATUS_SUCCESS;
|
||||||
if (!hal->Pci.FindClass(0x01, 0x06, &bus, &dev, &fn))
|
|
||||||
return STATUS_NOT_FOUND; // no AHCI controller
|
|
||||||
|
|
||||||
// BAR5 = AHCI base address.
|
|
||||||
uint32_t bar5 = hal->Pci.ConfigRead32(bus, dev, fn, 0x24) & ~0xFU;
|
|
||||||
if (!bar5) return STATUS_NOT_FOUND;
|
|
||||||
|
|
||||||
gAhci = (volatile uint32_t *)(gHal->PhysToVirt(bar5));
|
|
||||||
|
|
||||||
// Enable AHCI mode.
|
|
||||||
PWr(AHCI_GHC, PRd(AHCI_GHC) | (1 << 31));
|
|
||||||
|
|
||||||
// Find a port with a connected device.
|
|
||||||
uint32_t pi = PRd(AHCI_PI);
|
|
||||||
for (int p = 0; p < 32; p++) {
|
|
||||||
if (!(pi & (1 << p))) continue;
|
|
||||||
uint32_t ssts = PortRd((uint8_t)p, P_SSTS);
|
|
||||||
if ((ssts & 0xF) != 3) continue; // DET: device present + PHY
|
|
||||||
if (PortRd((uint8_t)p, P_SIG) != 0x00000101) continue; // SATA
|
|
||||||
gPort = (uint8_t)p;
|
|
||||||
goto found;
|
|
||||||
}
|
|
||||||
return STATUS_NOT_FOUND;
|
|
||||||
found:
|
|
||||||
// Allocate command list (1 header), FIS buffer, command table.
|
|
||||||
gCmdList = (HBA_CMD_HEADER *)MmAllocatePool(4096);
|
|
||||||
gFisBuf = (uint8_t *)MmAllocatePool(4096);
|
|
||||||
gCmdTable = (HBA_CMD_TABLE *)MmAllocatePool(4096);
|
|
||||||
if (!gCmdList || !gFisBuf || !gCmdTable) return STATUS_NO_MEMORY;
|
|
||||||
memset(gCmdList, 0, 4096);
|
|
||||||
memset(gFisBuf, 0, 4096);
|
|
||||||
memset(gCmdTable,0, 4096);
|
|
||||||
|
|
||||||
PortWr(gPort, P_CLB, (uint32_t)(MmGetPhysicalAddress((uintptr_t)gCmdList)));
|
|
||||||
PortWr(gPort, P_FB, (uint32_t)(MmGetPhysicalAddress((uintptr_t)gFisBuf)));
|
|
||||||
PortWr(gPort, P_CMD, PortRd(gPort, P_CMD) | CMD_FRE | CMD_ST);
|
|
||||||
|
|
||||||
// Identify to get sector count.
|
|
||||||
uint8_t fis[20] = {0};
|
|
||||||
fis[0] = 0x27; fis[1] = 0x80; fis[2] = 0xEC;
|
|
||||||
uint16_t ident[256];
|
|
||||||
memset(ident, 0, sizeof(ident));
|
|
||||||
AhciIssueCmd(fis, ident, 512, 0);
|
|
||||||
gSectors = *(uint64_t *)(&ident[100]);
|
|
||||||
if (!gSectors) gSectors = ((uint32_t)ident[61] << 16) | ident[60];
|
|
||||||
|
|
||||||
DISK_DRIVER drv = { AhciRead, AhciWrite, gSectors };
|
|
||||||
return IoRegisterDisk(1, &drv); // drive 1; drive 0 = IDE
|
|
||||||
}
|
}
|
||||||
@@ -6,4 +6,4 @@ KSTATUS DriverEntry(const HAL_API* hal) {
|
|||||||
(void)hal;
|
(void)hal;
|
||||||
DbgPrint("Test runtime driver\n");
|
DbgPrint("Test runtime driver\n");
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
+5
-5
@@ -24,7 +24,7 @@ typedef struct {
|
|||||||
size_t capacity;
|
size_t capacity;
|
||||||
} Header;
|
} Header;
|
||||||
|
|
||||||
#define ARR_INIT_CAPACITY 1
|
#define ARR_INIT_CAPACITY 2
|
||||||
|
|
||||||
#define _arr_header(arr) ((Header*)(arr) - 1)
|
#define _arr_header(arr) ((Header*)(arr) - 1)
|
||||||
|
|
||||||
@@ -384,8 +384,8 @@ extern void KernelMain(BOOT_INFO* bootInfo) {
|
|||||||
//
|
//
|
||||||
KeInitializeScheduler();
|
KeInitializeScheduler();
|
||||||
// hal->Screen.Clear(0x000000);
|
// hal->Screen.Clear(0x000000);
|
||||||
DbgPrint("KernelMain: initialisation complete. %u MB free.\n",
|
DbgPrint("KernelMain: initialisation complete. %.2f MB free.\n",
|
||||||
(unsigned)(MmFreeFrameCount() * PAGE_SIZE / (1024 * 1024)));
|
(float)MmFreeFrameCount() * PAGE_SIZE / (1024.0f * 1024.0f));
|
||||||
|
|
||||||
DbgPrint("KernelMain: Loading system DLLs...\n");
|
DbgPrint("KernelMain: Loading system DLLs...\n");
|
||||||
LoadAndRegisterDll("syscall.dll");
|
LoadAndRegisterDll("syscall.dll");
|
||||||
@@ -407,8 +407,8 @@ extern void KernelMain(BOOT_INFO* bootInfo) {
|
|||||||
_enable();
|
_enable();
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
DbgPrint("KernelMain: Idle loop. Free memory: %u MB\n",
|
//DbgPrint("KernelMain: Idle loop. Free memory: %.2f MB.\n",
|
||||||
(unsigned)(MmFreeFrameCount() * PAGE_SIZE / (1024 * 1024)));
|
//(float)(MmFreeFrameCount() * PAGE_SIZE) / (1024.0f * 1024.0f));
|
||||||
__halt(); // nothing to do
|
__halt(); // nothing to do
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+13
-12
@@ -23,7 +23,6 @@ static inline void* PhysToVirt(PHYSICAL_ADDRESS phys) {
|
|||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Frame stack
|
// Frame stack
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
#define MAX_FRAMES (256ULL * 1024) // up to 1 GB worth of 4 KB frames
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
PHYSICAL_ADDRESS* Stack; // pointer into physical window
|
PHYSICAL_ADDRESS* Stack; // pointer into physical window
|
||||||
@@ -50,12 +49,18 @@ static void PushFrame(PHYSICAL_ADDRESS frame) {
|
|||||||
void MmInitializePhysical(const MEMORY_MAP* map, uint64_t physicalWindowBase) {
|
void MmInitializePhysical(const MEMORY_MAP* map, uint64_t physicalWindowBase) {
|
||||||
gPhysBase = physicalWindowBase;
|
gPhysBase = physicalWindowBase;
|
||||||
|
|
||||||
// --- Phase 1: Find a region large enough to hold the stack array. ---
|
// --- Phase 0: Count total usable frames so we can size the stack
|
||||||
// We need MAX_FRAMES * sizeof(PHYSICAL_ADDRESS) = 2 MB worst-case.
|
// dynamically instead of capping at a hardcoded 1 GB. ---
|
||||||
// Take the first usable region that is large enough.
|
uint64_t totalUsableBytes = 0;
|
||||||
const size_t stackBytes = MAX_FRAMES * sizeof(PHYSICAL_ADDRESS);
|
for (uint32_t i = 0; i < map->RegionCount; i++) {
|
||||||
PHYSICAL_ADDRESS stackPhys = 0;
|
if (map->Regions[i].Type == MemoryUsable)
|
||||||
|
totalUsableBytes += map->Regions[i].Length;
|
||||||
|
}
|
||||||
|
const size_t maxFrames = (size_t)(totalUsableBytes / PAGE_SIZE);
|
||||||
|
const size_t stackBytes = maxFrames * sizeof(PHYSICAL_ADDRESS);
|
||||||
|
|
||||||
|
// --- Phase 1: Find a usable region large enough to hold the stack. ---
|
||||||
|
PHYSICAL_ADDRESS stackPhys = 0;
|
||||||
for (uint32_t i = 0; i < map->RegionCount; i++) {
|
for (uint32_t i = 0; i < map->RegionCount; i++) {
|
||||||
const MEMORY_REGION* r = &map->Regions[i];
|
const MEMORY_REGION* r = &map->Regions[i];
|
||||||
if (r->Type == MemoryUsable && r->Length >= stackBytes + PAGE_SIZE) {
|
if (r->Type == MemoryUsable && r->Length >= stackBytes + PAGE_SIZE) {
|
||||||
@@ -65,19 +70,16 @@ void MmInitializePhysical(const MEMORY_MAP* map, uint64_t physicalWindowBase) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!stackPhys) {
|
if (!stackPhys) {
|
||||||
// Should never happen on any machine with >= 4 MB RAM.
|
|
||||||
// Hang - there is nothing else we can do.
|
|
||||||
for (;;) { __halt(); }
|
for (;;) { __halt(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
gFrameStack.Stack = (PHYSICAL_ADDRESS *)PhysToVirt(stackPhys);
|
gFrameStack.Stack = (PHYSICAL_ADDRESS *)PhysToVirt(stackPhys);
|
||||||
gFrameStack.Top = 0;
|
gFrameStack.Top = 0;
|
||||||
gFrameStack.Capacity = MAX_FRAMES;
|
gFrameStack.Capacity = maxFrames;
|
||||||
gFrameStack.Total = 0;
|
gFrameStack.Total = 0;
|
||||||
gFrameStack.Lock = (SPINLOCK)SPINLOCK_INIT;
|
gFrameStack.Lock = (SPINLOCK)SPINLOCK_INIT;
|
||||||
|
|
||||||
// --- Phase 2: Push all free 4 KB frames from MemoryUsable regions. ---
|
// --- Phase 2: Push all free 4 KB frames, skipping the stack pages. ---
|
||||||
// Skip the pages occupied by the stack itself.
|
|
||||||
const PHYSICAL_ADDRESS stackEnd =
|
const PHYSICAL_ADDRESS stackEnd =
|
||||||
stackPhys + ((stackBytes + PAGE_SIZE - 1) & PAGE_MASK);
|
stackPhys + ((stackBytes + PAGE_SIZE - 1) & PAGE_MASK);
|
||||||
|
|
||||||
@@ -89,7 +91,6 @@ void MmInitializePhysical(const MEMORY_MAP* map, uint64_t physicalWindowBase) {
|
|||||||
PHYSICAL_ADDRESS end = r->Base + r->Length;
|
PHYSICAL_ADDRESS end = r->Base + r->Length;
|
||||||
|
|
||||||
for (PHYSICAL_ADDRESS frame = base; frame < end; frame += PAGE_SIZE) {
|
for (PHYSICAL_ADDRESS frame = base; frame < end; frame += PAGE_SIZE) {
|
||||||
// Skip the frames reserved for our own stack.
|
|
||||||
if (frame >= stackPhys && frame < stackEnd) continue;
|
if (frame >= stackPhys && frame < stackEnd) continue;
|
||||||
if (gFrameStack.Top < gFrameStack.Capacity) {
|
if (gFrameStack.Top < gFrameStack.Capacity) {
|
||||||
gFrameStack.Stack[gFrameStack.Top++] = frame;
|
gFrameStack.Stack[gFrameStack.Top++] = frame;
|
||||||
|
|||||||
+3
-3
@@ -37,9 +37,9 @@ int main() {
|
|||||||
// Pass the 32-bit buffer directly to BitBlt
|
// Pass the 32-bit buffer directly to BitBlt
|
||||||
BitBlt(600, 400, width, height, image);
|
BitBlt(600, 400, width, height, image);
|
||||||
|
|
||||||
for (size_t i = 0; i < 1000000000; i++) {
|
// for (size_t i = 0; i < 1000000000; i++) {
|
||||||
// burn!
|
// // burn!
|
||||||
}
|
// }
|
||||||
|
|
||||||
OutputDebugStringA("Goodbye from the shell!\n");
|
OutputDebugStringA("Goodbye from the shell!\n");
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user