From: Julien Grall Date: Thu, 10 Apr 2014 15:59:14 +0000 (+0100) Subject: arm: Add FDT support for Linux Boot ABI X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=d3dcd6210c81fa98324df9b842695b6ff3bc0162;p=people%2Fjulieng%2Ffreebsd.git arm: Add FDT support for Linux Boot ABI --- diff --git a/sys/arm/arm/machdep.c b/sys/arm/arm/machdep.c index 17b718d946d5..c5df05b2e092 100644 --- a/sys/arm/arm/machdep.c +++ b/sys/arm/arm/machdep.c @@ -58,7 +58,7 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include + #include #include #include #include @@ -113,6 +113,7 @@ __FBSDID("$FreeBSD$"); #ifdef FDT #include +#include #include #endif @@ -228,6 +229,7 @@ char atags[LBABI_MAX_COMMAND_LINE * 2]; uint32_t memstart[LBABI_MAX_BANKS]; uint32_t memsize[LBABI_MAX_BANKS]; uint32_t membanks; + #endif static uint32_t board_revision; @@ -864,14 +866,15 @@ makectx(struct trapframe *tf, struct pcb *pcb) * Fake up a boot descriptor table */ vm_offset_t -fake_preload_metadata(struct arm_boot_params *abp __unused) +fake_preload_metadata(struct arm_boot_params *abp __unused, + vm_offset_t fdt_addr) { #ifdef DDB vm_offset_t zstart = 0, zend = 0; #endif vm_offset_t lastaddr; int i = 0; - static uint32_t fake_preload[35]; + static uint32_t fake_preload[38]; fake_preload[i++] = MODINFO_NAME; fake_preload[i++] = strlen("kernel") + 1; @@ -887,6 +890,9 @@ fake_preload_metadata(struct arm_boot_params *abp __unused) fake_preload[i++] = MODINFO_SIZE; fake_preload[i++] = sizeof(uint32_t); fake_preload[i++] = (uint32_t)&end - KERNVIRTADDR; + fake_preload[i++] = MODINFOMD_DTBP | MODINFO_METADATA; + fake_preload[i++] = sizeof(vm_offset_t); + fake_preload[i++] = fdt_addr; #ifdef DDB if (*(uint32_t *)KERNVIRTADDR == MAGIC_TRAMP_NUMBER) { fake_preload[i++] = MODINFO_METADATA|MODINFOMD_SSYM; @@ -923,6 +929,7 @@ pcpu0_init(void) vm_offset_t linux_parse_boot_param(struct arm_boot_params *abp) { + void *ptr; struct arm_lbabi_tag *walker; uint32_t revision; uint64_t serial; @@ -936,10 +943,15 @@ linux_parse_boot_param(struct arm_boot_params *abp) return 0; board_id = abp->abp_r1; - walker = (struct arm_lbabi_tag *) - (abp->abp_r2 + KERNVIRTADDR - abp->abp_physaddr); + ptr = (void *)(abp->abp_r2 + KERNVIRTADDR - abp->abp_physaddr); + +#ifdef FDT + if (!fdt_check_header(ptr)) + return fake_preload_metadata(abp, (vm_offset_t)ptr); +#endif + + walker = ptr; - /* xxx - Need to also look for binary device tree */ if (ATAG_TAG(walker) != ATAG_CORE) return 0; @@ -978,7 +990,7 @@ linux_parse_boot_param(struct arm_boot_params *abp) bcopy(atag_list, atags, (char *)walker - (char *)atag_list + ATAG_SIZE(walker)); - return fake_preload_metadata(abp); + return fake_preload_metadata(abp, 0); } #endif @@ -1035,7 +1047,7 @@ default_parse_boot_param(struct arm_boot_params *abp) return lastaddr; #endif /* Fall back to hardcoded metadata. */ - lastaddr = fake_preload_metadata(abp); + lastaddr = fake_preload_metadata(abp, 0); return lastaddr; } @@ -1245,12 +1257,15 @@ initarm(struct arm_boot_params *abp) struct mem_region mem_regions[FDT_MEM_REGIONS]; struct pv_addr kernel_l1pt; struct pv_addr dpcpu; + struct pv_addr fdtpage; vm_offset_t dtbp, freemempos, l2_start, lastaddr; uint32_t memsize, l2size; char *env; void *kmdp; u_int l1pagetable; int i, j, err_devmap, mem_regions_sz; + vm_paddr_t fdt_paddr; + vm_size_t fdt_size; lastaddr = parse_boot_param(abp); arm_physmem_kernaddr = abp->abp_physaddr; @@ -1284,6 +1299,13 @@ initarm(struct arm_boot_params *abp) if (OF_init((void *)dtbp) != 0) panic("OF_init failed with the found device tree"); + /* Get the physical address of the device tree. This will be used + * later to correctly map the FDT in virtual memory when Linux boot + * ABI loader is used + */ + fdt_paddr = (dtbp - KERNVIRTADDR + abp->abp_physaddr); + fdt_size = fdt_totalsize(dtbp); + /* Grab physical memory regions information from device tree. */ if (fdt_get_mem_regions(mem_regions, &mem_regions_sz, &memsize) != 0) panic("Cannot get physical memory regions"); @@ -1294,6 +1316,10 @@ initarm(struct arm_boot_params *abp) arm_physmem_exclude_regions(mem_regions, mem_regions_sz, EXFLAG_NODUMP | EXFLAG_NOALLOC); + /* TODO: get correctly the DTB size */ + arm_physmem_exclude_region(fdt_paddr, fdt_size, + EXFLAG_NODUMP | EXFLAG_NOALLOC); + /* Platform-specific initialisation */ platform_probe_and_attach(); @@ -1363,6 +1389,11 @@ initarm(struct arm_boot_params *abp) valloc_pages(kernelstack, kstack_pages * MAXCPU); valloc_pages(msgbufpv, round_page(msgbufsize) / PAGE_SIZE); + /* Allocate virtual address for the device tree */ + fdt_size = round_page(fdt_size + fdt_paddr & PAGE_MASK); + valloc_pages(fdtpage, fdt_size >> PAGE_SHIFT); + fdtpage.pv_pa = trunc_page(fdt_paddr); + /* * Now we start construction of the L1 page table * We start by mapping the L2 page tables into the L1. @@ -1410,6 +1441,10 @@ initarm(struct arm_boot_params *abp) pmap_map_entry(l1pagetable, ARM_VECTORS_HIGH, systempage.pv_pa, VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE, PTE_CACHE); + /* Map the DTB */ + pmap_map_entry(l1pagetable, fdtpage.pv_va, fdtpage.pv_pa, + VM_PROT_READ, PTE_CACHE); + /* Establish static device mappings. */ err_devmap = platform_devmap_init(); arm_devmap_bootstrap(l1pagetable, NULL); @@ -1421,6 +1456,12 @@ initarm(struct arm_boot_params *abp) cpu_tlb_flushID(); cpu_domains(DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL * 2)); + /* We need to reinitalize OF subsystem to system the new DTB pointer */ + /* TODO: Find a nicer way... */ + dtbp = fdtpage.pv_va + (fdt_paddr - fdtpage.pv_pa); + if (OF_init((void *)dtbp) != 0) + panic("OF_init failed to update the DTB virtual address"); + /* * Now that proper page tables are installed, call cpu_setup() to enable * instruction and data caches and other chip-specific features. diff --git a/sys/arm/include/machdep.h b/sys/arm/include/machdep.h index 0f43284c852d..04f649c1756f 100644 --- a/sys/arm/include/machdep.h +++ b/sys/arm/include/machdep.h @@ -35,7 +35,8 @@ struct arm_boot_params; vm_offset_t default_parse_boot_param(struct arm_boot_params *abp); vm_offset_t freebsd_parse_boot_param(struct arm_boot_params *abp); vm_offset_t linux_parse_boot_param(struct arm_boot_params *abp); -vm_offset_t fake_preload_metadata(struct arm_boot_params *abp); +vm_offset_t fake_preload_metadata(struct arm_boot_params *abp, + vm_offset_t fdt_addr); vm_offset_t parse_boot_param(struct arm_boot_params *abp); void arm_generic_initclocks(void);