1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /*
3  * Derived from Xen 4.19's $xen/arch/arm/setup.c.
4  *
5  * bookkeeping routines.
6  *
7  * Tim Deegan <tim@xen.org>
8  * Copyright (c) 2011 Citrix Systems.
9  * Copyright (c) 2024 Raptor Engineering LLC
10  */
11 
12 #include <xen/acpi.h>
13 #include <xen/bootinfo.h>
14 #include <xen/bug.h>
15 #include <xen/device_tree.h>
16 #include <xen/init.h>
17 #include <xen/libfdt/libfdt-xen.h>
18 #include <xen/mm.h>
19 
20 #include <asm/setup.h>
21 
22 struct bootinfo __initdata bootinfo = BOOTINFO_INIT;
23 
boot_module_kind_as_string(boot_module_kind kind)24 const char * __init boot_module_kind_as_string(boot_module_kind kind)
25 {
26     switch ( kind )
27     {
28     case BOOTMOD_XEN:     return "Xen";
29     case BOOTMOD_FDT:     return "Device Tree";
30     case BOOTMOD_KERNEL:  return "Kernel";
31     case BOOTMOD_RAMDISK: return "Ramdisk";
32     case BOOTMOD_XSM_POLICY:    return "XSM Policy";
33     case BOOTMOD_GUEST_DTB:     return "DTB";
34     case BOOTMOD_MICROCODE:     return "Microcode";
35     case BOOTMOD_UNKNOWN: return "Unknown";
36     default: BUG();
37     }
38 }
39 
dt_unreserved_regions(paddr_t s,paddr_t e,void (* cb)(paddr_t ps,paddr_t pe),unsigned int first)40 static void __init dt_unreserved_regions(paddr_t s, paddr_t e,
41                                          void (*cb)(paddr_t ps, paddr_t pe),
42                                          unsigned int first)
43 {
44     const struct membanks *reserved_mem = bootinfo_get_reserved_mem();
45 #ifdef CONFIG_STATIC_SHM
46     const struct membanks *shmem = bootinfo_get_shmem();
47     unsigned int offset;
48 #endif
49     unsigned int i;
50 
51     /*
52      * i is the current boot_module we are evaluating across all possible
53      * kinds.
54      */
55     for ( i = first; i < reserved_mem->nr_banks; i++ )
56     {
57         paddr_t r_s = reserved_mem->bank[i].start;
58         paddr_t r_e = r_s + reserved_mem->bank[i].size;
59 
60         if ( s < r_e && r_s < e )
61         {
62             dt_unreserved_regions(r_e, e, cb, i + 1);
63             dt_unreserved_regions(s, r_s, cb, i + 1);
64             return;
65         }
66     }
67 
68 #ifdef CONFIG_STATIC_SHM
69     /*
70      * When retrieving the corresponding shared memory addresses
71      * below, we need to index the shmem->bank starting from 0, hence
72      * we need to use i - reserved_mem->nr_banks.
73     */
74     offset = reserved_mem->nr_banks;
75     for ( ; i - offset < shmem->nr_banks; i++ )
76     {
77         paddr_t r_s, r_e;
78 
79         r_s = shmem->bank[i - offset].start;
80 
81         /* Shared memory banks can contain INVALID_PADDR as start */
82         if ( INVALID_PADDR == r_s )
83             continue;
84 
85         r_e = r_s + shmem->bank[i - offset].size;
86 
87         if ( s < r_e && r_s < e )
88         {
89             dt_unreserved_regions(r_e, e, cb, i + 1);
90             dt_unreserved_regions(s, r_s, cb, i + 1);
91             return;
92         }
93     }
94 #endif
95 
96     cb(s, e);
97 }
98 
99 /*
100  * TODO: '*_end' could be 0 if the bank/region is at the end of the physical
101  * address space. This is for now not handled as it requires more rework.
102  */
meminfo_overlap_check(const struct membanks * mem,paddr_t region_start,paddr_t region_size,bool allow_memreserve_overlap)103 static bool __init meminfo_overlap_check(const struct membanks *mem,
104                                          paddr_t region_start,
105                                          paddr_t region_size,
106                                          bool allow_memreserve_overlap)
107 {
108     paddr_t bank_start = INVALID_PADDR, bank_end = 0;
109     paddr_t region_end = region_start + region_size;
110     unsigned int i, bank_num = mem->nr_banks;
111 
112     for ( i = 0; i < bank_num; i++ )
113     {
114         bank_start = mem->bank[i].start;
115         bank_end = bank_start + mem->bank[i].size;
116 
117         if ( INVALID_PADDR == bank_start || region_end <= bank_start ||
118              region_start >= bank_end )
119             continue;
120 
121         /*
122          * If allow_memreserve_overlap is set, this check allows a region to be
123          * included in a MEMBANK_FDT_RESVMEM bank, but struct membanks *mem of
124          * type STATIC_SHARED_MEMORY don't set the bank[].type field because
125          * that is declared in a union with a field that is instead used,
126          * in any case this restriction is ok since STATIC_SHARED_MEMORY banks
127          * are not meant to clash with FDT /memreserve/ ranges.
128          */
129         if ( allow_memreserve_overlap && mem->type != STATIC_SHARED_MEMORY &&
130              region_start >= bank_start && region_end <= bank_end &&
131              mem->bank[i].type == MEMBANK_FDT_RESVMEM )
132             continue;
133 
134         printk("Region: [%#"PRIpaddr", %#"PRIpaddr") overlapping with bank[%u]: [%#"PRIpaddr", %#"PRIpaddr")\n",
135                 region_start, region_end, i, bank_start, bank_end);
136         return true;
137     }
138 
139     return false;
140 }
141 
142 /*
143  * TODO: '*_end' could be 0 if the module/region is at the end of the physical
144  * address space. This is for now not handled as it requires more rework.
145  */
boot_modules_overlap_check(struct boot_modules * boot_modules,paddr_t region_start,paddr_t region_size)146 static bool __init boot_modules_overlap_check(struct boot_modules *boot_modules,
147                                               paddr_t region_start,
148                                               paddr_t region_size)
149 {
150     paddr_t mod_start = INVALID_PADDR, mod_end = 0;
151     paddr_t region_end = region_start + region_size;
152     unsigned int i, mod_num = boot_modules->nr_mods;
153 
154     for ( i = 0; i < mod_num; i++ )
155     {
156         mod_start = boot_modules->module[i].start;
157         mod_end = mod_start + boot_modules->module[i].size;
158 
159         if ( region_end <= mod_start || region_start >= mod_end )
160             continue;
161         else
162         {
163             printk("Region: [%#"PRIpaddr", %#"PRIpaddr") overlapping with mod[%u]: [%#"PRIpaddr", %#"PRIpaddr")\n",
164                    region_start, region_end, i, mod_start, mod_end);
165             return true;
166         }
167     }
168 
169     return false;
170 }
171 
fw_unreserved_regions(paddr_t s,paddr_t e,void (* cb)(paddr_t ps,paddr_t pe),unsigned int first)172 void __init fw_unreserved_regions(paddr_t s, paddr_t e,
173                                   void (*cb)(paddr_t ps, paddr_t pe),
174                                   unsigned int first)
175 {
176     if ( acpi_disabled )
177         dt_unreserved_regions(s, e, cb, first);
178     else
179         cb(s, e);
180 }
181 
182 /*
183  * Given an input physical address range, check if this range is overlapping
184  * with the existing reserved memory regions defined in bootinfo.
185  * Return true if the input physical address range is overlapping with any
186  * existing reserved memory regions, otherwise false.
187  */
check_reserved_regions_overlap(paddr_t region_start,paddr_t region_size,bool allow_memreserve_overlap)188 bool __init check_reserved_regions_overlap(paddr_t region_start,
189                                            paddr_t region_size,
190                                            bool allow_memreserve_overlap)
191 {
192     const struct membanks *mem_banks[] = {
193         bootinfo_get_reserved_mem(),
194 #ifdef CONFIG_ACPI
195         bootinfo_get_acpi(),
196 #endif
197 #ifdef CONFIG_STATIC_SHM
198         bootinfo_get_shmem(),
199 #endif
200     };
201     unsigned int i;
202 
203     /*
204      * Check if input region is overlapping with reserved memory banks or
205      * ACPI EfiACPIReclaimMemory (when ACPI feature is enabled) or static
206      * shared memory banks (when static shared memory feature is enabled)
207      */
208     for ( i = 0; i < ARRAY_SIZE(mem_banks); i++ )
209         if ( meminfo_overlap_check(mem_banks[i], region_start, region_size,
210                                    allow_memreserve_overlap) )
211             return true;
212 
213     /* Check if input region is overlapping with boot_modules */
214     if ( boot_modules_overlap_check(&bootinfo.modules,
215                                     region_start, region_size) )
216         return true;
217 
218     return false;
219 }
220 
add_boot_module(boot_module_kind kind,paddr_t start,paddr_t size,bool domU)221 struct boot_module __init *add_boot_module(boot_module_kind kind,
222                                            paddr_t start, paddr_t size,
223                                            bool domU)
224 {
225     struct boot_modules *mods = &bootinfo.modules;
226     struct boot_module *mod;
227     unsigned int i;
228 
229     if ( mods->nr_mods == MAX_MODULES )
230     {
231         printk("Ignoring %s boot module at %"PRIpaddr"-%"PRIpaddr" (too many)\n",
232                boot_module_kind_as_string(kind), start, start + size);
233         return NULL;
234     }
235 
236     /*
237      * u-boot adds boot module such as ramdisk to the /memreserve/, since these
238      * ranges are saved in reserved_mem at this stage, allow an eventual exact
239      * match with MEMBANK_FDT_RESVMEM banks.
240      */
241     if ( check_reserved_regions_overlap(start, size, true) )
242         return NULL;
243 
244     for ( i = 0 ; i < mods->nr_mods ; i++ )
245     {
246         mod = &mods->module[i];
247         if ( mod->kind == kind && mod->start == start )
248         {
249             if ( !domU )
250                 mod->domU = false;
251             return mod;
252         }
253     }
254 
255     mod = &mods->module[mods->nr_mods++];
256     mod->kind = kind;
257     mod->start = start;
258     mod->size = size;
259     mod->domU = domU;
260 
261     return mod;
262 }
263 
264 /*
265  * boot_module_find_by_kind can only be used to return Xen modules (e.g
266  * XSM, DTB) or Dom0 modules. This is not suitable for looking up guest
267  * modules.
268  */
boot_module_find_by_kind(boot_module_kind kind)269 struct boot_module * __init boot_module_find_by_kind(boot_module_kind kind)
270 {
271     struct boot_modules *mods = &bootinfo.modules;
272     struct boot_module *mod;
273     int i;
274     for (i = 0 ; i < mods->nr_mods ; i++ )
275     {
276         mod = &mods->module[i];
277         if ( mod->kind == kind && !mod->domU )
278             return mod;
279     }
280     return NULL;
281 }
282 
add_boot_cmdline(const char * name,const char * cmdline,boot_module_kind kind,paddr_t start,bool domU)283 void __init add_boot_cmdline(const char *name, const char *cmdline,
284                              boot_module_kind kind, paddr_t start, bool domU)
285 {
286     struct bootcmdlines *cmds = &bootinfo.cmdlines;
287     struct bootcmdline *cmd;
288 
289     if ( cmds->nr_mods == MAX_MODULES )
290     {
291         printk("Ignoring %s cmdline (too many)\n", name);
292         return;
293     }
294 
295     cmd = &cmds->cmdline[cmds->nr_mods++];
296     cmd->kind = kind;
297     cmd->domU = domU;
298     cmd->start = start;
299 
300     ASSERT(strlen(name) <= DT_MAX_NAME);
301     safe_strcpy(cmd->dt_name, name);
302 
303     if ( strlen(cmdline) > BOOTMOD_MAX_CMDLINE )
304         panic("module %s command line too long\n", name);
305     safe_strcpy(cmd->cmdline, cmdline);
306 }
307 
308 /*
309  * boot_cmdline_find_by_kind can only be used to return Xen modules (e.g
310  * XSM, DTB) or Dom0 modules. This is not suitable for looking up guest
311  * modules.
312  */
boot_cmdline_find_by_kind(boot_module_kind kind)313 struct bootcmdline * __init boot_cmdline_find_by_kind(boot_module_kind kind)
314 {
315     struct bootcmdlines *cmds = &bootinfo.cmdlines;
316     struct bootcmdline *cmd;
317     int i;
318 
319     for ( i = 0 ; i < cmds->nr_mods ; i++ )
320     {
321         cmd = &cmds->cmdline[i];
322         if ( cmd->kind == kind && !cmd->domU )
323             return cmd;
324     }
325     return NULL;
326 }
327 
boot_cmdline_find_by_name(const char * name)328 struct bootcmdline * __init boot_cmdline_find_by_name(const char *name)
329 {
330     struct bootcmdlines *mods = &bootinfo.cmdlines;
331     struct bootcmdline *mod;
332     unsigned int i;
333 
334     for (i = 0 ; i < mods->nr_mods ; i++ )
335     {
336         mod = &mods->cmdline[i];
337         if ( strcmp(mod->dt_name, name) == 0 )
338             return mod;
339     }
340     return NULL;
341 }
342 
boot_module_find_by_addr_and_kind(boot_module_kind kind,paddr_t start)343 struct boot_module * __init boot_module_find_by_addr_and_kind(
344     boot_module_kind kind, paddr_t start)
345 {
346     struct boot_modules *mods = &bootinfo.modules;
347     struct boot_module *mod;
348     unsigned int i;
349 
350     for (i = 0 ; i < mods->nr_mods ; i++ )
351     {
352         mod = &mods->module[i];
353         if ( mod->kind == kind && mod->start == start )
354             return mod;
355     }
356     return NULL;
357 }
358 
359 /*
360  * Return the end of the non-module region starting at s. In other
361  * words return s the start of the next modules after s.
362  *
363  * On input *end is the end of the region which should be considered
364  * and it is updated to reflect the end of the module, clipped to the
365  * end of the region if it would run over.
366  */
next_module(paddr_t s,paddr_t * end)367 static paddr_t __init next_module(paddr_t s, paddr_t *end)
368 {
369     struct boot_modules *mi = &bootinfo.modules;
370     paddr_t lowest = ~(paddr_t)0;
371     int i;
372 
373     for ( i = 0; i < mi->nr_mods; i++ )
374     {
375         paddr_t mod_s = mi->module[i].start;
376         paddr_t mod_e = mod_s + mi->module[i].size;
377 
378         if ( !mi->module[i].size )
379             continue;
380 
381         if ( mod_s < s )
382             continue;
383         if ( mod_s > lowest )
384             continue;
385         if ( mod_s > *end )
386             continue;
387         lowest = mod_s;
388         *end = min(*end, mod_e);
389     }
390     return lowest;
391 }
392 
393 /*
394  * Populate the boot allocator.
395  * If a static heap was not provided by the admin, all the RAM but the
396  * following regions will be added:
397  *  - Modules (e.g., Xen, Kernel)
398  *  - Reserved regions
399  *  - Xenheap (CONFIG_SEPARATE_XENHEAP only)
400  * If a static heap was provided by the admin, populate the boot
401  * allocator with the corresponding regions only, but with Xenheap excluded
402  * on CONFIG_SEPARATE_XENHEAP.
403  */
populate_boot_allocator(void)404 void __init populate_boot_allocator(void)
405 {
406     unsigned int i;
407     const struct membanks *banks = bootinfo_get_mem();
408     const struct membanks *reserved_mem = bootinfo_get_reserved_mem();
409     paddr_t s, e;
410 
411     if ( using_static_heap )
412     {
413         for ( i = 0 ; i < reserved_mem->nr_banks; i++ )
414         {
415             if ( reserved_mem->bank[i].type != MEMBANK_STATIC_HEAP )
416                 continue;
417 
418             s = reserved_mem->bank[i].start;
419             e = s + reserved_mem->bank[i].size;
420 #ifdef CONFIG_SEPARATE_XENHEAP
421             /* Avoid the xenheap, note that the xenheap cannot across a bank */
422             if ( s <= mfn_to_maddr(directmap_mfn_start) &&
423                  e >= mfn_to_maddr(directmap_mfn_end) )
424             {
425                 init_boot_pages(s, mfn_to_maddr(directmap_mfn_start));
426                 init_boot_pages(mfn_to_maddr(directmap_mfn_end), e);
427             }
428             else
429 #endif
430                 init_boot_pages(s, e);
431         }
432 
433         return;
434     }
435 
436     for ( i = 0; i < banks->nr_banks; i++ )
437     {
438         const struct membank *bank = &banks->bank[i];
439         paddr_t bank_end = bank->start + bank->size;
440 
441         s = bank->start;
442         while ( s < bank_end )
443         {
444             paddr_t n = bank_end;
445 
446             e = next_module(s, &n);
447 
448             if ( e == ~(paddr_t)0 )
449                 e = n = bank_end;
450 
451             /*
452              * Module in a RAM bank other than the one which we are
453              * not dealing with here.
454              */
455             if ( e > bank_end )
456                 e = bank_end;
457 
458 #ifdef CONFIG_SEPARATE_XENHEAP
459             /* Avoid the xenheap */
460             if ( s < mfn_to_maddr(directmap_mfn_end) &&
461                  mfn_to_maddr(directmap_mfn_start) < e )
462             {
463                 e = mfn_to_maddr(directmap_mfn_start);
464                 n = mfn_to_maddr(directmap_mfn_end);
465             }
466 #endif
467 
468             fw_unreserved_regions(s, e, init_boot_pages, 0);
469             s = n;
470         }
471     }
472 }
473 
474 /*
475  * Local variables:
476  * mode: C
477  * c-file-style: "BSD"
478  * c-basic-offset: 4
479  * indent-tabs-mode: nil
480  * End:
481  */
482