diff --git a/include/comrogue/internals/layout.h b/include/comrogue/internals/layout.h index 0db420b..95f7952 100644 --- a/include/comrogue/internals/layout.h +++ b/include/comrogue/internals/layout.h @@ -45,7 +45,8 @@ #define VMADDR_LIBRARY_FENCE 0xB0000000 /* base address for kernel "shared library" code */ #define VMADDR_KERNEL_FENCE 0xC0000000 /* base address for the internal kernel code */ #define VMADDR_IO_BASE 0xE0000000 /* base address for memory-mapped IO */ -#define PAGE_COUNT_IO 1024 /* 4 megabytes mapped for IO */ +#define PAGE_COUNT_IO 4096 /* 16 megabytes mapped for IO */ +#define VMADDR_KERNEL_NOMANS 0xFFFF0000 /* start of kernel "no man's land" */ #endif /* __COMROGUE_INTERNALS__ */ diff --git a/include/comrogue/internals/memmgr.h b/include/comrogue/internals/memmgr.h index 0f65bc0..41f844c 100644 --- a/include/comrogue/internals/memmgr.h +++ b/include/comrogue/internals/memmgr.h @@ -43,11 +43,18 @@ CDECL_BEGIN +/* Kernel address space functions */ +extern KERNADDR _MmAllocKernelAddr(UINT32 cpgNeeded); +extern void _MmFreeKernelAddr(KERNADDR kaBase, UINT32 cpgToFree); + /* Page mapping functions */ extern PHYSADDR MmGetPhysAddr(PTTB pTTB, KERNADDR vma); -extern HRESULT MmDemapPages(PTTB pTTB, KERNADDR vmaBase, UINT32 cpg); -extern HRESULT MmMapPages(PTTB pTTB, PHYSADDR paBase, KERNADDR vmaBase, UINT32 cpg, UINT32 uiTableFlags, - UINT32 uiPageFlags); +extern HRESULT MmDemapPages(PTTB pTTB, PTTBAUX pTTBAux, KERNADDR vmaBase, UINT32 cpg); +extern HRESULT MmMapPages(PTTB pTTB, PTTBAUX pTTBAux, PHYSADDR paBase, KERNADDR vmaBase, UINT32 cpg, + UINT32 uiTableFlags, UINT32 uiPageFlags, UINT32 uiAuxFlags); +extern HRESULT MmMapKernelPages(PTTB pTTB, PTTBAUX pTTBAux, PHYSADDR paBase, UINT32 cpg, UINT32 uiTableFlags, + UINT32 uiPageFlags, UINT32 uiAuxFlags, PKERNADDR pvmaLocation); +extern HRESULT MmDemapKernelPages(PTTB pTTB, PTTBAUX pTTBAux, KERNADDR vmaBase, UINT32 cpg); /* Initialization functions only */ extern void _MmInit(PSTARTUP_INFO pstartup); diff --git a/include/comrogue/internals/mmu.h b/include/comrogue/internals/mmu.h index 7bf3a64..4df7fe6 100644 --- a/include/comrogue/internals/mmu.h +++ b/include/comrogue/internals/mmu.h @@ -48,6 +48,7 @@ #define SYS_TTB1_ENTRIES 4096 /* SYS_TTB1_SIZE/4, number of entries in TTB1 */ #define SYS_TTB_BITS 12 /* log2(SYS_TTB1_SIZE/4), number of bits in a TTB address */ #define SYS_SEC_SIZE 1048576 /* standard section size */ +#define SYS_SEC_BITS 20 /* number of bits in a section address */ #define SYS_SEC_PAGES 256 /* SYS_SEC_SIZE/SYS_PAGE_SIZE, number of pages equivalent to a section */ #define SYS_PGTBL_SIZE 1024 /* page tables must be located on this boundary and are this size */ #define SYS_PGTBL_BITS 8 /* log2(SYS_PGTBL_SIZE/4), number of bits in a page table address */ @@ -100,6 +101,9 @@ #define TTBQUERY_SEC 0x00000002 /* indicates a section */ #define TTBQUERY_PXNSEC 0x00000003 /* indicates a section with PXN (or reserved) */ +/* TTB auxiliary descriptor bits */ +#define TTBAUX_SACRED 0x00000001 /* sacred entry, do not deallocate */ + /* Small page table entry bits */ #define PGTBLSM_XN 0x00000001 /* Execute-Never */ #define PGTBLSM_ALWAYS 0x00000002 /* this bit must always be set for a page table entry */ @@ -125,15 +129,29 @@ #define PGQUERY_SM 0x00000002 /* small page (4K) */ #define PGQUERY_SM_XN 0x00000003 /* small page with Execute-Never set */ +/* Page auxiliary descriptor bits */ +#define PGAUX_SACRED 0x00000001 /* sacred entry, do not deallocate */ + /* Combinations of flags we use regularly. */ #define TTBFLAGS_LIB_CODE TTBPGTBL_ALWAYS #define PGTBLFLAGS_LIB_CODE (PGTBLSM_ALWAYS | PGTBLSM_B | PGTBLSM_C | PGTBLSM_AP10) +#define PGAUXFLAGS_LIB_CODE PGAUX_SACRED #define TTBFLAGS_KERNEL_CODE TTBPGTBL_ALWAYS #define PGTBLFLAGS_KERNEL_CODE (PGTBLSM_ALWAYS | PGTBLSM_B | PGTBLSM_C | PGTBLSM_AP01) +#define PGAUXFLAGS_KERNEL_CODE PGAUX_SACRED #define TTBFLAGS_KERNEL_DATA TTBPGTBL_ALWAYS #define PGTBLFLAGS_KERNEL_DATA (PGTBLSM_XN | PGTBLSM_ALWAYS | PGTBLSM_B | PGTBLSM_C | PGTBLSM_AP01) +#define PGAUXFLAGS_KERNEL_DATA PGAUX_SACRED +#define TTBFLAGS_INIT_CODE TTBFLAGS_KERNEL_CODE +#define PGTBLFLAGS_INIT_CODE PGTBLFLAGS_KERNEL_CODE +#define PGAUXFLAGS_INIT_CODE 0 +#define TTBFLAGS_INIT_DATA TTBFLAGS_KERNEL_DATA +#define PGTBLFLAGS_INIT_DATA PGTBLFLAGS_KERNEL_DATA +#define PGAUXFLAGS_INIT_DATA 0 #define TTBFLAGS_MMIO TTBPGTBL_ALWAYS #define PGTBLFLAGS_MMIO (PGTBLSM_ALWAYS | PGTBLSM_AP01) +#define PGAUXFLAGS_MMIO PGAUX_SACRED +#define TTBAUXFLAGS_PAGETABLE 0 #ifndef __ASM__ @@ -186,6 +204,18 @@ typedef union tagTTB { TTBSEC sec; /* 1Mb section data */ } TTB, *PTTB; +/* TTB auxiliary descriptor */ +typedef struct tagTTBAUXENTRY { + unsigned sacred : 1; /* sacred TTB - should never be deallocated */ + unsigned reserved : 31; /* reserved for future allocation */ +} TTBAUXENTRY, *PTTBAUXENTRY; + +/* TTB auxiliary table entry */ +typedef union tagTTBAUX { + UINT32 data; /* raw data for entry */ + TTBAUXENTRY aux; /* aux entry itself */ +} TTBAUX, *PTTBAUX; + /* page table descriptor for a fault entry */ typedef struct tagPGTBLFAULT { unsigned always0 : 2; /* bits are always 0 for a fault entry */ @@ -213,10 +243,16 @@ typedef union tagPGTBL { PGTBLSM pg; /* small page descriptor */ } PGTBL, *PPGTBL; +/* page auxiliary descriptor */ +typedef struct tagPGAUXENTRY { + unsigned sacred : 1; /* sacred page - should never be deallocated */ + unsigned reserved : 31; /* reserved for future allocation */ +} PGAUXENTRY, *PPGAUXENTRY; + /* page table auxiliary entry */ typedef union tagPGAUX { UINT32 data; /* raw data for entry */ - /* TODO */ + PGAUXENTRY aux; /* the auxiliary entry itself */ } PGAUX, *PPGAUX; /* complete structure of a page table, hardware + auxiliary */ diff --git a/include/comrogue/internals/rbtree.h b/include/comrogue/internals/rbtree.h index 13ede4e..433647f 100644 --- a/include/comrogue/internals/rbtree.h +++ b/include/comrogue/internals/rbtree.h @@ -66,14 +66,14 @@ typedef struct tagRBTREENODE { #define rbtNodeRight(ptn) ((PRBTREENODE)((ptn)->ptnRightColor & ~1)) #define rbtNodeColor(ptn) ((ptn)->ptnRightColor & 1) #define rbtIsRed(ptn) ((ptn) ? rbtNodeColor(ptn) : FALSE) -#define rbtSetNodeRight(ptn, ptnRight) \ - do { (ptn)->ptnRightColor = (((UINT_PTR)(ptnRight)) & ~1) | ((ptn)->ptnRightColor & 1); } while (0) +#define rbtSetNodeRight(ptn, ptnR) \ + do { (ptn)->ptnRightColor = (((UINT_PTR)(ptnR)) & ~1) | ((ptn)->ptnRightColor & 1); } while (0) #define rbtSetNodeColor(ptn, clr) \ do { (ptn)->ptnRightColor = ((ptn)->ptnRightColor & ~1) | ((clr) ? 1 : 0); } while (0) #define rbtToggleColor(ptn) do { if (ptn) (ptn)->ptnRightColor ^= 1; } while (0) -#define rbtInitNode(ptn, ptnLeft, ptnRight, clr, key) \ - do { (ptn)->ptnLeft = (ptnLeft); (ptn)->ptnRightColor = (((UINT_PTR)(ptnRight)) & ~1) | ((clr) ? 1 : 0); \ - (ptn)->treekey = (key); } while (0) +#define rbtInitNode(ptn, ptnL, ptnR, clr, key) \ + do { (ptn)->ptnLeft = (ptnL); (ptn)->ptnRightColor = (((UINT_PTR)(ptnR)) & ~1) | ((clr) ? 1 : 0); \ + (ptn)->treekey = (TREEKEY)(key); } while (0) #define rbtNewNode(ptn, key) rbtInitNode(ptn, NULL, NULL, RED, key) /* The head-of-tree structure. */ @@ -86,14 +86,20 @@ typedef struct tagRBTREE { #define rbtInitTree(ptree, pfnCompare) \ do { (ptree)->pfnTreeCompare = (pfnCompare); (ptree)->ptnRoot = NULL; } while (0) +/* Type of function used by RbtWalk. */ +typedef BOOL (*PFNRBTWALK)(PRBTREE, PRBTREENODE, PVOID); + /* Function prototypes. */ CDECL_BEGIN extern INT32 RbtStdCompareByValue(TREEKEY k1, TREEKEY k2); extern void RbtInsert(PRBTREE ptree, PRBTREENODE ptnNew); extern PRBTREENODE RbtFind(PRBTREE ptree, TREEKEY key); +extern PRBTREENODE RbtFindPredecessor(PRBTREE ptree, TREEKEY key); +extern PRBTREENODE RbtFindSuccessor(PRBTREE ptree, TREEKEY key); extern PRBTREENODE RbtFindMin(PRBTREE ptree); extern void RbtDelete(PRBTREE ptree, TREEKEY key); +extern BOOL RbtWalk(PRBTREE ptree, PFNRBTWALK pfnWalk, PVOID pData); CDECL_END diff --git a/include/comrogue/internals/startup.h b/include/comrogue/internals/startup.h index 771e71f..0c27f54 100644 --- a/include/comrogue/internals/startup.h +++ b/include/comrogue/internals/startup.h @@ -177,6 +177,8 @@ typedef struct tagSTARTUP_INFO { UINT32 cpgSystemTotal; /* total number of memory pages in the system */ UINT32 cpgSystemAvail; /* available memory pages in the system after GPU takes its bite */ UINT32 cpgTTBGap; /* number of pages in the "gap" between the end of kernel and TTB */ + PHYSADDR paTTBAux; /* physical address of the auxiliary TTB data */ + KERNADDR kaTTBAux; /* kernel address of the auxiliary TTB data */ PHYSADDR paMPDB; /* physical address of the Master Page Database */ KERNADDR kaMPDB; /* kernel address of the Master Page Database */ UINT32 cpgMPDB; /* number of pages we allocated for Master Page Database */ diff --git a/include/comrogue/scode.h b/include/comrogue/scode.h index 5b6f579..5d7e7a3 100644 --- a/include/comrogue/scode.h +++ b/include/comrogue/scode.h @@ -102,5 +102,7 @@ #define MEMMGR_E_BADTTBFLG SCODE_CAST(0x86010002) /* bad TTB flags encountered */ #define MEMMGR_E_COLLIDED SCODE_CAST(0x86010003) /* memory mapping collided */ #define MEMMGR_E_ENDTTB SCODE_CAST(0x86010004) /* tried to "walk off" end of TTB */ +#define MEMMGR_E_NOSACRED SCODE_CAST(0x86010005) /* tried to demap a "sacred" entry */ +#define MEMMGR_E_NOKERNSPC SCODE_CAST(0x86010006) /* no kernel space */ #endif /* __SCODE_H_INCLUDED */ diff --git a/include/comrogue/types.h b/include/comrogue/types.h index 029ce48..30061a0 100644 --- a/include/comrogue/types.h +++ b/include/comrogue/types.h @@ -88,8 +88,10 @@ typedef unsigned long long uint64_t; #ifdef __COMROGUE_INTERNALS__ /* Internal system types */ -typedef UINT32 PHYSADDR; /* physical address */ -typedef UINT32 KERNADDR; /* kernel address */ +typedef UINT32 PHYSADDR; /* physical address */ +typedef UINT32 KERNADDR; /* kernel address */ +typedef PHYSADDR *PPHYSADDR; +typedef KERNADDR *PKERNADDR; #endif /* __COMROGUE_INTERNALS__ */ diff --git a/kernel/Makefile b/kernel/Makefile index e23bdd1..6d2aa92 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -49,7 +49,7 @@ ASM_CPP_FLAGS = $(INCLUDES) $(DEFS) -D__ASM__ PRESTART_OBJS = prestart.o early_trace.o collect_startup.o early_mm.o LIB_OBJS = divide.o qdivrem.o intlib.o objhelp.o rbtree.o str.o strcopymem.o strcomparemem.o strsetmem.o lib_guids.o -RES_OBJS = lowlevel.o trace.o memmgr.o vmmap.o pagealloc.o +RES_OBJS = lowlevel.o trace.o memmgr.o vmmap.o pagealloc.o kernel_space.o INIT_OBJS = start.o kistart.o init_heap.o all: kernel.img diff --git a/kernel/collect_startup.c b/kernel/collect_startup.c index b5a0749..1ade904 100644 --- a/kernel/collect_startup.c +++ b/kernel/collect_startup.c @@ -41,6 +41,8 @@ SEG_INIT_DATA static STARTUP_INFO startup_info = { .paTTB = 0, .kaTTB = 0, .cpgTTBGap = 0, + .paTTBAux = 0, + .kaTTBAux = 0, .paMPDB = 0, .kaMPDB = 0, .cpgMPDB = 0, diff --git a/kernel/early_mm.c b/kernel/early_mm.c index cc9fced..fc4fae7 100644 --- a/kernel/early_mm.c +++ b/kernel/early_mm.c @@ -49,6 +49,7 @@ DECLARE_THIS_FILE /* Data stored in here temporarily and reflected back to startup info when we're done. */ SEG_INIT_DATA static PTTB g_pTTB = NULL; /* pointer to TTB */ +SEG_INIT_DATA static PTTBAUX g_pTTBAux = NULL; /* pointer to TTB auxiliary data */ SEG_INIT_DATA static UINT32 g_cpgForPageTables = 0; /* number of pages being used for page tables */ SEG_INIT_DATA static UINT32 g_ctblFreeonLastPage = 0; /* number of page tables free on last page */ SEG_INIT_DATA static PPAGETAB g_ptblNext = NULL; /* pointer to next free page table */ @@ -83,17 +84,72 @@ SEG_INIT_CODE static UINT32 make_section_flags(UINT32 uiTableFlags, UINT32 uiPag return rc; } +/* + * Morphs the "auxiliary flags" bits used for a page table entry into "auxiliary flags" used for a TTB entry. + * + * Parameters: + * - uiPageAuxFlags = Page auxiliary flag bits that would be used for a page table entry. + * + * Returns: + * TTB auxiliary flag bits that would be used for a TTB entry. + */ +SEG_INIT_CODE static UINT32 make_section_aux_flags(UINT32 uiPageAuxFlags) +{ + register UINT32 rc = uiPageAuxFlags & (PGAUX_SACRED); + /* TODO if we define any other flags */ + return rc; +} + +/* + * Allocates a new page table, initializes it, and initializes the pointed-to TTB entry with a + * pointer to it. + * + * Parameters: + * - pTTBEntry = Pointer to the TTB entry to be filled; this entry is modified. + * - pAuxEntry = Pointer to the TTB aux entry to be filled; this entry is modified. + * - uiTableFlags = Flags to be used for the TTB entry. + * + * Returns: + * A pointer to the new page table. + * + * Side effects: + * Modifies the global variables g_cpgForPageTables, g_ctblFreeonLastPage, and g_ptblNext. + */ +SEG_INIT_CODE static PPAGETAB alloc_page_table(PTTB pTTBEntry, PTTBAUX pAuxEntry, UINT32 uiTableFlags) +{ + register PPAGETAB pTab; /* pointer to new page table */ + register UINT32 i; /* loop counter */ + + if (g_ctblFreeonLastPage == 0) + { + g_cpgForPageTables++; + g_ctblFreeonLastPage = 2; + } + g_ctblFreeonLastPage--; + pTab = g_ptblNext++; + for (i=0; ipgtbl[i].data = 0; /* blank out the new page table */ + pTab->pgaux[i].data = 0; + } + pTTBEntry->data = ((UINT32)pTab) | uiTableFlags; /* poke new entry */ + pAuxEntry->data = TTBAUXFLAGS_PAGETABLE; + return pTab; +} + /* * Allocates page mapping entries within a single current entry in the TTB. * * Parameters: * - paBase = The page-aligned base physical address to map. * - pTTBEntry = Pointer to the TTB entry to be used. + * - pAuxEntry = Pointer to the TTB auxiliary entry to be used. * - ndxPage = The "first" index within the current page to use. * - cpg = The maximum number of pages we want to map. This function will only map as many pages as will * fit in the current TTB entry, as indicated by ndxPage. * - uiTableFlags = Flags to be used or verified for the TTB entry. * - uiPageFlags = Flags to be used for new page table entries. + * - uiAuxFlags = Flags to be used for new page table auxiliary entries. * * Returns: * The number of pages that were actually mapped by this function call, or -1 if there was an error in the mapping. @@ -103,8 +159,8 @@ SEG_INIT_CODE static UINT32 make_section_flags(UINT32 uiTableFlags, UINT32 uiPag * table that the TTB entry points to, where applicable. If we need to allocate a new page table, may modify the * global variables g_cpgForPageTables, g_ctblFreeonLastPage, and g_ptblNext. */ -SEG_INIT_CODE static INT32 alloc_pages(PHYSADDR paBase, PTTB pTTBEntry, INT32 ndxPage, INT32 cpg, UINT32 uiTableFlags, - UINT32 uiPageFlags) +SEG_INIT_CODE static INT32 alloc_pages(PHYSADDR paBase, PTTB pTTBEntry, PTTBAUX pAuxEntry, INT32 ndxPage, + INT32 cpg, UINT32 uiTableFlags, UINT32 uiPageFlags, UINT32 uiAuxFlags) { INT32 cpgCurrent; /* number of pages we're mapping */ PPAGETAB pTab; /* pointer to current or new page table */ @@ -113,29 +169,24 @@ SEG_INIT_CODE static INT32 alloc_pages(PHYSADDR paBase, PTTB pTTBEntry, INT32 nd switch (pTTBEntry->data & TTBQUERY_MASK) { case TTBQUERY_FAULT: /* not allocated, allocate a new page table for the slot */ - if (g_ctblFreeonLastPage == 0) - { - g_cpgForPageTables++; - g_ctblFreeonLastPage = 2; - } - g_ctblFreeonLastPage--; - pTab = g_ptblNext++; - for (i=0; ipgtbl[i].data = 0; /* blank out the new page table */ - pTab->pgaux[i].data = 0; - } - pTTBEntry->data = ((UINT32)pTab) | uiTableFlags; /* poke new entry */ + pTab = alloc_page_table(pTTBEntry, pAuxEntry, uiTableFlags); break; case TTBQUERY_PGTBL: /* existing page table */ if ((pTTBEntry->data & TTBPGTBL_ALLFLAGS) != uiTableFlags) return -1; /* table flags not compatible */ + pTab = (PPAGETAB)(pTTBEntry->data & TTBPGTBL_BASE); break; case TTBQUERY_SEC: - case TTBQUERY_PXNSEC: - /* existing section, deal with this later */ + case TTBQUERY_PXNSEC: /* existing section */ + if ((pTTBEntry->data & TTBSEC_ALLFLAGS) != make_section_flags(uiTableFlags, uiPageFlags)) + return -1; + if (pAuxEntry->data != make_section_aux_flags(uiAuxFlags)) + return -1; + if ((pTTBEntry->data & TTBSEC_BASE) != (paBase & TTBSEC_BASE)) + return -1; + pTab = NULL; break; } @@ -144,24 +195,14 @@ SEG_INIT_CODE static INT32 alloc_pages(PHYSADDR paBase, PTTB pTTBEntry, INT32 nd if (cpg < cpgCurrent) cpgCurrent = cpg; /* only map up to max requested */ - if (pTTBEntry->data & TTBSEC_ALWAYS) - { - /* this is a section, make sure its base address covers this mapping and its flags are compatible */ - if ((pTTBEntry->data & TTBSEC_ALLFLAGS) != make_section_flags(uiTableFlags, uiPageFlags)) - return -1; - if ((pTTBEntry->data & TTBSEC_BASE) != (paBase & TTBSEC_BASE)) - return -1; - } - else - { - /* fill in entries in the page table */ - pTab = (PPAGETAB)(pTTBEntry->data & TTBPGTBL_BASE); + if (pTab) + { /* fill in entries in the page table */ for (i=0; ipgtbl[ndxPage + i].data & PGQUERY_MASK) != PGQUERY_FAULT) return -1; /* stepping on existing mapping */ pTab->pgtbl[ndxPage + i].data = paBase | uiPageFlags; - pTab->pgaux[ndxPage + i].data = 0; /* TODO */ + pTab->pgaux[ndxPage + i].data = uiAuxFlags; paBase += SYS_PAGE_SIZE; } } @@ -178,6 +219,7 @@ SEG_INIT_CODE static INT32 alloc_pages(PHYSADDR paBase, PTTB pTTBEntry, INT32 nd * - cpg = The number of pages to be mapped. * - uiTableFlags = Flags to be used or verified for TTB entries. * - uiPageFlags = Flags to be used for new page table entries. + * - uiAuxFlags = Flags to be used for new auxiliary TTB entries. * * Returns: * TRUE if the mapping succeeded, FALSE if it failed. @@ -188,13 +230,14 @@ SEG_INIT_CODE static INT32 alloc_pages(PHYSADDR paBase, PTTB pTTBEntry, INT32 nd * g_ctblFreeonLastPage, and g_ptblNext. */ SEG_INIT_CODE static BOOL map_pages(PHYSADDR paBase, KERNADDR vmaBase, INT32 cpg, UINT32 uiTableFlags, - UINT32 uiPageFlags) + UINT32 uiPageFlags, UINT32 uiAuxFlags) { static DECLARE_INIT_STRING8_CONST(sz1, "Map "); static DECLARE_INIT_STRING8_CONST(sz2, "->"); static DECLARE_INIT_STRING8_CONST(sz3, ",cpg="); static DECLARE_INIT_STRING8_CONST(sz4, ",tf="); static DECLARE_INIT_STRING8_CONST(sz5, ",pf="); + static DECLARE_INIT_STRING8_CONST(sz6, ",af="); INT32 ndxTTB = mmVMA2TTBIndex(vmaBase); /* TTB entry index */ INT32 ndxPage = mmVMA2PGTBLIndex(vmaBase); /* starting page entry index */ INT32 cpgCurrent; /* current number of pages mapped */ @@ -209,12 +252,15 @@ SEG_INIT_CODE static BOOL map_pages(PHYSADDR paBase, KERNADDR vmaBase, INT32 cpg ETrWriteWord(uiTableFlags); ETrWriteString8(sz5); ETrWriteWord(uiPageFlags); + ETrWriteString8(sz6); + ETrWriteWord(uiAuxFlags); ETrWriteChar8('\n'); if ((cpg > 0) && (ndxPage > 0)) { /* We are starting in the middle of a VM page. Map to the end of the VM page. */ - cpgCurrent = alloc_pages(paBase, g_pTTB + ndxTTB, ndxPage, cpg, uiTableFlags, uiPageFlags); + cpgCurrent = alloc_pages(paBase, g_pTTB + ndxTTB, g_pTTBAux + ndxTTB, ndxPage, cpg, uiTableFlags, + uiPageFlags, uiAuxFlags); if (cpgCurrent < 0) { /* ETrWriteChar8('a'); */ @@ -236,6 +282,7 @@ SEG_INIT_CODE static BOOL map_pages(PHYSADDR paBase, KERNADDR vmaBase, INT32 cpg { case TTBQUERY_FAULT: /* unmapped - map the section */ g_pTTB[ndxTTB].data = paBase | make_section_flags(uiTableFlags, uiPageFlags); + g_pTTBAux[ndxTTB].data = make_section_aux_flags(uiAuxFlags); break; case TTBQUERY_PGTBL: /* collided with a page table */ @@ -249,6 +296,11 @@ SEG_INIT_CODE static BOOL map_pages(PHYSADDR paBase, KERNADDR vmaBase, INT32 cpg /* ETrWriteChar8('c'); */ return FALSE; /* invalid flags */ } + if (g_pTTBAux[ndxTTB].data != make_section_aux_flags(uiAuxFlags)) + { + /* ETrWriteChar8('!'); */ + return FALSE; /* invalid aux flags */ + } if ((g_pTTB[ndxTTB].data & TTBSEC_BASE) != paBase) { /* ETrWriteChar8('d'); */ @@ -261,7 +313,8 @@ SEG_INIT_CODE static BOOL map_pages(PHYSADDR paBase, KERNADDR vmaBase, INT32 cpg else { /* just map 256 individual pages */ - cpgCurrent = alloc_pages(paBase, g_pTTB + ndxTTB, 0, cpg, uiTableFlags, uiPageFlags); + cpgCurrent = alloc_pages(paBase, g_pTTB + ndxTTB, g_pTTBAux + ndxTTB, 0, cpg, uiTableFlags, + uiPageFlags, uiAuxFlags); if (cpgCurrent < 0) { /* ETrWriteChar8('e'); */ @@ -277,7 +330,7 @@ SEG_INIT_CODE static BOOL map_pages(PHYSADDR paBase, KERNADDR vmaBase, INT32 cpg if (cpg > 0) { /* map the "tail end" onto the next TTB */ - if (alloc_pages(paBase, g_pTTB + ndxTTB, 0, cpg, uiTableFlags, uiPageFlags) < 0) + if (alloc_pages(paBase, g_pTTB + ndxTTB, g_pTTBAux + ndxTTB, 0, cpg, uiTableFlags, uiPageFlags, uiAuxFlags) < 0) { /* ETrWriteChar8('f'); */ return FALSE; @@ -308,8 +361,10 @@ extern char paFirstFree, cpgPrestartTotal, paLibraryCode, vmaLibraryCode, cpgLib SEG_INIT_CODE PHYSADDR EMmInit(PSTARTUP_INFO pstartup) { static DECLARE_INIT_STRING8_CONST(szTTBAt, "EMmInit: TTB1@"); +#if 0 static DECLARE_INIT_STRING8_CONST(szPageTable, "Page table pages:"); static DECLARE_INIT_STRING8_CONST(szFree, "\nFree last page:"); +#endif PHYSADDR paTTB = (PHYSADDR)(&paFirstFree); /* location of the system TTB1 */ UINT32 cbMPDB; /* number of bytes in the MPDB */ register INT32 i; /* loop counter */ @@ -332,8 +387,14 @@ SEG_INIT_CODE PHYSADDR EMmInit(PSTARTUP_INFO pstartup) for (i=0; ipaTTBAux = paTTB + SYS_TTB1_SIZE; + g_pTTBAux = (PTTBAUX)(pstartup->paTTBAux); + for (i=0; ipaMPDB = paTTB + SYS_TTB1_SIZE; + pstartup->paMPDB = pstartup->paTTBAux + SYS_TTB1_SIZE; cbMPDB = pstartup->cpgSystemTotal << 3; /* 8 bytes per entry */ pstartup->cpgMPDB = cbMPDB >> SYS_PAGE_BITS; if (cbMPDB & (SYS_PAGE_SIZE - 1)) @@ -347,38 +408,53 @@ SEG_INIT_CODE PHYSADDR EMmInit(PSTARTUP_INFO pstartup) g_ptblNext = (PPAGETAB)(pstartup->paFirstPageTable); /* Map the "prestart" area (everything below load address, plus prestart code & data) as identity. */ - VERIFY(map_pages(0, 0, (INT32)(&cpgPrestartTotal), TTBPGTBL_ALWAYS, PGTBLSM_ALWAYS | PGTBLSM_AP01)); + VERIFY(map_pages(0, 0, (INT32)(&cpgPrestartTotal), TTBPGTBL_ALWAYS, PGTBLSM_ALWAYS | PGTBLSM_AP01, 0)); /* Map the IO area as identity. */ - VERIFY(map_pages(PHYSADDR_IO_BASE, PHYSADDR_IO_BASE, PAGE_COUNT_IO, TTBFLAGS_MMIO, PGTBLFLAGS_MMIO)); + VERIFY(map_pages(PHYSADDR_IO_BASE, PHYSADDR_IO_BASE, PAGE_COUNT_IO, TTBFLAGS_MMIO, PGTBLFLAGS_MMIO, 0)); /* Map the library area. */ VERIFY(map_pages((PHYSADDR)(&paLibraryCode), (KERNADDR)(&vmaLibraryCode), (INT32)(&cpgLibraryCode), - TTBFLAGS_LIB_CODE, PGTBLFLAGS_LIB_CODE)); + TTBFLAGS_LIB_CODE, PGTBLFLAGS_LIB_CODE, PGAUXFLAGS_LIB_CODE)); /* Map the kernel code area. */ VERIFY(map_pages((PHYSADDR)(&paKernelCode), (KERNADDR)(&vmaKernelCode), (INT32)(&cpgKernelCode), - TTBFLAGS_KERNEL_CODE, PGTBLFLAGS_KERNEL_CODE)); + TTBFLAGS_KERNEL_CODE, PGTBLFLAGS_KERNEL_CODE, PGAUXFLAGS_KERNEL_CODE)); /* Map the kernel data/BSS area. */ VERIFY(map_pages((PHYSADDR)(&paKernelData), (KERNADDR)(&vmaKernelData), - (INT32)(&cpgKernelData) + (INT32)(&cpgKernelBss), TTBFLAGS_KERNEL_DATA, PGTBLFLAGS_KERNEL_DATA)); + (INT32)(&cpgKernelData) + (INT32)(&cpgKernelBss), TTBFLAGS_KERNEL_DATA, PGTBLFLAGS_KERNEL_DATA, + PGAUXFLAGS_KERNEL_DATA)); /* Map the kernel init code area. */ VERIFY(map_pages((PHYSADDR)(&paInitCode), (KERNADDR)(&vmaInitCode), (INT32)(&cpgInitCode), - TTBFLAGS_KERNEL_CODE, PGTBLFLAGS_KERNEL_CODE)); + TTBFLAGS_INIT_CODE, PGTBLFLAGS_INIT_CODE, PGAUXFLAGS_INIT_CODE)); /* Map the kernel init data/BSS area. */ VERIFY(map_pages((PHYSADDR)(&paInitData), (KERNADDR)(&vmaInitData), - (INT32)(&cpgInitData) + (INT32)(&cpgInitBss), TTBFLAGS_KERNEL_DATA, PGTBLFLAGS_KERNEL_DATA)); + (INT32)(&cpgInitData) + (INT32)(&cpgInitBss), TTBFLAGS_INIT_DATA, PGTBLFLAGS_INIT_DATA, + PGAUXFLAGS_INIT_DATA)); /* Map the TTB itself. */ pstartup->kaTTB = (KERNADDR)(&vmaFirstFree); VERIFY(map_pages(paTTB, pstartup->kaTTB, SYS_TTB1_SIZE / SYS_PAGE_SIZE, TTBFLAGS_KERNEL_DATA, - PGTBLFLAGS_KERNEL_DATA)); + PGTBLFLAGS_KERNEL_DATA, PGAUXFLAGS_KERNEL_DATA)); + /* Map the TTB auxiliary data. */ + pstartup->kaTTBAux = pstartup->kaTTB + SYS_TTB1_SIZE; + VERIFY(map_pages(pstartup->paTTBAux, pstartup->kaTTBAux, SYS_TTB1_SIZE / SYS_PAGE_SIZE, TTBFLAGS_KERNEL_DATA, + PGTBLFLAGS_KERNEL_DATA, PGAUXFLAGS_KERNEL_DATA)); /* Map the Master Page Database. */ - pstartup->kaMPDB = pstartup->kaTTB + SYS_TTB1_SIZE; + pstartup->kaMPDB = pstartup->kaTTBAux + SYS_TTB1_SIZE; VERIFY(map_pages(pstartup->paMPDB, pstartup->kaTTB + SYS_TTB1_SIZE, pstartup->cpgMPDB, TTBFLAGS_KERNEL_DATA, - PGTBLFLAGS_KERNEL_DATA)); + PGTBLFLAGS_KERNEL_DATA, PGAUXFLAGS_KERNEL_DATA)); /* Map the IO area into high memory as well. */ - VERIFY(map_pages(PHYSADDR_IO_BASE, VMADDR_IO_BASE, PAGE_COUNT_IO, TTBFLAGS_MMIO, PGTBLFLAGS_MMIO)); + VERIFY(map_pages(PHYSADDR_IO_BASE, VMADDR_IO_BASE, PAGE_COUNT_IO, TTBFLAGS_MMIO, PGTBLFLAGS_MMIO, PGAUXFLAGS_MMIO)); + + /* + * Allocate one extra page table, just to ensure that we have sufficient free page table entries when we get up + * to the startup code. + */ + i = mmVMA2TTBIndex(VMADDR_KERNEL_FENCE); + while ((g_pTTB[i].data & TTBQUERY_MASK) != TTBQUERY_FAULT) + i++; + alloc_page_table(g_pTTB + i, g_pTTBAux + i, TTBFLAGS_KERNEL_DATA); #if 0 /* Dump the TTB and page tables to trace output. */ - ETrDumpWords((PUINT32)paTTB, (SYS_TTB1_SIZE + (g_cpgForPageTables << SYS_PAGE_BITS)) >> 2); + ETrDumpWords((PUINT32)paTTB, (SYS_TTB1_SIZE + SYS_TTB1_SIZE + (g_cpgForPageTables << SYS_PAGE_BITS)) >> 2); ETrWriteString8(szPageTable); ETrWriteWord(g_cpgForPageTables); ETrWriteString8(szFree); diff --git a/kernel/init_heap.c b/kernel/init_heap.c index f5d3f86..f89f82f 100644 --- a/kernel/init_heap.c +++ b/kernel/init_heap.c @@ -30,6 +30,7 @@ * "Raspberry Pi" is a trademark of the Raspberry Pi Foundation. */ #include +#include #include #include #include @@ -60,6 +61,8 @@ typedef struct tagINITHEAP IMalloc hdr; /* object header must be first */ BLOCK blkBase; /* base "zero" block */ PBLOCK pblkLastAlloc; /* last allocated block */ + UINT32 cbAlloc; /* number of bytes currently allocated */ + UINT32 cbAllocHiWat; /* high watermark for bytes currently allocated */ } INITHEAP, *PINITHEAP; /* @@ -92,6 +95,9 @@ SEG_INIT_CODE static PVOID init_heap_Alloc(IMalloc *pThis, SIZE_T cb) p->data.cblk = nBlocks; } pih->pblkLastAlloc = q; + pih->cbAlloc += (nBlocks * sizeof(BLOCK)); + if (pih->cbAlloc > pih->cbAllocHiWat) + pih->cbAllocHiWat = pih->cbAlloc; return (PVOID)(p + 1); } if (p == pih->pblkLastAlloc) @@ -137,10 +143,12 @@ SEG_INIT_CODE static void init_heap_Free(IMalloc *pThis, PVOID pv) { PINITHEAP pih = (PINITHEAP)pThis; register PBLOCK p, q; + register UINT32 nBlocks; if (init_heap_DidAlloc(pThis, pv) != 1) return; /* not our business */ p = ((PBLOCK)pv) - 1; + nBlocks = p->data.cblk; for (q = pih->pblkLastAlloc; !((p > q) && (p < q->data.pNextFree)); q = q->data.pNextFree) if ((q >= q->data.pNextFree) && ((p > q) || (p < q->data.pNextFree))) break; /* at one end or another */ @@ -161,6 +169,7 @@ SEG_INIT_CODE static void init_heap_Free(IMalloc *pThis, PVOID pv) else q->data.pNextFree = p; /* chain to previous free block */ pih->pblkLastAlloc = q; + pih->cbAlloc -= (nBlocks * sizeof(BLOCK)); } /* @@ -182,6 +191,7 @@ SEG_INIT_CODE static PVOID init_heap_Realloc(IMalloc *pThis, PVOID pv, SIZE_T cb PINITHEAP pih = (PINITHEAP)pThis; SIZE_T nBlocksNew, nBlocksExtra; PVOID pNew; + UINT32 cbHiWatSave; register PBLOCK p, pNext, q, qp; /* Handle degenerate cases */ @@ -205,7 +215,7 @@ SEG_INIT_CODE static PVOID init_heap_Realloc(IMalloc *pThis, PVOID pv, SIZE_T cb pNext = p + nBlocksNew; pNext->data.cblk = p->data.cblk - nBlocksNew; p->data.cblk = nBlocksNew; - init_heap_Free(pThis, (PVOID)(pNext + 1)); + init_heap_Free(pThis, (PVOID)(pNext + 1)); /* adjusts cbAlloc */ return pv; } @@ -220,6 +230,7 @@ SEG_INIT_CODE static PVOID init_heap_Realloc(IMalloc *pThis, PVOID pv, SIZE_T cb if (q->data.cblk < nBlocksExtra) break; /* cannot get enough blocks by combining next free block */ qp->data.pNextFree = q->data.pNextFree; /* remove block from free list */ + pih->cbAlloc += (q->data.cblk * sizeof(BLOCK)); /* act like we allocated it all for the nonce */ if (q->data.cblk == nBlocksExtra) { /* take it all */ pih->pblkLastAlloc = qp->data.pNextFree; @@ -228,9 +239,11 @@ SEG_INIT_CODE static PVOID init_heap_Realloc(IMalloc *pThis, PVOID pv, SIZE_T cb { /* chop in two, add first block to existing, free second block */ pNext += nBlocksExtra; pNext->data.cblk = q->data.cblk - nBlocksExtra; - init_heap_Free(pThis, (PVOID)(pNext + 1)); + init_heap_Free(pThis, (PVOID)(pNext + 1)); /* also fixes cbAlloc */ } p->data.cblk = nBlocksNew; + if (pih->cbAlloc > pih->cbAllocHiWat) + pih->cbAllocHiWat = pih->cbAlloc; return pv; } if (q == pih->pblkLastAlloc) @@ -238,11 +251,13 @@ SEG_INIT_CODE static PVOID init_heap_Realloc(IMalloc *pThis, PVOID pv, SIZE_T cb } /* last ditch effort: allocate new block and copy old contents in */ + cbHiWatSave = pih->cbAllocHiWat; pNew = init_heap_Alloc(pThis, cb); if (!pNew) return NULL; /* cannot reallocate */ StrCopyMem(pv, pNew, (p->data.cblk - 1) * sizeof(BLOCK)); init_heap_Free(pThis, pv); + pih->cbAllocHiWat = intMax(cbHiWatSave, pih->cbAlloc); return pNew; } @@ -303,6 +318,7 @@ SEG_INIT_CODE IMalloc *_MmGetInitHeap(void) p = (PBLOCK)g_pInitHeapBlock; p->data.cblk = SIZE_INIT_HEAP / sizeof(BLOCK); init_heap_Free((IMalloc *)(&initheap), (PVOID)(p + 1)); + initheap.cbAlloc = initheap.cbAllocHiWat = 0; /* start from zero now */ } return (IMalloc *)(&initheap); } diff --git a/kernel/kernel_space.c b/kernel/kernel_space.c new file mode 100644 index 0000000..6957891 --- /dev/null +++ b/kernel/kernel_space.c @@ -0,0 +1,326 @@ +/* + * This file is part of the COMROGUE Operating System for Raspberry Pi + * + * Copyright (c) 2013, Eric J. Bowersox / Erbosoft Enterprises + * All rights reserved. + * + * This program is free for commercial and non-commercial use as long as the following conditions are + * adhered to. + * + * Copyright in this file remains Eric J. Bowersox and/or Erbosoft, and as such any copyright notices + * in the code are not to be removed. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and + * the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * "Raspberry Pi" is a trademark of the Raspberry Pi Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef THIS_FILE +#undef THIS_FILE +DECLARE_THIS_FILE +#endif + +/*------------------------------------------ + * Operations with kernel address intervals + *------------------------------------------ + */ + +/* Definiton of an address interval */ +typedef struct tagAINTERVAL { + KERNADDR kaFirst; /* first kernel address in the interval */ + KERNADDR kaLast; /* first kernel address NOT in the interval */ +} AINTERVAL, *PAINTERVAL; +typedef const AINTERVAL *PCAINTERVAL; + +/* + * Compares two address intervals. + * + * Parameters: + * - paiLeft = Pointer to first address interval to compare. + * - paiRight = Pointer to second address interval to compare. + * + * Returns: + * - -1 = If the interval paiLeft is entirely before the interval paiRight. + * - 0 = If the interval paiLeft is entirely contained within (or equal to) the interval paiRight. + * - 1 = If the interval paiLeft is entirely after the interval paiRight. + * + * N.B.: + * It is an error if the intervals overlap without paiLeft being entirely contained within paiRight. + * (This should not happen.) + */ +static INT32 interval_compare(PCAINTERVAL paiLeft, PCAINTERVAL paiRight) +{ + static DECLARE_STRING8_CONST(szFitCheck, "interval_compare fitcheck: [%08x,%08x] [%08x,%08x]"); + + ASSERT(paiLeft->kaFirst < paiLeft->kaLast); + ASSERT(paiRight->kaFirst < paiRight->kaLast); + if ((paiLeft->kaFirst >= paiRight->kaFirst) && (paiLeft->kaLast <= paiRight->kaLast)) + return 0; + if (paiLeft->kaLast <= paiRight->kaFirst) + return -1; + if (paiLeft->kaFirst >= paiRight->kaLast) + return 1; + /* if get here, bugbugbugbugbug */ + TrPrintf8(szFitCheck, paiLeft->kaFirst, paiLeft->kaLast, paiRight->kaFirst, paiRight->kaLast); + /* TODO: bugcheck */ + return 0; +} + +/* + * Determines if two intervals are adjacent, that is, if the end of the first is the start of the next. + * + * Parameters: + * - paiLeft = Pointer to first address interval to compare. + * - paiRight = Pointer to second address interval to compare. + * + * Returns: + * TRUE if paiLeft is adjacent to paiRight, FALSE otherwise. + */ +static inline BOOL intervals_adjacent(PCAINTERVAL paiLeft, PCAINTERVAL paiRight) +{ + return MAKEBOOL(paiLeft->kaLast == paiRight->kaFirst); +} + +/* + * Returns the number of pages described by an interval. + * + * Parameters: + * - pai = The interval to test. + * + * Returns: + * The number of pages described by this interval. + */ +static inline UINT32 interval_numpages(PCAINTERVAL pai) +{ + return (pai->kaLast - pai->kaFirst) >> SYS_PAGE_BITS; +} + +/* + * Initializes an interval's start and end points. + * + * Parameters: + * - pai = Pointer to the interval to be initialized. + * - kaFirst = First address in the interval. + * - kaLast = Last address in the interval. + * + * Returns: + * pai. + */ +static inline PAINTERVAL init_interval(PAINTERVAL pai, KERNADDR kaFirst, KERNADDR kaLast) +{ + pai->kaFirst = kaFirst; + pai->kaLast = kaLast; + return pai; +} + +/* + * Initializes an interval to start at a specified location and cover a specific number of pages. + * + * Parameters: + * - pai = Pointer to the interval to be initialized. + * - kaBase = Base address of the interval. + * - cpg = Number of pages the interval is to contain. + * + * Returns: + * pai. + */ +static inline PAINTERVAL init_interval_pages(PAINTERVAL pai, KERNADDR kaBase, UINT32 cpg) +{ + pai->kaFirst = kaBase; + pai->kaLast = kaBase + (cpg << SYS_PAGE_BITS); + return pai; +} + +/*---------------------------------------- + * Kernel address manipulation operations + *---------------------------------------- + */ + +/* Tree structure in which we store "free" address intervals. */ +typedef struct tagADDRTREENODE { + RBTREENODE rbtn; /* tree node structure */ + AINTERVAL ai; /* address interval this represents */ +} ADDRTREENODE, *PADDRTREENODE; + +/* Structure used in allocating address space. */ +typedef struct tagALLOC_STRUC { + UINT32 cpgNeeded; /* count of number of pages needed */ + PADDRTREENODE patnFound; /* pointer to "found" tree node */ +} ALLOC_STRUC, *PALLOC_STRUC; + +static RBTREE g_rbtFreeAddrs; /* free address tree */ +static PMALLOC g_pMalloc = NULL; /* allocator we use */ + +/* + * Inserts a kernel address range into the tree. + * + * Parameters: + * - kaFirst = First address in the range to be inserted. + * - kaLast = Last address in the range to be inserted. + * + * Returns: + * - Nothing. + * + * Side effects: + * Modifies g_rbtFreeAddrs; allocates space from the g_pMalloc heap. + */ +static void insert_into_tree(KERNADDR kaFirst, KERNADDR kaLast) +{ + PADDRTREENODE pnode = IMalloc_Alloc(g_pMalloc, sizeof(ADDRTREENODE)); + ASSERT(pnode); + rbtNewNode(&(pnode->rbtn), init_interval(&(pnode->ai), kaFirst, kaLast)); + RbtInsert(&g_rbtFreeAddrs, (PRBTREENODE)pnode); +} + +/* + * Subfunction called from a tree walk to find a free address interval in the tree that can supply us with + * the number of pages we need. + * + * Parameters: + * - pUnused = Not used. + * - pnode = Current tree node we're walking over. + * - palloc = Pointer to allocation structure. + * + * Returns: + * FALSE if we found a node containing enough space (written to palloc->patnFound), TRUE otherwise. + */ +static BOOL alloc_check_space(PVOID pUnused, PADDRTREENODE pnode, PALLOC_STRUC palloc) +{ + if (interval_numpages(&(pnode->ai)) >= palloc->cpgNeeded) + { + palloc->patnFound = pnode; + return FALSE; + } + return TRUE; +} + +/* + * Allocates a block of kernel addresses suitable to contain a certain number of pages. + * + * Parameters: + * - cpgNeeded = Number of pages of kernel address space that are needed. + * + * Returns: + * Base address of the block of address space we got. + * + * Side effects: + * May modify g_rbtFreeAddrs and free space to the g_pMalloc heap. + * + * N.B.: + * Running out of kernel address space should be a bug. + */ +KERNADDR _MmAllocKernelAddr(UINT32 cpgNeeded) +{ + register KERNADDR rc; /* return from this function */ + BOOL bResult; /* result of tree walk */ + ALLOC_STRUC alloc_struc = { cpgNeeded, NULL }; /* allocation structure */ + + /* Walk the tree to find a block of free addresses that are big enough. */ + bResult = RbtWalk(&g_rbtFreeAddrs, (PFNRBTWALK)alloc_check_space, &alloc_struc); + ASSERT(!bResult); + if (bResult) + { + /* TODO: bug check */ + return 0; + } + + /* We allocate address space from the start of the interval we found. */ + rc = alloc_struc.patnFound->ai.kaFirst; + if (interval_numpages(&(alloc_struc.patnFound->ai)) == cpgNeeded) + { + /* This node is all used up by this allocation. Remove it from the tree and free it. */ + RbtDelete(&g_rbtFreeAddrs, (TREEKEY)(&(alloc_struc.patnFound->ai))); + IMalloc_Free(g_pMalloc, alloc_struc.patnFound); + } + else + { + /* + * Chop off the number of pages we're taking. This does not change the ordering of nodes in the tree + * because we're just shortening this one's interval. + */ + alloc_struc.patnFound->ai.kaFirst += (cpgNeeded << SYS_PAGE_BITS); + } + return rc; +} + +/* + * Frees a block of kernel addresses that was previously allocated. + * + * Parameters: + * - kaBase = Base address of the kernel address space region to be freed. + * - cpgToFree = Number of pages of kernel address space to be freed. + * + * Returns: + * Nothing. + * + * Side effects: + * May modify g_rbtFreeAddrs and allocate or free space in the g_pMalloc heap. + */ +void _MmFreeKernelAddr(KERNADDR kaBase, UINT32 cpgToFree) +{ + register PADDRTREENODE patnPred, patnSucc; /* predecessor and successor pointers */ + AINTERVAL aiFree; /* actual interval we're freeing */ + + init_interval_pages(&aiFree, kaBase, cpgToFree); + ASSERT(!RbtFind(&g_rbtFreeAddrs, (TREEKEY)(&aiFree))); + patnPred = (PADDRTREENODE)RbtFindPredecessor(&g_rbtFreeAddrs, (TREEKEY)(&aiFree)); + patnSucc = (PADDRTREENODE)RbtFindSuccessor(&g_rbtFreeAddrs, (TREEKEY)(&aiFree)); + if (patnPred && intervals_adjacent(&(patnPred->ai), &aiFree)) + { + if (patnSucc && intervals_adjacent(&aiFree, &(patnSucc->ai))) + { /* combine predecessor, interval, and successor into one big node */ + RbtDelete(&g_rbtFreeAddrs, (TREEKEY)(&(patnPred->ai))); + patnPred->ai.kaLast = patnSucc->ai.kaLast; + IMalloc_Free(g_pMalloc, patnSucc); + } + else /* combine with predecessor */ + patnPred->ai.kaLast = aiFree.kaLast; + } + else if (patnSucc && intervals_adjacent(&aiFree, &(patnSucc->ai))) + patnSucc->ai.kaFirst = aiFree.kaFirst; /* combine with successor */ + else /* insert as a new address range */ + insert_into_tree(aiFree.kaFirst, aiFree.kaLast); +} + +/* + * Initializes the kernel address space management code. + * + * Parameters: + * - pstartup = Pointer to startup information block. + * - pmInitHeap = Pointer to initialization heap allocator. + * + * Returns: + * Nothing. + */ +SEG_INIT_CODE void _MmInitKernelSpace(PSTARTUP_INFO pstartup, PMALLOC pmInitHeap) +{ + g_pMalloc = pmInitHeap; + IUnknown_AddRef(g_pMalloc); + rbtInitTree(&g_rbtFreeAddrs, (PFNTREECOMPARE)interval_compare); + insert_into_tree(pstartup->vmaFirstFree, VMADDR_IO_BASE); + insert_into_tree(VMADDR_IO_BASE + (PAGE_COUNT_IO * SYS_PAGE_SIZE), VMADDR_KERNEL_NOMANS); +} diff --git a/kernel/memmgr.c b/kernel/memmgr.c index 3ceed8a..922bfef 100644 --- a/kernel/memmgr.c +++ b/kernel/memmgr.c @@ -30,6 +30,8 @@ * "Raspberry Pi" is a trademark of the Raspberry Pi Foundation. */ #include +#include +#include #include #include #include @@ -39,11 +41,16 @@ *--------------------- */ -extern void _MmInitVMMap(PSTARTUP_INFO pstartup); +extern IMalloc *_MmGetInitHeap(void); +extern void _MmInitKernelSpace(PSTARTUP_INFO pstartup, PMALLOC pmInitHeap); +extern void _MmInitVMMap(PSTARTUP_INFO pstartup, PMALLOC pmInitHeap); extern void _MmInitPageAlloc(PSTARTUP_INFO pstartup); SEG_INIT_CODE void _MmInit(PSTARTUP_INFO pstartup) { - _MmInitVMMap(pstartup); + IMalloc *pmInitHeap = _MmGetInitHeap(); + _MmInitKernelSpace(pstartup, pmInitHeap); + _MmInitVMMap(pstartup, pmInitHeap); _MmInitPageAlloc(pstartup); + IUnknown_Release(pmInitHeap); } diff --git a/kernel/rbtree.c b/kernel/rbtree.c index 525b3d5..f75f601 100644 --- a/kernel/rbtree.c +++ b/kernel/rbtree.c @@ -97,7 +97,7 @@ SEG_LIB_CODE static PRBTREENODE rotate_left(PRBTREENODE ptn) * The new root node inherits the former root node's color, and the former root node turns red. * * Parameters: - * - ptn = Pointer to theroot node of the subtree. + * - ptn = Pointer to the root node of the subtree. * * Returns: * Pointer to the new root node of the subtree after the rotation. @@ -229,6 +229,76 @@ SEG_LIB_CODE PRBTREENODE RbtFind(PRBTREE ptree, TREEKEY key) return ptn; } +/* + * Given a key, returns either the node that matches the key, if the key is in the tree, or the node + * that has a key that most immediately precedes the supplied key. An O(log n) operation. + * + * Parameters: + * - ptree = Pointer to the tree head structure. + * - key = Key value to be looked up. + * + * Returns: + * Pointer to the node where the key is found, or pointer to the predecessor node, or NULL if the key + * is less than every key in the tree and hence has no predecessor. + */ +SEG_LIB_CODE PRBTREENODE RbtFindPredecessor(PRBTREE ptree, TREEKEY key) +{ + register PRBTREENODE ptn = ptree->ptnRoot; /* current node */ + register int cmp; /* compare result */ + + while (ptn) + { + cmp = (*(ptree->pfnTreeCompare))(key, ptn->treekey); + if (cmp == 0) + break; /* found */ + else if (cmp > 0) + { + if (rbtNodeRight(ptn)) + ptn = rbtNodeRight(ptn); + else + break; /* found predecessor */ + } + else + ptn = ptn->ptnLeft; + } + return ptn; +} + +/* + * Given a key, returns either the node that matches the key, if the key is in the tree, or the node + * that has a key that most immediately succeeds the supplied key. An O(log n) operation. + * + * Parameters: + * - ptree = Pointer to the tree head structure. + * - key = Key value to be looked up. + * + * Returns: + * Pointer to the node where the key is found, or pointer to the successor node, or NULL if the key + * is greater than every key in the tree and hence has no successor. + */ +SEG_LIB_CODE PRBTREENODE RbtFindSuccessor(PRBTREE ptree, TREEKEY key) +{ + register PRBTREENODE ptn = ptree->ptnRoot; /* current node */ + register int cmp; /* compare result */ + + while (ptn) + { + cmp = (*(ptree->pfnTreeCompare))(key, ptn->treekey); + if (cmp == 0) + break; /* found */ + else if (cmp < 0) + { + if (ptn->ptnLeft) + ptn = ptn->ptnLeft; + else + break; /* found successor */ + } + else + ptn = rbtNodeRight(ptn); + } + return ptn; +} + /* * Finds the "minimum" node in the subtree (the one at the bottom end of the left spine of the subtree). * @@ -246,7 +316,7 @@ SEG_LIB_CODE static PRBTREENODE find_min(PRBTREENODE ptn) } /* - * Finds the "minimum" node int he tree (the one at the bottom end of the left spine of the tree). + * Finds the "minimum" node in the tree (the one at the bottom end of the left spine of the tree). * * Parameters: * - ptree = Pointer to the tree head structure. @@ -327,7 +397,8 @@ SEG_LIB_CODE static PRBTREENODE delete_min(PRBTREENODE ptn) } /* - * Detetes the node in the subtree having an arbitrary key. An O(log n) operation. + * Deletes the node in the subtree having an arbitrary key. (Note that "deletes" means "removes from the tree." + * No memory delete operation is actually performed.) An O(log n) operation. * * Parameters: * - ptree = Pointer to the tree head structure, containing the compare function. @@ -386,7 +457,8 @@ SEG_LIB_CODE static PRBTREENODE delete_from_under(PRBTREE ptree, PRBTREENODE ptn } /* - * Detetes the node in the tree having an arbitrary key. An O(log n) operation. + * Deletes the node in the tree having an arbitrary key. (Note that "deletes" means "removes from the tree." + * No memory delete operation is actually performed.) An O(log n) operation. * * Parameters: * - ptree = Pointer to the tree head structure. @@ -401,3 +473,49 @@ SEG_LIB_CODE void RbtDelete(PRBTREE ptree, TREEKEY key) if (ptree->ptnRoot) rbtSetNodeColor(ptree->ptnRoot, BLACK); } + +/* + * Performs an inorder traversal of the tree rooted at the specified node. An O(n) operation. + * + * Parameters: + * - ptree = Pointer to the tree head structure. + * - ptn = Pointer to the root of the current tree node. + * - pfnWalk = Pointer to a function called for each tree node we encounter. This function returns TRUE + * to continue the traversal or FALSE to stop it. + * - pData = Arbitrary data pointer that gets passed to the pfnWalk function. + * + * Returns: + * TRUE if the tree was entirely traversed, FALSE if the tree walk was interrupted. + * + * N.B.: + * This function is recursive; however, the nature of the tree guarantees that the stack space consumed + * by its stack frames will be O(log n). + */ +SEG_LIB_CODE static BOOL do_walk(PRBTREE ptree, PRBTREENODE ptn, PFNRBTWALK pfnWalk, PVOID pData) +{ + register BOOL rc = TRUE; + if (ptn->ptnLeft) + rc = do_walk(ptree, ptn->ptnLeft, pfnWalk, pData); + if (rc) + rc = (*pfnWalk)(ptree, ptn, pData); + if (rc && rbtNodeRight(ptn)) + rc = do_walk(ptree, rbtNodeRight(ptn), pfnWalk, pData); + return rc; +} + +/* + * Performs an inorder traversal of the tree. An O(n) operation. + * + * Parameters: + * - ptree = Pointer to the tree head structure. + * - pfnWalk = Pointer to a function called for each tree node we encounter. This function returns TRUE + * to continue the traversal or FALSE to stop it. + * - pData = Arbitrary data pointer that gets passed to the pfnWalk function. + * + * Returns: + * TRUE if the tree was entirely traversed, FALSE if the tree walk was interrupted. + */ +SEG_LIB_CODE BOOL RbtWalk(PRBTREE ptree, PFNRBTWALK pfnWalk, PVOID pData) +{ + return (ptree->ptnRoot ? do_walk(ptree, ptree->ptnRoot, pfnWalk, pData) : TRUE); +} diff --git a/kernel/start.S b/kernel/start.S index 253439b..1271e62 100644 --- a/kernel/start.S +++ b/kernel/start.S @@ -68,7 +68,6 @@ COMROGUEStart: /* copy startup info to our local buffer */ mov r1, r0 ldr r0, =kiStartupInfo - mov r11, r0 /* save for later */ ldr r2, [r1] /* get number of bytes to copy */ ldr ip, =StrCopyMem /* this is needed to branch to a library function */ ldr lr, =.postCopy diff --git a/kernel/vmmap.c b/kernel/vmmap.c index 200bde4..1845178 100644 --- a/kernel/vmmap.c +++ b/kernel/vmmap.c @@ -31,18 +31,36 @@ */ #include #include +#include #include #include #include +#include #include +#include + +#ifdef THIS_FILE +#undef THIS_FILE +DECLARE_THIS_FILE +#endif + +/* Tree node storing mapping of physical addresses of page table pages to their kernel addresses */ +typedef struct tagPGTMAP { + RBTREENODE rbtn; /* tree node structure */ + KERNADDR kaPGTPage; /* page table page kernel address */ + UINT32 uiRefCount; /* reference count for mapping */ +} PGTMAP, *PPGTMAP; #define NMAPFRAMES 4 /* number of frame mappings */ +static PMALLOC g_pMalloc = NULL; /* allocator used */ static PTTB g_pttb1 = NULL; /* pointer to TTB1 */ -static KERNADDR g_kaEndFence = 0; /* end fence in kernel addresses, after we reserve some */ -static KERNADDR g_kaTableMap[NMAPFRAMES] = { 0 }; /* kernel addresses for page table mappings */ -static PHYSADDR g_paTableMap[NMAPFRAMES] = { 0 }; /* physical addresses for page table mappings */ -static UINT32 g_refTableMap[NMAPFRAMES] = { 0 }; /* reference counts for table mappings */ +static PTTBAUX g_pttb1Aux = NULL; /* pointer to TTB1 aux data */ +static RBTREE g_rbtPageTables; /* tree mapping page table PAs to KAs */ + +/* Forward declaration. */ +static HRESULT map_pages0(PTTB pTTB, PTTBAUX pTTBAux, PHYSADDR paBase, KERNADDR vmaBase, UINT32 cpg, + UINT32 uiTableFlags, UINT32 uiPageFlags, UINT32 uiAuxFlags); /* * Maps a page table's page into kernel memory space where we can examine it. @@ -54,44 +72,42 @@ static UINT32 g_refTableMap[NMAPFRAMES] = { 0 }; /* reference counts for table * Pointer to the pagetable in kernel memory, or NULL if we weren't able to map it. * * Side effects: - * May modify g_paTableMap and g_refTableMap, and may modify TTB1 if we map a page into memory. + * May modify g_rbtPageTables, and may modify TTB1 if we map a page into memory. May allocate + * memory from g_pMalloc. */ static PPAGETAB map_pagetable(PHYSADDR paPageTable) { - PHYSADDR paOfPage = paPageTable & ~(SYS_PAGE_SIZE - 1); /* actual page table page's PA */ - register UINT32 i; /* loop counter */ + register PHYSADDR paOfPage = paPageTable & ~(SYS_PAGE_SIZE - 1); /* actual page table page's PA */ + register PPGTMAP ppgtmap; - for (i = 0; i < NMAPFRAMES; i++) + ppgtmap = (PPGTMAP)RbtFind(&g_rbtPageTables, (TREEKEY)paOfPage); + if (!ppgtmap) { - if (g_paTableMap[i] == paOfPage) + ppgtmap = IMalloc_Alloc(g_pMalloc, sizeof(PGTMAP)); + ppgtmap->kaPGTPage = _MmAllocKernelAddr(1); + ASSERT(ppgtmap->kaPGTPage); + if (SUCCEEDED(map_pages0(g_pttb1, g_pttb1Aux, paOfPage, ppgtmap->kaPGTPage, 1, TTBFLAGS_KERNEL_DATA, + PGTBLFLAGS_KERNEL_DATA, PGAUXFLAGS_KERNEL_DATA))) { - g_refTableMap[i]++; /* already mapped, return it */ - goto returnOK; + ppgtmap->uiRefCount = 1; + rbtNewNode(&(ppgtmap->rbtn), paOfPage); + RbtInsert(&g_rbtPageTables, (PRBTREENODE)ppgtmap); + } + else + { + _MmFreeKernelAddr(ppgtmap->kaPGTPage, 1); + IMalloc_Free(g_pMalloc, ppgtmap); + return NULL; } } - - for (i = 0; i < NMAPFRAMES; i++) - { - if (!(g_paTableMap[i])) - { - g_paTableMap[i] = paOfPage; /* claim slot and map into it */ - g_refTableMap[i] = 1; - if (FAILED(MmMapPages(g_pttb1, g_paTableMap[i], g_kaTableMap[i], 1, TTBFLAGS_KERNEL_DATA, - PGTBLFLAGS_KERNEL_DATA))) - { - g_refTableMap[i] = 0; - g_paTableMap[i] = 0; - return NULL; - } - break; - } - } - if (i == NMAPFRAMES) - return NULL; -returnOK: - return (PPAGETAB)(g_kaTableMap[i] | (paPageTable & (SYS_PAGE_SIZE - 1))); + else + ppgtmap->uiRefCount++; + return (PPAGETAB)(ppgtmap->kaPGTPage | (paPageTable & (SYS_PAGE_SIZE - 1))); } +/* Forward declaration. */ +static HRESULT demap_pages0(PTTB pTTB, PTTBAUX pTTBAux, KERNADDR vmaBase, UINT32 cpg, UINT32 uiFlags); + /* * Demaps a page table's page from kernel memory space. * @@ -102,23 +118,24 @@ returnOK: * Nothing. * * Side effects: - * May modify g_paTableMap and g_refTableMap, and may modify TTB1 if we unmap a page from memory. + * May modify g_rbtPageTables, and may modify TTB1 if we unmap a page from memory. May free + * memory in g_pMalloc. */ static void demap_pagetable(PPAGETAB ppgtbl) { - KERNADDR kaOfPage = ((KERNADDR)ppgtbl) & ~(SYS_PAGE_SIZE - 1); - register UINT32 i; /* loop counter */ + register PHYSADDR paOfPage; + register PPGTMAP ppgtmap; - for (i = 0; i < NMAPFRAMES; i++) + paOfPage = MmGetPhysAddr(g_pttb1, ((KERNADDR)ppgtbl) & ~(SYS_PAGE_SIZE - 1)); + ppgtmap = (PPGTMAP)RbtFind(&g_rbtPageTables, (TREEKEY)paOfPage); + if (ppgtmap) { - if (g_kaTableMap[i] == kaOfPage) + if (--(ppgtmap->uiRefCount) == 0) { - if (--g_refTableMap[i] == 0) - { - MmDemapPages(g_pttb1, g_kaTableMap[i], 1); - g_paTableMap[i] = 0; - } - break; + RbtDelete(&g_rbtPageTables, (TREEKEY)paOfPage); + demap_pages0(g_pttb1, g_pttb1Aux, ppgtmap->kaPGTPage, 1, 0); + _MmFreeKernelAddr(ppgtmap->kaPGTPage, 1); + IMalloc_Free(g_pMalloc, ppgtmap); } } } @@ -134,13 +151,31 @@ static void demap_pagetable(PPAGETAB ppgtbl) * Returns: * The pointer to the selected TTB, which may be the global variable g_pttb1. */ -static PTTB resolve_ttb(PTTB pTTB, KERNADDR vma) +static inline PTTB resolve_ttb(PTTB pTTB, KERNADDR vma) { if (!pTTB || (vma & 0x80000000)) return g_pttb1; /* if no TTB specified or address is out of range for TTB0, use TTB1 */ return pTTB; } +/* + * Resolves a specified TTB auxiliary table to either itself or the global TTB1Aux, depending on whether one + * was specified and on the virtual address to be worked with. + * + * Parameters: + * - pTTBAux = The specified TTB aux table pointer. + * - vma = The base virtual address we're working with. + * + * Returns: + * The pointer to the selected TTB aux table, which may be the global variable g_pttb1Aux. + */ +static inline PTTBAUX resolve_ttbaux(PTTBAUX pTTBAux, KERNADDR vma) +{ + if (!pTTBAux || (vma & 0x80000000)) + return g_pttb1Aux; + return pTTBAux; +} + /* * Returns the physical address corresponding to a virtual memory address. * @@ -171,24 +206,29 @@ PHYSADDR MmGetPhysAddr(PTTB pTTB, KERNADDR vma) return rc; } +/* Flags for demapping. */ +#define DEMAP_NOTHING_SACRED 0x00000001 /* disregard "sacred" flag */ + /* * Deallocates page mapping entries within a single current entry in the TTB. * * Parameters: * - pTTBEntry = Pointer to the TTB entry to deallocate in. + * - pTTBAuxEntry = Pointer to the TTB aux table entry to deallocate in. * - ndxPage = Starting index in the page table of the first entry to deallocate. * - cpg = Count of the number of pages to deallocate. Note that this function will not deallocate more * page mapping entries than remain on the page, as indicated by ndxPage. + * - uiFlags = Flags for operation. * * Returns: * Standard HRESULT success/failure. If the result is successful, the SCODE_CODE of the result will * indicate the number of pages actually deallocated. * * Side effects: - * May modify the TTB entry pointed to, and the page table it points to, where applicable. If the + * May modify the TTB entry/aux entry pointed to, and the page table it points to, where applicable. If the * page table is empty after we finish demapping entries, it may be deallocated. */ -static HRESULT demap_pages1(PTTB pTTBEntry, UINT32 ndxPage, UINT32 cpg) +static HRESULT demap_pages1(PTTB pTTBEntry, PTTBAUX pTTBAuxEntry, UINT32 ndxPage, UINT32 cpg, UINT32 uiFlags) { UINT32 cpgCurrent; /* number of pages we're mapping */ PPAGETAB pTab = NULL; /* pointer to current or new page table */ @@ -203,7 +243,10 @@ static HRESULT demap_pages1(PTTB pTTBEntry, UINT32 ndxPage, UINT32 cpg) if ((pTTBEntry->data & TTBSEC_ALWAYS) && (cpgCurrent == SYS_PGTBL_ENTRIES) && (ndxPage == 0)) { /* we can kill off the whole section */ + if (pTTBAuxEntry->aux.sacred && !(uiFlags & DEMAP_NOTHING_SACRED)) + return MEMMGR_E_NOSACRED; /* can't demap a sacred mapping */ pTTBEntry->data = 0; + pTTBAuxEntry->data = 0; /* TODO: handle TLB and cache */ } else if (pTTBEntry->data & TTBPGTBL_ALWAYS) @@ -212,21 +255,29 @@ static HRESULT demap_pages1(PTTB pTTBEntry, UINT32 ndxPage, UINT32 cpg) if (!pTab) return MEMMGR_E_NOPGTBL; for (i = 0; ipgaux[ndxPage + i].aux.sacred && !(uiFlags & DEMAP_NOTHING_SACRED)) + { /* can't demap a sacred mapping */ + hr = MEMMGR_E_NOSACRED; + goto pageError; + } + } + for (i = 0; ipgtbl[ndxPage + i].data = 0; pTab->pgaux[ndxPage + i].data = 0; /* TODO: handle TLB and cache */ } /* TODO: check to see if page table can be deallocated */ +pageError: demap_pagetable(pTab); } return hr; } -HRESULT MmDemapPages(PTTB pTTB, KERNADDR vmaBase, UINT32 cpg) +static HRESULT demap_pages0(PTTB pTTB, PTTBAUX pTTBAux, KERNADDR vmaBase, UINT32 cpg, UINT32 uiFlags) { - PTTB pMyTTB = resolve_ttb(pTTB, vmaBase); /* the TTB we use */ - UINT32 ndxTTBMax = (pMyTTB == g_pttb1) ? SYS_TTB1_ENTRIES : SYS_TTB0_ENTRIES; + UINT32 ndxTTBMax = (pTTB == g_pttb1) ? SYS_TTB1_ENTRIES : SYS_TTB0_ENTRIES; UINT32 ndxTTB = mmVMA2TTBIndex(vmaBase); /* TTB entry index */ UINT32 ndxPage = mmVMA2PGTBLIndex(vmaBase); /* starting page entry index */ UINT32 cpgRemaining = cpg; /* number of pages remaining to demap */ @@ -235,7 +286,7 @@ HRESULT MmDemapPages(PTTB pTTB, KERNADDR vmaBase, UINT32 cpg) if ((cpgRemaining > 0) && (ndxPage > 0)) { /* We are starting in the middle of a VM page. Demap to the end of the VM page. */ - hr = demap_pages1(pMyTTB + ndxTTB, ndxPage, cpgRemaining); + hr = demap_pages1(pTTB + ndxTTB, pTTBAux + ndxTTB, ndxPage, cpgRemaining, uiFlags); if (FAILED(hr)) return hr; cpgRemaining -= SCODE_CODE(hr); @@ -245,7 +296,7 @@ HRESULT MmDemapPages(PTTB pTTB, KERNADDR vmaBase, UINT32 cpg) while (cpgRemaining > 0) { - hr = demap_pages1(pMyTTB + ndxTTB, 0, cpgRemaining); + hr = demap_pages1(pTTB + ndxTTB, pTTBAux + ndxTTB, 0, cpgRemaining, uiFlags); if (FAILED(hr)) return hr; cpgRemaining -= SCODE_CODE(hr); @@ -255,6 +306,11 @@ HRESULT MmDemapPages(PTTB pTTB, KERNADDR vmaBase, UINT32 cpg) return S_OK; } +HRESULT MmDemapPages(PTTB pTTB, PTTBAUX pTTBAux, KERNADDR vmaBase, UINT32 cpg) +{ + return demap_pages0(resolve_ttb(pTTB, vmaBase), resolve_ttbaux(pTTBAux, vmaBase), vmaBase, cpg, 0); +} + /* * Morphs the "flags" bits used for a page table entry in the TTB and for a page entry in the page table * into the "flags" bits used for a section entry in the TTB. @@ -285,8 +341,44 @@ static UINT32 make_section_flags(UINT32 uiTableFlags, UINT32 uiPageFlags) return rc; } -static HRESULT map_pages1(PTTB pttbEntry, PHYSADDR paBase, UINT32 ndxPage, UINT32 cpg, UINT32 uiTableFlags, - UINT32 uiPageFlags) +/* + * Morphs the "auxiliary flags" bits used for a page table entry into "auxiliary flags" used for a TTB entry. + * + * Parameters: + * - uiPageAuxFlags = Page auxiliary flag bits that would be used for a page table entry. + * + * Returns: + * TTB auxiliary flag bits that would be used for a TTB entry. + */ +static UINT32 make_section_aux_flags(UINT32 uiPageAuxFlags) +{ + register UINT32 rc = uiPageAuxFlags & (PGAUX_SACRED); + /* TODO if we define any other flags */ + return rc; +} + +static PPAGETAB alloc_page_table(PTTB pttbEntry, PTTBAUX pttbAuxEntry, UINT32 uiTableFlags) +{ + PPAGETAB pTab = NULL; /* new page table pointer */ + register INT32 i; /* loop counter */ + + /* TODO: pull pTab out of our ass somewhere */ + if (pTab) + { + for (i=0; ipgtbl[i].data = 0; /* blank out the new page table */ + pTab->pgaux[i].data = 0; + } + /* TODO: use physical address of page here */ + pttbEntry->data = MmGetPhysAddr(g_pttb1, (KERNADDR)pTab) | uiTableFlags; /* poke new entry */ + pttbAuxEntry->data = TTBAUXFLAGS_PAGETABLE; + } + return pTab; +} + +static HRESULT map_pages1(PTTB pttbEntry, PTTBAUX pttbAuxEntry, PHYSADDR paBase, UINT32 ndxPage, UINT32 cpg, + UINT32 uiTableFlags, UINT32 uiPageFlags, UINT32 uiAuxFlags) { UINT32 cpgCurrent; /* number of pages we're mapping */ PPAGETAB pTab = NULL; /* pointer to current or new page table */ @@ -296,16 +388,9 @@ static HRESULT map_pages1(PTTB pttbEntry, PHYSADDR paBase, UINT32 ndxPage, UINT3 switch (pttbEntry->data & TTBQUERY_MASK) { case TTBQUERY_FAULT: /* not allocated, allocate a new page table for the slot */ - /* TODO: allocate something into pTab */ + pTab = alloc_page_table(pttbEntry, pttbAuxEntry, uiTableFlags); if (!pTab) return MEMMGR_E_NOPGTBL; - for (i=0; ipgtbl[i].data = 0; /* blank out the new page table */ - pTab->pgaux[i].data = 0; - } - /* TODO: use physical address of page here */ - pttbEntry->data = MmGetPhysAddr(g_pttb1, (KERNADDR)pTab) | uiTableFlags; /* poke new entry */ break; case TTBQUERY_PGTBL: /* existing page table */ @@ -321,8 +406,11 @@ static HRESULT map_pages1(PTTB pttbEntry, PHYSADDR paBase, UINT32 ndxPage, UINT3 /* this is a section, make sure its base address covers this mapping and its flags are compatible */ if ((pttbEntry->data & TTBSEC_ALLFLAGS) != make_section_flags(uiTableFlags, uiPageFlags)) return MEMMGR_E_BADTTBFLG; + if (pttbAuxEntry->data != make_section_aux_flags(uiAuxFlags)) + return MEMMGR_E_BADTTBFLG; if ((pttbEntry->data & TTBSEC_BASE) != (paBase & TTBSEC_BASE)) return MEMMGR_E_COLLIDED; + pTab = NULL; break; } @@ -332,9 +420,8 @@ static HRESULT map_pages1(PTTB pttbEntry, PHYSADDR paBase, UINT32 ndxPage, UINT3 cpgCurrent = cpg; /* only map up to max requested */ hr = MAKE_SCODE(SEVERITY_SUCCESS, FACILITY_MEMMGR, cpgCurrent); - if (!(pttbEntry->data & TTBSEC_ALWAYS)) - { - /* fill in entries in the page table */ + if (pTab) + { /* fill in entries in the page table */ for (i=0; i < cpgCurrent; i++) { if ((pTab->pgtbl[ndxPage + i].data & PGQUERY_MASK) != PGQUERY_FAULT) @@ -348,7 +435,7 @@ static HRESULT map_pages1(PTTB pttbEntry, PHYSADDR paBase, UINT32 ndxPage, UINT3 goto exit; } pTab->pgtbl[ndxPage + i].data = paBase | uiPageFlags; - pTab->pgaux[ndxPage + i].data = 0; /* TODO */ + pTab->pgaux[ndxPage + i].data = uiAuxFlags; paBase += SYS_PAGE_SIZE; } } @@ -357,11 +444,10 @@ exit: return hr; } -HRESULT MmMapPages(PTTB pTTB, PHYSADDR paBase, KERNADDR vmaBase, UINT32 cpg, UINT32 uiTableFlags, - UINT32 uiPageFlags) +static HRESULT map_pages0(PTTB pTTB, PTTBAUX pTTBAux, PHYSADDR paBase, KERNADDR vmaBase, UINT32 cpg, + UINT32 uiTableFlags, UINT32 uiPageFlags, UINT32 uiAuxFlags) { - PTTB pMyTTB = resolve_ttb(pTTB, vmaBase); /* the TTB we use */ - UINT32 ndxTTBMax = (pMyTTB == g_pttb1) ? SYS_TTB1_ENTRIES : SYS_TTB0_ENTRIES; + UINT32 ndxTTBMax = (pTTB == g_pttb1) ? SYS_TTB1_ENTRIES : SYS_TTB0_ENTRIES; UINT32 ndxTTB = mmVMA2TTBIndex(vmaBase); /* TTB entry index */ UINT32 ndxPage = mmVMA2PGTBLIndex(vmaBase); /* starting page entry index */ UINT32 cpgRemaining = cpg; /* number of pages remaining to map */ @@ -370,7 +456,8 @@ HRESULT MmMapPages(PTTB pTTB, PHYSADDR paBase, KERNADDR vmaBase, UINT32 cpg, UIN if ((cpgRemaining > 0) && (ndxPage > 0)) { /* We are starting in the middle of a VM page. Map to the end of the VM page. */ - hr = map_pages1(pMyTTB + ndxTTB, paBase, ndxPage, cpgRemaining, uiTableFlags, uiPageFlags); + hr = map_pages1(pTTB + ndxTTB, pTTBAux + ndxTTB, paBase, ndxPage, cpgRemaining, uiTableFlags, + uiPageFlags, uiAuxFlags); if (FAILED(hr)) return hr; cpgRemaining -= SCODE_CODE(hr); @@ -388,10 +475,11 @@ HRESULT MmMapPages(PTTB pTTB, PHYSADDR paBase, KERNADDR vmaBase, UINT32 cpg, UIN if ((paBase & TTBSEC_BASE) == paBase) { /* paBase is section-aligned now as well, we can use a direct 1Mb section mapping */ - switch (pMyTTB[ndxTTB].data & TTBQUERY_MASK) + switch (pTTB[ndxTTB].data & TTBQUERY_MASK) { case TTBQUERY_FAULT: /* unmapped - map the section */ - pMyTTB[ndxTTB].data = paBase | make_section_flags(uiTableFlags, uiPageFlags); + pTTB[ndxTTB].data = paBase | make_section_flags(uiTableFlags, uiPageFlags); + pTTBAux[ndxTTB].data = make_section_aux_flags(uiAuxFlags); break; case TTBQUERY_PGTBL: /* collided with a page table */ @@ -400,12 +488,17 @@ HRESULT MmMapPages(PTTB pTTB, PHYSADDR paBase, KERNADDR vmaBase, UINT32 cpg, UIN case TTBQUERY_SEC: /* test existing section */ case TTBQUERY_PXNSEC: - if ((pMyTTB[ndxTTB].data & TTBSEC_ALLFLAGS) != make_section_flags(uiTableFlags, uiPageFlags)) + if ((pTTB[ndxTTB].data & TTBSEC_ALLFLAGS) != make_section_flags(uiTableFlags, uiPageFlags)) { hr = MEMMGR_E_BADTTBFLG; goto errorExit; } - if ((pMyTTB[ndxTTB].data & TTBSEC_BASE) != paBase) + if (pTTBAux[ndxTTB].data != make_section_aux_flags(uiAuxFlags)) + { + hr = MEMMGR_E_BADTTBFLG; + goto errorExit; + } + if ((pTTB[ndxTTB].data & TTBSEC_BASE) != paBase) { hr = MEMMGR_E_COLLIDED; goto errorExit; @@ -418,7 +511,7 @@ HRESULT MmMapPages(PTTB pTTB, PHYSADDR paBase, KERNADDR vmaBase, UINT32 cpg, UIN else { /* just map 256 individual pages */ - hr = map_pages1(pMyTTB + ndxTTB, paBase, 0, cpgRemaining, uiTableFlags, uiPageFlags); + hr = map_pages1(pTTB + ndxTTB, pTTBAux + ndxTTB, paBase, 0, cpgRemaining, uiTableFlags, uiPageFlags, uiAuxFlags); if (FAILED(hr)) goto errorExit; } @@ -435,14 +528,52 @@ HRESULT MmMapPages(PTTB pTTB, PHYSADDR paBase, KERNADDR vmaBase, UINT32 cpg, UIN if (cpgRemaining > 0) { /* map the "tail end" onto the next TTB */ - hr = map_pages1(pMyTTB + ndxTTB, paBase, 0, cpgRemaining, uiTableFlags, uiPageFlags); + hr = map_pages1(pTTB + ndxTTB, pTTBAux + ndxTTB, paBase, 0, cpgRemaining, uiTableFlags, uiPageFlags, uiAuxFlags); if (FAILED(hr)) goto errorExit; } return S_OK; errorExit: /* demap everything we've managed to map thusfar */ - MmDemapPages(pMyTTB, vmaBase, cpg - cpgRemaining); + demap_pages0(pTTB, pTTBAux, vmaBase, cpg - cpgRemaining, DEMAP_NOTHING_SACRED); + return hr; +} + +HRESULT MmMapPages(PTTB pTTB, PTTBAUX pTTBAux, PHYSADDR paBase, KERNADDR vmaBase, UINT32 cpg, UINT32 uiTableFlags, + UINT32 uiPageFlags, UINT32 uiAuxFlags) +{ + return map_pages0(resolve_ttb(pTTB, vmaBase), resolve_ttbaux(pTTBAux, vmaBase), paBase, vmaBase, cpg, + uiTableFlags, uiPageFlags, uiAuxFlags); +} + +HRESULT MmMapKernelPages(PTTB pTTB, PTTBAUX pTTBAux, PHYSADDR paBase, UINT32 cpg, UINT32 uiTableFlags, + UINT32 uiPageFlags, UINT32 uiAuxFlags, PKERNADDR pvmaLocation) +{ + register HRESULT hr; + + if (!pvmaLocation) + return E_POINTER; + *pvmaLocation = _MmAllocKernelAddr(cpg); + if (!(*pvmaLocation)) + return MEMMGR_E_NOKERNSPC; + hr = MmMapPages(pTTB, pTTBAux, paBase, *pvmaLocation, cpg, uiTableFlags, uiPageFlags, uiAuxFlags); + if (FAILED(hr)) + { + _MmFreeKernelAddr(*pvmaLocation, cpg); + *pvmaLocation = NULL; + } + return hr; +} + +HRESULT MmDemapKernelPages(PTTB pTTB, PTTBAUX pTTBAux, KERNADDR vmaBase, UINT32 cpg) +{ + register HRESULT hr; + + if ((vmaBase & 0xC0000000) != 0xC0000000) + return E_INVALIDARG; + hr = MmDemapPages(pTTB, pTTBAux, vmaBase, cpg); + if (SUCCEEDED(hr)) + _MmFreeKernelAddr(vmaBase, cpg); return hr; } @@ -451,15 +582,11 @@ errorExit: *--------------------- */ -SEG_INIT_CODE void _MmInitVMMap(PSTARTUP_INFO pstartup) +SEG_INIT_CODE void _MmInitVMMap(PSTARTUP_INFO pstartup, PMALLOC pmInitHeap) { - UINT32 i; /* loop counter */ - + g_pMalloc = pmInitHeap; + IUnknown_AddRef(g_pMalloc); g_pttb1 = (PTTB)(pstartup->kaTTB); - g_kaEndFence = pstartup->vmaFirstFree; - for (i=0; ikaTTBAux); + rbtInitTree(&g_rbtPageTables, RbtStdCompareByValue); } diff --git a/tools/pidl/lib/Parse/Pidl/COMROGUE/Header.pm b/tools/pidl/lib/Parse/Pidl/COMROGUE/Header.pm index b346f86..caf4055 100644 --- a/tools/pidl/lib/Parse/Pidl/COMROGUE/Header.pm +++ b/tools/pidl/lib/Parse/Pidl/COMROGUE/Header.pm @@ -232,10 +232,10 @@ sub ParseInterface($) my $args = GetArgumentList($d); if (defined($args)) { $res .= "#define $if->{NAME}_$d->{NAME}(pInterface, $args) \\\n"; - $res .= "\t(*((pInterface)->pVTable->$d->{NAME}))(pInterface, $args)\n"; + $res .= "\t(*((pInterface)->pVTable->$d->{NAME}))(($if->{NAME} *)(pInterface), $args)\n"; } else { $res .= "#define $if->{NAME}_$d->{NAME}(pInterface) \\\n"; - $res .= "\t(*((pInterface)->pVTable->$d->{NAME}))(pInterface)\n"; + $res .= "\t(*((pInterface)->pVTable->$d->{NAME}))(($if->{NAME} *)(pInterface))\n"; } }