int _pg_dir_vpxlate(pg_dir_t*, u32_t, u32_t*);
int _pg_dir_pagesize(pg_dir_t*, u32_t, u32_t*);
int _pg_dir_xfer(pg_dir_t*, void*, pg_dir_t*, void*, u32_t);
+static int _pg_dir_heap_map(pg_dir_t*, u32_t);
static void* _phys_alloc(u32_t size, u32_t align)
{
return(ret_val);
}
+static int _pg_dir_heap_map(pg_dir_t *pd, u32_t heap_size)
+{
+ /*
+ * The pg_dir_heap_map() function is used to add a heap segment
+ * to a page dir that does not already have one.
+ *
+ * It should work as follows:
+ * 1. Make sure the page dir doesn't already have a heap
+ * 2. Find the highest segment that is not a stack segment
+ * 3. Add the heap segment right after the segement located in 2
+ */
+
+ u32_t heap_start;
+ int ret_val;
+ int i;
+
+ /* FIXME: Make sure heap_size is aligned to the page directory's page size */
+ /* FIXME: Set heap_size to the page directory's page size if set to zero */
+
+ if(!pd) {
+ ret_val = -EINVAL;
+ goto gtfo;
+ }
+
+ /* FIXME: Lock the page directory */
+
+ for(i = 0, heap_start = 0, ret_val = 0;
+ i < CONFIG_PAGING_DIR_MAXREGIONS && ret_val > 0;
+ i++) {
+ struct region *reg;
+ u32_t limit;
+
+ reg = pd->pd_regions[i];
+
+ switch(reg->reg_type) {
+ case REGION_HEAP:
+ /* the page directory apparently already contains a heap */
+ ret_val = -EALREADY;
+ break;
+
+ case REGION_STACK:
+ case REGION_KSTACK:
+ /*
+ * Ignore stack segments in the calculation because they are supposed to
+ * be at the end of the address space, and not in front of the heap.
+ */
+ break;
+
+ case REGION_TEXT:
+ case REGION_BSS:
+ case REGION_DATA:
+ case REGION_RODATA:
+ /*
+ * Calculate the address of the first byte after this region. It *should*
+ * already be aligned, but nevertheless align it again. 念の為.
+ */
+ limit = ALIGN((u32_t)reg->reg_base + reg->reg_size,
+ reg->reg_pgsize);
+
+ if(limit > heap_start) {
+ heap_start = limit;
+ }
+ break;
+
+ default:
+ /* this should absolutely not have happened */
+ ret_val = -EBADFD;
+ break;
+ }
+ }
+
+ if(!ret_val) {
+ /* we found a place to allocate the heap segment */
+
+ if(heap_start) {
+ u32_t attrs;
+
+ /* the heap shouldn't be executable, right? */
+ attrs = PAGE_ATTR_PRESENT | PAGE_ATTR_WRITABLE |
+ PAGE_ATTR_USER | PAGE_ATTR_NO_EXEC;
+
+ /* allocate page frames from wherever */
+ ret_val = pg_dir_map(pd, NULL, (void*)heap_start,
+ heap_size, attrs);
+
+ if(!ret_val) {
+ /* add a struct region so the memory is accounted for */
+ ret_val = _pg_dir_add_region(pd, (void*)heap_start, heap_size,
+ REGION_HEAP, attrs, REGION_PRIV);
+
+ if(ret_val < 0) {
+ /* oops - ran out of kernel heap space */
+ pg_dir_unmap(pd, (void*)heap_start, heap_size);
+ }
+ } else {
+ /* Failed to map the heap. Wat do? */
+ ret_val = -ENOMEM;
+ }
+ } else {
+ /* the page directory doesn't appear to contain any regions? */
+ ret_val = -EBADFD;
+ }
+ }
+
+gtfo:
+ return(ret_val);
+}
+
int _clone_kernel_region(pg_dir_t *kdir, region_t *reg, void *data)
{
pg_dir_t *dir;
{
return(pd->pd_base);
}
+
+void* pg_dir_get_heap(pg_dir_t *pd)
+{
+ void *ret_val;
+ int i;
+
+ for(ret_val = NULL, i = 0; i < CONFIG_PAGING_DIR_MAXREGIONS; i++) {
+ if(pd->pd_regions[i]->reg_type == REGION_HEAP) {
+ ret_val = pd->pd_regions[i]->reg_base;
+ break;
+ }
+ }
+
+ return(ret_val);
+}
+
+void* pg_dir_sbrk(pg_dir_t *pd, i32_t increment)
+{
+ struct region *heap;
+ void *ret_val;
+ int i;
+
+ /* special case where the heap is not touched */
+ if(!increment) {
+ for(i = 0, ret_val = NULL; i < CONFIG_PAGING_DIR_MAXREGIONS; i++) {
+ if(pd->pd_regions[i]->reg_type == REGION_HEAP) {
+ ret_val = pd->pd_regions[i]->reg_base +
+ pd->pd_regions[i]->reg_size;
+ break;
+ }
+ }
+
+ return(ret_val);
+ }
+
+ for(heap = NULL, i = 0; i < CONFIG_PAGING_DIR_MAXREGIONS; i++) {
+ if(pd->pd_regions[i]->reg_type == REGION_HEAP) {
+ heap = pd->pd_regions[i];
+ break;
+ }
+ }
+
+ if(!heap) {
+ u32_t heap_size;
+ int err;
+
+ heap_size = ALIGN(increment, PAGE_SIZE);
+
+ err = _pg_dir_heap_map(pd, heap_size);
+
+ if(!err) {
+ /* the new heap has been created with the correct size */
+ return(pg_dir_sbrk(pd, 0));
+ } else {
+ /* could not map a heap - how do we get the error to the caller? */
+ return(NULL);
+ }
+ } else {
+ u32_t nbytes;
+ int err;
+
+ if(increment > 0) {
+ /* round up to the page size */
+ nbytes = ALIGN(increment, heap->reg_pgsize);
+
+ err = pg_dir_map(pd, 0, heap->reg_base + heap->reg_size, nbytes, heap->reg_attrs);
+
+ if(!err) {
+ /* successfully mapped pages - keep track of the increased heap size */
+ heap->reg_size += nbytes;
+ }
+ } else { /* increment < 0 */
+ /* request to reduce the heap size, round down */
+ nbytes = (u32_t)-increment & ~(heap->reg_pgsize - 1);
+
+ /* value may be zero, e.g. if the caller wants to free less than a page */
+ if(nbytes) {
+ /* remove nbytes of space at the end of the region */
+ err = pg_dir_unmap(pd, heap->reg_base + heap->reg_size - nbytes, nbytes);
+
+ if(!err) {
+ heap->reg_size -= nbytes;
+ }
+ }
+ }
+
+ /* FIXME: We need to somehow set errno if the mapping failed */
+ }
+
+ /* either way return the new/current sbrk value */
+ ret_val = heap->reg_base + heap->reg_size;
+
+ return(ret_val);
+}
int pg_dir_create(pg_dir_t**);
+/*
+ * pg_dir_map() - Map page frames into a page directory
+ *
+ * SYNOPSIS
+ * int pg_dir_map(pg_dir_t* pd, const void *paddr, const void *vaddr,
+ * const u32_t bytes, const u32_t attrs);
+ *
+ * DESCRIPTION
+ * The pg_dir_map() function attempts to map page frames (physical pages) into
+ * the page directory pointed to by `pd'. It will attempt to allocate the page
+ * frames pointed to by `paddr', or if `paddr' is NULL it will use whatever is
+ * available. The virtual address where the frames will be mapped has to be
+ * provided by the caller in `vaddr'. Unlike `paddr', `vaddr' may not be NULL.
+ * The number of pages that will be mapped depends on the page directory. If
+ * PAE-mode paging is employed, pg_dir_map() will attempt to map pages of the
+ * largest-possible size, meaning that it will attempt to map 4M pages if the
+ * alignment of the addresses and the page directory's page size permitts.
+ * Any pages that have been mapped into the page directory will have their
+ * page attributes set according to the value passed in `attrs'.
+ * The PAGE_ATTR_PRESENT will be set regardless of the value in `attrs'.
+ *
+ * RETURN VALUE
+ * 0 The frames have been successfully mapped
+ * -EALREADY The virtual addresses are already mapped
+ * -ENOMEM Not enough unused page frames to be mapped
+ * -ENOSYS The function is not implemented for this paging mode
+ * -EFAULT Could not determine the paging mode used by the page directory
+ */
int pg_dir_map(pg_dir_t*, const void*, const void*, const u32_t, const u32_t);
int pg_dir_map_region(pg_dir_t*, pg_dir_t*, region_t*);
int pg_dir_clone_region(pg_dir_t*, pg_dir_t*, region_t*);
int pg_dir_unmap(pg_dir_t*, const void*, const u32_t);
+void* pg_dir_get_heap(pg_dir_t*);
void* pg_dir_get_pdbr(pg_dir_t*);
int _pg_dir_vpxlate(pg_dir_t*, u32_t, u32_t*);
void* pg_dir_get_kstack(pg_dir_t*);
void* pg_dir_get_ustack(pg_dir_t*);
+void* pg_dir_sbrk(pg_dir_t*, i32_t);
int pg_dir_foreach_region(pg_dir_t*, int(*)(pg_dir_t*, struct region*, void*), void*);
int pg_dir_memcpy(pg_dir_t*, void*, pg_dir_t*, void*, u32_t);