moved memory manager sources into their own directory to consolidate everything

locally
This commit is contained in:
Eric J. Bowersox
2013-05-02 23:48:40 -06:00
parent ab31b81050
commit 621aec75bb
8 changed files with 246 additions and 4 deletions

44
kernel/mm/Makefile Normal file
View File

@@ -0,0 +1,44 @@
#
# 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.
MAKEFLAGS += -rR
CRBASEDIR := $(abspath ../..)
include $(CRBASEDIR)/armcompile.mk
MM_OBJS = memmgr.o vmmap.o pagealloc.o kernel_space.o
MM_INIT_OBJS = init_heap.o
all: kernel-mm.o
kernel-mm.o: $(MM_OBJS) $(MM_INIT_OBJS) kernel-mm.lds
$(LD) -r -T kernel-mm.lds $(MM_OBJS) $(MM_INIT_OBJS) -o kernel-mm.o
clean:
-rm *.o *.s *.lds

324
kernel/mm/init_heap.c Normal file
View File

@@ -0,0 +1,324 @@
/*
* 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 <comrogue/types.h>
#include <comrogue/intlib.h>
#include <comrogue/str.h>
#include <comrogue/allocator.h>
#include <comrogue/objhelp.h>
#include <comrogue/internals/seg.h>
#include <comrogue/internals/layout.h>
/*-------------------------------------------------------------------------------------------------------------
* Initial heap implementation. Since this will only be used by initializer code and freed with the rest
* of the initializer code and data, it doesn't need to be very efficient. The implementation is adapted from
* the original K&R storage allocator, with modifications to implement the full IMalloc interface.
*-------------------------------------------------------------------------------------------------------------
*/
extern PCHAR g_pInitHeapBlock; /* pointer to heap init block defined in assembly code */
typedef union tagBLOCK
{
struct
{
union tagBLOCK *pNextFree; /* pointer to next free block */
SIZE_T cblk; /* size of this free block (in blocks) */
} data;
INT64 x; /* to force alignment */
} BLOCK, *PBLOCK;
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;
/*
* Allocates a block of memory.
*
* Parameters:
* - pThis = Base interface pointer.
* - cb = Size of the memory block to be allocated, in bytes.
*
* Returns:
* A pointer to the allocated block of memory, or NULL if memory could not be allocated.
*/
SEG_INIT_CODE static PVOID init_heap_Alloc(IMalloc *pThis, SIZE_T cb)
{
PINITHEAP pih = (PINITHEAP)pThis;
register PBLOCK p, q;
register SIZE_T nBlocks = 1 + (cb + sizeof(BLOCK) - 1) / sizeof(BLOCK);
q = pih->pblkLastAlloc;
for (p = q->data.pNextFree; ; q = p, p = p->data.pNextFree)
{
if (p->data.cblk >= nBlocks)
{
if (p->data.cblk == nBlocks)
q->data.pNextFree = p->data.pNextFree;
else
{
p->data.cblk -= nBlocks;
p += p->data.cblk;
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)
break;
}
return NULL;
}
/*
* Determines whether this allocator was used to allocate a block of memory.
*
* Parameters:
* - pThis = Base interface pointer.
* - pv = Pointer to the memory block to test. If this parameter is NULL, -1 is returned.
*
* Returns:
* - 1 = If the memory block was allocated by this allocator.
* - 0 = If the memory block was not allocated by this allocator.
* - -1 = If this method cannot determine whether the allocator allocated the memory block.
*/
SEG_INIT_CODE static INT32 init_heap_DidAlloc(IMalloc *pThis, PVOID pv)
{
register PCHAR p = (PCHAR)pv;
if (!pv)
return -1; /* not our business */
return ((p >= g_pInitHeapBlock) && (p < g_pInitHeapBlock + SIZE_INIT_HEAP)) ? 1 : 0;
}
/*
* Frees a previously allocated block of memory.
*
* Parameters:
* - pThis = Base interface pointer.
* - pv = Pointer to the memory block to be freed. If this parameter is NULL, this method has no effect.
*
* Returns:
* Nothing.
*
* Side effects:
* After this call, the memory pointed to by pv is invalid and should not be used.
*/
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 */
if (p + p->data.cblk == q->data.pNextFree)
{
/* coalesce block with next (free) block */
p->data.cblk += q->data.pNextFree->data.cblk;
p->data.pNextFree = q->data.pNextFree->data.pNextFree;
}
else
p->data.pNextFree = q->data.pNextFree; /* chain to next free block */
if (q + q->data.cblk == p)
{
/* coalesce free block with previous (free) block */
q->data.cblk += p->data.cblk;
q->data.pNextFree = p->data.pNextFree;
}
else
q->data.pNextFree = p; /* chain to previous free block */
pih->pblkLastAlloc = q;
pih->cbAlloc -= (nBlocks * sizeof(BLOCK));
}
/*
* Changes the size of a previously allocated block.
*
* Parameters:
* - pThis = Base interface pointer.
* - pv = Pointer to the block of memory to be reallocated. If this parameter is NULL, a block of memory
* of size cb is allocated and returned.
* - cb = The new size of the memory block to be reallocated, in bytes. If this parameter is 0 and pv is
* not NULL, the block of memory pointed to by pv is freed and NULL is returned.
*
* Returns:
* If pv is not NULL and cb is 0, NULL is always returned. Otherwise, NULL is returned if the block of memory
* could not be reallocated, or the pointer to the reallocated block of memory is returned.
*/
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 */
if (!pv)
return init_heap_Alloc(pThis, cb);
if (cb == 0)
{
init_heap_Free(pThis, pv);
return NULL;
}
if (init_heap_DidAlloc(pThis, pv) != 1)
return NULL; /* not our business */
p = ((PBLOCK)pv) - 1;
nBlocksNew = 1 + (cb + sizeof(BLOCK) - 1) / sizeof(BLOCK);
if (nBlocksNew == p->data.cblk)
return pv; /* nothing to do! */
if (nBlocksNew < p->data.cblk)
{ /* shrinking block - chop block in middle and free the upper end */
pNext = p + nBlocksNew;
pNext->data.cblk = p->data.cblk - nBlocksNew;
p->data.cblk = nBlocksNew;
init_heap_Free(pThis, (PVOID)(pNext + 1)); /* adjusts cbAlloc */
return pv;
}
/* see if next block is free so we can expand in place */
nBlocksExtra = nBlocksNew - p->data.cblk;
pNext = p + p->data.cblk;
qp = pih->pblkLastAlloc;
for (q = qp->data.pNextFree; ; qp = q, q = q->data.pNextFree)
{
if (q == pNext)
{
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;
}
else
{ /* 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)); /* also fixes cbAlloc */
}
p->data.cblk = nBlocksNew;
if (pih->cbAlloc > pih->cbAllocHiWat)
pih->cbAllocHiWat = pih->cbAlloc;
return pv;
}
if (q == pih->pblkLastAlloc)
break; /* not found */
}
/* 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;
}
/*
* Returns the size of a previously-allocated block of memory.
*
* Parameters:
* - pThis = Base interface pointer.
* - pv = Pointer to the block of memory.
*
* Returns:
* The size of the allocated block of memory in bytes, which may be greater than the size requested when
* it was allocated.
*/
SEG_INIT_CODE static SIZE_T init_heap_GetSize(IMalloc *pThis, PVOID pv)
{
register PBLOCK p;
if (init_heap_DidAlloc(pThis, pv) != 1)
return (SIZE_T)(-1); /* not our business */
p = ((PBLOCK)pv) - 1;
return (p->data.cblk - 1) * sizeof(BLOCK);
}
static const SEG_INIT_RODATA struct IMallocVTable vtblInitHeap =
{
.QueryInterface = ObjHlpStandardQueryInterface_IMalloc,
.AddRef = ObjHlpStaticAddRefRelease,
.Release = ObjHlpStaticAddRefRelease,
.Alloc = init_heap_Alloc,
.Realloc = init_heap_Realloc,
.Free = init_heap_Free,
.GetSize = init_heap_GetSize,
.DidAlloc = init_heap_DidAlloc,
.HeapMinimize = (void (*)(IMalloc *))ObjHlpDoNothingReturnVoid
};
/*
* Returns a reference to the initial heap.
*
* Parameters:
* None.
*
* Returns:
* A reference to the initial heap, in the form of a pointer to its IMalloc interface.
*/
SEG_INIT_CODE IMalloc *_MmGetInitHeap(void)
{
static SEG_INIT_DATA INITHEAP initheap = { .pblkLastAlloc = NULL };
register PBLOCK p;
if (!(initheap.pblkLastAlloc))
{ /* initialize fields of initheap */
initheap.hdr.pVTable = &vtblInitHeap;
initheap.pblkLastAlloc = initheap.blkBase.data.pNextFree = &(initheap.blkBase);
initheap.blkBase.data.cblk = 0;
/* add g_pInitHeapBlock as the free block in the heap */
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);
}

