/** * Recursive lock of the malloc */ void __malloc_lock(struct _reent *ptr) { uint32_t timerenable, interruptenable; uint32_t id, old_owner; // Disable timer and interrupt exception, store TEE and IEE flag temporarily // to restore them later on unlock timerenable = or1k_timer_disable(); interruptenable = or1k_interrupts_disable(); // Now we cannot be disturbed by an interrupt or timer exception id = (uint32_t) ptr; // Our id is the address of the reentrancy data do { do { // Read current lock owner old_owner = or1k_sync_ll(&_malloc_lock_own); // .. and spin while it is locked and we are not the owner } while (old_owner && (old_owner != id)); } while (!or1k_sync_sc(&_malloc_lock_own, id)); // Store the TEE and IEE flags for later restore _malloc_lock_restore_timer = timerenable; _malloc_lock_restore_interrupts = interruptenable; // Increment counter. The lock may be accessed recursively _malloc_lock_cnt++; return; }
int optimsoc_vmm_map(optimsoc_page_dir_t directory, uint32_t vaddr, uint32_t paddr) { optimsoc_pte_t dirpte; optimsoc_page_table_t table; optimsoc_pte_t pte; // Verify input VERIFY_DIR_ADDR(directory); // Address of the table's pte from the directory base void *taddr = (void*) &directory[OR1K_ADDR_L1_INDEX_GET(vaddr)]; // Load-linked the pointer, as we may change it dirpte = or1k_sync_ll(taddr); // Check if table is present if (OR1K_PTE_PRESENT_GET(dirpte) == 0) { // There is no page table, allocate and map one table = _optimsoc_vmm_create_page_table(); assert(table); // We now try to set this as te new table by updating the pte. As other // cores may have set a table at the same index concurrently, we do // a store-conditional. while (1) { // Set table present dirpte = OR1K_PTE_PRESENT_SET(dirpte, 1); // Set the physical page number, that is the table base address dirpte = OR1K_PTE_PPN_SET(dirpte, OR1K_PTE_PPN_GET(table)); // Try to store this pte if (or1k_sync_sc(taddr,dirpte) == 1) { // The operation was successful break; } else { // There has been a write access to this PTE // Load the pte again. It may have been changed after we loaded // it or there was another LL call in between. dirpte = or1k_sync_ll(taddr); // Check if someone else modified or the store failed for other // reasons. if (OR1K_PTE_PRESENT_GET(dirpte) == 1) { // Another core added this table. Simply free our // table and continue. free(table); break; } // Otherwise we simply retry, do the operation again } } } else { // There already is a page, load base table = (optimsoc_page_table_t) OR1K_PTABLE(dirpte); } // This is a huge table what we do not support for now assert(OR1K_PTE_LAST_GET(dirpte) == 0); // Load the address of the pte in the page table void *pteaddr = (void*) &table[OR1K_ADDR_L2_INDEX_GET(vaddr)]; // Load this entry pte = or1k_sync_ll(pteaddr); if (OR1K_PTE_PRESENT_GET(pte) == 1) { // There already is a page mapped return 0; } // Try to set this entry while (1) { // Get PN from physical address uint32_t ppn = OR1K_PTE_PPN_GET(paddr); // Assemble pte pte = OR1K_PTE_PPN_SET(0, ppn); pte = OR1K_PTE_PRESENT_SET(pte, 1); // TODO: Allow to set page policies // Allow all page accesses uint32_t ppi = (1 << OR1K_PTE_PPI_USER_BIT) | \ (1 << OR1K_PTE_PPI_WRITE_BIT) | (1 << OR1K_PTE_PPI_EXEC_BIT); pte = OR1K_PTE_PPI_SET(pte, ppi); // Try to write pte if (or1k_sync_sc(pteaddr, pte) == 1) { // Operation was successful break; } else { // Another write occured pte = or1k_sync_ll(pteaddr); // Check why this failed if (OR1K_PTE_PRESENT_GET(pte) == 1) { // Another core added the same address return 0; } // Otherwise just retry } } return 1; }