/ src / lib / ext_stage_cache.c
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);