Switch to an array of heaps in the heap manager, and heap IDs in the allocation functions.

This commit is contained in:
Lionel Debroux 2022-07-14 18:30:37 +02:00 committed by Lionel Debroux
parent 13d9569041
commit 408fdb8db6
7 changed files with 62 additions and 110 deletions

View File

@ -515,11 +515,11 @@ bool ehci_init(int bus, int dev, int func, uintptr_t base_addr, usb_hcd_t *hcd)
if (!reset_host_controller(op_regs)) return false;
// Record the heap state to allow us to free memory.
uintptr_t initial_heap_mark = lm_heap_mark();
uintptr_t initial_heap_mark = heap_mark(HEAP_TYPE_LM_1);
// Allocate and initialise a periodic frame list. This needs to be aligned on a 4K page boundary. Some controllers
// don't support a programmable list length, so we just use the default length.
uintptr_t pfl_addr = lm_heap_alloc(EHCI_MAX_PFL_LENGTH * sizeof(uint32_t), PAGE_SIZE);
uintptr_t pfl_addr = heap_alloc(HEAP_TYPE_LM_1, EHCI_MAX_PFL_LENGTH * sizeof(uint32_t), PAGE_SIZE);
if (pfl_addr == 0) {
goto no_keyboards_found;
}
@ -530,7 +530,7 @@ bool ehci_init(int bus, int dev, int func, uintptr_t base_addr, usb_hcd_t *hcd)
}
// Allocate and initialise a workspace for this controller. This needs to be permanently mapped into virtual memory.
uintptr_t workspace_addr = lm_heap_alloc(sizeof(workspace_t), PAGE_SIZE);
uintptr_t workspace_addr = heap_alloc(HEAP_TYPE_LM_1, sizeof(workspace_t), PAGE_SIZE);
if (workspace_addr == 0) {
goto no_keyboards_found;
}
@ -684,6 +684,6 @@ bool ehci_init(int bus, int dev, int func, uintptr_t base_addr, usb_hcd_t *hcd)
return true;
no_keyboards_found:
lm_heap_rewind(initial_heap_mark);
heap_rewind(HEAP_TYPE_LM_1, initial_heap_mark);
return false;
}

View File

