#include <xen/pfn.h>
#include <xen/sizes.h>
#include <xen/libfdt/libfdt.h>
-
#include <asm/setup.h>
+#include <asm/coloring.h>
/* Override macros from asm/page.h to make them work with mfn_t */
#undef virt_to_mfn
DEFINE_BOOT_PAGE_TABLE(boot_third_id);
DEFINE_BOOT_PAGE_TABLE(boot_second);
DEFINE_BOOT_PAGE_TABLE(boot_third);
+#ifdef CONFIG_COLORING
+DEFINE_BOOT_PAGE_TABLE(boot_colored_xen);
+#endif
/* Main runtime page tables */
clean_and_invalidate_dcache_va_range(table, PAGE_SIZE);
}
+#ifdef CONFIG_COLORING
+/*
+ * Translate a Xen (.text) virtual address to the colored physical one
+ * depending on the hypervisor configuration.
+ * N.B: this function must be used only when migrating from non colored to
+ * colored pagetables since it assumes to have the temporary mappings created
+ * during setup_pagetables that starts from BOOT_RELOC_VIRT_START.
+ * After the migration we have to use virt_to_maddr.
+ */
+static paddr_t virt_to_maddr_colored(vaddr_t virt)
+{
+ unsigned int va_offset;
+
+ va_offset = virt - XEN_VIRT_START;
+ return __pa(BOOT_RELOC_VIRT_START + va_offset);
+}
+
+static void __init coloring_temp_mappings(paddr_t xen_paddr, vaddr_t virt_start)
+{
+ int i;
+ lpae_t pte;
+ unsigned int xen_text_size = (_end - _start);
+
+ xen_text_size = PAGE_ALIGN(xen_text_size);
+
+ C_DEBUG("First level mapping\n");
+ pte = mfn_to_xen_entry(maddr_to_mfn(__pa(boot_second)), MT_NORMAL);
+ pte.pt.table = 1;
+ boot_first[first_table_offset(virt_start)] = pte;
+
+ C_DEBUG("Second level mapping\n");
+ pte = mfn_to_xen_entry(maddr_to_mfn(__pa(boot_colored_xen)), MT_NORMAL);
+ pte.pt.table = 1;
+ boot_second[second_table_offset(virt_start)] = pte;
+
+ C_DEBUG("Third level mapping\n");
+ for ( i = 0; i < (xen_text_size/PAGE_SIZE); i++ )
+ {
+ mfn_t mfn;
+ xen_paddr = next_xen_colored(xen_paddr);
+ mfn = maddr_to_mfn(xen_paddr);
+ pte = mfn_to_xen_entry(mfn, MT_NORMAL);
+ pte.pt.table = 1; /* 4k mappings always have this bit set */
+ boot_colored_xen[i] = pte;
+ xen_paddr += PAGE_SIZE;
+ }
+
+ flush_xen_tlb_local();
+}
+
+/*
+ * Boot-time pagetable setup with coloring support
+ * Changes here may need matching changes in head.S
+ *
+ * The process can be explained as follows:
+ * - Create a temporary colored mapping that conforms to Xen color selection.
+ * - Update all the pagetables links that point to the next level table(s):
+ * this process is crucial beacause the translation tables are not physically
+ * contiguous and we cannot calculate the physical addresses by using the
+ * standard method (physical offset). In order to get the correct physical
+ * address we use virt_to_maddr_colored that translates the virtual address
+ * into a physical one based on the Xen coloring configuration.
+ * - Copy Xen to the new location.
+ * - Update TTBR0_EL2 with the new root page table address.
+ */
+void __init setup_pagetables(unsigned long boot_phys_offset, paddr_t xen_paddr)
+{
+ int i;
+ lpae_t pte, *p;
+ paddr_t pt_phys;
+ mfn_t pt_phys_mfn;
+ paddr_t _xen_paddr = xen_paddr;
+
+ phys_offset = boot_phys_offset;
+
+ ASSERT((_end - _start) < SECOND_SIZE);
+ /* Create temporary mappings */
+ coloring_temp_mappings(xen_paddr, BOOT_RELOC_VIRT_START);
+
+ /* Build pagetables links */
+ p = (void *)xen_pgtable;
+ pt_phys = virt_to_maddr_colored((vaddr_t)xen_first);
+ pt_phys_mfn = maddr_to_mfn(pt_phys);
+ p[0] = mfn_to_xen_entry(pt_phys_mfn, MT_NORMAL);
+ p[0].pt.table = 1;
+ p[0].pt.xn = 0;
+ p = (void *)xen_first;
+
+ for ( i = 0; i < 2; i++ )
+ {
+ pt_phys = virt_to_maddr_colored((vaddr_t)(xen_second + i * LPAE_ENTRIES));
+ pt_phys_mfn = maddr_to_mfn(pt_phys);
+ p[i] = mfn_to_xen_entry(pt_phys_mfn, MT_NORMAL);
+ p[i].pt.table = 1;
+ p[i].pt.xn = 0;
+ }
+
+ for ( i = 0; i < LPAE_ENTRIES; i++ )
+ {
+ mfn_t mfn;
+ vaddr_t va = XEN_VIRT_START + (i << PAGE_SHIFT);
+ _xen_paddr = next_xen_colored(_xen_paddr);
+ mfn = maddr_to_mfn(_xen_paddr);
+ if ( !is_kernel(va) )
+ break;
+ pte = mfn_to_xen_entry(mfn, MT_NORMAL);
+ pte.pt.table = 1; /* 4k mappings always have this bit set */
+ if ( is_kernel_text(va) || is_kernel_inittext(va) )
+ {
+ pte.pt.xn = 0;
+ pte.pt.ro = 1;
+ }
+ if ( is_kernel_rodata(va) )
+ pte.pt.ro = 1;
+ xen_xenmap[i] = pte;
+ _xen_paddr += PAGE_SIZE;
+ }
+
+ /* Initialise xen second level entries ... */
+ /* ... Xen's text etc */
+ pt_phys = virt_to_maddr_colored((vaddr_t)(xen_xenmap));
+ pt_phys_mfn = maddr_to_mfn(pt_phys);
+ pte = mfn_to_xen_entry(pt_phys_mfn, MT_NORMAL);
+ pte.pt.table = 1;
+ xen_second[second_table_offset(XEN_VIRT_START)] = pte;
+
+ /* ... Fixmap */
+ pt_phys = virt_to_maddr_colored((vaddr_t)(xen_fixmap));
+ pt_phys_mfn = maddr_to_mfn(pt_phys);
+ pte = mfn_to_xen_entry(pt_phys_mfn, MT_NORMAL);
+ pte.pt.table = 1;
+ xen_second[second_table_offset(FIXMAP_ADDR(0))] = pte;
+
+ /* ... DTB */
+ pte = boot_second[second_table_offset(BOOT_FDT_VIRT_START)];
+ xen_second[second_table_offset(BOOT_FDT_VIRT_START)] = pte;
+ pte = boot_second[second_table_offset(BOOT_FDT_VIRT_START + SZ_2M)];
+ xen_second[second_table_offset(BOOT_FDT_VIRT_START + SZ_2M)] = pte;
+
+ /* Update the value of init_ttbr */
+ init_ttbr = virt_to_maddr_colored((vaddr_t)xen_pgtable);
+ clean_dcache(init_ttbr);
+
+ /* Copy Xen to the new location */
+ memcpy((void*)BOOT_RELOC_VIRT_START,
+ (const void*)XEN_VIRT_START, (_end - _start));
+ clean_dcache_va_range((void*)BOOT_RELOC_VIRT_START, (_end - _start));
+
+ /* Change ttbr */
+ switch_ttbr(init_ttbr);
+
+ /*
+ * Keep mapped old Xen memory in a contiguous mapping
+ * for other cpus to boot. This mapping will also replace the
+ * one created at the beginning of setup_pagetables.
+ */
+ C_DEBUG("Keeping mapping from 0x%lx (VA: 0x%lx) for 2 MiB\n",
+ XEN_VIRT_START + phys_offset, BOOT_RELOC_VIRT_START);
+ create_mappings(xen_second, BOOT_RELOC_VIRT_START,
+ paddr_to_pfn(XEN_VIRT_START + phys_offset),
+ SZ_2M >> PAGE_SHIFT, SZ_2M);
+
+ xen_pt_enforce_wnx();
+}
+#else
/* Boot-time pagetable setup.
* Changes here may need matching changes in head.S */
void __init setup_pagetables(unsigned long boot_phys_offset, paddr_t xen_paddr)
per_cpu(xen_dommap, 0) = cpu0_dommap;
#endif
}
+#endif /* !CONFIG_COLORING */
static void clear_boot_pagetables(void)
{
#endif
clear_table(boot_second);
clear_table(boot_third);
+#ifdef CONFIG_COLORING
+ clear_table(boot_colored_xen);
+#endif
}
#ifdef CONFIG_ARM_64
{
clear_boot_pagetables();
+ /*
+ * For coloring the value of the ttbr was already set up during
+ * setup_pagetables.
+ */
+#ifndef CONFIG_COLORING
/* Set init_ttbr for this CPU coming up. All CPus share a single setof
* pagetables, but rewrite it each time for consistency with 32 bit. */
init_ttbr = (uintptr_t) xen_pgtable + phys_offset;
clean_dcache(init_ttbr);
+#endif
return 0;
}
#else
else if ( xenheap_first_first_slot == -1)
{
/* Use xenheap_first_first to bootstrap the mappings */
- first = xenheap_first_first;
+ paddr_t phys_addr;
+
+ /*
+ * At this stage is safe to use virt_to_maddr because Xen mapping
+ * is already in place. Using virt_to_maddr allows us to unify
+ * codepath with and without cache coloring enabled.
+ */
+ phys_addr = virt_to_maddr((vaddr_t)xenheap_first_first);
+ pte = mfn_to_xen_entry(maddr_to_mfn(phys_addr),MT_NORMAL);
- pte = pte_of_xenaddr((vaddr_t)xenheap_first_first);
pte.pt.table = 1;
write_pte(p, pte);
+ first = xenheap_first_first;
xenheap_first_first_slot = slot;
}
else
mi->nr_mods = 0;
remove_early_mappings(BOOT_FDT_VIRT_START, SZ_2M);
+ /*
+ * This removal is useful if cache coloring is enabled but
+ * it should not affect non coloring configuration
+ */
+ remove_early_mappings(BOOT_RELOC_VIRT_START, SZ_2M);
}
/* Relocate the FDT in Xen heap */
.max_maptrack_frames = -1,
};
int rc;
+ uint32_t xen_size = (_end - _start);
+ paddr_t xen_paddr;
dcache_line_bytes = read_dcache_line_bytes();
/* Initialize traps early allow us to get backtrace when an error occurred */
init_traps();
- setup_pagetables(boot_phys_offset, 0);
-
smp_clear_cpu_maps();
device_tree_flattened = early_fdt_map(fdt_paddr);
fdt_size = boot_fdt_info(device_tree_flattened, fdt_paddr);
- if ( !coloring_init() )
- panic("Xen Coloring support: setup failed\n");
-
- xen_paddr = get_xen_paddr(_end - _start);
- setup_pagetables(boot_phys_offset, xen_paddr);
-
cmdline = boot_fdt_cmdline(device_tree_flattened);
printk("Command line: %s\n", cmdline);
cmdline_parse(cmdline);
+ if ( !coloring_init() )
+ panic("Xen Coloring support: setup failed\n");
+ xen_size = XEN_COLOR_MAP_SIZE;
+
/* Register Xen's load address as a boot module. */
xen_bootmodule = add_boot_module(BOOTMOD_XEN,
(paddr_t)(uintptr_t)(_start + boot_phys_offset),
- (paddr_t)(uintptr_t)(_end - _start + 1), false);
+ (paddr_t)(uintptr_t)(xen_size + 1), false);
BUG_ON(!xen_bootmodule);
+ xen_paddr = get_xen_paddr(xen_size);
+ setup_pagetables(boot_phys_offset, xen_paddr);
+
+ /* Update Xen's address now that we have relocated. */
+ printk("Update BOOTMOD_XEN from %"PRIpaddr"-%"PRIpaddr" => %"PRIpaddr"-%"PRIpaddr"\n",
+ xen_bootmodule->start, xen_bootmodule->start + xen_bootmodule->size,
+ xen_paddr, xen_paddr + xen_bootmodule->size);
+ xen_bootmodule->start = xen_paddr;
+
setup_mm();
/* Parse the ACPI tables for possible boot-time configuration */