moved memory manager sources into their own directory to consolidate everything
locally
This commit is contained in:
44
kernel/mm/Makefile
Normal file
44
kernel/mm/Makefile
Normal 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
324
kernel/mm/init_heap.c
Normal 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
193
kernel/mm/kernel-mm.ldi
Normal 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
326
kernel/mm/kernel_space.c
Normal 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
56
kernel/mm/memmgr.c
Normal 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
398
kernel/mm/pagealloc.c
Normal 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
1162
kernel/mm/vmmap.c
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user