@ -24,8 +24,10 @@ typedef struct {
// Private Variables
//------------------------------------------------------------------------------
static heap_t lm_heap = { .segment = -1, .start = 0, .end = 0 };
static heap_t hm_heap = { .segment = -1, .start = 0, .end = 0 };
static heap_t heaps[HEAP_TYPE_LAST] = {
{ .segment = -1, .start = 0, .end = 0 },
{ .segment = -1, .start = 0, .end = 0 }
};
//------------------------------------------------------------------------------
// Private Functions
@ -36,8 +38,9 @@ static size_t num_pages(size_t size)
return (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
}
static uintptr_t heap_alloc(const heap_t *heap, size_t size, uintptr_t alignment)
uintptr_t heap_alloc(heap_type_t heap_id, size_t size, uintptr_t alignment)
{
const heap_t * heap = &heaps[heap_id];
if (heap->segment < 0) {
return 0;
}
@ -50,16 +53,18 @@ static uintptr_t heap_alloc(const heap_t *heap, size_t size, uintptr_t alignment
return addr << PAGE_SHIFT;
}
static uintptr_t heap_mark(const heap_t *heap)
uintptr_t heap_mark(heap_type_t heap_id)
{
const heap_t * heap = &heaps[heap_id];
if (heap->segment < 0) {
return 0;
}
return pm_map[heap->segment].end;
}
static void heap_rewind(const heap_t *heap, uintptr_t mark)
void heap_rewind(heap_type_t heap_id, uintptr_t mark)
{
const heap_t * heap = &heaps[heap_id];
if (heap->segment >= 0 && mark > pm_map[heap->segment].end && mark <= heap->end) {
pm_map[heap->segment].end = mark;
}
@ -86,43 +91,13 @@ void heap_init(void)
if (segment_size >= max_segment_size) {
max_segment_size = segment_size;
if (try_heap_end <= PAGE_C(1,MB)) {
lm_heap.segment = i;
lm_heap.start = try_heap_start;
lm_heap.end = try_heap_end;
heaps[HEAP_TYPE_LM_1].segment = i;
heaps[HEAP_TYPE_LM_1].start = try_heap_start;
heaps[HEAP_TYPE_LM_1].end = try_heap_end;
}
hm_heap.segment = i;
hm_heap.start = try_heap_start;
hm_heap.end = try_heap_end;
heaps[HEAP_TYPE_HM_1].segment = i;
heaps[HEAP_TYPE_HM_1].start = try_heap_start;
heaps[HEAP_TYPE_HM_1].end = try_heap_end;
}
}
}
uintptr_t lm_heap_alloc(size_t size, uintptr_t alignment)
{
return heap_alloc(&lm_heap, size, alignment);
}
uintptr_t lm_heap_mark(void)
{
return heap_mark(&lm_heap);
}
void lm_heap_rewind(uintptr_t mark)
{
heap_rewind(&lm_heap, mark);
}
uintptr_t hm_heap_alloc(size_t size, uintptr_t alignment)
{
return heap_alloc(&hm_heap, size, alignment);
}
uintptr_t hm_heap_mark(void)
{
return heap_mark(&hm_heap);
}
void hm_heap_rewind(uintptr_t mark)
{
heap_rewind(&hm_heap, mark);
}

View File

@ -16,71 +16,48 @@
#include <stddef.h>
#include <stdint.h>
typedef enum {
HEAP_TYPE_LM_1,
HEAP_TYPE_HM_1,
HEAP_TYPE_LAST
} heap_type_t;
/**
* Initialises the heaps.
*/
void heap_init(void);
/**
* Allocates a chunk of physical memory below 1MB. The allocated region will
* be at least the requested size with the requested alignment. This memory
* is always mapped to the identical address in virtual memory.
* Allocates a chunk of physical memory in the given heap. The allocated
* region will be at least the requested size with the requested alignment.
* This memory is always mapped to the identical address in virtual memory.
*
* \param size - the requested size in bytes.
* \param alignment - the requested byte alignment (must be a power of 2).
* \param size - the requested size in bytes.
* \param alignment - the requested byte alignment (must be a power of 2).
* \param heap - the heap on which this allocation shall be performed.
*
* \returns
* On success, the allocated address in physical memory. On failure, 0.
*/
uintptr_t lm_heap_alloc(size_t size, uintptr_t alignment);
uintptr_t heap_alloc(heap_type_t heap_id, size_t size, uintptr_t alignment);
/**
* Returns a value indicating the current allocation state of the low-memory
* heap. This value may be passed to lm_heap_rewind() to free any low memory
* allocated after this call.
* Returns a value indicating the current allocation state of the given
* memory heap. This value may be passed to heap_rewind() to free any
* memory from that heap allocated after this call.
*
* \returns
* An opaque value indicating the current allocation state.
*/
uintptr_t lm_heap_mark(void);
uintptr_t heap_mark(heap_type_t heap_id);
/**
* Frees any low memory allocated since the specified mark was obtained from
* a call to lm_heap_mark().
* Frees any memory allocated in the given heap since the specified mark was
* obtained from a call to heap_mark().
*
* \param mark - the mark that indicates how much memory to free.
* \param mark - the mark that indicates how much memory to free.
* \param heap - the heap on which this rewind shall be performed.
*/
void lm_heap_rewind(uintptr_t mark);
/**
* Allocates a chunk of physical memory below 4GB. The allocated region will
* be at least the requested size with the requested alignment. The caller is
* responsible for mapping it into virtual memory if required.
*
* \param size - the requested size in bytes.
* \param alignment - the requested byte alignment (must be a power of 2).
*
* \returns
* On success, the allocated address in physical memory. On failure, 0.
*/
uintptr_t hm_heap_alloc(size_t size, uintptr_t alignment);
/**
* Returns a value indicating the current allocation state of the high-memory
* heap. This value may be passed to hm_heap_rewind() to free any high memory
* allocated after this call.
*
* \returns
* An opaque value indicating the current allocation state.
*/
uintptr_t hm_heap_mark(void);
/**
* Frees any high memory allocated since the specified mark was obtained from
* a call to hm_heap_mark().
*
* \param mark - the mark that indicates how much memory to free.
*/
void hm_heap_rewind(uintptr_t mark);
void heap_rewind(heap_type_t heap_id, uintptr_t mark);
#endif // HEAP_H

View File

@ -457,10 +457,10 @@ bool ohci_init(uintptr_t base_addr, usb_hcd_t *hcd)
}
// Record the heap state to allow us to free memory.
uintptr_t initial_heap_mark = lm_heap_mark();
uintptr_t initial_heap_mark = heap_mark(HEAP_TYPE_LM_1);
// Allocate and initialise a workspace for this controller. This needs to be permanently mapped into virtual memory.
uintptr_t workspace_addr = lm_heap_alloc(sizeof(workspace_t), PAGE_SIZE);
uintptr_t workspace_addr = heap_alloc(HEAP_TYPE_LM_1, sizeof(workspace_t), PAGE_SIZE);
if (workspace_addr == 0) {
goto no_keyboards_found;
}
@ -608,6 +608,6 @@ bool ohci_init(uintptr_t base_addr, usb_hcd_t *hcd)
return true;
no_keyboards_found:
lm_heap_rewind(initial_heap_mark);
heap_rewind(HEAP_TYPE_LM_1, initial_heap_mark);
return false;
}

