]> xenbits.xensource.com Git - people/julieng/freebsd.git/commitdiff
arm: Add FDT support for Linux Boot ABI
authorJulien Grall <julien.grall@linaro.org>
Thu, 10 Apr 2014 15:59:14 +0000 (16:59 +0100)
committerJulien Grall <julien.grall@citrix.com>
Mon, 5 Oct 2015 17:55:36 +0000 (18:55 +0100)
sys/arm/arm/machdep.c
sys/arm/include/machdep.h

index 17b718d946d52163d460fa1cd5434492694d7982..c5df05b2e0927ddaf67485ecdbaae905b4edc15b 100644 (file)
@@ -58,7 +58,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/bio.h>
 #include <sys/buf.h>
 #include <sys/bus.h>
-#include <sys/cons.h>
+ #include <sys/cons.h>
 #include <sys/cpu.h>
 #include <sys/efi.h>
 #include <sys/exec.h>
@@ -113,6 +113,7 @@ __FBSDID("$FreeBSD$");
 
 #ifdef FDT
 #include <dev/fdt/fdt_common.h>
+#include <libfdt.h>
 #include <dev/ofw/openfirm.h>
 #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.
index 0f43284c852df132b06f23f1a46fd94c81f962d1..04f649c1756f6db6230d74f7d84c8b04ba09c136 100644 (file)
@@ -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);