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 39 char *initrd; 40 u32 initrd_size; 41 42 u64 cpus[NR_CPUS] = { [0 ... NR_CPUS-1] = (u64)~0 }; 43 int nr_cpus; 44 45 static struct mem_region arm_mem_regions[NR_MEM_REGIONS + 1]; 46 phys_addr_t __phys_offset = (phys_addr_t)-1, __phys_end = 0; 47 48 extern void exceptions_init(void); 49 extern void asm_mmu_disable(void); 50 51 int mpidr_to_cpu(uint64_t mpidr) 52 { 53 int i; 54 55 for (i = 0; i < nr_cpus; ++i) 56 if (cpus[i] == (mpidr & MPIDR_HWID_BITMASK)) 57 return i; 58 return -1; 59 } 60 61 static void cpu_set_fdt(int fdtnode __unused, u64 regval, void *info __unused) 62 { 63 int cpu = nr_cpus++; 64 65 assert_msg(cpu < NR_CPUS, "Number cpus exceeds maximum supported (%d).", NR_CPUS); 66 67 cpus[cpu] = regval; 68 set_cpu_present(cpu, true); 69 } 70 71 #ifdef CONFIG_EFI 72 73 #include <acpi.h> 74 75 static int cpu_set_acpi(struct acpi_subtable_header *header) 76 { 77 int cpu = nr_cpus++; 78 struct acpi_madt_generic_interrupt *gicc = (void *)header; 79 80 assert_msg(cpu < NR_CPUS, "Number cpus exceeds maximum supported (%d).", NR_CPUS); 81 82 cpus[cpu] = gicc->arm_mpidr; 83 set_cpu_present(cpu, true); 84 85 return 0; 86 } 87 88 static void cpu_init_acpi(void) 89 { 90 acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT, cpu_set_acpi); 91 } 92 93 #else 94 95 static void cpu_init_acpi(void) 96 { 97 assert_msg(false, "ACPI not available"); 98 } 99 100 #endif 101 102 static void cpu_init(void) 103 { 104 int ret; 105 106 nr_cpus = 0; 107 if (dt_available()) { 108 ret = dt_for_each_cpu_node(cpu_set_fdt, NULL); 109 assert(ret == 0); 110 } else { 111 cpu_init_acpi(); 112 } 113 114 set_cpu_online(0, true); 115 } 116 117 static void arm_memregions_add_assumed(void) 118 { 119 struct mem_region *code, *data; 120 121 /* Split the region with the code into two regions; code and data */ 122 memregions_split((unsigned long)&_etext, &code, &data); 123 assert(code); 124 code->flags |= MR_F_CODE; 125 126 /* 127 * mach-virt I/O regions: 128 * - The first 1G (arm/arm64) 129 * - 512M at 256G (arm64, arm uses highmem=off) 130 * - 512G at 512G (arm64, arm uses highmem=off) 131 */ 132 memregions_add(&(struct mem_region){ 0, (1ul << 30), MR_F_IO }); 133 #ifdef __aarch64__ 134 memregions_add(&(struct mem_region){ (1ul << 38), (1ul << 38) | (1ul << 29), MR_F_IO }); 135 memregions_add(&(struct mem_region){ (1ul << 39), (1ul << 40), MR_F_IO }); 136 #endif 137 } 138 139 static void mem_init(phys_addr_t freemem_start) 140 { 141 phys_addr_t base, top; 142 struct mem_region *freemem, *r, mem = { 143 .start = (phys_addr_t)-1, 144 }; 145 146 freemem = memregions_find(freemem_start); 147 assert(freemem && !(freemem->flags & (MR_F_IO | MR_F_CODE))); 148 149 for (r = mem_regions; r->end; ++r) { 150 if (!(r->flags & MR_F_IO)) { 151 if (r->start < mem.start) 152 mem.start = r->start; 153 if (r->end > mem.end) 154 mem.end = r->end; 155 } 156 } 157 assert(mem.end && !(mem.start & ~PHYS_MASK)); 158 mem.end &= PHYS_MASK; 159 160 /* Check for holes */ 161 r = memregions_find(mem.start); 162 while (r && r->end != mem.end) 163 r = memregions_find(r->end); 164 assert(r); 165 166 /* Ensure our selected freemem range is somewhere in our full range */ 167 assert(freemem_start >= mem.start && freemem->end <= mem.end); 168 169 __phys_offset = mem.start; /* PHYS_OFFSET */ 170 __phys_end = mem.end; /* PHYS_END */ 171 172 phys_alloc_init(freemem_start, freemem->end - freemem_start); 173 phys_alloc_set_minimum_alignment(SMP_CACHE_BYTES); 174 175 phys_alloc_get_unused(&base, &top); 176 base = PAGE_ALIGN(base); 177 top = top & PAGE_MASK; 178 assert(sizeof(long) == 8 || !(base >> 32)); 179 if (sizeof(long) != 8 && (top >> 32) != 0) 180 top = ((uint64_t)1 << 32); 181 page_alloc_init_area(0, base >> PAGE_SHIFT, top >> PAGE_SHIFT); 182 page_alloc_ops_enable(); 183 } 184 185 static void freemem_push_fdt(void **freemem, const void *fdt) 186 { 187 u32 fdt_size; 188 int ret; 189 190 fdt_size = fdt_totalsize(fdt); 191 ret = fdt_move(fdt, *freemem, fdt_size); 192 assert(ret == 0); 193 ret = dt_init(*freemem); 194 assert(ret == 0); 195 *freemem += fdt_size; 196 } 197 198 static void freemem_push_dt_initrd(void **freemem) 199 { 200 const char *tmp; 201 int ret; 202 203 ret = dt_get_initrd(&tmp, &initrd_size); 204 assert(ret == 0 || ret == -FDT_ERR_NOTFOUND); 205 if (ret == 0) { 206 initrd = *freemem; 207 memmove(initrd, tmp, initrd_size); 208 *freemem += initrd_size; 209 } 210 } 211 212 static void initrd_setup(void) 213 { 214 char *env; 215 216 if (!initrd) 217 return; 218 219 /* environ is currently the only file in the initrd */ 220 env = malloc(initrd_size); 221 memcpy(env, initrd, initrd_size); 222 setup_env(env, initrd_size); 223 } 224 225 void setup(const void *fdt, phys_addr_t freemem_start) 226 { 227 void *freemem; 228 const char *bootargs; 229 int ret; 230 231 assert(sizeof(long) == 8 || freemem_start < (3ul << 30)); 232 freemem = (void *)(unsigned long)freemem_start; 233 234 freemem_push_fdt(&freemem, fdt); 235 freemem_push_dt_initrd(&freemem); 236 237 memregions_init(arm_mem_regions, NR_MEM_REGIONS); 238 memregions_add_dt_regions(MAX_DT_MEM_REGIONS); 239 arm_memregions_add_assumed(); 240 mem_init(PAGE_ALIGN((unsigned long)freemem)); 241 242 psci_set_conduit(); 243 cpu_init(); 244 245 /* cpu_init must be called before thread_info_init */ 246 thread_info_init(current_thread_info(), 0); 247 248 /* mem_init must be called before io_init */ 249 io_init(); 250 251 timer_save_state(); 252 253 ret = dt_get_bootargs(&bootargs); 254 assert(ret == 0 || ret == -FDT_ERR_NOTFOUND); 255 setup_args_progname(bootargs); 256 257 initrd_setup(); 258 259 if (!(auxinfo.flags & AUXINFO_MMU_OFF)) 260 setup_vm(); 261 } 262 263 #ifdef CONFIG_EFI 264 265 #include <efi.h> 266 267 static efi_status_t setup_rsdp(efi_bootinfo_t *efi_bootinfo) 268 { 269 efi_status_t status; 270 struct acpi_table_rsdp *rsdp; 271 272 /* 273 * RSDP resides in an EFI_ACPI_RECLAIM_MEMORY region, which is not used 274 * by kvm-unit-tests arm64 memory allocator. So it is not necessary to 275 * copy the data structure to another memory region to prevent 276 * unintentional overwrite. 277 */ 278 status = efi_get_system_config_table(ACPI_20_TABLE_GUID, (void **)&rsdp); 279 if (status != EFI_SUCCESS) 280 return status; 281 282 set_efi_rsdp(rsdp); 283 284 return EFI_SUCCESS; 285 } 286 287 static efi_status_t efi_mem_init(efi_bootinfo_t *efi_bootinfo) 288 { 289 int i; 290 unsigned long free_mem_pages = 0; 291 unsigned long free_mem_start = 0; 292 struct efi_boot_memmap *map = &(efi_bootinfo->mem_map); 293 efi_memory_desc_t *buffer = *map->map; 294 efi_memory_desc_t *d = NULL; 295 phys_addr_t base, top; 296 struct mem_region r; 297 uintptr_t text = (uintptr_t)&_text, etext = ALIGN((uintptr_t)&_etext, 4096); 298 uintptr_t data = (uintptr_t)&_data, edata = ALIGN((uintptr_t)&_edata, 4096); 299 const void *fdt = efi_bootinfo->fdt; 300 301 /* 302 * Record the largest free EFI_CONVENTIONAL_MEMORY region 303 * which will be used to set up the memory allocator, so that 304 * the memory allocator can work in the largest free 305 * continuous memory region. 306 */ 307 for (i = 0; i < *(map->map_size); i += *(map->desc_size)) { 308 d = (efi_memory_desc_t *)(&((u8 *)buffer)[i]); 309 310 r.start = d->phys_addr; 311 r.end = d->phys_addr + d->num_pages * EFI_PAGE_SIZE; 312 r.flags = 0; 313 314 switch (d->type) { 315 case EFI_RESERVED_TYPE: 316 case EFI_LOADER_DATA: 317 case EFI_BOOT_SERVICES_CODE: 318 case EFI_BOOT_SERVICES_DATA: 319 case EFI_RUNTIME_SERVICES_CODE: 320 case EFI_RUNTIME_SERVICES_DATA: 321 case EFI_UNUSABLE_MEMORY: 322 case EFI_ACPI_RECLAIM_MEMORY: 323 case EFI_ACPI_MEMORY_NVS: 324 case EFI_PAL_CODE: 325 r.flags = MR_F_RESERVED; 326 break; 327 case EFI_MEMORY_MAPPED_IO: 328 case EFI_MEMORY_MAPPED_IO_PORT_SPACE: 329 r.flags = MR_F_IO; 330 break; 331 case EFI_LOADER_CODE: 332 if (r.start <= text && r.end > text) { 333 /* This is the unit test region. Flag the code separately. */ 334 phys_addr_t tmp = r.end; 335 336 assert(etext <= data); 337 assert(edata <= r.end); 338 r.flags = MR_F_CODE; 339 r.end = data; 340 memregions_add(&r); 341 r.start = data; 342 r.end = tmp; 343 r.flags = 0; 344 } else { 345 r.flags = MR_F_RESERVED; 346 } 347 break; 348 case EFI_CONVENTIONAL_MEMORY: 349 if (free_mem_pages < d->num_pages) { 350 free_mem_pages = d->num_pages; 351 free_mem_start = d->phys_addr; 352 } 353 break; 354 } 355 356 if (!(r.flags & MR_F_IO)) { 357 if (r.start < __phys_offset) 358 __phys_offset = r.start; 359 if (r.end > __phys_end) 360 __phys_end = r.end; 361 } 362 memregions_add(&r); 363 } 364 365 if (fdt) { 366 unsigned long old_start = free_mem_start; 367 void *freemem = (void *)free_mem_start; 368 369 freemem_push_fdt(&freemem, fdt); 370 371 free_mem_start = ALIGN((unsigned long)freemem, EFI_PAGE_SIZE); 372 free_mem_pages = (free_mem_start - old_start) >> EFI_PAGE_SHIFT; 373 } 374 375 __phys_end &= PHYS_MASK; 376 asm_mmu_disable(); 377 378 if (free_mem_pages == 0) 379 return EFI_OUT_OF_RESOURCES; 380 381 assert(sizeof(long) == 8 || free_mem_start < (3ul << 30)); 382 383 phys_alloc_init(free_mem_start, free_mem_pages << EFI_PAGE_SHIFT); 384 phys_alloc_set_minimum_alignment(SMP_CACHE_BYTES); 385 386 phys_alloc_get_unused(&base, &top); 387 base = PAGE_ALIGN(base); 388 top = top & PAGE_MASK; 389 assert(sizeof(long) == 8 || !(base >> 32)); 390 if (sizeof(long) != 8 && (top >> 32) != 0) 391 top = ((uint64_t)1 << 32); 392 page_alloc_init_area(0, base >> PAGE_SHIFT, top >> PAGE_SHIFT); 393 page_alloc_ops_enable(); 394 395 return EFI_SUCCESS; 396 } 397 398 efi_status_t setup_efi(efi_bootinfo_t *efi_bootinfo) 399 { 400 efi_status_t status; 401 402 struct thread_info *ti = current_thread_info(); 403 404 memset(ti, 0, sizeof(*ti)); 405 406 exceptions_init(); 407 408 memregions_init(arm_mem_regions, NR_MEM_REGIONS); 409 410 status = efi_mem_init(efi_bootinfo); 411 if (status != EFI_SUCCESS) { 412 printf("Failed to initialize memory: "); 413 switch (status) { 414 case EFI_OUT_OF_RESOURCES: 415 printf("No free memory region\n"); 416 break; 417 default: 418 printf("Unknown error\n"); 419 break; 420 } 421 return status; 422 } 423 424 if (!dt_available()) { 425 status = setup_rsdp(efi_bootinfo); 426 if (status != EFI_SUCCESS) { 427 printf("Cannot find RSDP in EFI system table\n"); 428 return status; 429 } 430 } 431 432 psci_set_conduit(); 433 cpu_init(); 434 /* cpu_init must be called before thread_info_init */ 435 thread_info_init(current_thread_info(), 0); 436 /* mem_init must be called before io_init */ 437 io_init(); 438 439 timer_save_state(); 440 441 initrd_setup(); 442 443 if (!(auxinfo.flags & AUXINFO_MMU_OFF)) 444 setup_vm(); 445 446 return EFI_SUCCESS; 447 } 448 449 #endif 450