From f86563aa4b8766959e7b2d1bee1829c431ac1acb Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Tue, 2 Sep 2014 08:05:11 -0600 Subject: sbrk() need to initialized the memory manager on the first call --- nuttx/arch/arm/src/armv7-a/arm_pgalloc.c | 39 ++++++++++++++++++++++---------- nuttx/include/nuttx/arch.h | 17 +++++++++++++- nuttx/mm/mm_sbrk.c | 36 ++++++++++++++++++++++------- nuttx/sched/init/os_start.c | 4 ++-- 4 files changed, 73 insertions(+), 23 deletions(-) diff --git a/nuttx/arch/arm/src/armv7-a/arm_pgalloc.c b/nuttx/arch/arm/src/armv7-a/arm_pgalloc.c index e55e92c25..e58c20cd0 100644 --- a/nuttx/arch/arm/src/armv7-a/arm_pgalloc.c +++ b/nuttx/arch/arm/src/armv7-a/arm_pgalloc.c @@ -186,9 +186,24 @@ static int get_pgtable(FAR group_addrenv_t *addrenv, uintptr_t vaddr) * Therefore, it is a system interface and follows a different naming * convention. * + * Input Parameters: + * brkaddr - The heap break address. The next page will be allocated and + * mapped to this address. Must be page aligned. If the memory manager + * has not yet been initialized and this is the first block requested for + * the heap, then brkaddr should be zero. pgalloc will then assigned the + * well-known virtual address of the beginning of the heap. + * npages - The number of pages to allocate and map. Mapping of pages + * will be contiguous beginning beginning at 'brkaddr' + * + * Returned Value: + * The (virtual) base address of the mapped page will returned on success. + * Normally this will be the same as the 'brkaddr' input. However, if + * the 'brkaddr' input was zero, this will be the virtual address of the + * beginning of the heap. Zero is returned on any failure. + * ****************************************************************************/ -int pgalloc(uintptr_t vaddr, unsigned int npages) +uintptr_t pgalloc(uintptr_t brkaddr, unsigned int npages) { FAR struct tcb_s *tcb = sched_self(); FAR struct task_group_s *group; @@ -209,24 +224,24 @@ int pgalloc(uintptr_t vaddr, unsigned int npages) DEBUGASSERT((group->flags & GROUP_FLAG_ADDRENV) != 0); - /* vaddr = 0 means that no heap has yet been allocated */ + /* brkaddr = 0 means that no heap has yet been allocated */ - if (vaddr == 0) + if (brkaddr == 0) { - vaddr = CONFIG_ARCH_HEAP_VBASE; + brkaddr = CONFIG_ARCH_HEAP_VBASE; } - DEBUGASSERT(vadddr >= CONFIG_ARCH_HEAP_VBASE && vaddr < ARCH_HEAP_VEND); - DEBUGASSERT(MM_ISALIGNED(vaddr)); + DEBUGASSERT(vadddr >= CONFIG_ARCH_HEAP_VBASE && brkaddr < ARCH_HEAP_VEND); + DEBUGASSERT(MM_ISALIGNED(brkaddr)); for (; npages > 0; npages--) { /* Get the physical address of the level 2 page table */ - paddr = get_pgtable(&group->addrenv, vaddr); + paddr = get_pgtable(&group->addrenv, brkaddr); if (paddr == 0) { - return -ENOMEM; /* ENOMEM might have correct meaning for sbrk? */ + return 0; } /* Temporarily map the level 2 page table into the "scratch" virtual @@ -245,7 +260,7 @@ int pgalloc(uintptr_t vaddr, unsigned int npages) { mmu_l1_restore(ARCH_SCRATCH_VBASE, l1save); irqrestore(flags); - return -EAGAIN; /* ENOMEM has different meaning for sbrk */ + return 0; } /* The table divides a 1Mb address space up into 256 entries, each @@ -253,13 +268,13 @@ int pgalloc(uintptr_t vaddr, unsigned int npages) * related to the offset from the beginning of 1Mb region. */ - index = (vaddr & 0x000ff000) >> 12; + index = (brkaddr & 0x000ff000) >> 12; /* Map the .text region virtual address to this physical address */ DEBUGASSERT(l2table[index] == 0); l2table[index] = paddr | MMU_L2_UDATAFLAGS; - vaddr += MM_PGSIZE; + brkaddr += MM_PGSIZE; /* Make sure that the modified L2 table is flushed to physical * memory. @@ -274,7 +289,7 @@ int pgalloc(uintptr_t vaddr, unsigned int npages) irqrestore(flags); } - return OK; + return brkaddr; } #endif /* CONFIG_MM_PGALLOC && CONFIG_ARCH_USE_MMU */ diff --git a/nuttx/include/nuttx/arch.h b/nuttx/include/nuttx/arch.h index f60ec6d8d..2a27bf6d8 100644 --- a/nuttx/include/nuttx/arch.h +++ b/nuttx/include/nuttx/arch.h @@ -678,10 +678,25 @@ void up_allocate_pgheap(FAR void **heap_start, size_t *heap_size); * Therefore, it is a system interface and follows a different naming * convention. * + * Input Parameters: + * brkaddr - The heap break address. The next page will be allocated and + * mapped to this address. Must be page aligned. If the memory manager + * has not yet been initialized and this is the first block requested for + * the heap, then brkaddr should be zero. pgalloc will then assigned the + * well-known virtual address of the beginning of the heap. + * npages - The number of pages to allocate and map. Mapping of pages + * will be contiguous beginning beginning at 'brkaddr' + * + * Returned Value: + * The (virtual) base address of the mapped page will returned on success. + * Normally this will be the same as the 'brkaddr' input. However, if + * the 'brkaddr' input was zero, this will be the virtual address of the + * beginning of the heap. Zero is returned on any failure. + * ****************************************************************************/ #ifdef CONFIG_ARCH_ADDRENV -int pgalloc(uintptr_t vaddr, unsigned int npages); +uintptr_t pgalloc(uintptr_t brkaddr, unsigned int npages); #endif /**************************************************************************** diff --git a/nuttx/mm/mm_sbrk.c b/nuttx/mm/mm_sbrk.c index c0c640735..f8c22b33a 100644 --- a/nuttx/mm/mm_sbrk.c +++ b/nuttx/mm/mm_sbrk.c @@ -93,9 +93,10 @@ FAR void *mm_sbrk(FAR struct mm_heap_s *heap, intptr_t incr, uintptr_t maxbreak) { uintptr_t brkaddr; + uintptr_t allocbase; unsigned int pgincr; + size_t bytesize; int err; - int ret; DEBUGASSERT(incr >= 0); if (incr < 0) @@ -104,7 +105,10 @@ FAR void *mm_sbrk(FAR struct mm_heap_s *heap, intptr_t incr, goto errout; } - /* Get the current break address (NOTE: assumes region 0) */ + /* Get the current break address (NOTE: assumes region 0). If + * the memory manager is uninitialized, mm_brkaddr() will return + * zero. + */ brkaddr = (uintptr_t)mm_brkaddr(heap, 0); if (incr > 0) @@ -122,19 +126,35 @@ FAR void *mm_sbrk(FAR struct mm_heap_s *heap, intptr_t incr, } /* Allocate the requested number of pages and map them to the - * break address. + * break address. If we provide a zero brkaddr to pgalloc(), it + * will create the first block in the correct virtual address + * space and return the start address of that block. */ - ret = pgalloc(brkaddr, pgincr); - if (ret < 0) + allocbase = pgalloc(brkaddr, pgincr); + if (allocbase == 0) { - err = -ret; + err = EAGAIN; goto errout; } - /* Extend the heap (region 0) */ + /* Has the been been initialized? brkaddr will be zero if the + * memory manager has not yet been initialized. + */ + + bytesize = pgincr << MM_PGSHIFT; + if (brkaddr != 0) + { + /* No... then initialize it now */ - mm_extend(heap, (FAR void *)brkaddr, pgincr << MM_PGSHIFT, 0); + mm_initialize(heap, (FAR void *)allocbase, bytesize); + } + else + { + /* Extend the heap (region 0) */ + + mm_extend(heap, (FAR void *)allocbase, bytesize, 0); + } } return (FAR void *)brkaddr; diff --git a/nuttx/sched/init/os_start.c b/nuttx/sched/init/os_start.c index 7879eaeec..8991cc608 100644 --- a/nuttx/sched/init/os_start.c +++ b/nuttx/sched/init/os_start.c @@ -220,7 +220,7 @@ static FAR const char g_idlename[] = "Idle Task"; /* This the IDLE idle threads argument list. */ -static char *g_idleargv[2]; +static FAR char *g_idleargv[2]; /**************************************************************************** * Private Function Prototypes @@ -321,7 +321,7 @@ void os_start(void) g_idleargv[0] = (FAR char *)g_idlename; #endif /* CONFIG_TASK_NAME_SIZE */ g_idleargv[1] = NULL; - g_idletcb.argv = &g_idleargv; + g_idletcb.argv = g_idleargv; /* Then add the idle task's TCB to the head of the ready to run list */ -- cgit v1.2.3