1 /* 2 * Initialize machine setup information and I/O. 3 * 4 * After running setup() unit tests may query how many cpus they have 5 * (nr_cpus), how much memory they have (PHYS_END - PHYS_OFFSET), may 6 * use dynamic memory allocation (malloc, etc.), printf, and exit. 7 * Finally, argc and argv are also ready to be passed to main(). 8 * 9 * Copyright (C) 2014, Red Hat Inc, Andrew Jones <drjones@redhat.com> 10 * 11 * This work is licensed under the terms of the GNU LGPL, version 2. 12 */ 13 #include <libcflat.h> 14 #include <libfdt/libfdt.h> 15 #include <devicetree.h> 16 #include <memregions.h> 17 #include <alloc.h> 18 #include <alloc_phys.h> 19 #include <alloc_page.h> 20 #include <vmalloc.h> 21 #include <auxinfo.h> 22 #include <argv.h> 23 #include <asm/thread_info.h> 24 #include <asm/setup.h> 25 #include <asm/page.h> 26 #include <asm/processor.h> 27 #include <asm/smp.h> 28 #include <asm/timer.h> 29 #include <asm/psci.h> 30 31 #include "io.h" 32 33 #define MAX_DT_MEM_REGIONS 16 34 #define NR_EXTRA_MEM_REGIONS 64 35 #define NR_MEM_REGIONS (MAX_DT_MEM_REGIONS + NR_EXTRA_MEM_REGIONS) 36 37 extern unsigned long _text, _etext, _data, _edata; 38 extern unsigned long stacktop; 39 40 char *initrd; 41 u32 initrd_size; 42 43 u64 cpus[NR_CPUS] = { [0 ... NR_CPUS-1] = (u64)~0 }; 44 int nr_cpus; 45 46 static struct mem_region arm_mem_regions[NR_MEM_REGIONS + 1]; 47 phys_addr_t __phys_offset = (phys_addr_t)-1, __phys_end = 0; 48 49 extern void exceptions_init(void); 50 extern void asm_mmu_disable(void); 51 52 int mpidr_to_cpu(uint64_t mpidr) 53 { 54 int i; 55 56 for (i = 0; i < nr_cpus; ++i) 57 if (cpus[i] == (mpidr & MPIDR_HWID_BITMASK)) 58 return i; 59 return -1; 60 } 61 62 static void cpu_set_fdt(int fdtnode __unused, u64 regval, void *info __unused) 63 { 64 int cpu = nr_cpus++; 65 66 assert_msg(cpu < NR_CPUS, "Number cpus exceeds maximum supported (%d).", NR_CPUS); 67 68 cpus[cpu] = regval; 69 set_cpu_present(cpu, true); 70 } 71 72 #ifdef CONFIG_EFI 73 74 #include <acpi.h> 75 76 static int cpu_set_acpi(struct acpi_subtable_header *header) 77 { 78 int cpu = nr_cpus++; 79 struct acpi_madt_generic_interrupt *gicc = (void *)header; 80 81 assert_msg(cpu < NR_CPUS, "Number cpus exceeds maximum supported (%d).", NR_CPUS); 82 83 cpus[cpu] = gicc->arm_mpidr; 84 set_cpu_present(cpu, true); 85 86 return 0; 87 } 88 89 static void cpu_init_acpi(void) 90 { 91 acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT, cpu_set_acpi); 92 } 93 94 #else 95 96 static void cpu_init_acpi(void) 97 { 98 assert_msg(false, "ACPI not available"); 99 } 100 101 #endif 102 103 static void cpu_init(void) 104 { 105 int ret; 106 107 nr_cpus = 0; 108 if (dt_available()) { 109 ret = dt_for_each_cpu_node(cpu_set_fdt, NULL); 110 assert(ret == 0); 111 } else { 112 cpu_init_acpi(); 113 } 114 115 set_cpu_online(0, true); 116 } 117 118 static void arm_memregions_add_assumed(void) 119 { 120 struct mem_region *code, *data; 121 122 /* Split the region with the code into two regions; code and data */ 123 memregions_split((unsigned long)&_etext, &code, &data); 124 assert(code); 125 code->flags |= MR_F_CODE; 126 127 /* 128 * mach-virt I/O regions: 129 * - The first 1G (arm/arm64) 130 * - 512M at 256G (arm64, arm uses highmem=off) 131 * - 512G at 512G (arm64, arm uses highmem=off) 132 */ 133 memregions_add(&(struct mem_region){ 0, (1ul << 30), MR_F_IO }); 134 #ifdef __aarch64__ 135 memregions_add(&(struct mem_region){ (1ul << 38), (1ul << 38) | (1ul << 29), MR_F_IO }); 136 memregions_add(&(struct mem_region){ (1ul << 39), (1ul << 40), MR_F_IO }); 137 #endif 138 } 139 140 static void mem_allocator_init(phys_addr_t freemem_start, phys_addr_t freemem_end) 141 { 142 phys_addr_t base, top; 143 144 freemem_start = PAGE_ALIGN(freemem_start); 145 freemem_end &= PAGE_MASK; 146 147 phys_alloc_init(freemem_start, freemem_end - freemem_start); 148 phys_alloc_set_minimum_alignment(SMP_CACHE_BYTES); 149 150 phys_alloc_get_unused(&base, &top); 151 base = PAGE_ALIGN(base); 152 top &= PAGE_MASK; 153 assert(sizeof(long) == 8 || !(base >> 32)); 154 if (sizeof(long) != 8 && (top >> 32) != 0) 155 top = ((uint64_t)1 << 32); 156 page_alloc_init_area(0, base >> PAGE_SHIFT, top >> PAGE_SHIFT); 157 page_alloc_ops_enable(); 158 } 159 160 static void mem_init(phys_addr_t freemem_start) 161 { 162 struct mem_region *freemem, *r, mem = { 163 .start = (phys_addr_t)-1, 164 }; 165 166 freemem = memregions_find(freemem_start); 167 assert(freemem && !(freemem->flags & (MR_F_IO | MR_F_CODE))); 168 169 for (r = mem_regions; r->end; ++r) { 170 if (!(r->flags & MR_F_IO)) { 171 if (r->start < mem.start) 172 mem.start = r->start; 173 if (r->end > mem.end) 174 mem.end = r->end; 175 } 176 } 177 assert(mem.end && !(mem.start & ~PHYS_MASK)); 178 mem.end &= PHYS_MASK; 179 180 /* Check for holes */ 181 r = memregions_find(mem.start); 182 while (r && r->end != mem.end) 183 r = memregions_find(r->end); 184 assert(r); 185 186 /* Ensure our selected freemem range is somewhere in our full range */ 187 assert(freemem_start >= mem.start && freemem->end <= mem.end); 188 189 __phys_offset = mem.start; /* PHYS_OFFSET */ 190 __phys_end = mem.end; /* PHYS_END */ 191 192 mem_allocator_init(freemem_start, freemem->end); 193 } 194 195 static void freemem_push_fdt(void **freemem, const void *fdt) 196 { 197 u32 fdt_size; 198 int ret; 199 200 #ifndef CONFIG_EFI 201 /* 202 * Ensure that the FDT was not overlapping with the uninitialised 203 * data that was overwritten. 204 */ 205 assert((unsigned long)fdt > (unsigned long)&stacktop); 206 #endif 207 208 fdt_size = fdt_totalsize(fdt); 209 ret = fdt_move(fdt, *freemem, fdt_size); 210 assert(ret == 0); 211 ret = dt_init(*freemem); 212 assert(ret == 0); 213 *freemem += fdt_size; 214 } 215 216 static void freemem_push_dt_initrd(void **freemem) 217 { 218 const char *tmp; 219 int ret; 220 221 ret = dt_get_initrd(&tmp, &initrd_size); 222 assert(ret == 0 || ret == -FDT_ERR_NOTFOUND); 223 if (ret == 0) { 224 initrd = *freemem; 225 memmove(initrd, tmp, initrd_size); 226 *freemem += initrd_size; 227 } 228 } 229 230 static void initrd_setup(void) 231 { 232 char *env; 233 234 if (!initrd) 235 return; 236 237 /* environ is currently the only file in the initrd */ 238 env = malloc(initrd_size); 239 memcpy(env, initrd, initrd_size); 240 setup_env(env, initrd_size); 241 } 242 243 void setup(const void *fdt, phys_addr_t freemem_start) 244 { 245 void *freemem; 246 const char *bootargs; 247 int ret; 248 249 assert(sizeof(long) == 8 || freemem_start < (3ul << 30)); 250 freemem = (void *)(unsigned long)freemem_start; 251 252 freemem_push_fdt(&freemem, fdt); 253 freemem_push_dt_initrd(&freemem); 254 255 memregions_init(arm_mem_regions, NR_MEM_REGIONS); 256 memregions_add_dt_regions(MAX_DT_MEM_REGIONS); 257 arm_memregions_add_assumed(); 258 mem_init(PAGE_ALIGN((unsigned long)freemem)); 259 260 psci_set_conduit(); 261 cpu_init(); 262 263 /* cpu_init must be called before thread_info_init */ 264 thread_info_init(current_thread_info(), 0); 265 266 /* mem_init must be called before io_init */ 267 io_init(); 268 269 timer_save_state(); 270 271 ret = dt_get_bootargs(&bootargs); 272 assert(ret == 0 || ret == -FDT_ERR_NOTFOUND); 273 setup_args_progname(bootargs); 274 275 initrd_setup(); 276 277 if (!(auxinfo.flags & AUXINFO_MMU_OFF)) 278 setup_vm(); 279 } 280 281 #ifdef CONFIG_EFI 282 283 #include <efi.h> 284 285 static efi_status_t setup_rsdp(efi_bootinfo_t *efi_bootinfo) 286 { 287 efi_status_t status; 288 struct acpi_table_rsdp *rsdp; 289 290 /* 291 * RSDP resides in an EFI_ACPI_RECLAIM_MEMORY region, which is not used 292 * by kvm-unit-tests arm64 memory allocator. So it is not necessary to 293 * copy the data structure to another memory region to prevent 294 * unintentional overwrite. 295 */ 296 status = efi_get_system_config_table(ACPI_20_TABLE_GUID, (void **)&rsdp); 297 if (status != EFI_SUCCESS) 298 return status; 299 300 set_efi_rsdp(rsdp); 301 302 return EFI_SUCCESS; 303 } 304 305 static efi_status_t efi_mem_init(efi_bootinfo_t *efi_bootinfo) 306 { 307 struct mem_region *freemem_mr = NULL, *code, *data; 308 phys_addr_t freemem_start; 309 void *freemem; 310 311 memregions_efi_init(&efi_bootinfo->mem_map, &freemem_mr); 312 if (!freemem_mr) 313 return EFI_OUT_OF_RESOURCES; 314 315 memregions_split((unsigned long)&_etext, &code, &data); 316 assert(code && (code->flags & MR_F_CODE)); 317 if (data) 318 data->flags &= ~MR_F_CODE; 319 320 for (struct mem_region *m = mem_regions; m->end; ++m) { 321 if (m != code) 322 assert(!(m->flags & MR_F_CODE)); 323 324 if (!(m->flags & MR_F_IO)) { 325 if (m->start < __phys_offset) 326 __phys_offset = m->start; 327 if (m->end > __phys_end) 328 __phys_end = m->end; 329 } 330 } 331 __phys_end &= PHYS_MASK; 332 333 freemem = (void *)PAGE_ALIGN(freemem_mr->start); 334 335 if (efi_bootinfo->fdt) 336 freemem_push_fdt(&freemem, efi_bootinfo->fdt); 337 338 freemem_start = PAGE_ALIGN((unsigned long)freemem); 339 assert(sizeof(long) == 8 || freemem_start < (3ul << 30)); 340 341 asm_mmu_disable(); 342 343 mem_allocator_init(freemem_start, freemem_mr->end); 344 345 return EFI_SUCCESS; 346 } 347 348 efi_status_t setup_efi(efi_bootinfo_t *efi_bootinfo) 349 { 350 efi_status_t status; 351 352 exceptions_init(); 353 354 memregions_init(arm_mem_regions, NR_MEM_REGIONS); 355 356 status = efi_mem_init(efi_bootinfo); 357 if (status != EFI_SUCCESS) { 358 printf("Failed to initialize memory: "); 359 switch (status) { 360 case EFI_OUT_OF_RESOURCES: 361 printf("No free memory region\n"); 362 break; 363 default: 364 printf("Unknown error\n"); 365 break; 366 } 367 return status; 368 } 369 370 if (!dt_available()) { 371 status = setup_rsdp(efi_bootinfo); 372 if (status != EFI_SUCCESS) { 373 printf("Cannot find RSDP in EFI system table\n"); 374 return status; 375 } 376 } 377 378 psci_set_conduit(); 379 cpu_init(); 380 /* cpu_init must be called before thread_info_init */ 381 thread_info_init(current_thread_info(), 0); 382 /* mem_init must be called before io_init */ 383 io_init(); 384 385 timer_save_state(); 386 387 initrd_setup(); 388 389 if (!(auxinfo.flags & AUXINFO_MMU_OFF)) 390 setup_vm(); 391 392 return EFI_SUCCESS; 393 } 394 395 #endif 396