View File

@ -550,7 +550,7 @@ void smp_init(bool smp_enable)
// Allocate a page of low memory for AP trampoline and sync objects.
// These need to remain pinned in place during relocation.
smp_heap_page = lm_heap_alloc(PAGE_SIZE, PAGE_SIZE) >> PAGE_SHIFT;
smp_heap_page = heap_alloc(HEAP_TYPE_LM_1, PAGE_SIZE, PAGE_SIZE) >> PAGE_SHIFT;
ap_startup_addr = (uintptr_t)startup;

View File

@ -430,17 +430,17 @@ bool uhci_init(int bus, int dev, int func, uint16_t io_base, usb_hcd_t *hcd)
if (!reset_host_controller(io_base)) return false;
// Record the heap state to allow us to free memory.
uintptr_t initial_heap_mark = lm_heap_mark();
uintptr_t initial_heap_mark = heap_mark(HEAP_TYPE_LM_1);
// Allocate the frame list. This needs to be aligned on a 4K page boundary.
uintptr_t fl_addr = lm_heap_alloc(UHCI_FL_LENGTH * sizeof(uint32_t), PAGE_SIZE);
uintptr_t fl_addr = heap_alloc(HEAP_TYPE_LM_1, UHCI_FL_LENGTH * sizeof(uint32_t), PAGE_SIZE);
if (fl_addr == 0) {
goto no_keyboards_found;
}
uint32_t *fl = (uint32_t *)fl_addr;
// Allocate and initialise a workspace for this controller. This needs to be permanently mapped into virtual memory.
uintptr_t workspace_addr = lm_heap_alloc(sizeof(workspace_t), PAGE_SIZE);
uintptr_t workspace_addr = heap_alloc(HEAP_TYPE_LM_1, sizeof(workspace_t), PAGE_SIZE);
if (workspace_addr == 0) {
goto no_keyboards_found;
}
@ -574,6 +574,6 @@ bool uhci_init(int bus, int dev, int func, uint16_t io_base, usb_hcd_t *hcd)
return true;
no_keyboards_found:
lm_heap_rewind(initial_heap_mark);
heap_rewind(HEAP_TYPE_LM_1, initial_heap_mark);
return false;
}

View File