193
kernel/mm/kernel-mm.ldi Normal file
View File

@@ -0,0 +1,193 @@
/*
* 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.
*/
/* Copied from default linker script for relocatable linking under ARM & modified */
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
OUTPUT_ARCH(arm)
SECTIONS
{
/* Read-only sections, merged into text segment: */
.interp 0 : { *(.interp) }
.note.gnu.build-id : { *(.note.gnu.build-id) }
.hash 0 : { *(.hash) }
.gnu.hash 0 : { *(.gnu.hash) }
.dynsym 0 : { *(.dynsym) }
.dynstr 0 : { *(.dynstr) }
.gnu.version 0 : { *(.gnu.version) }
.gnu.version_d 0: { *(.gnu.version_d) }
.gnu.version_r 0: { *(.gnu.version_r) }
.rel.init 0 : { *(.rel.init) }
.rela.init 0 : { *(.rela.init) }
.rel.text 0 : { *(.rel.text) }
.rela.text 0 : { *(.rela.text) }
.rel.fini 0 : { *(.rel.fini) }
.rela.fini 0 : { *(.rela.fini) }
.rel.rodata 0 : { *(.rel.rodata) }
.rela.rodata 0 : { *(.rela.rodata) }
.rel.data.rel.ro 0 : { *(.rel.data.rel.ro) }
.rela.data.rel.ro 0 : { *(.rela.data.rel.ro) }
.rel.data 0 : { *(.rel.data) }
.rela.data 0 : { *(.rela.data) }
.rel.tdata 0 : { *(.rel.tdata) }
.rela.tdata 0 : { *(.rela.tdata) }
.rel.tbss 0 : { *(.rel.tbss) }
.rela.tbss 0 : { *(.rela.tbss) }
.rel.ctors 0 : { *(.rel.ctors) }
.rela.ctors 0 : { *(.rela.ctors) }
.rel.dtors 0 : { *(.rel.dtors) }
.rela.dtors 0 : { *(.rela.dtors) }
.rel.got 0 : { *(.rel.got) }
.rela.got 0 : { *(.rela.got) }
.rel.bss 0 : { *(.rel.bss) }
.rela.bss 0 : { *(.rela.bss) }
.rel.iplt 0 :
{
*(.rel.iplt)
}
.rela.iplt 0 :
{
*(.rela.iplt)
}
.rel.plt 0 :
{
*(.rel.plt)
}
.rela.plt 0 :
{
*(.rela.plt)
}
.init 0 :
{
KEEP (*(.init))
} =0
.plt 0 : { *(.plt) }
.iplt 0 : { *(.iplt) }
.text 0 :
{
*(.text .stub)
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
} =0
.init.text 0 : { *(.init.text) }
.fini 0 :
{
KEEP (*(.fini))
} =0
.rodata 0 : { *(.rodata) }
.rodata1 0 : { *(.rodata1) }
.init.rodata 0 : { *(.init.rodata) }
.ARM.extab 0 : { *(.ARM.extab) }
.ARM.exidx 0 : { *(.ARM.exidx) }
.eh_frame_hdr : { *(.eh_frame_hdr) }
.eh_frame 0 : ONLY_IF_RO { KEEP (*(.eh_frame)) }
.gcc_except_table 0 : ONLY_IF_RO { *(.gcc_except_table
.gcc_except_table.*) }
/* These sections are generated by the Sun/Oracle C++ compiler. */
.exception_ranges 0 : ONLY_IF_RO { *(.exception_ranges
.exception_ranges*) }
/* Adjust the address for the data segment. We want to adjust up to
the same address within the page on the next page up. */
/* Exception handling */
.eh_frame 0 : ONLY_IF_RW { KEEP (*(.eh_frame)) }
.gcc_except_table 0 : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
.exception_ranges 0 : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) }
/* Thread Local Storage sections */
.tdata 0 : { *(.tdata) }
.tbss 0 : { *(.tbss) }
.preinit_array 0 :
{
KEEP (*(.preinit_array))
}
.jcr 0 : { KEEP (*(.jcr)) }
.dynamic 0 : { *(.dynamic) }
.got 0 : { *(.got.plt) *(.igot.plt) *(.got) *(.igot) }
.data 0 :
{
*(.data)
}
.data1 0 : { *(.data1) }
.init.data 0 : { *(.init.data) }
.bss 0 :
{
*(.dynbss)
*(.bss)
*(COMMON)
/* Align here to ensure that the .bss section occupies space up to
_end. Align after .bss to ensure correct alignment even if the
.bss section disappears because there are no input sections.
FIXME: Why do we need it? When there is no .bss section, we don't
pad the .data section. */
}
.init.bss 0 : { *(.init.bss) }
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
/* DWARF 3 */
.debug_pubtypes 0 : { *(.debug_pubtypes) }
.debug_ranges 0 : { *(.debug_ranges) }
.stack 0 :
{
*(.stack)
}
.ARM.attributes 0 : { KEEP (*(.ARM.attributes)) KEEP (*(.gnu.attributes)) }
.note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) }
}

