/* * Function: freeSecureMemory() * * Description: * Free a single page of secure memory. * * Inputs: * p - The first virtual address of the secure memory to free. * size - The amount of secure memory to allocate measured in bytes. * */ void freeSecureMemory (void) { /* * Get the current interrupt context; the arguments will be in it. */ sva_icontext_t * icp = getCPUState()->newCurrentIC; /* * Get the pointer address and size out of the interrupt context. */ unsigned char * p = (unsigned char *)(icp->rdi); uintptr_t size = icp->rsi; /* * Verify that the memory is within the secure memory portion of the * address space. */ uintptr_t pint = (uintptr_t) p; if ((SECMEMSTART <= pint) && (pint < SECMEMEND) && (SECMEMSTART <= (pint + size)) && ((pint + size) < SECMEMEND)) { /* * Zero out the memory. */ memset (p, 0, size); /* * Get the physical address before unmapping the page. We do this because * unmapping the page may remove page table pages that are no longer * needed for mapping secure pages. */ uintptr_t paddr = getPhysicalAddr (p); /* * Unmap the memory from the secure memory virtual address space. */ unmapSecurePage (get_pagetable(), p); /* * Release the memory to the operating system. Note that we must first * get the physical address of the data page as that is what the OS is * expecting. */ releaseSVAMemory (paddr, size); } return; }
/* * Function: sva_ghost_fault() * * Description: * Handle page faults of ghost memory pages. * * Inputs: * vaddr - The virtual address of the faulting ghost memory page. * code - The page fault code. * */ void sva_ghost_fault (uintptr_t vaddr, unsigned long code) { /* Old interrupt flags */ uintptr_t rflags; /* * Disable interrupts. */ rflags = sva_enter_critical(); /* Physical address of allocated secure memory pointer */ uintptr_t sp; /* The address of the PML4e page table */ pml4e_t pml4e; /* * Get the current interrupt context; the arguments will be in it. */ struct CPUState * cpup = getCPUState(); struct SVAThread * threadp = cpup->currentThread; /* copy-on-write page fault */ if((code & PGEX_P) && (code & PGEX_W)){ pml4e_t * pml4e_ptr = get_pml4eVaddr (get_pagetable(), vaddr); if(!isPresent (pml4e_ptr)) panic("sva_ghost_fault: cow pgfault pml4e %p does not exist\n", pml4e); pdpte_t * pdpte = get_pdpteVaddr (pml4e_ptr, vaddr); if(!isPresent (pdpte)) panic("sva_ghost_fault: cow pgfault pdpte %p does not exist\n", pdpte); pde_t * pde = get_pdeVaddr (pdpte, vaddr); if(!isPresent (pde)) panic("sva_ghost_fault: cow pgfault pde %p does not exist\n", pde); pte_t * pte = get_pteVaddr (pde, vaddr); uintptr_t paddr = *pte & PG_FRAME; page_desc_t * pgDesc = getPageDescPtr (paddr); if(pgDesc->type != PG_GHOST) panic("SVA: sva_ghost_fault: vaddr = 0x%lx paddr = 0x%lx is not a ghost memory page!\n", vaddr, paddr); /* If only one process maps this page, directly grant this process write permission */ if(pgDesc->count == 1) { * pte = (* pte) | PTE_CANWRITE; } /* Otherwise copy-on-write */ else { uintptr_t vaddr_old = (uintptr_t) getVirtualSVADMAP(paddr); uintptr_t paddr_new = alloc_frame(); page_desc_t * pgDesc_new = getPageDescPtr (paddr_new); if (pgRefCount (pgDesc_new) > 1) { panic ("SVA: Ghost page still in use somewhere else!\n"); } if (isPTP(pgDesc_new) || isCodePG (pgDesc_new)) { panic ("SVA: Ghost page has wrong type!\n"); } memcpy(getVirtualSVADMAP(paddr_new), (void *) vaddr_old, X86_PAGE_SIZE); *pte = (paddr_new & addrmask) | PTE_CANWRITE | PTE_CANUSER | PTE_PRESENT; invlpg(vaddr); getPageDescPtr (paddr_new)->type = PG_GHOST; getPageDescPtr (paddr_new)->count = 1; pgDesc->count --; } return; } /* * Determine if this is the first secure memory allocation. */ unsigned char firstSecAlloc = (threadp->secmemSize == 0); /* * Get a page of memory from the operating system. Note that the OS provides * the physical address of the allocated memory. */ if ((sp = alloc_frame()) != 0) { /* Physical address of the allocated page */ uintptr_t paddr = (uintptr_t) sp; /* * Map the memory into a part of the address space reserved for secure * memory. */ pml4e = mapSecurePage ((uintptr_t)vaddr, paddr); /* * If this is the first piece of secure memory that we've allocated, * record the address of the top-level page table that maps in the secure * memory region. The context switching intrinsics will want to know * where this entry is so that it can quickly enable and disable it on * context switches. */ if (firstSecAlloc) { threadp->secmemPML4e = pml4e; } } else { panic ("SVA: Kernel secure memory allocation failed!\n"); } /* * Zero out the ghost memory contents. */ memset ((void *)vaddr, 0, X86_PAGE_SIZE); /* Re-enable interrupts if necessary */ sva_exit_critical (rflags); return; }