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 void setup(const void *fdt, phys_addr_t freemem_start) 186 { 187 void *freemem; 188 const char *bootargs, *tmp; 189 u32 fdt_size; 190 int ret; 191 192 assert(sizeof(long) == 8 || freemem_start < (3ul << 30)); 193 freemem = (void *)(unsigned long)freemem_start; 194 195 /* Move the FDT to the base of free memory */ 196 fdt_size = fdt_totalsize(fdt); 197 ret = fdt_move(fdt, freemem, fdt_size); 198 assert(ret == 0); 199 ret = dt_init(freemem); 200 assert(ret == 0); 201 freemem += fdt_size; 202 203 /* Move the initrd to the top of the FDT */ 204 ret = dt_get_initrd(&tmp, &initrd_size); 205 assert(ret == 0 || ret == -FDT_ERR_NOTFOUND); 206 if (ret == 0) { 207 initrd = freemem; 208 memmove(initrd, tmp, initrd_size); 209 freemem += initrd_size; 210 } 211 212 memregions_init(arm_mem_regions, NR_MEM_REGIONS); 213 memregions_add_dt_regions(MAX_DT_MEM_REGIONS); 214 arm_memregions_add_assumed(); 215 mem_init(PAGE_ALIGN((unsigned long)freemem)); 216 217 psci_set_conduit(); 218 cpu_init(); 219 220 /* cpu_init must be called before thread_info_init */ 221 thread_info_init(current_thread_info(), 0); 222 223 /* mem_init must be called before io_init */ 224 io_init(); 225 226 timer_save_state(); 227 228 ret = dt_get_bootargs(&bootargs); 229 assert(ret == 0 || ret == -FDT_ERR_NOTFOUND); 230 setup_args_progname(bootargs); 231 232 if (initrd) { 233 /* environ is currently the only file in the initrd */ 234 char *env = malloc(initrd_size); 235 memcpy(env, initrd, initrd_size); 236 setup_env(env, initrd_size); 237 } 238 239 if (!(auxinfo.flags & AUXINFO_MMU_OFF)) 240 setup_vm(); 241 } 242 243 #ifdef CONFIG_EFI 244 245 #include <efi.h> 246 247 static efi_status_t setup_rsdp(efi_bootinfo_t *efi_bootinfo) 248 { 249 efi_status_t status; 250 struct acpi_table_rsdp *rsdp; 251 252 /* 253 * RSDP resides in an EFI_ACPI_RECLAIM_MEMORY region, which is not used 254 * by kvm-unit-tests arm64 memory allocator. So it is not necessary to 255 * copy the data structure to another memory region to prevent 256 * unintentional overwrite. 257 */ 258 status = efi_get_system_config_table(ACPI_20_TABLE_GUID, (void **)&rsdp); 259 if (status != EFI_SUCCESS) 260 return status; 261 262 set_efi_rsdp(rsdp); 263 264 return EFI_SUCCESS; 265 } 266 267 static efi_status_t efi_mem_init(efi_bootinfo_t *efi_bootinfo) 268 { 269 int i; 270 unsigned long free_mem_pages = 0; 271 unsigned long free_mem_start = 0; 272 struct efi_boot_memmap *map = &(efi_bootinfo->mem_map); 273 efi_memory_desc_t *buffer = *map->map; 274 efi_memory_desc_t *d = NULL; 275 phys_addr_t base, top; 276 struct mem_region r; 277 uintptr_t text = (uintptr_t)&_text, etext = ALIGN((uintptr_t)&_etext, 4096); 278 uintptr_t data = (uintptr_t)&_data, edata = ALIGN((uintptr_t)&_edata, 4096); 279 const void *fdt = efi_bootinfo->fdt; 280 int fdt_size, ret; 281 282 /* 283 * Record the largest free EFI_CONVENTIONAL_MEMORY region 284 * which will be used to set up the memory allocator, so that 285 * the memory allocator can work in the largest free 286 * continuous memory region. 287 */ 288 for (i = 0; i < *(map->map_size); i += *(map->desc_size)) { 289 d = (efi_memory_desc_t *)(&((u8 *)buffer)[i]); 290 291 r.start = d->phys_addr; 292 r.end = d->phys_addr + d->num_pages * EFI_PAGE_SIZE; 293 r.flags = 0; 294 295 switch (d->type) { 296 case EFI_RESERVED_TYPE: 297 case EFI_LOADER_DATA: 298 case EFI_BOOT_SERVICES_CODE: 299 case EFI_BOOT_SERVICES_DATA: 300 case EFI_RUNTIME_SERVICES_CODE: 301 case EFI_RUNTIME_SERVICES_DATA: 302 case EFI_UNUSABLE_MEMORY: 303 case EFI_ACPI_RECLAIM_MEMORY: 304 case EFI_ACPI_MEMORY_NVS: 305 case EFI_PAL_CODE: 306 r.flags = MR_F_RESERVED; 307 break; 308 case EFI_MEMORY_MAPPED_IO: 309 case EFI_MEMORY_MAPPED_IO_PORT_SPACE: 310 r.flags = MR_F_IO; 311 break; 312 case EFI_LOADER_CODE: 313 if (r.start <= text && r.end > text) { 314 /* This is the unit test region. Flag the code separately. */ 315 phys_addr_t tmp = r.end; 316 317 assert(etext <= data); 318 assert(edata <= r.end); 319 r.flags = MR_F_CODE; 320 r.end = data; 321 memregions_add(&r); 322 r.start = data; 323 r.end = tmp; 324 r.flags = 0; 325 } else { 326 r.flags = MR_F_RESERVED; 327 } 328 break; 329 case EFI_CONVENTIONAL_MEMORY: 330 if (free_mem_pages < d->num_pages) { 331 free_mem_pages = d->num_pages; 332 free_mem_start = d->phys_addr; 333 } 334 break; 335 } 336 337 if (!(r.flags & MR_F_IO)) { 338 if (r.start < __phys_offset) 339 __phys_offset = r.start; 340 if (r.end > __phys_end) 341 __phys_end = r.end; 342 } 343 memregions_add(&r); 344 } 345 if (fdt) { 346 /* Move the FDT to the base of free memory */ 347 fdt_size = fdt_totalsize(fdt); 348 ret = fdt_move(fdt, (void *)free_mem_start, fdt_size); 349 assert(ret == 0); 350 ret = dt_init((void *)free_mem_start); 351 assert(ret == 0); 352 free_mem_start += ALIGN(fdt_size, EFI_PAGE_SIZE); 353 free_mem_pages -= ALIGN(fdt_size, EFI_PAGE_SIZE) >> EFI_PAGE_SHIFT; 354 } 355 356 __phys_end &= PHYS_MASK; 357 asm_mmu_disable(); 358 359 if (free_mem_pages == 0) 360 return EFI_OUT_OF_RESOURCES; 361 362 assert(sizeof(long) == 8 || free_mem_start < (3ul << 30)); 363 364 phys_alloc_init(free_mem_start, free_mem_pages << EFI_PAGE_SHIFT); 365 phys_alloc_set_minimum_alignment(SMP_CACHE_BYTES); 366 367 phys_alloc_get_unused(&base, &top); 368 base = PAGE_ALIGN(base); 369 top = top & PAGE_MASK; 370 assert(sizeof(long) == 8 || !(base >> 32)); 371 if (sizeof(long) != 8 && (top >> 32) != 0) 372 top = ((uint64_t)1 << 32); 373 page_alloc_init_area(0, base >> PAGE_SHIFT, top >> PAGE_SHIFT); 374 page_alloc_ops_enable(); 375 376 return EFI_SUCCESS; 377 } 378 379 efi_status_t setup_efi(efi_bootinfo_t *efi_bootinfo) 380 { 381 efi_status_t status; 382 383 struct thread_info *ti = current_thread_info(); 384 385 memset(ti, 0, sizeof(*ti)); 386 387 exceptions_init(); 388 389 memregions_init(arm_mem_regions, NR_MEM_REGIONS); 390 391 status = efi_mem_init(efi_bootinfo); 392 if (status != EFI_SUCCESS) { 393 printf("Failed to initialize memory: "); 394 switch (status) { 395 case EFI_OUT_OF_RESOURCES: 396 printf("No free memory region\n"); 397 break; 398 default: 399 printf("Unknown error\n"); 400 break; 401 } 402 return status; 403 } 404 405 if (!dt_available()) { 406 status = setup_rsdp(efi_bootinfo); 407 if (status != EFI_SUCCESS) { 408 printf("Cannot find RSDP in EFI system table\n"); 409 return status; 410 } 411 } 412 413 psci_set_conduit(); 414 cpu_init(); 415 /* cpu_init must be called before thread_info_init */ 416 thread_info_init(current_thread_info(), 0); 417 /* mem_init must be called before io_init */ 418 io_init(); 419 420 timer_save_state(); 421 if (initrd) { 422 /* environ is currently the only file in the initrd */ 423 char *env = malloc(initrd_size); 424 425 memcpy(env, initrd, initrd_size); 426 setup_env(env, initrd_size); 427 } 428 429 if (!(auxinfo.flags & AUXINFO_MMU_OFF)) 430 setup_vm(); 431 432 return EFI_SUCCESS; 433 } 434 435 #endif 436