326
kernel/mm/kernel_space.c Normal file
View File

@@ -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 <comrogue/types.h>
#include <comrogue/allocator.h>
#include <comrogue/internals/memmgr.h>
#include <comrogue/internals/rbtree.h>
#include <comrogue/internals/layout.h>
#include <comrogue/internals/mmu.h>
#include <comrogue/internals/seg.h>
#include <comrogue/internals/startup.h>
#include <comrogue/internals/trace.h>
#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);
}

56
kernel/mm/memmgr.c Normal file
View File

@@ -0,0 +1,56 @@
/*
* 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 <comrogue/types.h>
#include <comrogue/objectbase.h>
#include <comrogue/allocator.h>
#include <comrogue/internals/seg.h>
#include <comrogue/internals/memmgr.h>
#include <comrogue/internals/startup.h>
/*---------------------
* Initialization code
*---------------------
*/
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)
{
IMalloc *pmInitHeap = _MmGetInitHeap();
_MmInitKernelSpace(pstartup, pmInitHeap);
_MmInitVMMap(pstartup, pmInitHeap);
_MmInitPageAlloc(pstartup);
IUnknown_Release(pmInitHeap);
}

398
kernel/mm/pagealloc.c Normal file
View File

@@ -0,0 +1,398 @@
/*
* 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 <comrogue/types.h>
#include <comrogue/scode.h>
#include <comrogue/str.h>
#include <comrogue/internals/seg.h>
#include <comrogue/internals/mmu.h>
#include <comrogue/internals/memmgr.h>
#include <comrogue/internals/startup.h>
#include <comrogue/internals/trace.h>
#ifdef THIS_FILE
#undef THIS_FILE
DECLARE_THIS_FILE
#endif
/* Lists we keep track of various pages on. */
typedef struct tagPAGELIST {
UINT32 ndxLast; /* index of last page in list */
UINT32 cpg; /* count of pages in list */
} PAGELIST, *PPAGELIST;
/* The Master Page Database */
static PMPDB g_pMasterPageDB = NULL;
static UINT32 g_cpgMaster = 0;
/* Individual page lists. */
static PAGELIST g_pglFree = { 0, 0 }; /* pages that are free */
static PAGELIST g_pglZeroed = { 0, 0 }; /* pages that are free and zeroed */
//static PAGELIST g_pglStandby = { 0, 0 }; /* pages removed but "in transition" */
//static PAGELIST g_pglModified = { 0, 0 }; /* pages removed but "in transition" and modified */
//static PAGELIST g_pglBad = { 0, 0 }; /* bad pages */
SEG_INIT_DATA static PAGELIST g_pglInit = { 0, 0 }; /* pages to be freed after initialization */
static KERNADDR g_kaZero = 0; /* kernel address where we map a page to zero it */
/*
* Zeroes a page of memory by index.
*
* Parameters:
* - ndxPage = Index of the page to be zeroed.
*
* Returns:
* Nothing.
*
* Side effects:
* Specified page is zeroed. TTB temporarily modified to map and unmap the page in memory.
*/
static void zero_page(UINT32 ndxPage)
{
HRESULT hr = MmMapPages(NULL, mmPageIndex2PA(ndxPage), g_kaZero, 1, TTBPGTBL_ALWAYS,
PGTBLSM_ALWAYS|PGTBLSM_AP01|PGTBLSM_XN, PGAUX_NOTPAGE);
ASSERT(SUCCEEDED(hr));
if (SUCCEEDED(hr))
{
StrSetMem(g_kaZero, 0, SYS_PAGE_SIZE);
VERIFY(SUCCEEDED(MmDemapPages(NULL, g_kaZero, 1)));
}
}
/*
* Sets the page table entry physical address pointer and the section-mapped flag for a given page.
*
* Parameters:
* - ndxPage = Index of the page to set the PTE and section flag for.
* - paPTE = Physical address of the page table entry that points to this page.
* - bIsSection = If TRUE, paPTE is actually the physical address of the TTB section entry that points
* to this page.
*
* Returns:
* Nothing.
*
* Side effects:
* Updates the MPDB entry indicated by ndxPage.
*/
static void set_pte_address(UINT32 ndxPage, PHYSADDR paPTE, BOOL bIsSection)
{
g_pMasterPageDB[ndxPage].d.paPTE = paPTE;
g_pMasterPageDB[ndxPage].d.sectionmap = (bIsSection ? 1 : 0);
}
/*
* Finds the given page's predecessor in a circular list.
*
* Parameters:
* - ndxPage = Index of the page to find the predecessor of. Assumes that the page is part of a circular list.
*
* Returns:
* Index of the page's predecessor in the circular list.
*/
static inline UINT32 find_predecessor(UINT32 ndxPage)
{
register UINT32 i = ndxPage; /* search page index */
while (g_pMasterPageDB[i].d.next != ndxPage)
i = g_pMasterPageDB[i].d.next;
return i;
}
/*
* Unchains the given page from the circular list it's in.
*
* Parameters:
* - ndxPage = Index of the page to be unchained from the list.
* - ndxStartForScan = Index of the page to start scanning for the ndxPage page at. Assumes that this page is
* part of a circular list.
*
* Returns:
* TRUE if the page was successfully unchained, FALSE if not.
*
* Side effects:
* Entries in the MPDB may have their "next" pointer modified.
*/
static BOOL unchain_page(UINT32 ndxPage, UINT32 ndxStartForScan)
{
register UINT32 i = ndxStartForScan; /* search page index */
do
{
if (g_pMasterPageDB[i].d.next == ndxPage)
{
g_pMasterPageDB[i].d.next = g_pMasterPageDB[ndxPage].d.next;
return TRUE;
}
i = g_pMasterPageDB[i].d.next;
} while (i != ndxStartForScan);
return FALSE;
}
/*
* Removes a page from a list.
*
* Parameters:
* - ppgl = Pointer to page list to remove the page from.
* - ndxPage = Index of the page to be removed from the list.
*
* Returns:
* Nothing.
*
* Side effects:
* Modifies fields of the page list, and possibly links in the MPDB.
*/
static void remove_from_list(PPAGELIST ppgl, UINT32 ndxPage)
{
if (ppgl->ndxLast == ndxPage)
ppgl->ndxLast = find_predecessor(ndxPage);
VERIFY(unchain_page(ndxPage, ppgl->ndxLast));
if (--ppgl->cpg == 0)
ppgl->ndxLast = 0;
}
/*
* Adds a page to the end of a list.
*
* Parameters:
* - ppgl = Pointer to page list to add the page to.
* - ndxPage = Index of the page to be added to the list.
*
* Returns:
* Nothing.
*
* Side effects:
* Modifies fields of the page list, and possibly links in the MPDB.
*/
static void add_to_list(PPAGELIST ppgl, UINT32 ndxPage)
{
if (ppgl->cpg++ == 0)
g_pMasterPageDB[ndxPage].d.next = ndxPage;
else
{
g_pMasterPageDB[ndxPage].d.next = g_pMasterPageDB[ppgl->ndxLast].d.next;
g_pMasterPageDB[ppgl->ndxLast].d.next = ndxPage;
}
ppgl->ndxLast = ndxPage;
}
/*
* Allocates a page off one of our lists.
*
* Parameters:
* - uiFlags = Flags for the page allocation.
*
* Returns:
* INVALID_PAGE if the page could not be allocated, otherwise the index of the allocated page.
*/
static UINT32 allocate_page(UINT32 uiFlags)
{
UINT32 rc;
PPAGELIST ppgl = NULL;
BOOL bZero = FALSE;
if (uiFlags & PGALLOC_ZERO)
{ /* try zeroed list first, then free (but need to zero afterwards) */
if (g_pglZeroed.cpg > 0)
ppgl = &g_pglZeroed;
else if (g_pglFree.cpg > 0)
{
ppgl = &g_pglFree;
bZero = TRUE;
}
}
else
{ /* try free list first, then zeroed */
if (g_pglFree.cpg > 0)
ppgl = &g_pglFree;
else if (g_pglZeroed.cpg > 0)
ppgl = &g_pglZeroed;
}
/* TODO: apply additional strategy if we don't yet have a page list */
if (!ppgl)
return INVALID_PAGE;
rc = g_pMasterPageDB[ppgl->ndxLast].d.next; /* take first page on list */
remove_from_list(ppgl, rc);
if (bZero)
zero_page(rc);
return rc;
}
/*
* Allocate a memory page and return its physical address.
*
* Parameters:
* - uiFlags = Flags for page allocation.
* - tag = Tag to give the newly-allocated page.
* - subtag = Subtag to give the newly-allocated page.
* - ppaNewPage = Pointer to location that will receive the physical address of the new page.
*
* Returns:
* Standard HRESULT success/failure indication.
*/
HRESULT MmAllocatePage(UINT32 uiFlags, UINT32 tag, UINT32 subtag, PPHYSADDR ppaNewPage)
{
register UINT32 ndxPage; /* index of page to be allocated */
if (!ppaNewPage)
return E_POINTER;
ndxPage = allocate_page(uiFlags);
if (ndxPage == INVALID_PAGE)
return E_OUTOFMEMORY;
g_pMasterPageDB[ndxPage].d.tag = tag;
g_pMasterPageDB[ndxPage].d.subtag = subtag;
*ppaNewPage = mmPageIndex2PA(ndxPage);
return S_OK;
}
/*
* Frees up a previously-allocated memory page.
*
* Parameters:
* - paPage = Physical address of the page to be freed.
* - tag = Tag value we expect the page to have.
* - subtag = Subtag value we expect the page to have.
*
* Returns:
* Standard HRESULT success/failure indication.
*/
HRESULT MmFreePage(PHYSADDR paPage, UINT32 tag, UINT32 subtag)
{
register UINT32 ndxPage = mmPA2PageIndex(paPage);
if ((g_pMasterPageDB[ndxPage].d.tag != tag) || (g_pMasterPageDB[ndxPage].d.subtag != subtag))
return MEMMGR_E_BADTAGS;
g_pMasterPageDB[ndxPage].d.tag = MPDBTAG_NORMAL;
g_pMasterPageDB[ndxPage].d.subtag = 0;
add_to_list(&g_pglFree, ndxPage);
return S_OK;
}
/*
* Builds a "chain" of linked pages in the MPDB, setting their tags to known values, and optionally linking
* them into a page list.
*
* Parameters:
* - ndxFirstPage = First page of the chain to be built.
* - cpg = Count of pages to include in the chain.
* - tag = Tag value to give the pages in the chain.
* - subtag = Subtag value to give the pages in the chain.
* - ppglAddTo = Pointer to the page list we want to add the new page chain to. May be NULL.
*
* Returns:
* The index of the first page following the new chain that was built, i.e. the next start point for a chain.
*
* Side effects:
* Modifies the MPDB accordingly.
*/
SEG_INIT_CODE static UINT32 build_page_chain(UINT32 ndxFirstPage, UINT32 cpg, unsigned tag, unsigned subtag,
PPAGELIST ppglAddTo)
{
register UINT32 i; /* loop counter */
if (cpg == 0)
return ndxFirstPage; /* do nothing */
for (i=0; i < cpg; i++)
{
g_pMasterPageDB[ndxFirstPage + i].d.tag = tag;
g_pMasterPageDB[ndxFirstPage + i].d.subtag = subtag;
if (i<(cpg - 1))
g_pMasterPageDB[ndxFirstPage + i].d.next = ndxFirstPage + i + 1;
}
if (ppglAddTo)
{
if (ppglAddTo->cpg == 0)
/* link as a circular list */
g_pMasterPageDB[ndxFirstPage + cpg - 1].d.next = ndxFirstPage;
else
{
/* link into existing circular list */
g_pMasterPageDB[ndxFirstPage + cpg - 1].d.next = g_pMasterPageDB[ppglAddTo->ndxLast].d.next;
g_pMasterPageDB[ppglAddTo->ndxLast].d.next = ndxFirstPage;
}
ppglAddTo->ndxLast = ndxFirstPage + cpg - 1;
ppglAddTo->cpg += cpg;
}
return ndxFirstPage + cpg;
}
/* External references to symbols defined by the linker script. */
extern char cpgPrestartTotal, cpgLibraryCode, cpgKernelCode, cpgKernelData, cpgKernelBss, cpgInitCode,
cpgInitData, cpgInitBss;
/* secondary init function in the VM mapper */
extern void _MmInitPTEMappings(PFNSETPTEADDR pfnSetPTEAddr);
/*
* Initializes the page allocator and the Master Page Database.
*
* Parameters:
* - pstartup = Pointer to startup information data structure.
*
* Returns:
* Nothing.
*
* Side effects:
* Local variables and the Master Page Database initialized.
*/
SEG_INIT_CODE void _MmInitPageAlloc(PSTARTUP_INFO pstartup)
{
register UINT32 i; /* loop counter */
/* Setup the master data pointers and zero the MPDB. */
g_pMasterPageDB = (PMPDB)(pstartup->kaMPDB);
g_cpgMaster = pstartup->cpgSystemTotal;
StrSetMem(g_pMasterPageDB, 0, pstartup->cpgMPDB * SYS_PAGE_SIZE);
/* Classify all pages in the system and add them to lists. */
i = build_page_chain(0, 1, MPDBTAG_SYSTEM, MPDBSYS_ZEROPAGE, NULL);
i = build_page_chain(i, (INT32)(&cpgPrestartTotal) - 1, MPDBTAG_NORMAL, 0, &g_pglFree);
i = build_page_chain(i, (INT32)(&cpgLibraryCode), MPDBTAG_SYSTEM, MPDBSYS_LIBCODE, NULL);
i = build_page_chain(i, (INT32)(&cpgKernelCode), MPDBTAG_SYSTEM, MPDBSYS_KCODE, NULL);
i = build_page_chain(i, (INT32)(&cpgKernelData) + (INT32)(&cpgKernelBss), MPDBTAG_SYSTEM, MPDBSYS_KDATA, NULL);
i = build_page_chain(i, (INT32)(&cpgInitCode) + (INT32)(&cpgInitData) + (INT32)(&cpgInitBss), MPDBTAG_SYSTEM,
MPDBSYS_INIT, &g_pglInit);
i = build_page_chain(i, pstartup->cpgTTBGap, MPDBTAG_NORMAL, 0, &g_pglFree);
i = build_page_chain(i, SYS_TTB1_SIZE / SYS_PAGE_SIZE, MPDBTAG_SYSTEM, MPDBSYS_TTB, NULL);
i = build_page_chain(i, SYS_TTB1_SIZE / SYS_PAGE_SIZE, MPDBTAG_SYSTEM, MPDBSYS_TTBAUX, NULL);
i = build_page_chain(i, pstartup->cpgMPDB, MPDBTAG_SYSTEM, MPDBSYS_MPDB, NULL);
i = build_page_chain(i, pstartup->cpgPageTables, MPDBTAG_SYSTEM, MPDBSYS_PGTBL, NULL);
i = build_page_chain(i, pstartup->cpgSystemAvail - i, MPDBTAG_NORMAL, 0, &g_pglFree);
i = build_page_chain(i, pstartup->cpgSystemTotal - pstartup->cpgSystemAvail, MPDBTAG_SYSTEM, MPDBSYS_GPU, NULL);
ASSERT(i == g_cpgMaster);
/* Initialize the PTE mappings in the MPDB, and the VM mapper's hook function by which it keeps this up to date. */
_MmInitPTEMappings(set_pte_address);
/* Allocate the address we map a page to to zero it. */
g_kaZero = _MmAllocKernelAddr(1);
}

1162
kernel/mm/vmmap.c Normal file

File diff suppressed because it is too large Load Diff