Multitasking problem
Posted: Wed May 13, 2009 7:00 pm
Hullo all.
I've been having a bit of trouble with multitasking. You see, I'm following various JamesM kernel dev. tutorials, but have run into a bit of a snag. The problem appears to be a problem with switching tasks. I assume the problem has something to do with the stack, since it occurs at the RET instruction of my code (C++ return after the EIP "magic number" test.)
I also suspect the problem could just as well be a paging error -- ex: not mapping correctly, or not switching the correct page address -- though I did check for that.
I've been working on solving this problem for quite some time, and it's rather an annoying bug. To be honest, I have got absolutely no idea what piece of code is wrong, what's actually going wrong, or any idea as to how to fix it (aside from not supporting multitasking.) I really need some help here and am hoping someone might be able to lend me a hand.
I've already fixed several potential bugs, and removed several other bugs, but its a bit difficult to tell if any of those were directly related to the problem I'm currently having (not being able to switch tasks.)
-- What happens, more specifically, is the EIP is NOT where it's supposed to be once the RET instruction finishes -- and I get a paging error at an obscure address, 0xF0000FE or something like that -- well, not that exact address (Somewhere in the 0xFXXXXXXX range) but nowhere in my code do I reference memory that high, I don't even put the stack that high! (The stack is being placed so that the very top of it is 0xE0002000, and the bottom of it is 0xE0000000.) Sometimes outputing debug messages causes QEMU to crash, which is rather unhelpful. I'm very certain its not a "heap-alloc'd" memory error, rather a combination of interrupt/stack error that causes QEMU to crash (QEMU becomes completely unresponsive, and outputs no debug information.)
Anyways, this error is bothering me greatly -- I'm so close to having multitasking working -- Once this bug is out of the way (provided there are no hidden bugs, lurking in the dark) I'll have basic multitasking (and then expand on to priorities and such ). But I can't for the life of me figure out the problem. Here are some source files:
task.c
paging.c
kernel.h
dragon.h
If you need to see more code, or use the build kit I used to compile all this, go to http://code.google.com/p/dragon-os
The current packages would be the dragon-0.05-alpha-unstable and dragonkit
Thanks for your time.
Cheers,
-naota
I've been having a bit of trouble with multitasking. You see, I'm following various JamesM kernel dev. tutorials, but have run into a bit of a snag. The problem appears to be a problem with switching tasks. I assume the problem has something to do with the stack, since it occurs at the RET instruction of my code (C++ return after the EIP "magic number" test.)
I also suspect the problem could just as well be a paging error -- ex: not mapping correctly, or not switching the correct page address -- though I did check for that.
I've been working on solving this problem for quite some time, and it's rather an annoying bug. To be honest, I have got absolutely no idea what piece of code is wrong, what's actually going wrong, or any idea as to how to fix it (aside from not supporting multitasking.) I really need some help here and am hoping someone might be able to lend me a hand.
I've already fixed several potential bugs, and removed several other bugs, but its a bit difficult to tell if any of those were directly related to the problem I'm currently having (not being able to switch tasks.)
-- What happens, more specifically, is the EIP is NOT where it's supposed to be once the RET instruction finishes -- and I get a paging error at an obscure address, 0xF0000FE or something like that -- well, not that exact address (Somewhere in the 0xFXXXXXXX range) but nowhere in my code do I reference memory that high, I don't even put the stack that high! (The stack is being placed so that the very top of it is 0xE0002000, and the bottom of it is 0xE0000000.) Sometimes outputing debug messages causes QEMU to crash, which is rather unhelpful. I'm very certain its not a "heap-alloc'd" memory error, rather a combination of interrupt/stack error that causes QEMU to crash (QEMU becomes completely unresponsive, and outputs no debug information.)
Anyways, this error is bothering me greatly -- I'm so close to having multitasking working -- Once this bug is out of the way (provided there are no hidden bugs, lurking in the dark) I'll have basic multitasking (and then expand on to priorities and such ). But I can't for the life of me figure out the problem. Here are some source files:
task.c
Code: Select all
/* Includes */
#include <kernel.h>
/* Globals */
// From main.c
extern u32 g_esp;
// From paging.c
extern sPageDir* g_pKrnlPgDir;
extern sPageDir* g_pCurPgDir;
// From mm.c
extern sHeap* g_pKrnlHeap;
// Our own
sTask* g_pKrnlTask = (sTask*)0;
sTask* g_pCurTask = (sTask*)0;
sList g_taskList;
u32 g_freePid = 1;
/* Functions */
// Move the stack
SYS_FUNC void SYS_API tsMoveStack(void)
{
// Preliminary
u32 i;
//u32 addr;
u32 offset;
u32 oldEsp, newEsp;
u32 oldEbp, newEbp;
u32 tmp, *pTmp;
// Allocate the stack
//dbgWrite(" (tsMoveStack) - Allocate the stack\n");
for(i = STACK_TOP_ADDR; i >= STACK_BASE_ADDR; i -= 0x1000)
{
//dbgShowVar(i);
pgAllocFrame(pgGetPage(g_pCurPgDir, i, B_TRUE), B_FALSE, B_TRUE);
}
// Flush the TLB
//dbgWrite(" (tsMoveStack) - Flush the TLB\n");
//asm volatile("push eax\n"
// "mov eax, cr3\n"
// "mov cr3, eax\n"
// "pop eax");
asm volatile("mov eax, cr3" : "=a" (tmp));
asm volatile("mov cr3, eax" :: "a" (tmp));
// Grab the old ESP and EBP
//dbgWrite(" (tsMoveStack) - Grab the OLD ESP & EBP\n");
asm volatile("mov eax, esp" : "=a" (oldEsp));
asm volatile("mov edx, ebp" : "=d" (oldEbp));
// Find the new ESP and EBP
//dbgWrite(" (tsMoveStack) - Find the new ESP & EBP\n");
offset = STACK_TOP_ADDR-g_esp;
newEsp = oldEsp+offset;
newEbp = oldEbp+offset;
// -- Extreme debugging
//dbgShowVar(g_esp);
//dbgShowVar(offset);
//dbgShowVar(newEsp);
//dbgShowVar(newEbp);
// Copy over the stack
//dbgWrite(" (tsMoveStack) - Copy over the stack\n");
kMemCpy((u8*)newEsp, (u8*)oldEsp, g_esp-oldEsp);
// Backtrace using JamesM's method -- must change
//dbgWrite(" (tsMoveStack) - Backtrace the stack\n");
//for(i = addr-size; i < addr; i += 4)
for(i = STACK_TOP_ADDR; i > STACK_BASE_ADDR; i -= 4)
{
tmp = *(u32*)i;
if ((oldEsp < tmp) && (tmp < g_esp))
{
tmp = tmp + offset;
pTmp = (u32*)i;
*pTmp = tmp;
//dbgShowVar(tmp);
}
/*
dbeWrite("--a\n");
u32* pIterator = (u32*)i;
dbeWrite("--b\n");
tmp = *pIterator;
dbeWrite("--c\n");
if ((oldEsp < tmp) && (tmp < g_esp))
{
dbeWrite("--d\n");
tmp = tmp + offset;
dbeWrite("--e\n");
pIterator[0] = tmp; // u32* tmp2 = (u32*)i; *tmp2 = tmp;
}
dbgShowVar(tmp);
dbgShowVar(pIterator[0]);
dbeWrite("--f\n");
*/
}
// Finally, change the esp and EBP
//dbgWrite(" (tsMoveStack) - Change the ESP & EBP\n");
asm volatile("mov esp, eax" :: "a" (newEsp));
asm volatile("mov ebp, edx" :: "d" (newEbp));
//dbgWrite(" (tsMoveStack) - Done\n");
}
// Initialize the use of tasking
SYS_FUNC bool_t SYS_API tsInit(void)
{
// Stop interrupts
//dbgWrite(" (tsInit) - Stop interrupts\n");
asm volatile("cli");
// Relocate the stack
//dbgWrite(" (tsInit) - Relocate the stack\n");
tsMoveStack();
// Initialize the task list
//dbgWrite(" (tsInit) - Initialize the task list\n");
lsInit(&g_taskList);
// Allocate the kernel task
//dbgWrite(" (tsInit) - Allocate the kernel task\n");
g_pKrnlTask = mmKrnlAllocType(sTask);
if (!g_pKrnlTask)
{
errSetError(TS_EC_CANT_ALLOC_TASK, TS_ES_CANT_ALLOC_TASK);
return B_FALSE;
}
// Setup the task
//dbgWrite(" (tsInit) - Setup the kernel task\n");
g_pKrnlTask->pProcess = (sTask*)0; // no parent process - we're the kernel
g_pKrnlTask->pid = g_freePid++;
g_pKrnlTask->priority = PL_KERNEL; // Only the kernel can have this priority
g_pKrnlTask->pPgDir = g_pKrnlPgDir;
g_pKrnlTask->pDefHeap = g_pKrnlHeap;
g_pKrnlTask->esp = 0;
g_pKrnlTask->ebp = 0;
g_pKrnlTask->eip = 0;
// Add the kernel process to the list
//dbgWrite(" (tsInit) - Add the kernel task to the list\n");
lsInitItem(&g_pKrnlTask->item, (void*)g_pKrnlTask, 0);
lsAddItem(&g_taskList, &g_pKrnlTask->item);
// Set the current task
//dbgWrite(" (tsInit) - Set the current task\n");
g_pCurTask = g_pKrnlTask;
// Set no error
//dbgWrite(" (tsInit) - Set that no error has occurred\n");
errSetError(EC_NONE, ES_NONE);
// Re-enable interrupts
//dbgWrite(" (tsInit) - Re-enable interrupts and return\n");
asm volatile("sti");
return B_TRUE;
}
// Fork the current process
SYS_FUNC u32 SYS_API tsFork(void)
{
// Preliminary
sTask* pParentTask;
sTask* pTask;
sPageDir* pPgDir;
u32 esp, ebp, eip;
// Disable interrupts
//dbgWrite(" (tsFork) - Disable interrupts\n");
asm volatile("cli");
// Get the parent task
//dbgWrite(" (tsFork) - Get the parent task\n");
pParentTask = g_pCurTask;
// Clone the address space
//dbgWrite(" (tsFork) - Clone the address space\n");
pPgDir = pgCloneDir(g_pCurPgDir);
if (!pPgDir)
return 0;
// Create a new task
//dbgWrite(" (tsFork) - Create a new task\n");
pTask = mmKrnlAllocType(sTask);
if (!pTask)
return 0;
// Setup the task
//dbgWrite(" (tsFork) - Setup the new task\n");
pTask->pProcess = pParentTask;
pTask->pid = g_freePid++;
pTask->priority = PL_NORMAL;
pTask->pPgDir = pPgDir;
pTask->pDefHeap = (sHeap*)0;
pTask->esp = 0;
pTask->ebp = 0;
pTask->eip = 0;
lsInitItem(&pTask->item, (void*)pTask, 0);
lsAddItem(&g_taskList, &pTask->item);
// Grab the EIP
//dbgWrite(" (tsFork) - Grab the EIP\n");
eip = kGetEip(); // Save the EIP now
// Check if the task is the parent or child
if (g_pCurTask == pParentTask)
{
// Grab the ESP and EBP
//dbgWrite(" (tsFork::parent) - Grab the ESP & EBP\n");
asm volatile("mov eax, esp\nmov edx, ebp" : "=a" (esp), "=d" (ebp));
// Set the task's ESP, EBP, and EIP
//dbgWrite(" (tsFork::parent) - Set the task's ESP, EBP, & EIP\n");
pTask->esp = esp;
pTask->ebp = ebp;
pTask->eip = eip;
// Done
//dbgWrite(" (tsFork::parent) - Re-enable interrupts\n");
asm volatile("sti");
//dbgWrite(" (tsFork::parent) - Done\n");
return pTask->pid;
}
//dbgWrite(" (tsFork) - Done\n");
return 0;
}
// Switch the task
SYS_FUNC void SYS_API tsSwitchTask(void)
{
// Preliminary
u32 esp, ebp, eip;
// Don't interrupt me, I'm executing
asm volatile("cli");
// Make sure multitasking has been initialized
if (!g_pCurTask)
return;
// Grab some registers
//dbgWrite(" (tsSwitchTask) - Grab some registers\n");
asm volatile("mov eax, esp\n"
"mov edx, ebp" : "=a" (esp), "=d" (ebp));
//dbgWrite(" (tsSwitchTask) - Grab and check the EIP\n");
eip = kGetEip();
// Check if we just switched tasks
if (eip == 0x12345)
{
dbgWrite(" (tsSwitchTask) - Returning\n");
asm volatile("pop ecx" : "=c" (eip));
dbgShowVar(eip);
asm volatile("push ecx" :: "c" (eip));
return;
}
// Set the EIP, ESP, and EBP of the current task
// -- wouldn't it be better to pass in a sRegs* to tsSwitchTask and do this:
// g_pCurTask->eip = pRegs->eip;
// g_pCurTask->esp = pRegs->esp;
// g_pCurTask->ebp = pRegs->ebp;
// -- is there some reason why this wouldn't work?
//dbgWrite(" (tsSwitchTask) - Save some registers and values\n");
g_pCurTask->eip = eip;
g_pCurTask->esp = esp;
g_pCurTask->ebp = ebp;
// Get the next task
//dbgWrite(" (tsSwitchTask) - Get the next task\n");
g_pCurTask = (sTask*)lsAfter(&g_taskList, &g_pCurTask->item);
if (!g_pCurTask)
g_pCurTask = (sTask*)lsFirst(&g_taskList);
// Grab stack info from the new current stack
//dbgShowVar(g_pCurTask);
//dbgWrite(" (tsSwitchTask) - Grab stack info\n");
esp = g_pCurTask->esp;
ebp = g_pCurTask->ebp;
dbgShowVar(eip);
//dbgShowVar(esp);
//dbgShowVar(ebp);
// Jump to the new EIP
dbgWrite(" (tsSwitchTask) - Jump to the new EIP\n");
asm volatile("mov esp, edx\n"
"mov ebp, ebx\n"
"mov cr3, eax\n"
"mov eax, 0x12345\n"
"sti\n"
"jmp dword ptr ecx" :: "c" (eip), "d" (esp), "b" (ebp), "a" (g_pCurTask->pPgDir->physAddr));
}
// Get the PID of the current task
SYS_FUNC u32 SYS_API tsGetPid(void)
{
if (!g_pCurTask)
{
errSetError(EC_NOT_INITIALIZED, ES_NOT_INITIALIZED);
return 0;
}
return g_pCurTask->pid;
}
Code: Select all
/* Includes */
#include <kernel.h>
/* Globals */
// External
extern u32 g_placementAddr;
// Kernel page directory
sPageDir* g_pKrnlPgDir;
sPageDir* g_pCurPgDir;
// Kernel heap
extern sHeap* g_pKrnlHeap;
/* Internal Functions */
// Allocate a single page table
INT_FUNC void INT_API allocPageTable(sPageDir* pDir, u32 entry, u32 flags)
{
// Preliminary
u32 tmp;
// Allocate the table
pDir->pEntries[entry] = (sPageTable*)mmKrnlAllocEx(0x1000, B_TRUE, (void**)&tmp);
kMemSet((u8*)pDir->pEntries[entry], 0, 0x1000);
pDir->physEntries[entry] = tmp|flags;
// Debug info
dbgWrite("Allocated page table at address ");
dbgWriteHex(tmp);
dbgWrite(" -- physEnt = ");
dbgWriteHex(tmp|flags);
dbgWriteChar('\n');
}
// Copy a page table
INT_FUNC sPageTable* INT_API cloneTable(sPageTable* pSrc, u32* pPhysAddr)
{
// Preliminary
sPageTable* pTable;
u32 i;
// Allocate a page table
pTable = mmKrnlAllocTypeEx(sPageTable, B_TRUE, pPhysAddr);
if (!pTable)
return (sPageTable*)0;
// Zero out the table
kMemSet((u8*)pTable, 0, sizeof(sPageTable)); // JamesM's was sizeof page directory (sizeof(sPageDir))
// Set every page table entry
for(i = 0; i < 1024; i++)
{
// Check the base address
if (!pSrc->pages[i].baseAddr)
continue;
// Allocate a new frame
pgAllocFrame(&pTable->pages[i], B_FALSE, B_FALSE);
// Copy over certain flags
pTable->pages[i].flags = 0;
if (pSrc->pages[i].flags & PG_PRESENT)
pTable->pages[i].flags |= PG_PRESENT;
if (pSrc->pages[i].flags & PG_RW)
pTable->pages[i].flags |= PG_RW;
if (pSrc->pages[i].flags & PG_USER)
pTable->pages[i].flags |= PG_USER;
if (pSrc->pages[i].flags & PG_ACCESSED)
pTable->pages[i].flags |= PG_ACCESSED;
if (pSrc->pages[i].flags & PG_DIRTY)
pTable->pages[i].flags |= PG_DIRTY;
// Copy the page
pgCopyPage(pSrc->pages[i].baseAddr*0x1000, pTable->pages[i].baseAddr*0x1000);
/*
asm volatile("pushf\n"
"cli\n"
"mov edx, cr0\n"
"and edx, 0x7FFFFFFF\n"
"mov cr0, edx\n" // disable paging
"mov edx, 1024\n"
".jump_pt:\n"
"\tmov eax, [edx]\n"
"\tmov [ecx], eax\n"
"\tadd ebx, 4\n"
"\tadd ecx, 4\n"
"\tdec edx\n"
"\tjnz .jump_pt\n"
"mov edx, cr0\n"
"or edx, 0x80000000\n"
"mov cr0, edx\n" // enable paging
"popf" :: "b" (pSrc->pages[i].baseAddr*PAGE_SIZE), "c" (pTable->pages[i].baseAddr*PAGE_SIZE));
*/
}
}
/* Functions */
// Allocate a frame
SYS_FUNC void SYS_API pgAllocFrame(sPage* pPage, bool_t user, bool_t rw)
{
// Find the first free frame
u32 index;
// Check if the frame is already allocated
if (pPage->baseAddr != 0)
return;
// Find the index of the first free frame
index = pfaAllocFrame();
pPage->flags = PG_PRESENT | ((user == B_TRUE) ? PG_USER : 0) | ((rw == B_TRUE) ? PG_RW : 0);
pPage->baseAddr = index;
}
// Deallocate a frame
SYS_FUNC void SYS_API pgFreeFrame(sPage* pPage)
{
// Preliminary
u32 frame;
// Grab the frame
frame = pPage->baseAddr;
if (!frame)
return;
// Clear the frame and zero out the pages frame address
pfaFreeFrame(frame);
pPage->baseAddr = 0;
}
// Get a page from a page directory
SYS_FUNC sPage* SYS_API pgGetPage(sPageDir* pDir, u32 addr, bool_t make)
{
// Preliminary
u32 index;
u32 tableIndex;
u32 tmp;
sPageTable* pTable;
// Find the table index
index = addr/0x1000;
tableIndex = index/1024;
// Is the table assigned?
if (pDir->pEntries[tableIndex])
{
// Grab the table, and return the page
pTable = pDir->pEntries[tableIndex];
return &pTable->pages[index%1024];
}
// Should we make the table, considering it doesn't exist?
if (make)
{
// Allocate a new page table, and return the requested page
allocPageTable(pDir, tableIndex, PT_PRESENT|PT_RW|PT_USER);
pTable = pDir->pEntries[tableIndex];
return &pTable->pages[index%1024];
}
// Utter failure, return null
return (sPage*)0;
}
// Clone a page directory
SYS_FUNC sPageDir* SYS_API pgCloneDir(sPageDir* pSrc)
{
// Preliminary
sPageDir* pDir;
u32 phys;
u32 offset;
u32 i;
// Allocate the page directory
pDir = mmKrnlAllocTypeEx(sPageDir, B_TRUE, &phys);
if (!pDir)
return (sPageDir*)0;
// Zero out the page directory
kMemSet((u8*)pDir, 0, sizeof(sPageDir));
// Grab the offset
offset = ((u32)pDir->physEntries)-((u32)pDir);
// Setup the physical address
pDir->physAddr = offset+phys;
// Go through the tables
for(i = 0; i < 1024; i++)
{
// Should we link?
if (g_pKrnlPgDir->pEntries[i] == pSrc->pEntries[i])
{
// Link -- Just copy the pointers
pDir->pEntries[i] = pSrc->pEntries[i];
pDir->physEntries[i] = pSrc->physEntries[i];
}
// Or should we copy?
else if (pSrc->pEntries[i])
{
// Copy the page table
pDir->pEntries[i] = cloneTable(pSrc->pEntries[i], &phys);
pDir->physEntries[i] = phys|PT_PRESENT|PT_RW|PT_USER;
}
}
// Return the page directory
return pDir;
}
// Initialize paging
SYS_FUNC void SYS_API pgInit(void)
{
// Preliminary
u32 i, phys;
// Allocate a page directory entry
g_pKrnlPgDir = mmKrnlAllocTypeEx(sPageDir, B_TRUE, (void**)&phys);
kMemSet((u8*)g_pKrnlPgDir, 0, sizeof(sPageDir));
g_pKrnlPgDir->physAddr = (u32)(g_pKrnlPgDir->physEntries);
dbgWriteVar(g_pKrnlPgDir);
// Allocate pages for the heap
dbgWrite(" - Allocating pages to allow the page table for the kernel heap to be made.\n");
for(i = KHEAP_START; i < KHEAP_START+KHEAP_DEF_SIZE; i += 0x1000)
pgGetPage(g_pKrnlPgDir, i, B_TRUE);
// Identity map
for(i = 0; i < g_placementAddr+0x1000; i += 0x1000)
pgAllocFrame(pgGetPage(g_pKrnlPgDir, i, B_TRUE), B_FALSE, B_FALSE);
// Allocate the pages mapped earlier
dbgWrite(" - Setting the kernel pages allocated earlier.\n");
for(i = KHEAP_START; i < KHEAP_START+KHEAP_DEF_SIZE; i += 0x1000)
pgAllocFrame(pgGetPage(g_pKrnlPgDir, i, B_TRUE), B_FALSE, B_FALSE);
// Set the page directory
pgSwitchDir(g_pKrnlPgDir);
// Show the placement address
dbgShowVar(g_placementAddr);
#if defined(EXTREMEDEBUG)
// Debug Preliminary
u32 cr0, cr3;
// Grab some values
asm volatile("mov eax, cr0" : "=a" (cr0));
asm volatile("mov eax, cr3" : "=a" (cr3));
// Write the values
dbeWriteVar(cr0);
dbeWriteVar(cr3);
#endif
// Create the heap
dbgWrite(" - Creating the kernel heap\n");
g_pKrnlHeap = mmCreateHeap(KHEAP_START, KHEAP_DEF_SIZE, KHEAP_MAX_SIZE, 0);
dbgWrite(" - Done creating the kernel heap\n");
// Change the page directory
g_pCurPgDir = pgCloneDir(g_pKrnlPgDir);
if (!g_pCurPgDir)
{
errKernelPanic(__FILE__, __LINE__, "g_pCurPgDir != (sPageDir*)0", "Unable to clone page directory");
}
pgSwitchDir(g_pCurPgDir);
}
// Page fault handler
SYS_FUNC void ASM_API pgFaultHandler(sRegs* pRegs)
{
// Preliminary
u32 faultAddr, flags;
// Ask the processor for the fault address and grab the flags
asm volatile("mov eax, cr2" : "=a" (faultAddr));
flags = pRegs->errCode;
/*
TODO: Check rather or not the page is allocated.
If the page IS allocated, then support swapping from hard disk.
If the page isn't allocated, then send the task the exception
signal.
*/
// Write the error to the screen
ktmSetColor(0xC, 0);
ktmWrite("\nPage Fault! - The kernel has died with some information\n");
ktmSetColor(0xF, 0);
if (flags & 2)
ktmWrite("Unable to write memory to address ");
else
ktmWrite("Unable to read memory from address ");
ktmWriteHex(faultAddr); ktmWrite("\n\n");
ktmSetColor(0xC, 0);
ktmWrite("Details:\n");
ktmSetColor(4, 0);
if (!(flags & 1))
ktmWrite(" - Page not present\n");
if (flags & 2)
ktmWrite(" - Write operation\n");
else
ktmWrite(" - Read operation\n");
if (flags & 4)
ktmWrite(" - User mode write\n");
if (flags & 8)
ktmWrite(" - Overwrote reserved bits\n");
if (flags & 16)
ktmWrite(" - Caused by instruction fetch\n");
errShowInfo();
ktmSetColor(0xE, 0);
ktmWrite("\nEAX = "); ktmWriteHex(pRegs->eax);
ktmWrite(", EDX = "); ktmWriteHex(pRegs->edx);
ktmWrite(", ECX = "); ktmWriteHex(pRegs->ecx);
ktmWrite(", EBX = "); ktmWriteHex(pRegs->ebx);
ktmWrite("\nEIP = "); ktmWriteHex(pRegs->eip);
ktmWrite(", ESP = "); ktmWriteHex(pRegs->esp);
ktmWrite(", EBP = "); ktmWriteHex(pRegs->ebp);
// Halt the system
while(1) asm volatile("hlt");
}
// Switch the page directory
SYS_FUNC void SYS_API pgSwitchDir(sPageDir* pDir)
{
// Preliminary
u32 cr0;
// Set the current page directory
g_pCurPgDir = pDir;
// Set the page directory address to the PDBA register (CR3)
asm volatile("mov cr3, eax" :: "a" (pDir->physAddr));
// Set the PG bit of CR0 so that paging may be enabled
asm volatile("mov eax, cr0" : "=a" (cr0));
cr0 |= 0x80000000;
asm volatile("mov cr0, eax" :: "a" (cr0));
// Inform the world that we are in paging mode!
dbgWrite("\nSwitched page directory!\n\n");
}
Code: Select all
#ifndef KERNEL_H
#define KERNEL_H
/* Includes */
#define sObject_defined
#include "dragon.h"
/* Defines */
// Version states
#define VS_ALPHA 0
#define VS_BETA 1
#define VS_RELEASE_CANDIDATE 2
#define VS_RELEASE 3
// Kernel version
#define KERNEL_VERSION_MAJOR 0
#define KERNEL_VERSION_MINOR 0
#define KERNEL_VERSION_MINOR_MINOR 5
#define KERNEL_VERSION_STATE VS_ALPHA
#if defined(DEBUG)
# define KERNEL_VERSION "dragon-kernel-0.05-alpha(debug)"
#else
# define KERNEL_VERSION "dragon-kernel-0.05-alpha"
#endif
// Multiboot defines
#define MULTIBOOT_FLAG_MEM 0x001
#define MULTIBOOT_FLAG_DEVICE 0x002
#define MULTIBOOT_FLAG_CMDLINE 0x004
#define MULTIBOOT_FLAG_MODS 0x008
#define MULTIBOOT_FLAG_AOUT 0x010
#define MULTIBOOT_FLAG_ELF 0x020
#define MULTIBOOT_FLAG_MMAP 0x040
#define MULTIBOOT_FLAG_CONFIG 0x080
#define MULTIBOOT_FLAG_LOADER 0x100
#define MULTIBOOT_FLAG_APM 0x200
#define MULTIBOOT_FLAG_VBE 0x400
// Kernel boot modes
#define KBM_GUI 1 // boot with a GUI
#define KBM_NETWORK 2 // boot allowing internet/network connections
#define KBM_SAFE_MODE 4 // boot in safe mode
// Screen (ktm)
#define TAB_WIDTH 8
// Size of a page
#define PAGE_SIZE 0x1000
// Kernel heap information
#define KHEAP_START 0xC0000000
#define KHEAP_DEF_SIZE 0x700000
#define KHEAP_MAX_SIZE 0x20000000
// Page table flags
#define PT_PRESENT 1
#define PT_RW 2
#define PT_USER 4
#define PT_WT 8
#define PT_CD 16
#define PT_ACCESSED 32
#define PT_RESERVED 64
#define PT_SIZE 128
#define PT_GLOBAL 256
// Page flags
#define PG_PRESENT 1
#define PG_RW 2
#define PG_USER 4
#define PG_WT 8
#define PG_CD 16
#define PG_ACCESSED 32
#define PG_DIRTY 64
#define PG_PTAI 128
#define PG_GLOBAL 256
// Heap magic values
#define HEAP_MAGIC 0xFACEBEEF
#define HEAP_ENTRY_OCCUPIED 0xCBC0BCB1
#define HEAP_ENTRY_VACANT 0x5456763C
#define HEAP_ENTRY_FOOTER 0xFAD0F001
// Heap values
#define HEAP_INDEX_SIZE 0x20000
#define HEAP_MIN_SIZE 0x50000
// Heap flags
#define HF_KERNEL 1
#define HF_READ_ONLY 2
// Heap entry flags
#define HEF_PAGE_ALIGN 1
// Node masks
#define FSM_VIRTUAL 0 // virtual node (implies directory styled access)
#define FSM_FILE 1 // file
#define FSM_DIR 2 // directory
#define FSM_CHAR_DEVICE 3 // device; ex, stdio, stdlib
#define FSM_BLOCK_DEVICE 4 // device; ex, hdd, fdd, cd, etc
#define FSM_PIPE 5 // process pipe
#define FSM_SYM_LINK 6 // symbolic link/shortcut
// Node flags
#define FSF_SYSTEM 1 // system file (cannot be moved)
#define FSF_READ_ONLY 2 // read-only file
#define FSF_HIDDEN 4 // hidden file
#define FSF_EXECUTABLE 8 // executable file
#define FSF_COMPRESSED 16 // compressed file
#define FSF_ENCRYPTED 32 // encrypted file
// Open flags
#define OPN_WRITE 1 // write access for self
#define OPN_READ 2 // read access for self
#define OPN_SHARE_WRITE 4 // write access for others
#define OPN_SHARE_READ 8 // read access for others
// File block size
#define FILE_BLOCK_SIZE 0x1000
// Object magic header
#define OBJ_MAGIC 0xBABAF00D
// InitRD header magic values
#define IRD_MAGIC_1 0x04305478
#define IRD_MAGIC_2 0xFEEDBEEF
// File seek relative location
#define FSR_START 0
#define FSR_CURRENT 1
#define FSR_END 2
// Priority levels
#define PL_IDLE 0
#define PL_VERY_LOW 1
#define PL_LOW 2
#define PL_NORMAL 3
#define PL_HIGH 4
#define PL_VERY_HIGH 5
#define PL_REAL_TIME 6
#define PL_KERNEL 0xFFFFFFFF
// Priority times
#define PT_IDLE 4 // 4 milliseconds run time - useful for apps that are waiting for a resource to become available
#define PT_VERY_LOW 7 // 7 milliseconds run time - useful for apps that do very little work
#define PT_LOW 13 // 13 milliseconds run time - useful for apps that do little work
#define PT_NORMAL 25 // 25 milliseconds run time - useful for normal apps
#define PT_HIGH 50 // 50 milliseconds run time - useful for video editing software
#define PT_VERY_HIGH 100 // 100 milliseconds run time - useful for games
#define PT_REAL_TIME 200 // 200 milliseconds run time - useful for high-end games
#define PT_KERNEL 0xFFFFFFFF
// Shared data area
#define STACK_BASE_ADDR 0xE0000000
#define STACK_TOP_ADDR 0xE0002000
#define STACK_SIZE (STACK_TOP_ADDR-STACK_BASE_ADDR)
/* Macros */
// Page frame allocator (PFA) macros
#define MakeFrameId(i,b) (((i)*32)+(b))
#define GetFrameIndex(f) ((f)/32)
#define GetFrameBit(f) ((f)%8)
// Assertion
#define assert(x) {\
if (!(x))\
errKernelPanic(__FILE__, __LINE__, #x, "Kernel Assertion Failed");\
}
// Debug macros
#if defined(DEBUG)
# define dbgWrite(s) { ktmWrite(s); errSetDebugInfo(__LINE__, __FILE__); }
# define dbgWriteChar(c) { ktmWriteChar(c); errSetDebugInfo(__LINE__, __FILE__); }
# define dbgWriteDec(s) { ktmWriteDec(s); errSetDebugInfo(__LINE__, __FILE__); }
# define dbgWriteHex(s) { ktmWriteHex(s); errSetDebugInfo(__LINE__, __FILE__); }
# define dbgWriteOct(s) { ktmWriteOct(s); errSetDebugInfo(__LINE__, __FILE__); }
# define dbgWriteBin(s) { ktmWriteBin(s); errSetDebugInfo(__LINE__, __FILE__); }
# define dbgShowVar(v) {\
ktmWrite(#v " = ");\
ktmWriteDec((s32)(v));\
ktmWrite(" (");\
ktmWriteHex((u32)(v));\
ktmWrite(")\n");\
errSetDebugInfo(__LINE__, __FILE__);\
}
#else
# define dbgWrite(s) // not in debug mode...
# define dbgWriteChar(c) // not in debug mode...
# define dbgWriteDec(s) // not in debug mode...
# define dbgWriteHex(s) // not in debug mode...
# define dbgWriteOct(s) // not in debug mode...
# define dbgWriteBin(s) // not in debug mode...
# define dbgShowVar(v) // not in debug mode...
#endif
#if defined(EXTREMEDEBUG)
# define dbeWrite(s) { ktmWrite(s); errSetDebugInfo(__LINE__, __FILE__); }
# define dbeWriteChar(c) { ktmWriteChar(c); errSetDebugInfo(__LINE__, __FILE__); }
# define dbeWriteDec(s) { ktmWriteDec(s); errSetDebugInfo(__LINE__, __FILE__); }
# define dbeWriteHex(s) { ktmWriteHex(s); errSetDebugInfo(__LINE__, __FILE__); }
# define dbeWriteOct(s) { ktmWriteOct(s); errSetDebugInfo(__LINE__, __FILE__); }
# define dbeWriteBin(s) { ktmWriteBin(s); errSetDebugInfo(__LINE__, __FILE__); }
# define dbeShowVar(v) {\
ktmWrite(#v " = ");\
ktmWriteDec((s32)(v));\
ktmWrite(" (");\
ktmWriteHex((u32)(v));\
ktmWrite(")\n");\
errSetDebugInfo(__LINE__, __FILE__);\
}
#else
# define dbeWrite(s) // not in extreme debug mode...
# define dbeWriteChar(c) // not in extreme debug mode...
# define dbeWriteDec(s) // not in extreme debug mode...
# define dbeWriteHex(s) // not in extreme debug mode...
# define dbeWriteOct(s) // not in extreme debug mode...
# define dbeWriteBin(s) // not in extreme debug mode...
# define dbeShowVar(v) // not in extreme debug mode...
#endif
#define dbgWriteVar(v) dbgShowVar(v)
#define dbeWriteVar(v) dbeShowVar(v)
/* Typedefs (Pre Structures) */
// Callback function for when an item is deleted in a linked list
typedef void (*deleteListItem_t) (void* pObj);
typedef deleteListItem_t deleteFunc_t;
// Sorting callback
typedef bool_t (*sortFunc_t) (void* pA, void* pB);
// Handle types
typedef struct sHandle_t* handle_t;
typedef handle_t file_t; // more handle types here
/* Structures */
// Linked list base
typedef struct sList_t
{
struct sListItem_t *pFirst, *pLast;
} sList;
// Linked list item
typedef struct sListItem_t
{
void* pObj;
deleteListItem_t pfnDelete;
struct sListItem_t *pPrev, *pNext;
} sListItem;
// Multiboot structure
typedef struct sMultiBoot_t
{
u32 flags;
u32 memLower;
u32 memUpper;
u32 bootDevice;
u32 cmdline;
u32 numMods;
u32* pMods;
u32 num;
u32 size;
u32 addr;
u32 shndx;
u32 mmapLength;
u32 mmapAddr;
u32 drivesLength;
u32 drivesAddr;
u32 configTable;
u32 bootLoaderName;
u32 apmTable;
u32 vbeControlInfo;
u32 vbeModeInfo;
u32 vbeMode;
u32 vbeInterfaceSeg;
u32 vbeInterfaceOff;
u32 vbeInterfaceLen;
} __attribute__((packed)) sMultiBoot;
// Kernel initialization structure
typedef struct sKernelInit_t
{
sMultiBoot* pMultiBoot;
u32 kernelStack;
u32 kernelStackBase;
u32 mode;
} __attribute__((packed)) sKernelInit;
// Screen character
typedef struct sScrChar_t
{
u8 c; // Character
u8 a; // Attribute
} __attribute__((packed)) sScrChar;
// GDT Entry
typedef struct sGdtEntry_t
{
u16 limitLow;
u16 baseLow;
u8 baseMiddle;
u8 access;
u8 granularity;
u8 baseHigh;
} __attribute__((packed)) sGdtEntry;
// GDT Pointer
typedef struct sGdtPtr_t
{
u16 limit;
u32 base;
} __attribute__((packed)) sGdtPtr;
// IDT Entry
typedef struct sIdtEntry_t
{
u16 baseLow;
u16 selector;
u8 poison;
u8 flags;
u16 baseHigh;
} __attribute__((packed)) sIdtEntry;
// IDT Pointer
typedef struct sIdtPtr_t
{
u16 limit;
u32 base;
} __attribute__((packed)) sIdtPtr;
// Registers
typedef struct sRegs_t
{
u32 gs, fs, es, ds;
u32 edi, esi, ebp, esp, ebx, edx, ecx, eax;
u32 intNum, errCode;
u32 eip, cs, eflags, useResp, ss;
} __attribute__((packed)) sRegs;
// Page table entry (page)
typedef struct sPage_t
{
unsigned flags : 9; // Flags
unsigned avail : 3; // Available for the kernel's use
unsigned baseAddr : 20; // Page base address
} __attribute__((packed)) sPage;
// An actual page table
typedef struct sPageTable_t
{
sPage pages[1024];
} __attribute__((packed)) sPageTable;
// Page directory
typedef struct sPageDir_t
{
sPageTable* pEntries[1024]; // Page table pointers
// end-of-page-table-page (0x1000 bytes)
u32 physEntries[1024]; // Physical addresses of the page tables
u32 physAddr; // Physical address of the page directory
} __attribute__((packed)) sPageDir;
// Ordered array
typedef struct sOrderedArray_t
{
void** ppArray;
u32 size;
u32 maxSize;
sortFunc_t pfnLessThan;
} sOrderedArray;
// The heap
typedef struct sHeap_t
{
u32 magic; // HEAP_MAGIC
sOrderedArray index;
u32 flags; // HF_*
u32 baseAddr;
u32 size;
u32 maxSize;
} __attribute__((packed)) sHeap;
// An entry in the heap (header)
typedef struct sHeapEntryHeader_t
{
u32 magic; // HEAP_ENTRY_OCCUPIED or HEAP_ENTRY_VACANT
u32 size;
} __attribute__((packed)) sHeapEntryHeader;
// An entry in the heap (footer)
typedef struct sHeapEntryFooter_t
{
u32 magic; // HEAP_ENTRY_FOOTER
sHeapEntryHeader* pHeader;
} __attribute__((packed)) sHeapEntryFooter;
// Individual handle
typedef struct sHandle_t
{
u32 magic;
u32 typeValue;
struct sHandleType_t* pType;
u32 refCount;
void* pData;
u32 userData;
sListItem item;
} __attribute__((packed)) sHandle;
// Handle type
typedef struct sHandleType_t
{
u32 typeValue;
u32 typeSize;
u32 numHandles;
sList handleList;
sListItem item;
void* pData; // shared data between all handles of this type
bool_t (*pfnConstructor) (sHandle* pHandle);
void (*pfnDestructor) (sHandle* pHandle);
} __attribute__((packed)) sHandleType;
// Type-Descriptor
typedef struct HANDLE_TYPE_DESC_T
{
u32 typeValue;
u32 typeSize;
u32 sharedDataSize;
bool_t (*pfnConstructor) (sHandle* pHandle);
void (*pfnDestructor) (sHandle* pHandle);
} HANDLE_TYPE_DESC;
// Virtual file system node
typedef struct sVfsNode_t
{
char szName[MAX_PATH]; // name of the file
sHandle* pFileHandle; // handle currently attached to this file
u32 mask; // one of the FSM values
u32 flags; // a combination of FSF flags
struct sVfsNode_t* pMountPoint; // if this is a mount point, this is a pointer to the mounted node, otherwise null
u32 uid; // user identifier
u32 gid; // group identifier
u32 inode; // node identifier -- reserved for FS driver use
u32 privateData; // private data -- reserved for FS driver use
struct sVfsNode_t* pParent; // parent node
sList dirList; // list of opened subnodes to this node
sListItem item; // list item to parent
bool_t (*pfnOpen) (struct sVfsNode_t* pNode, u32 flags);
bool_t (*pfnClose) (struct sVfsNode_t* pNode);
u32 (*pfnWrite) (struct sVfsNode_t* pNode, void* pData, u32 dataLen);
u32 (*pfnRead) (struct sVfsNode_t* pNode, void* pData, u32 dataLen);
bool_t (*pfnSeek) (struct sVfsNode_t* pNode, u32 location);
u32 (*pfnTell) (struct sVfsNode_t* pNode);
u32 (*pfnGetLength) (struct sVfsNode_t* pNode);
bool_t (*pfnReadDir) (struct sVfsNode_t* pNode); // causes dirList to repopulate
struct sVfsNode_t* (*pfnFindDir) (struct sVfsNode_t* pNode, char* pszFileName); // check to see if pszPath specifies a file from here
struct sVfsNode_t* (*pfnCreateFile) (struct sVfsNode_t* pNode, char* pszFileName, u32 mask, u32 flags);
void (*pfnDelete) (struct sVfsNode_t* pNode);
} sVfsNode;
// File system descriptor
typedef struct sFileSystem_t
{
// TODO: Add stuff
bool_t readOnly; // is this a read-only fs?
u32 uid; // default user identifier
u32 gid; // default group identifier
u32 privateData; // private data for the file system
bool_t (*pfnOpen) (sVfsNode* pNode, u32 flags);
bool_t (*pfnClose) (sVfsNode* pNode);
u32 (*pfnWrite) (sVfsNode* pNode, void* pData, u32 dataLen);
u32 (*pfnRead) (sVfsNode* pNode, void* pData, u32 dataLen);
bool_t (*pfnSeek) (sVfsNode* pNode, u32 location);
u32 (*pfnTell) (sVfsNode* pNode);
u32 (*pfnGetLength) (sVfsNode* pNode);
bool_t (*pfnReadDir) (sVfsNode* pNode);
sVfsNode* (*pfnFindDir) (sVfsNode* pNode, char* pszFileName);
sVfsNode* (*pfnCreateFile) (sVfsNode* pNode, char* pszFileName, u32 mask, u32 flags);
void (*pfnDelete) (sVfsNode* pNode);
} sFileSystem;
// Path information structure
typedef struct PATH_INFO_T
{
sVfsNode* pDirNode;
sVfsNode* pFileNode;
char szDirName[MAX_PATH];
char szFileName[MAX_PATH];
} PATH_INFO;
// A task (process or thread)
typedef struct sTask_t
{
struct sTask_t* pProcess; // parent process
sVfsNode* pCurDir; // current directory for file access
u32 pid; // process identifier
u32 priority; // the process' priority
sPageDir* pPgDir; // process page directory
sHeap* pDefHeap; // default heap for process
u32 esp, ebp; // ESP and EBP regs
u32 eip; // EIP reg
sListItem item; // list item for process list
} sTask;
/* Typedefs (Post Structs) */
// ISR handler callback
typedef void (*isr_t) (sRegs* pRegs);
/* Functions */
// Text mode screen
SYS_FUNC void SYS_API ktmScrollScreen(void);
SYS_FUNC void SYS_API ktmWriteChar(char c);
SYS_FUNC void SYS_API ktmWrite(const char* pszText);
SYS_FUNC void SYS_API ktmWriteDec(s32 d);
SYS_FUNC void SYS_API ktmWriteHex(u32 h);
SYS_FUNC void SYS_API ktmWriteOct(u32 o);
SYS_FUNC void SYS_API ktmWriteBin(u32 b);
SYS_FUNC void SYS_API ktmClear(void);
SYS_FUNC void SYS_API ktmSetColor(u8 fg, u8 bg);
SYS_FUNC void SYS_API ktmSetCursorPos(u16 x, u16 y);
SYS_FUNC void SYS_API ktmGetCursorPos(u16* pX, u16* pY);
SYS_FUNC u16 SYS_API ktmGetCursorX(void);
SYS_FUNC u16 SYS_API ktmGetCursorY(void);
SYS_FUNC u8 SYS_API ktmGetColors(void);
// Global descriptor table
ASM_FUNC void ASM_API gdtInit(void);
// Interrupt descriptor table
SYS_FUNC void SYS_API idtSetGate(u32 index, u32 base, u16 selector, u8 flags);
SYS_FUNC void SYS_API idtInit(void);
ASM_FUNC void ASM_API idtFlush(void);
// Interrupt service routines
SYS_FUNC void SYS_API isrInit(void);
SYS_FUNC void ASM_API isrFaultHandler(sRegs* pRegs);
SYS_FUNC void SYS_API isrSetHandler(u32 index, isr_t pfnHandlerCallback);
// Interrupt request routines
ASM_FUNC void ASM_API irqRemap(void);
SYS_FUNC void SYS_API irqInit(void);
SYS_FUNC void SYS_API irqSetHandler(u32 index, isr_t pfnHandlerCallback);
SYS_FUNC void ASM_API irqFaultHandler(sRegs* pRegs);
// Timer
SYS_FUNC void ASM_API timIrqHandler(sRegs* pRegs);
SYS_FUNC void SYS_API timSetPhase(u32 hz);
SYS_FUNC void SYS_API timInit(void);
// Memory manager
SYS_FUNC void* SYS_API mmKrnlAlloc(u32 size);
SYS_FUNC void* SYS_API mmKrnlAllocEx(u32 size, bool_t align, void** ppPhysAddr);
SYS_FUNC sHeap* SYS_API mmCreateHeap(u32 start, u32 size, u32 maxSize, u32 flags);
SYS_FUNC void* SYS_API mmAlloc(sHeap* pHeap, u32 flags, u32 size);
SYS_FUNC bool_t SYS_API mmIsPointerValidEx(void* pPtr, sHeapEntryHeader** ppOutHeader, sHeapEntryFooter** ppOutFooter);
#define mmIsPointerValid(p) mmIsPointerValidEx(p,(sHeapEntryHeader**)0,(sHeapEntryFooter**)0)
SYS_FUNC void SYS_API mmFree(sHeap* pHeap, void* pPtr);
#define mmKrnlAllocType(t) ((t*)mmKrnlAlloc(sizeof(t)))
#define mmKrnlAllocTypeEx(t,a,p) ((t*)mmKrnlAllocEx(sizeof(t),(a),(void**)(p)))
#define mmAllocType(t,h,f) ((t*)mmAlloc((h),(f),sizeof(t)))
// Page frame allocator
SYS_FUNC bool_t SYS_API pfaInitFrames(u32 numFrames);
SYS_FUNC u32 SYS_API pfaFindFreeFrame(void);
SYS_FUNC u32 SYS_API pfaAllocFrame(void);
SYS_FUNC void SYS_API pfaFreeFrame(u32 frame);
SYS_FUNC bool_t SYS_API pfaFrameExist(u32 frame);
// Paging
SYS_FUNC void SYS_API pgAllocFrame(sPage* pPage, bool_t user, bool_t rw);
SYS_FUNC void SYS_API pgFreeFrame(sPage* pPage);
SYS_FUNC sPage* SYS_API pgGetPage(sPageDir* pDir, u32 addr, bool_t make);
SYS_FUNC sPageDir* SYS_API pgCloneDir(sPageDir* pSrc);
ASM_FUNC void ASM_API pgCopyPage(u32 a, u32 b);
SYS_FUNC void SYS_API pgInit(void);
SYS_FUNC void ASM_API pgFaultHandler(sRegs* pRegs);
SYS_FUNC void SYS_API pgSwitchDir(sPageDir* pDir);
// Errors
SYS_FUNC void SYS_API errSetErrorEx(u32 error, char* pszErrorMsg, char* pszFile, u32 line);
#define errSetError(err,msg) errSetErrorEx((err),(msg),__FILE__,__LINE__)
SYS_FUNC u32 SYS_API errGetError(void);
SYS_FUNC char* SYS_API errGetErrorMsg(char* pszOutBuff, u32 buffSize);
SYS_FUNC void SYS_API errKernelPanic(char* pszFile, u32 line, char* pszExpression, char* pszDetails);
SYS_FUNC void SYS_API errShowInfo(void);
SYS_FUNC void SYS_API errSetDebugInfo(u32 debugValue, char* pszDebugString);
// Ordered array
SYS_FUNC bool_t SYS_API oaCreate(sOrderedArray* pArray, u32 maxSize, sortFunc_t pfnLessThan);
SYS_FUNC bool_t SYS_API oaCreateEx(sOrderedArray* pArray, void* pAddr, u32 maxSize, sortFunc_t pfnLessThan);
SYS_FUNC void SYS_API oaFree(sOrderedArray* pArray);
SYS_FUNC bool_t SYS_API oaInsert(sOrderedArray* pArray, void* pItem);
SYS_FUNC void SYS_API oaRemove(sOrderedArray* pArray, u32 i);
SYS_FUNC void* SYS_API oaGet(sOrderedArray* pArray, u32 i);
// Virtual file system
SYS_FUNC void SYS_API vfsInit(void);
SYS_FUNC sVfsNode* SYS_API vfsAddVirtualNode(sVfsNode* pParent, char* pszName);
SYS_FUNC sVfsNode* SYS_API vfsAddDevice(char* pszName, sFileSystem* pFsDesc, u32 mask);
SYS_FUNC sVfsNode* SYS_API vfsMount(char* pszName, sVfsNode* pDevice);
SYS_FUNC sVfsNode* SYS_API vfsAddFile(sVfsNode* pParent, char* pszName, u32 mask, u32 flags);
SYS_FUNC bool_t SYS_API vfsOpen(sVfsNode* pNode, u32 flags);
SYS_FUNC bool_t SYS_API vfsClose(sVfsNode* pNode);
SYS_FUNC u32 SYS_API vfsWrite(sVfsNode* pNode, void* pData, u32 dataLen);
SYS_FUNC u32 SYS_API vfsRead(sVfsNode* pNode, void* pData, u32 dataLen);
SYS_FUNC bool_t SYS_API vfsSeek(sVfsNode* pNode, u32 location);
SYS_FUNC u32 SYS_API vfsTell(sVfsNode* pNode);
SYS_FUNC u32 SYS_API vfsGetLength(sVfsNode* pNode);
SYS_FUNC bool_t SYS_API vfsReadDir(sVfsNode* pNode);
SYS_FUNC sVfsNode* SYS_API vfsFindDir(sVfsNode* pNode, char* pszFileName);
SYS_FUNC sVfsNode* SYS_API vfsCreateFile(sVfsNode* pNode, char* pszFileName, u32 mask, u32 flags);
SYS_FUNC void SYS_API vfsDelete(sVfsNode* pNode);
SYS_FUNC sVfsNode* SYS_API vfsFindPathNode(char* pszName);
// Object system
SYS_FUNC void SYS_API obInit(void);
SYS_FUNC bool_t SYS_API obIsTypeValid(u32 typeValue);
SYS_FUNC bool_t SYS_API obMakeType(HANDLE_TYPE_DESC* pDesc);
SYS_FUNC sHandle* SYS_API obAlloc(u32 typeValue);
SYS_FUNC bool_t SYS_API obIsValid(sHandle* pHandle);
SYS_FUNC bool_t SYS_API obIsType(sHandle* pHandle, u32 typeValue);
SYS_FUNC void SYS_API obCapture(sHandle* pHandle);
SYS_FUNC bool_t SYS_API obRelease(sHandle* pHandle);
SYS_FUNC void SYS_API obSetUserData(sHandle* pHandle, u32 userData);
SYS_FUNC u32 SYS_API obGetUserData(sHandle* pHandle, u32 userData);
// The ramdisk file system
SYS_FUNC void SYS_API ramfsInit(void);
// The initial ramdisk
SYS_FUNC bool_t SYS_API irdInit(u32 addr);
// File system API
/*
SYS_FUNC bool_t SYS_API fsInit(void);
SYS_FUNC sHandle* SYS_API fsOpen(char* pszFileName, u32 flags);
SYS_FUNC void SYS_API fsClose(sHandle* pHandle);
SYS_FUNC u32 SYS_API fsWrite(sHandle* pHandle, void* pData, u32 dataLen);
SYS_FUNC u32 SYS_API fsRead(sHandle* pHandle, void* pData, u32 dataLen);
SYS_FUNC bool_t SYS_API fsSeek(sHandle* pHandle, u32 location, u32 rel);
SYS_FUNC u32 SYS_API fsTell(sHandle* pHandle);
SYS_FUNC bool_t SYS_API fsEndOfFile(sHandle* pHandle);
SYS_FUNC void SYS_API fsDeleteFile(char* pszFileName);
SYS_FUNC bool_t SYS_API fsCopyFile(char* pszSrc, char* pszDest, bool_t overwrite);
SYS_FUNC bool_t SYS_API fsMoveFile(char* pszSrc, char* pszDest, bool_t overwrite);
*/
// Multitasking
ASM_FUNC u32 ASM_API kGetEip(void);
SYS_FUNC void SYS_API tsMoveStack(void);
SYS_FUNC bool_t SYS_API tsInit(void);
SYS_FUNC u32 SYS_API tsFork(void);
SYS_FUNC void SYS_API tsSwitchTask(void);
// External ISRs
ASM_FUNC void ASM_API isr0(void);
ASM_FUNC void ASM_API isr1(void);
ASM_FUNC void ASM_API isr2(void);
ASM_FUNC void ASM_API isr3(void);
ASM_FUNC void ASM_API isr4(void);
ASM_FUNC void ASM_API isr5(void);
ASM_FUNC void ASM_API isr6(void);
ASM_FUNC void ASM_API isr7(void);
ASM_FUNC void ASM_API isr8(void);
ASM_FUNC void ASM_API isr9(void);
ASM_FUNC void ASM_API isr10(void);
ASM_FUNC void ASM_API isr11(void);
ASM_FUNC void ASM_API isr12(void);
ASM_FUNC void ASM_API isr13(void);
ASM_FUNC void ASM_API isr14(void);
ASM_FUNC void ASM_API isr15(void);
ASM_FUNC void ASM_API isr16(void);
ASM_FUNC void ASM_API isr17(void);
ASM_FUNC void ASM_API isr18(void);
ASM_FUNC void ASM_API isr19(void);
ASM_FUNC void ASM_API isr20(void);
ASM_FUNC void ASM_API isr21(void);
ASM_FUNC void ASM_API isr22(void);
ASM_FUNC void ASM_API isr23(void);
ASM_FUNC void ASM_API isr24(void);
ASM_FUNC void ASM_API isr25(void);
ASM_FUNC void ASM_API isr26(void);
ASM_FUNC void ASM_API isr27(void);
ASM_FUNC void ASM_API isr28(void);
ASM_FUNC void ASM_API isr29(void);
ASM_FUNC void ASM_API isr30(void);
ASM_FUNC void ASM_API isr31(void);
// External IRQs
ASM_FUNC void ASM_API irq0(void);
ASM_FUNC void ASM_API irq1(void);
ASM_FUNC void ASM_API irq2(void);
ASM_FUNC void ASM_API irq3(void);
ASM_FUNC void ASM_API irq4(void);
ASM_FUNC void ASM_API irq5(void);
ASM_FUNC void ASM_API irq6(void);
ASM_FUNC void ASM_API irq7(void);
ASM_FUNC void ASM_API irq8(void);
ASM_FUNC void ASM_API irq9(void);
ASM_FUNC void ASM_API irq10(void);
ASM_FUNC void ASM_API irq11(void);
ASM_FUNC void ASM_API irq12(void);
ASM_FUNC void ASM_API irq13(void);
ASM_FUNC void ASM_API irq14(void);
ASM_FUNC void ASM_API irq15(void);
/* Inlined Functions */
// Read a byte from a port
INLINE u8 INT_API kInB(u16 port)
{
u8 ret = 0;
asm volatile("in al, dx" : "=a" (ret) : "d" (port));
return ret;
}
// Write a byte to a port
INLINE void INT_API kOutB(u16 port, u8 value)
{
asm volatile("out dx, al" :: "d" (port), "a" (value));
}
// Read a word from a port
INLINE u16 INT_API kInW(u16 port)
{
u16 ret = 0;
asm volatile("in ax, dx" : "=a" (ret) : "d" (port));
return ret;
}
// Write a word to a port
INLINE void INT_API kOutW(u16 port, u16 value)
{
asm volatile("out dx, ax" :: "d" (port), "a" (value));
}
/*
TODO: Convert kMemSet to an assembly function
TODO: Convert kMemCpy to an assembly function
TODO: Convert kStrLen to an assembly function
TODO: Add a kMemCmp function
TODO: Add a kToUpper macro
TODO: Add a kToLower macro
TODO: Add a kIsDigit macro
TODO: Add a kIsAlpha macro
TODO: Add a kIsAlphaNum macro
TODO: Add a kStrCaseCmp function (Ignores case)
*/
// Set a block of memory to a specific byte
INLINE void INT_API kMemSet(u8* pDest, u8 value, u32 size)
{
u32 i;
for(i = 0; i < size; i++)
pDest[i] = value;
}
// Copy one block of memory to another
INLINE void INT_API kMemCpy(u8* pDest, u8* pSrc, u32 size)
{
u32 i;
for(i = 0; i < size; i++)
pDest[i] = pSrc[i];
}
// Find the length of a string
INLINE u32 INT_API kStrLen(char* pszString)
{
if (!pszString)
return 0;
char* pszDelta = pszString;
while(*pszString)
pszString++;
return (u32)(pszString-pszDelta);
}
// Copy a string into another string
INLINE char* INT_API kStrCpy(char* pszDest, char* pszSrc)
{
u32 i = 0;
if (!pszSrc[0])
{
pszDest[0] = 0;
return pszDest;
}
while(pszSrc[i])
{
pszDest[i] = pszSrc[i];
i++;
}
pszDest[i] = 0;
return pszDest;
}
// Copy a string into another string -- extended version
INLINE char* INT_API kStrCpyEx(char* pszDest, char* pszSrc, u32 maxLen)
{
u32 i = 0;
if (!pszSrc[0])
{
pszDest[0] = 0;
return pszDest;
}
while(pszSrc[i] && i < maxLen)
{
pszDest[i] = pszSrc[i];
i++;
}
pszDest[i] = 0;
return pszDest;
}
// Add to a string
INLINE char* INT_API kStrCat(char* pszDest, char* pszSrc)
{
u32 i = 0, l = kStrLen(pszDest);
if (!kStrCpy(&pszDest[l], pszSrc))
return (char*)0;
return pszDest;
}
// Add a certain amount of characters to the string
INLINE char* INT_API kStrCatEx(char* pszDest, char* pszSrc, u32 maxLen)
{
u32 i = 0, l = kStrLen(pszDest);
if (!kStrCpyEx(&pszDest[l], pszSrc, maxLen-l))
return (char*)0;
return pszDest;
}
// Compare one string to another string
INLINE s32 INT_API kStrCmp(char* pszTestA, char* pszTestB)
{
u32 i = 0;
s32 delta = 0;
// Test for stupid occurrances
if (pszTestA == pszTestB)
return 0;
// Test if either pszTestA or pszTestB is null
if (!pszTestA || !pszTestB)
return 1;
// Compare the strings
while(pszTestA[i] && pszTestB[i])
{
delta = delta + (pszTestA[i]-pszTestB[i]);
i++;
}
// Check if either of these strings are different
delta = delta + (pszTestA[i]-pszTestB[i]);
// Return the delta
return delta;
}
// Find the address of a single character in a string
INLINE char* INT_API kStrChr(char* pszTest, char c)
{
while(*pszTest)
{
if (*pszTest == c)
return pszTest;
pszTest++;
}
return (char*)0;
}
// Find the address of a single character from a string in a string
INLINE char* INT_API kStrBrk(char* pszTest, char* pszDelims)
{
u32 i;
while(*pszTest)
{
for(i = 0; pszDelims[i]; i++)
{
if (*pszTest == pszDelims[i])
return pszTest;
}
pszTest++;
}
return (char*)0;
}
// Signed integer to string
INLINE char* INT_API kSiToStr(s32 value, char* pszString, u32 radix, bool_t upper, char** ppRsvd)
{
// Preliminary
static char* pszUpperDigits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
static char* pszLowerDigits = "0123456789abcdefghijklmnopqrstuvwxyz";
char* pszTmp = pszString;
char* pszDigits = (upper > 0) ? pszUpperDigits : pszLowerDigits;
// Check for a negative
if (value < 0)
{
// Write the negative character
*pszString = '-';
pszString++;
// Convert the value to positive
value = (-value);
}
// Do a recursive loop until we're at a single digit
if (value >= radix)
{
// Iterate
kSiToStr(value/radix, pszString, radix, upper, &pszString);
value = value % radix;
}
// Set the value
*pszString = pszDigits[value];
pszString++;
*pszString = 0;
// Check the reserved value
if (ppRsvd)
*ppRsvd = pszString;
// Return the string
return pszTmp;
}
// Unsigned integer to string
INLINE char* INT_API kUiToStr(u32 value, char* pszString, u32 radix, bool_t upper, char** ppRsvd)
{
// Preliminary
static char* pszUpperDigits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
static char* pszLowerDigits = "0123456789abcdefghijklmnopqrstuvwxyz";
char* pszTmp = pszString;
char* pszDigits = (upper > 0) ? pszUpperDigits : pszLowerDigits;
// Do a recursive loop until we're at a single digit
if (value >= radix)
{
// Iterate
kSiToStr(value/radix, pszString, radix, upper, &pszString);
value = value % radix;
}
// Set the value
*pszString = pszDigits[value];
pszString++;
*pszString = 0;
// Check the reserved value
if (ppRsvd)
*ppRsvd = pszString;
// Return the string
return pszTmp;
}
// Initialize a linked list
INLINE void INT_API lsInit(sList* pList)
{
pList->pFirst = pList->pLast = (sListItem*)0;
}
// Initialize a list item
INLINE void INT_API lsInitItem(sListItem* pItem, void* pObj, deleteListItem_t pfnDelFunc)
{
pItem->pObj = pObj;
pItem->pfnDelete = pfnDelFunc;
pItem->pPrev = (sListItem*)0;
pItem->pNext = (sListItem*)0;
}
// Add an item to a list
INLINE void INT_API lsAddItem(sList* pList, sListItem* pItem)
{
if (pList->pLast)
pList->pLast->pNext = pItem;
pItem->pPrev = pList->pLast;
pList->pLast = pItem;
if (!pList->pFirst)
pList->pFirst = pItem;
}
// Insert an item before another item
INLINE void INT_API lsInsertBefore(sList* pList, sListItem* pNew, sListItem* pOld)
{
if (pOld->pPrev)
pOld->pPrev->pNext = pNew;
pNew->pPrev = pOld->pPrev;
pNew->pNext = pOld;
pOld->pPrev = pNew;
if (pOld == pList->pFirst)
pList->pFirst = pNew;
}
// Insert an item after another item
INLINE void INT_API lsInsertAfter(sList* pList, sListItem* pNew, sListItem* pOld)
{
if (pOld->pNext)
pOld->pNext->pPrev = pNew;
pNew->pNext = pOld->pNext;
pNew->pPrev = pOld;
pOld->pNext = pNew;
if (pOld == pList->pLast)
pList->pLast = pNew;
}
// Remove an item from the list
INLINE void INT_API lsRemove(sList* pList, sListItem* pItem)
{
if (pItem->pPrev)
pItem->pPrev->pNext = pItem->pNext;
if (pItem->pNext)
pItem->pNext->pPrev = pItem->pPrev;
if (pItem == pList->pFirst)
pList->pFirst = pItem->pNext;
if (pItem == pList->pLast)
pList->pLast = pItem->pPrev;
pItem->pPrev = pItem->pNext = (sListItem*)0;
if (pItem->pfnDelete)
pItem->pfnDelete(pItem->pObj);
}
// Remove all items
INLINE void INT_API lsRemoveAll(sList* pList)
{
while(pList->pFirst)
lsRemove(pList, pList->pFirst);
}
// Retrieve the first object in a list
INLINE void* INT_API lsFirst(sList* pList)
{
return (pList->pFirst) ? pList->pFirst->pObj : (void*)0;
}
// Retrieve the last object in a list
INLINE void* INT_API lsLast(sList* pList)
{
return (pList->pLast) ? pList->pLast->pObj : (void*)0;
}
// Retrieve the previous object in a list
INLINE void* INT_API lsBefore(sList* pList, sListItem* pItem)
{
return (pItem->pPrev) ? pItem->pPrev->pObj : (void*)0;
}
// Retrieve the next object in a list
INLINE void* INT_API lsAfter(sList* pList, sListItem* pItem)
{
return (pItem->pNext) ? pItem->pNext->pObj : (void*)0;
}
#endif
Code: Select all
#ifndef DRAGON_H
#define DRAGON_H
/* Defines */
// Compilers
#define C_GCC 100
#define C_MSVC 200
// Architectures
#define A_I386 100
#define A_IA64 110
#define A_PPC 200
#define A_ARM 300
// C language version
#define CV_C 100 // C : .c
#define CV_CPP 200 // C++ : .cpp
#define CV_CS 300 // C# (C-Sharp) : .cs
// Is C in use, or is C++ in use?
#if defined(__cplusplus) || defined(cplusplus)
# define USING_CPP
# define CVER CV_CPP
#else
# define USING_C
# define CVER CV_C
#endif
// Determine which compiler is in use
#if defined(__GNUC__) || defined(__MINGW32_VERSION)
# define USING_GCC
# define COMPILER C_GCC
#elif defined(_MSC_VER)
# define USING_MSVC
# define COMPILER C_MSVC
#endif
// Determine which architecture is in use
#if defined(__i386__) || defined(_M_IX86)
# define USING_I386
# define ARCH A_I386
# define BITS 32
#elif defined(__amd64__) || defined(__ia64__) || defined(_M_IA64)
# define USING_IA64
# define ARCH A_IA64
# define BITS 64
#elif defined(__powerpc__) || defined(_M_PPC) || defined(__PPC__)
# define USING_PPC
# define ARCH A_PPC
# define BITS 32
#elif defined(__arm__) || defined(_M_ARM) || defined(__ARM__)
# define USING_ARM
# define ARCH A_ARM
# define BITS 32
#endif
// Booleans
#define B_TRUE 1
#define B_FALSE 0
// Results
#define R_SUCCESS 1 // Generic success
#define R_FAILURE 0 // Generic failure
#define R_NO_MEMORY (-1) // Not enough memory to complete call
#define R_INVALID_CALL (-2) // One of the arguments to the function was invalid
#define R_INTERNAL_ERROR (-3) // Internal error occured
#define R_NOT_INITIALIZED (-4) // One of the components that the function requires wasn't initialized properly
#define R_BAD_MEMORY (-5) // A bad memory location was passed in
#define R_INVALID_FILE (-6) // Either the file/stream requested doesn't exist or isn't of the right type
// Invalid values
#define INVALID_INDEX_VALUE 0xFFFFFFFF
// Inline
#if CVER == CV_CPP || CVER == CV_CS
# if COMPILER == C_MSVC
# define INLINE __forceinline
# else
# define INLINE inline
# endif
#else
# define INLINE static
#endif
// Function modifiers
#if CVER == CV_CPP || CVER == CV_CS
# define SYS_FUNC extern "C"
#else
# define SYS_FUNC extern
#endif
#if COMPILER == C_GCC
# define SYS_API __attribute__((stdcall))
#else
# define SYS_API __stdcall
#endif
#define INT_FUNC static
#if COMPILER == C_GCC
# define INT_API __attribute__((fastcall))
#else
# define INT_API __fastcall
#endif
#define ASM_FUNC SYS_FUNC
#define ASM_API
// OS limits
#define MAX_PATH 256 // includes null character
// Handle types
#define HT_FILE 0xF0324CC8
// Error codes
#define EC_NONE 0
#define EC_NO_MEMORY 1
#define EC_INVALID_CALL 2
#define EC_INTERNAL_ERROR 3
#define EC_NOT_INITIALIZED 4
#define EC_BAD_MEMORY 5
#define EC_INVALID_FILE 6
// Task error codes
#define TS_EC_CANT_ALLOC_TASK 0x100
#define TS_EC_CANT_ALLOC_SHARED_HEAP 0x101
// Error code messages
#define ES_NONE "No error, or unknown error."
#define ES_NO_MEMORY "Not enough memory for call."
#define ES_INVALID_CALL "Bad parameter (invalid pointer?)"
#define ES_NOT_INITIALIZED "The component hasn't been initialized."
#define ES_BAD_MEMORY "'Bad' memory."
#define ES_INVALID_FILE "The referenced file doesn't exist or is inaccessible."
// Task error messages
#define TS_ES_CANT_ALLOC_TASK "Unable to allocate memory for the task."
#define TS_ES_CANT_ALLOC_SHARED_HEAP "Unable to allocate memory for the shared heap."
/* Macros */
// Bit Management
#define Bits8To16(a,b) ((u16)(((u8)(a))|(((u16)((u8)(b)))<<8)))
#define Bits16To32(a,b) ((u32)(((u16)(a))|(((u32)((u16)(b)))<<16)))
#define Bits8To32(a,b,c,d) (Bits16To32(Bits8To16(a,b),Bits8To16(c,d)))
#define Bits32To16L(a) ((u16)((u32)(a)))
#define Bits32To16H(a) ((u16)(((u32)(a)>>16)&0xFFFF))
#define Bits16To8L(a) ((u8)(a))
#define Bits16To8H(a) ((u8)(((u16)(a)>>8)&0xFF))
#define Bits32To8LL(a) (Bits16To8L(Bits32To16L(a)))
#define Bits32To8LH(a) (Bits16To8L(Bits32To16H(a)))
#define Bits32To8HL(a) (Bits16To8H(Bits32To16L(a)))
#define Bits32To8HH(a) (Bits16To8H(Bits32To16H(a)))
// Bit Management (Windows Equivalents)
#define LOWORD(a) (Bits32To16L(a))
#define HIWORD(a) (Bits32To16H(a))
#define LOBYTE(a) (Bits16To8L(a))
#define HIBYTE(a) (Bits16To8H(a))
// Flags & Bits
#define MakeFlag(id) (((u32)1)<<(id))
#define ClearBit(value,bit) (value &= ~(1<<bit))
#define SetBit(value,bit) (value |= (1<<bit))
#define GetBit(value,bit) (value & (1<<bit))
/* Typedefs */
// 32-bit processors
#if BITS == 32
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef signed char s8;
typedef signed short s16;
typedef signed int s32;
typedef unsigned long long int u64;
typedef signed long long int s64;
// 64-bit processors
#elif BITS == 64 // redundant here, I suppose
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef signed char s8;
typedef signed short s16;
typedef signed int s32;
typedef unsigned long long int u64; // should just be 'long'?
typedef signed long long int s64; // should just be 'long'?
#endif
// OS types
typedef s32 result_t; // One of the 'R_' values
typedef u32 bool_t; // One of the 'B_' values
typedef u32 bitfield_t; // Use the flag macros on this type (ClearBit, SetBit, GetBit)
// Character mode
#if defined(UNICODE) || defined(_UNICODE)
typedef short char_t, tchar;
#else
typedef char char_t, tchar;
#endif
// Handles
#if !defined(sObject_defined)
typedef struct sHandle_t { u32 __unused; } sHandle, *handle_t;
typedef handle_t file_t;
#endif
#endif
If you need to see more code, or use the build kit I used to compile all this, go to http://code.google.com/p/dragon-os
The current packages would be the dragon-0.05-alpha-unstable and dragonkit
Thanks for your time.
Cheers,
-naota