@ -645,10 +645,10 @@ static int allocate_slot(const usb_hcd_t *hcd)
xhci_trb_t event;
// Record the heap state to allow us to free memory.
ws->initial_heap_mark = lm_heap_mark();
ws->initial_heap_mark = heap_mark(HEAP_TYPE_LM_1);
// Allocate and initialise a private workspace for this device.
uintptr_t device_workspace_addr = lm_heap_alloc(DEVICE_WS_SIZE, PAGE_SIZE);
uintptr_t device_workspace_addr = heap_alloc(HEAP_TYPE_LM_1, DEVICE_WS_SIZE, PAGE_SIZE);
if (device_workspace_addr == 0) {
goto free_memory;
}
@ -672,7 +672,7 @@ static int allocate_slot(const usb_hcd_t *hcd)
return slot_id;
free_memory:
lm_heap_rewind(ws->initial_heap_mark);
heap_rewind(HEAP_TYPE_LM_1, ws->initial_heap_mark);
return 0;
}
@ -690,7 +690,7 @@ static bool release_slot(const usb_hcd_t *hcd, int slot_id)
write64(&ws->device_context_index[slot_id], 0);
lm_heap_rewind(ws->initial_heap_mark);
heap_rewind(HEAP_TYPE_LM_1, ws->initial_heap_mark);
return true;
}
@ -987,8 +987,8 @@ bool xhci_init(uintptr_t base_addr, usb_hcd_t *hcd)
if (!reset_host_controller(op_regs)) return false;
// Record the heap states to allow us to free memory.
uintptr_t initial_lm_heap_mark = lm_heap_mark();
uintptr_t initial_hm_heap_mark = hm_heap_mark();
uintptr_t initial_lm_heap_mark = heap_mark(HEAP_TYPE_LM_1);
uintptr_t initial_hm_heap_mark = heap_mark(HEAP_TYPE_HM_1);
// Record the controller page size.
uintptr_t xhci_page_size = (read32(&op_regs->page_size) & 0xffff) << 12;
@ -1002,7 +1002,7 @@ bool xhci_init(uintptr_t base_addr, usb_hcd_t *hcd)
// Allocate and clear the scratchpad memory on the heap. This must be aligned to the controller page size.
uintptr_t scratchpad_size = num_scratchpad_buffers * xhci_page_size;
uintptr_t scratchpad_paddr = hm_heap_alloc(scratchpad_size, xhci_page_size);
uintptr_t scratchpad_paddr = heap_alloc(HEAP_TYPE_HM_1, scratchpad_size, xhci_page_size);
if (scratchpad_paddr == 0) {
goto no_keyboards_found;
}
@ -1018,7 +1018,7 @@ bool xhci_init(uintptr_t base_addr, usb_hcd_t *hcd)
uintptr_t device_context_index_size = (1 + max_slots) * sizeof(uint64_t);
uintptr_t scratchpad_buffer_index_offs = round_up(device_context_index_size, 64);
uintptr_t scratchpad_buffer_index_size = num_scratchpad_buffers * sizeof(uint64_t);
uintptr_t device_context_index_paddr = hm_heap_alloc(scratchpad_buffer_index_offs + scratchpad_buffer_index_size, 64);
uintptr_t device_context_index_paddr = heap_alloc(HEAP_TYPE_HM_1, scratchpad_buffer_index_offs + scratchpad_buffer_index_size, 64);
if (device_context_index_paddr == 0) {
goto no_keyboards_found;
}
@ -1041,7 +1041,7 @@ bool xhci_init(uintptr_t base_addr, usb_hcd_t *hcd)
}
// Allocate and initialise a workspace for this controller. This needs to be permanently mapped into virtual memory.
uintptr_t workspace_addr = lm_heap_alloc(sizeof(workspace_t), PAGE_SIZE);
uintptr_t workspace_addr = heap_alloc(HEAP_TYPE_LM_1, sizeof(workspace_t), PAGE_SIZE);
if (workspace_addr == 0) {
goto no_keyboards_found;
}
@ -1061,7 +1061,7 @@ bool xhci_init(uintptr_t base_addr, usb_hcd_t *hcd)
ws->er_dequeue_state = WS_ER_SIZE; // cycle = 1, index = 0
// Allocate and initialise the input context data structure. This needs to be contained within a single page.
ws->input_context_addr = lm_heap_alloc(XHCI_MAX_IP_CONTEXT_SIZE, PAGE_SIZE);
ws->input_context_addr = heap_alloc(HEAP_TYPE_LM_1, XHCI_MAX_IP_CONTEXT_SIZE, PAGE_SIZE);
if (ws->input_context_addr == 0) {
goto no_keyboards_found;
}
@ -1167,7 +1167,7 @@ bool xhci_init(uintptr_t base_addr, usb_hcd_t *hcd)
return true;
no_keyboards_found:
lm_heap_rewind(initial_lm_heap_mark);
hm_heap_rewind(initial_hm_heap_mark);
heap_rewind(HEAP_TYPE_LM_1, initial_lm_heap_mark);
heap_rewind(HEAP_TYPE_HM_1, initial_hm_heap_mark);
return false;
}