ext_stage_cache.c
1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 3 #include <cbmem.h> 4 #include <console/console.h> 5 #include <imd.h> 6 #include <stage_cache.h> 7 #include <string.h> 8 9 static struct imd imd_stage_cache; 10 11 static void stage_cache_create_empty(void) 12 { 13 struct imd *imd; 14 void *base; 15 size_t size; 16 17 imd = &imd_stage_cache; 18 stage_cache_external_region(&base, &size); 19 if (base == NULL || size == 0) 20 return; 21 imd_handle_init(imd, (void *)(size + (uintptr_t)base)); 22 23 printk(BIOS_DEBUG, "External stage cache:\n"); 24 imd_create_tiered_empty(imd, 4096, 4096, 1024, 32); 25 if (imd_limit_size(imd, size)) 26 printk(BIOS_DEBUG, "Could not limit stage cache size.\n"); 27 } 28 29 static void stage_cache_recover(void) 30 { 31 struct imd *imd; 32 void *base; 33 size_t size; 34 35 imd = &imd_stage_cache; 36 stage_cache_external_region(&base, &size); 37 if (base == NULL || size == 0) 38 return; 39 imd_handle_init(imd, (void *)(size + (uintptr_t)base)); 40 if (imd_recover(imd)) 41 printk(BIOS_DEBUG, "Unable to recover external stage cache.\n"); 42 } 43 44 void stage_cache_add(int stage_id, const struct prog *stage) 45 { 46 struct imd *imd; 47 const struct imd_entry *e; 48 struct stage_cache *meta; 49 void *c; 50 51 imd = &imd_stage_cache; 52 e = imd_entry_add(imd, CBMEM_ID_STAGEx_META + stage_id, sizeof(*meta)); 53 54 if (e == NULL) { 55 printk(BIOS_DEBUG, "Error: Can't add %x metadata to imd\n", 56 CBMEM_ID_STAGEx_META + stage_id); 57 return; 58 } 59 60 meta = imd_entry_at(imd, e); 61 62 meta->load_addr = (uintptr_t)prog_start(stage); 63 meta->entry_addr = (uintptr_t)prog_entry(stage); 64 meta->arg = (uintptr_t)prog_entry_arg(stage); 65 66 unsigned int p_size = prog_size(stage); 67 if (stage_id == STAGE_RAMSTAGE) { 68 /* heap resides at the end of the image and will be 69 * reinitialized, so it doesn't make sense to copy it around. 70 */ 71 p_size -= CONFIG_HEAP_SIZE; 72 } 73 74 e = imd_entry_add(imd, CBMEM_ID_STAGEx_CACHE + stage_id, p_size); 75 76 if (e == NULL) { 77 printk(BIOS_DEBUG, "Error: Can't add stage_cache %x to imd\n", 78 CBMEM_ID_STAGEx_CACHE + stage_id); 79 return; 80 } 81 82 c = imd_entry_at(imd, e); 83 84 memcpy(c, prog_start(stage), p_size); 85 } 86 87 void stage_cache_add_raw(int stage_id, const void *base, const size_t size) 88 { 89 struct imd *imd; 90 const struct imd_entry *e; 91 void *c; 92 93 imd = &imd_stage_cache; 94 e = imd_entry_add(imd, CBMEM_ID_STAGEx_RAW + stage_id, size); 95 if (e == NULL) { 96 printk(BIOS_DEBUG, "Error: Can't add %x raw data to imd\n", 97 CBMEM_ID_STAGEx_RAW + stage_id); 98 return; 99 } 100 101 c = imd_entry_at(imd, e); 102 if (c == NULL) { 103 printk(BIOS_DEBUG, "Error: Can't get %x raw entry in imd\n", 104 CBMEM_ID_STAGEx_RAW + stage_id); 105 return; 106 } 107 108 memcpy(c, base, size); 109 } 110 111 void stage_cache_get_raw(int stage_id, void **base, size_t *size) 112 { 113 struct imd *imd; 114 const struct imd_entry *e; 115 116 imd = &imd_stage_cache; 117 e = imd_entry_find(imd, CBMEM_ID_STAGEx_RAW + stage_id); 118 if (e == NULL) { 119 printk(BIOS_DEBUG, "Error: Can't find %x raw data to imd\n", 120 CBMEM_ID_STAGEx_RAW + stage_id); 121 return; 122 } 123 124 *base = imd_entry_at(imd, e); 125 *size = imd_entry_size(e); 126 } 127 128 void stage_cache_load_stage(int stage_id, struct prog *stage) 129 { 130 struct imd *imd; 131 struct stage_cache *meta; 132 const struct imd_entry *e; 133 void *c; 134 size_t size; 135 136 imd = &imd_stage_cache; 137 e = imd_entry_find(imd, CBMEM_ID_STAGEx_META + stage_id); 138 if (e == NULL) { 139 printk(BIOS_DEBUG, "Error: Can't find %x metadata in imd\n", 140 CBMEM_ID_STAGEx_META + stage_id); 141 return; 142 } 143 144 meta = imd_entry_at(imd, e); 145 146 e = imd_entry_find(imd, CBMEM_ID_STAGEx_CACHE + stage_id); 147 148 if (e == NULL) { 149 printk(BIOS_DEBUG, "Error: Can't find stage_cache %x in imd\n", 150 CBMEM_ID_STAGEx_CACHE + stage_id); 151 return; 152 } 153 154 c = imd_entry_at(imd, e); 155 size = imd_entry_size(e); 156 157 memcpy((void *)(uintptr_t)meta->load_addr, c, size); 158 159 prog_set_area(stage, (void *)(uintptr_t)meta->load_addr, size); 160 prog_set_entry(stage, (void *)(uintptr_t)meta->entry_addr, 161 (void *)(uintptr_t)meta->arg); 162 } 163 164 static void stage_cache_setup(int is_recovery) 165 { 166 if (is_recovery) 167 stage_cache_recover(); 168 else 169 stage_cache_create_empty(); 170 } 171 172 CBMEM_READY_HOOK(stage_cache_setup);