1*fe85eae5SJens Wiklander // SPDX-License-Identifier: BSD-2-Clause 2*fe85eae5SJens Wiklander /* 3*fe85eae5SJens Wiklander * Copyright (c) 2024, Linaro Limited 4*fe85eae5SJens Wiklander */ 5*fe85eae5SJens Wiklander 6*fe85eae5SJens Wiklander #include <assert.h> 7*fe85eae5SJens Wiklander #include <kernel/boot.h> 8*fe85eae5SJens Wiklander #include <mm/core_memprot.h> 9*fe85eae5SJens Wiklander #include <mm/core_mmu.h> 10*fe85eae5SJens Wiklander #include <mm/phys_mem.h> 11*fe85eae5SJens Wiklander #include <mm/tee_mm.h> 12*fe85eae5SJens Wiklander #include <stdalign.h> 13*fe85eae5SJens Wiklander #include <string.h> 14*fe85eae5SJens Wiklander #include <util.h> 15*fe85eae5SJens Wiklander 16*fe85eae5SJens Wiklander /* 17*fe85eae5SJens Wiklander * struct boot_mem_reloc - Pointers relocated in memory during boot 18*fe85eae5SJens Wiklander * @ptrs: Array of relocation 19*fe85eae5SJens Wiklander * @count: Number of cells used in @ptrs 20*fe85eae5SJens Wiklander * @next: Next relocation array when @ptrs is fully used 21*fe85eae5SJens Wiklander */ 22*fe85eae5SJens Wiklander struct boot_mem_reloc { 23*fe85eae5SJens Wiklander void **ptrs[64]; 24*fe85eae5SJens Wiklander size_t count; 25*fe85eae5SJens Wiklander struct boot_mem_reloc *next; 26*fe85eae5SJens Wiklander }; 27*fe85eae5SJens Wiklander 28*fe85eae5SJens Wiklander /* 29*fe85eae5SJens Wiklander * struct boot_mem_desc - Stack like boot memory allocation pool 30*fe85eae5SJens Wiklander * @orig_mem_start: Boot memory stack base address 31*fe85eae5SJens Wiklander * @orig_mem_end: Boot memory start end address 32*fe85eae5SJens Wiklander * @mem_start: Boot memory free space start address 33*fe85eae5SJens Wiklander * @mem_end: Boot memory free space end address 34*fe85eae5SJens Wiklander * @reloc: Boot memory pointers requiring relocation 35*fe85eae5SJens Wiklander */ 36*fe85eae5SJens Wiklander struct boot_mem_desc { 37*fe85eae5SJens Wiklander vaddr_t orig_mem_start; 38*fe85eae5SJens Wiklander vaddr_t orig_mem_end; 39*fe85eae5SJens Wiklander vaddr_t mem_start; 40*fe85eae5SJens Wiklander vaddr_t mem_end; 41*fe85eae5SJens Wiklander struct boot_mem_reloc *reloc; 42*fe85eae5SJens Wiklander }; 43*fe85eae5SJens Wiklander 44*fe85eae5SJens Wiklander static struct boot_mem_desc *boot_mem_desc; 45*fe85eae5SJens Wiklander 46*fe85eae5SJens Wiklander static void *mem_alloc_tmp(struct boot_mem_desc *desc, size_t len, size_t align) 47*fe85eae5SJens Wiklander { 48*fe85eae5SJens Wiklander vaddr_t va = 0; 49*fe85eae5SJens Wiklander 50*fe85eae5SJens Wiklander assert(desc && desc->mem_start && desc->mem_end); 51*fe85eae5SJens Wiklander assert(IS_POWER_OF_TWO(align) && !(len % align)); 52*fe85eae5SJens Wiklander if (SUB_OVERFLOW(desc->mem_end, len, &va)) 53*fe85eae5SJens Wiklander panic(); 54*fe85eae5SJens Wiklander va = ROUNDDOWN(va, align); 55*fe85eae5SJens Wiklander if (va < desc->mem_start) 56*fe85eae5SJens Wiklander panic(); 57*fe85eae5SJens Wiklander desc->mem_end = va; 58*fe85eae5SJens Wiklander return (void *)va; 59*fe85eae5SJens Wiklander } 60*fe85eae5SJens Wiklander 61*fe85eae5SJens Wiklander static void *mem_alloc(struct boot_mem_desc *desc, size_t len, size_t align) 62*fe85eae5SJens Wiklander { 63*fe85eae5SJens Wiklander vaddr_t va = 0; 64*fe85eae5SJens Wiklander vaddr_t ve = 0; 65*fe85eae5SJens Wiklander 66*fe85eae5SJens Wiklander runtime_assert(!IS_ENABLED(CFG_WITH_PAGER)); 67*fe85eae5SJens Wiklander assert(desc && desc->mem_start && desc->mem_end); 68*fe85eae5SJens Wiklander assert(IS_POWER_OF_TWO(align) && !(len % align)); 69*fe85eae5SJens Wiklander va = ROUNDUP(desc->mem_start, align); 70*fe85eae5SJens Wiklander if (ADD_OVERFLOW(va, len, &ve)) 71*fe85eae5SJens Wiklander panic(); 72*fe85eae5SJens Wiklander if (ve > desc->mem_end) 73*fe85eae5SJens Wiklander panic(); 74*fe85eae5SJens Wiklander desc->mem_start = ve; 75*fe85eae5SJens Wiklander return (void *)va; 76*fe85eae5SJens Wiklander } 77*fe85eae5SJens Wiklander 78*fe85eae5SJens Wiklander void boot_mem_init(vaddr_t start, vaddr_t end, vaddr_t orig_end) 79*fe85eae5SJens Wiklander { 80*fe85eae5SJens Wiklander struct boot_mem_desc desc = { 81*fe85eae5SJens Wiklander .orig_mem_start = start, 82*fe85eae5SJens Wiklander .orig_mem_end = orig_end, 83*fe85eae5SJens Wiklander .mem_start = start, 84*fe85eae5SJens Wiklander .mem_end = end, 85*fe85eae5SJens Wiklander }; 86*fe85eae5SJens Wiklander 87*fe85eae5SJens Wiklander boot_mem_desc = mem_alloc_tmp(&desc, sizeof(desc), alignof(desc)); 88*fe85eae5SJens Wiklander *boot_mem_desc = desc; 89*fe85eae5SJens Wiklander boot_mem_desc->reloc = mem_alloc_tmp(boot_mem_desc, 90*fe85eae5SJens Wiklander sizeof(*boot_mem_desc->reloc), 91*fe85eae5SJens Wiklander alignof(*boot_mem_desc->reloc)); 92*fe85eae5SJens Wiklander memset(boot_mem_desc->reloc, 0, sizeof(*boot_mem_desc->reloc)); 93*fe85eae5SJens Wiklander } 94*fe85eae5SJens Wiklander 95*fe85eae5SJens Wiklander void boot_mem_add_reloc(void *ptr) 96*fe85eae5SJens Wiklander { 97*fe85eae5SJens Wiklander struct boot_mem_reloc *reloc = NULL; 98*fe85eae5SJens Wiklander 99*fe85eae5SJens Wiklander assert(boot_mem_desc && boot_mem_desc->reloc); 100*fe85eae5SJens Wiklander reloc = boot_mem_desc->reloc; 101*fe85eae5SJens Wiklander 102*fe85eae5SJens Wiklander /* If the reloc struct is full, allocate a new and link it first */ 103*fe85eae5SJens Wiklander if (reloc->count == ARRAY_SIZE(reloc->ptrs)) { 104*fe85eae5SJens Wiklander reloc = boot_mem_alloc_tmp(sizeof(*reloc), alignof(*reloc)); 105*fe85eae5SJens Wiklander reloc->next = boot_mem_desc->reloc; 106*fe85eae5SJens Wiklander boot_mem_desc->reloc = reloc; 107*fe85eae5SJens Wiklander } 108*fe85eae5SJens Wiklander 109*fe85eae5SJens Wiklander reloc->ptrs[reloc->count] = ptr; 110*fe85eae5SJens Wiklander reloc->count++; 111*fe85eae5SJens Wiklander } 112*fe85eae5SJens Wiklander 113*fe85eae5SJens Wiklander static void *add_offs(void *p, size_t offs) 114*fe85eae5SJens Wiklander { 115*fe85eae5SJens Wiklander assert(p); 116*fe85eae5SJens Wiklander return (uint8_t *)p + offs; 117*fe85eae5SJens Wiklander } 118*fe85eae5SJens Wiklander 119*fe85eae5SJens Wiklander void boot_mem_relocate(size_t offs) 120*fe85eae5SJens Wiklander { 121*fe85eae5SJens Wiklander struct boot_mem_reloc *reloc = NULL; 122*fe85eae5SJens Wiklander size_t n = 0; 123*fe85eae5SJens Wiklander 124*fe85eae5SJens Wiklander boot_mem_desc = add_offs(boot_mem_desc, offs); 125*fe85eae5SJens Wiklander 126*fe85eae5SJens Wiklander boot_mem_desc->orig_mem_start += offs; 127*fe85eae5SJens Wiklander boot_mem_desc->orig_mem_end += offs; 128*fe85eae5SJens Wiklander boot_mem_desc->mem_start += offs; 129*fe85eae5SJens Wiklander boot_mem_desc->mem_end += offs; 130*fe85eae5SJens Wiklander boot_mem_desc->reloc = add_offs(boot_mem_desc->reloc, offs); 131*fe85eae5SJens Wiklander 132*fe85eae5SJens Wiklander for (reloc = boot_mem_desc->reloc;; reloc = reloc->next) { 133*fe85eae5SJens Wiklander for (n = 0; n < reloc->count; n++) { 134*fe85eae5SJens Wiklander reloc->ptrs[n] = add_offs(reloc->ptrs[n], offs); 135*fe85eae5SJens Wiklander *reloc->ptrs[n] = add_offs(*reloc->ptrs[n], offs); 136*fe85eae5SJens Wiklander } 137*fe85eae5SJens Wiklander if (!reloc->next) 138*fe85eae5SJens Wiklander break; 139*fe85eae5SJens Wiklander reloc->next = add_offs(reloc->next, offs); 140*fe85eae5SJens Wiklander } 141*fe85eae5SJens Wiklander } 142*fe85eae5SJens Wiklander 143*fe85eae5SJens Wiklander void *boot_mem_alloc(size_t len, size_t align) 144*fe85eae5SJens Wiklander { 145*fe85eae5SJens Wiklander return mem_alloc(boot_mem_desc, len, align); 146*fe85eae5SJens Wiklander } 147*fe85eae5SJens Wiklander 148*fe85eae5SJens Wiklander void *boot_mem_alloc_tmp(size_t len, size_t align) 149*fe85eae5SJens Wiklander { 150*fe85eae5SJens Wiklander return mem_alloc_tmp(boot_mem_desc, len, align); 151*fe85eae5SJens Wiklander } 152*fe85eae5SJens Wiklander 153*fe85eae5SJens Wiklander vaddr_t boot_mem_release_unused(void) 154*fe85eae5SJens Wiklander { 155*fe85eae5SJens Wiklander tee_mm_entry_t *mm = NULL; 156*fe85eae5SJens Wiklander paddr_t pa = 0; 157*fe85eae5SJens Wiklander vaddr_t va = 0; 158*fe85eae5SJens Wiklander size_t n = 0; 159*fe85eae5SJens Wiklander vaddr_t tmp_va = 0; 160*fe85eae5SJens Wiklander paddr_t tmp_pa = 0; 161*fe85eae5SJens Wiklander size_t tmp_n = 0; 162*fe85eae5SJens Wiklander 163*fe85eae5SJens Wiklander assert(boot_mem_desc); 164*fe85eae5SJens Wiklander 165*fe85eae5SJens Wiklander n = boot_mem_desc->mem_start - boot_mem_desc->orig_mem_start; 166*fe85eae5SJens Wiklander DMSG("Allocated %zu bytes at va %#"PRIxVA" pa %#"PRIxPA, 167*fe85eae5SJens Wiklander n, boot_mem_desc->orig_mem_start, 168*fe85eae5SJens Wiklander vaddr_to_phys(boot_mem_desc->orig_mem_start)); 169*fe85eae5SJens Wiklander 170*fe85eae5SJens Wiklander DMSG("Tempalloc %zu bytes at va %#"PRIxVA, 171*fe85eae5SJens Wiklander (size_t)(boot_mem_desc->orig_mem_end - boot_mem_desc->mem_end), 172*fe85eae5SJens Wiklander boot_mem_desc->mem_end); 173*fe85eae5SJens Wiklander 174*fe85eae5SJens Wiklander if (IS_ENABLED(CFG_WITH_PAGER)) 175*fe85eae5SJens Wiklander goto out; 176*fe85eae5SJens Wiklander 177*fe85eae5SJens Wiklander pa = vaddr_to_phys(ROUNDUP(boot_mem_desc->orig_mem_start, 178*fe85eae5SJens Wiklander SMALL_PAGE_SIZE)); 179*fe85eae5SJens Wiklander mm = nex_phys_mem_mm_find(pa); 180*fe85eae5SJens Wiklander if (!mm) 181*fe85eae5SJens Wiklander panic(); 182*fe85eae5SJens Wiklander 183*fe85eae5SJens Wiklander va = ROUNDUP(boot_mem_desc->mem_start, SMALL_PAGE_SIZE); 184*fe85eae5SJens Wiklander 185*fe85eae5SJens Wiklander tmp_va = ROUNDDOWN(boot_mem_desc->mem_end, SMALL_PAGE_SIZE); 186*fe85eae5SJens Wiklander tmp_n = boot_mem_desc->orig_mem_end - tmp_va; 187*fe85eae5SJens Wiklander tmp_pa = vaddr_to_phys(tmp_va); 188*fe85eae5SJens Wiklander 189*fe85eae5SJens Wiklander pa = tee_mm_get_smem(mm); 190*fe85eae5SJens Wiklander n = vaddr_to_phys(boot_mem_desc->mem_start) - pa; 191*fe85eae5SJens Wiklander tee_mm_free(mm); 192*fe85eae5SJens Wiklander DMSG("Carving out %#"PRIxPA"..%#"PRIxPA, pa, pa + n - 1); 193*fe85eae5SJens Wiklander mm = nex_phys_mem_alloc2(pa, n); 194*fe85eae5SJens Wiklander if (!mm) 195*fe85eae5SJens Wiklander panic(); 196*fe85eae5SJens Wiklander mm = nex_phys_mem_alloc2(tmp_pa, tmp_n); 197*fe85eae5SJens Wiklander if (!mm) 198*fe85eae5SJens Wiklander panic(); 199*fe85eae5SJens Wiklander 200*fe85eae5SJens Wiklander n = tmp_va - boot_mem_desc->mem_start; 201*fe85eae5SJens Wiklander DMSG("Releasing %zu bytes from va %#"PRIxVA, n, va); 202*fe85eae5SJens Wiklander 203*fe85eae5SJens Wiklander /* Unmap the now unused pages */ 204*fe85eae5SJens Wiklander core_mmu_unmap_pages(va, n / SMALL_PAGE_SIZE); 205*fe85eae5SJens Wiklander 206*fe85eae5SJens Wiklander out: 207*fe85eae5SJens Wiklander /* Stop further allocations. */ 208*fe85eae5SJens Wiklander boot_mem_desc->mem_start = boot_mem_desc->mem_end; 209*fe85eae5SJens Wiklander return va; 210*fe85eae5SJens Wiklander } 211*fe85eae5SJens Wiklander 212*fe85eae5SJens Wiklander void boot_mem_release_tmp_alloc(void) 213*fe85eae5SJens Wiklander { 214*fe85eae5SJens Wiklander tee_mm_entry_t *mm = NULL; 215*fe85eae5SJens Wiklander vaddr_t va = 0; 216*fe85eae5SJens Wiklander paddr_t pa = 0; 217*fe85eae5SJens Wiklander size_t n = 0; 218*fe85eae5SJens Wiklander 219*fe85eae5SJens Wiklander assert(boot_mem_desc && 220*fe85eae5SJens Wiklander boot_mem_desc->mem_start == boot_mem_desc->mem_end); 221*fe85eae5SJens Wiklander 222*fe85eae5SJens Wiklander if (IS_ENABLED(CFG_WITH_PAGER)) { 223*fe85eae5SJens Wiklander n = boot_mem_desc->orig_mem_end - boot_mem_desc->mem_end; 224*fe85eae5SJens Wiklander va = boot_mem_desc->mem_end; 225*fe85eae5SJens Wiklander boot_mem_desc = NULL; 226*fe85eae5SJens Wiklander DMSG("Releasing %zu bytes from va %#"PRIxVA, n, va); 227*fe85eae5SJens Wiklander return; 228*fe85eae5SJens Wiklander } 229*fe85eae5SJens Wiklander 230*fe85eae5SJens Wiklander va = ROUNDDOWN(boot_mem_desc->mem_end, SMALL_PAGE_SIZE); 231*fe85eae5SJens Wiklander pa = vaddr_to_phys(va); 232*fe85eae5SJens Wiklander 233*fe85eae5SJens Wiklander mm = nex_phys_mem_mm_find(pa); 234*fe85eae5SJens Wiklander if (!mm) 235*fe85eae5SJens Wiklander panic(); 236*fe85eae5SJens Wiklander assert(pa == tee_mm_get_smem(mm)); 237*fe85eae5SJens Wiklander n = tee_mm_get_bytes(mm); 238*fe85eae5SJens Wiklander 239*fe85eae5SJens Wiklander /* Boot memory allocation is now done */ 240*fe85eae5SJens Wiklander boot_mem_desc = NULL; 241*fe85eae5SJens Wiklander 242*fe85eae5SJens Wiklander DMSG("Releasing %zu bytes from va %#"PRIxVA, n, va); 243*fe85eae5SJens Wiklander 244*fe85eae5SJens Wiklander /* Unmap the now unused pages */ 245*fe85eae5SJens Wiklander core_mmu_unmap_pages(va, n / SMALL_PAGE_SIZE); 246*fe85eae5SJens Wiklander } 247