@@ -89,7 +89,8 @@
#define DIRECTMAP_SLOT_END 509
#define DIRECTMAP_SLOT_START 200
#define DIRECTMAP_VIRT_START SLOTN(DIRECTMAP_SLOT_START)
-#define DIRECTMAP_SIZE (SLOTN(DIRECTMAP_SLOT_END) - SLOTN(DIRECTMAP_SLOT_START))
+#define DIRECTMAP_SIZE (SLOTN(DIRECTMAP_SLOT_END + 1) - SLOTN(DIRECTMAP_SLOT_START))
+#define DIRECTMAP_VIRT_END (DIRECTMAP_VIRT_START + DIRECTMAP_SIZE - 1)
#define FRAMETABLE_SCALE_FACTOR (PAGE_SIZE/sizeof(struct page_info))
#define FRAMETABLE_SIZE_IN_SLOTS (((DIRECTMAP_SIZE / SLOTN(1)) / FRAMETABLE_SCALE_FACTOR) + 1)
@@ -12,6 +12,8 @@
#include <asm/page-bits.h>
+extern vaddr_t directmap_virt_start;
+
#define pfn_to_paddr(pfn) ((paddr_t)(pfn) << PAGE_SHIFT)
#define paddr_to_pfn(pa) ((unsigned long)((pa) >> PAGE_SHIFT))
@@ -25,8 +27,11 @@
static inline void *maddr_to_virt(paddr_t ma)
{
- BUG_ON("unimplemented");
- return NULL;
+ unsigned long va = directmap_virt_start + maddr_to_directmapoff(ma);
+
+ ASSERT((va >= DIRECTMAP_VIRT_START) && (va <= DIRECTMAP_VIRT_END));
+
+ return (void *)va;
}
/*
@@ -38,8 +43,8 @@ static inline void *maddr_to_virt(paddr_t ma)
static inline unsigned long virt_to_maddr(unsigned long va)
{
if ((va >= DIRECTMAP_VIRT_START) &&
- (va < (DIRECTMAP_VIRT_START + DIRECTMAP_SIZE)))
- return directmapoff_to_maddr(va - DIRECTMAP_VIRT_START);
+ (va <= DIRECTMAP_VIRT_END))
+ return directmapoff_to_maddr(va - directmap_virt_start);
BUILD_BUG_ON(XEN_VIRT_SIZE != MB(2));
ASSERT((va >> (PAGETABLE_ORDER + PAGE_SHIFT)) ==
@@ -127,11 +132,13 @@ struct page_info
};
};
+extern struct page_info *frametable_virt_start;
+
#define frame_table ((struct page_info *)FRAMETABLE_VIRT_START)
/* Convert between machine frame numbers and page-info structures. */
-#define mfn_to_page(mfn) (frame_table + mfn_x(mfn))
-#define page_to_mfn(pg) _mfn((pg) - frame_table)
+#define mfn_to_page(mfn) (frametable_virt_start + mfn_x(mfn))
+#define page_to_mfn(pg) _mfn((pg) - frametable_virt_start)
static inline void *page_to_virt(const struct page_info *pg)
{
@@ -5,6 +5,8 @@
#define max_init_domid (0)
+void setup_mm(void);
+
#endif /* ASM__RISCV__SETUP_H */
/*
@@ -372,6 +372,12 @@ int destroy_xen_mappings(unsigned long s, unsigned long e)
return -1;
}
+void share_xen_page_with_guest(struct page_info *page, struct domain *d,
+ enum XENSHARE_flags flags)
+{
+ BUG_ON("unimplemented");
+}
+
void * __init early_fdt_map(paddr_t fdt_paddr)
{
/* We are using 2MB superpage for mapping the FDT */
@@ -423,3 +429,145 @@ void * __init early_fdt_map(paddr_t fdt_paddr)
return fdt_virt;
}
+
+vaddr_t __ro_after_init directmap_virt_start = DIRECTMAP_VIRT_START;
+
+struct page_info *__ro_after_init frametable_virt_start = frame_table;
+
+#ifndef CONFIG_RISCV_32
+
+/*
+ * Map a frame table to cover physical addresses ps through pe.
+ * This function is expected to be called only once.
+ */
+static void __init setup_frametable_mappings(paddr_t ps, paddr_t pe)
+{
+ paddr_t aligned_ps = ROUNDUP(ps, PAGE_SIZE);
+ paddr_t aligned_pe = ROUNDDOWN(pe, PAGE_SIZE);
+ unsigned long nr_mfns = PFN_DOWN(aligned_pe - aligned_ps);
+ unsigned long frametable_size = nr_mfns * sizeof(*frame_table);
+ mfn_t base_mfn;
+
+ frametable_virt_start -= paddr_to_pfn(aligned_ps);
+
+ if ( frametable_size > FRAMETABLE_SIZE )
+ panic("The frametable cannot cover [%#"PRIpaddr", %#"PRIpaddr")\n",
+ ps, pe);
+
+ /*
+ * align base_mfn and frametable_size to MB(2) to have superpage mapping
+ * in map_pages_to_xen()
+ */
+ frametable_size = ROUNDUP(frametable_size, MB(2));
+ base_mfn = alloc_boot_pages(PFN_DOWN(frametable_size), PFN_DOWN(MB(2)));
+
+ if ( map_pages_to_xen(FRAMETABLE_VIRT_START, base_mfn,
+ PFN_DOWN(frametable_size),
+ PAGE_HYPERVISOR_RW) )
+ panic("frametable mappings failed: %#lx -> %#lx\n",
+ FRAMETABLE_VIRT_START, mfn_x(base_mfn));
+
+ memset(&frame_table[0], 0, nr_mfns * sizeof(*frame_table));
+ memset(&frame_table[nr_mfns], -1,
+ frametable_size - (nr_mfns * sizeof(*frame_table)));
+}
+
+/* Map the region in the directmap area. */
+static void __init setup_directmap_mappings(unsigned long base_mfn,
+ unsigned long nr_mfns)
+{
+ static mfn_t __initdata directmap_mfn_start = INVALID_MFN_INITIALIZER;
+
+ mfn_t base_mfn_t = _mfn(base_mfn);
+ unsigned long base_addr = mfn_to_maddr(base_mfn_t);
+ unsigned long high_bits_mask = XEN_PT_LEVEL_MAP_MASK(HYP_PT_ROOT_LEVEL);
+ int res;
+
+ /* First call sets the directmap physical and virtual offset. */
+ if ( mfn_eq(directmap_mfn_start, INVALID_MFN) )
+ {
+ directmap_mfn_start = base_mfn_t;
+
+ /*
+ * The base address may not be aligned to the second level
+ * size in case of Sv39 (e.g. 1GB when using 4KB pages).
+ * This would prevent superpage mappings for all the regions
+ * because the virtual address and machine address should
+ * both be suitably aligned.
+ *
+ * Prevent that by offsetting the start of the directmap virtual
+ * address.
+ */
+ directmap_virt_start -= (base_addr & high_bits_mask);
+ }
+
+ if ( base_mfn < mfn_x(directmap_mfn_start) )
+ panic("can't add directmap mapping at %#lx below directmap start %#lx\n",
+ base_mfn, mfn_x(directmap_mfn_start));
+
+ if ( (res = map_pages_to_xen((vaddr_t)mfn_to_virt(base_mfn),
+ base_mfn_t, nr_mfns,
+ PAGE_HYPERVISOR_RW)) )
+ panic("Directmap mappings for [%#"PRIpaddr", %#"PRIpaddr") failed: %d\n",
+ mfn_to_maddr(base_mfn_t),
+ mfn_to_maddr(mfn_add(base_mfn_t, nr_mfns)), res);
+}
+
+#else /* CONFIG_RISCV_32 */
+#error setup_{directmap,frametable}_mapping() should be implemented for RV_32
+#endif
+
+/*
+ * Setup memory management
+ *
+ * RISC-V 64 has a large virtual address space (the minimum supported
+ * MMU mode is Sv39, which provides GBs of VA space).
+ *
+ * The directmap_virt_start is shifted lower in the VA space to
+ * (DIRECTMAP_VIRT_START - masked_low_bits_of_ram_start_address) to avoid
+ * wasting a large portion of the directmap space, this also allows for simple
+ * VA <-> PA translations. Also aligns DIRECTMAP_VIRT_START to a GB boundary
+ * (for Sv39; for other MMU mode boundaries will be bigger ) by masking the
+ * bits of the RAM start address to enable the use of superpages in
+ * map_pages_to_xen().
+ *
+ * The frametable is mapped starting from physical address RAM_START, so an
+ * additional offset is applied in setup_frametable_mappings() to initialize
+ * frametable_virt_start to minimize wasting of VA space and simplifying
+ * page_to_mfn() and mfn_to_page() translations.
+ */
+void __init setup_mm(void)
+{
+ const struct membanks *banks = bootinfo_get_mem();
+ paddr_t ram_start = INVALID_PADDR;
+ paddr_t ram_end = 0;
+ unsigned int i;
+
+ /*
+ * We need some memory to allocate the page-tables used for the directmap
+ * mappings. But some regions may contain memory already allocated
+ * for other uses (e.g. modules, reserved-memory...).
+ *
+ * For simplicity, add all the free regions in the boot allocator.
+ */
+ populate_boot_allocator();
+
+ if ( !banks->nr_banks )
+ panic("bank->nr_banks shouldn't be zero, check memory node in dts\n");
+
+ for ( i = 0; i < banks->nr_banks; i++ )
+ {
+ const struct membank *bank = &banks->bank[i];
+ paddr_t bank_start = ROUNDUP(bank->start, PAGE_SIZE);
+ paddr_t bank_end = ROUNDDOWN(bank->start + bank->size, PAGE_SIZE);
+ unsigned long bank_size = bank_end - bank_start;
+
+ ram_start = min(ram_start, bank_start);
+ ram_end = max(ram_end, bank_end);
+
+ setup_directmap_mappings(PFN_DOWN(bank_start), PFN_DOWN(bank_size));
+ }
+
+ setup_frametable_mappings(ram_start, ram_end);
+ max_page = PFN_DOWN(ram_end);
+}
@@ -12,6 +12,7 @@
#include <asm/early_printk.h>
#include <asm/sbi.h>
+#include <asm/setup.h>
#include <asm/smp.h>
#include <asm/traps.h>
@@ -59,6 +60,8 @@ void __init noreturn start_xen(unsigned long bootcpu_id,
printk("Command line: %s\n", cmdline);
cmdline_parse(cmdline);
+ setup_mm();
+
printk("All set up\n");
machine_halt();
@@ -2,6 +2,7 @@
#define __MACROS_H__
#define ROUNDUP(x, a) (((x) + (a) - 1) & ~((a) - 1))
+#define ROUNDDOWN(x, a) ((x) & ~((a) - 1))
#define IS_ALIGNED(val, align) (!((val) & ((align) - 1)))