Message ID | 20200701162959.9814-12-vicooodin@gmail.com |
---|---|
State | New |
Headers | show |
Series | Add new board: Xen guest for ARM64 | expand |
On 01/07/2020 17:29, Anastasiia Lukianenko wrote: > From: Oleksandr Andrushchenko <oleksandr_andrushchenko at epam.com> > > Make required updates to run on u-boot. > > Signed-off-by: Oleksandr Andrushchenko <oleksandr_andrushchenko at epam.com> > Signed-off-by: Anastasiia Lukianenko <anastasiia_lukianenko at epam.com> > --- > board/xen/xenguest_arm64/xenguest_arm64.c | 13 ++ > drivers/xen/Makefile | 1 + > drivers/xen/gnttab.c | 258 ++++++++++++++++++++++ > drivers/xen/hypervisor.c | 2 + > include/xen/gnttab.h | 25 +++ > 5 files changed, 299 insertions(+) > create mode 100644 drivers/xen/gnttab.c > create mode 100644 include/xen/gnttab.h > > diff --git a/board/xen/xenguest_arm64/xenguest_arm64.c b/board/xen/xenguest_arm64/xenguest_arm64.c > index e8621f7174..b4e1650f99 100644 > --- a/board/xen/xenguest_arm64/xenguest_arm64.c > +++ b/board/xen/xenguest_arm64/xenguest_arm64.c > @@ -22,6 +22,7 @@ > > #include <linux/compiler.h> > > +#include <xen/gnttab.h> > #include <xen/hvm.h> > > DECLARE_GLOBAL_DATA_PTR; > @@ -64,6 +65,8 @@ static int setup_mem_map(void) > struct fdt_resource res; > const void *blob = gd->fdt_blob; > u64 gfn; > + phys_addr_t gnttab_base; > + phys_size_t gnttab_sz; > > /* > * Add "magic" region which is used by Xen to provide some essentials > @@ -97,6 +100,16 @@ static int setup_mem_map(void) > PTE_BLOCK_INNER_SHARE); > i++; > > + /* Get Xen's suggested physical page assignments for the grant table. */ > + get_gnttab_base(&gnttab_base, &gnttab_sz); > + > + xen_mem_map[i].virt = gnttab_base; > + xen_mem_map[i].phys = gnttab_base; > + xen_mem_map[i].size = gnttab_sz; > + xen_mem_map[i].attrs = (PTE_BLOCK_MEMTYPE(MT_NORMAL) | > + PTE_BLOCK_INNER_SHARE); > + i++; > + > mem = get_next_memory_node(blob, -1); > if (mem < 0) { > printf("%s: Missing /memory node\n", __func__); > diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile > index 9d0f604aaa..243b13277a 100644 > --- a/drivers/xen/Makefile > +++ b/drivers/xen/Makefile > @@ -5,3 +5,4 @@ > obj-y += hypervisor.o > obj-y += events.o > obj-y += xenbus.o > +obj-y += gnttab.o > diff --git a/drivers/xen/gnttab.c b/drivers/xen/gnttab.c > new file mode 100644 > index 0000000000..b18102e329 > --- /dev/null > +++ b/drivers/xen/gnttab.c > @@ -0,0 +1,258 @@ > +/* > + **************************************************************************** > + * (C) 2006 - Cambridge University > + * (C) 2020 - EPAM Systems Inc. > + **************************************************************************** > + * > + * File: gnttab.c > + * Author: Steven Smith (sos22 at cam.ac.uk) > + * Changes: Grzegorz Milos (gm281 at cam.ac.uk) > + * > + * Date: July 2006 > + * > + * Environment: Xen Minimal OS > + * Description: Simple grant tables implementation. About as stupid as it's > + * possible to be and still work. > + * > + **************************************************************************** > + */ > +#include <common.h> > +#include <linux/compiler.h> > +#include <log.h> > +#include <malloc.h> > + > +#include <asm/armv8/mmu.h> > +#include <asm/io.h> > +#include <asm/xen/system.h> > + > +#include <linux/bug.h> > + > +#include <xen/gnttab.h> > +#include <xen/hvm.h> > + > +#include <xen/interface/memory.h> > + > +DECLARE_GLOBAL_DATA_PTR; > + > +#define NR_RESERVED_ENTRIES 8 > + > +/* NR_GRANT_FRAMES must be less than or equal to that configured in Xen */ > +#define NR_GRANT_FRAMES 1 > +#define NR_GRANT_ENTRIES (NR_GRANT_FRAMES * PAGE_SIZE / sizeof(struct grant_entry_v1)) > + > +static struct grant_entry_v1 *gnttab_table; > +static grant_ref_t gnttab_list[NR_GRANT_ENTRIES]; > + > +static void put_free_entry(grant_ref_t ref) > +{ > + unsigned long flags; > + > + local_irq_save(flags); > + gnttab_list[ref] = gnttab_list[0]; > + gnttab_list[0] = ref; > + local_irq_restore(flags); > +} > + > +static grant_ref_t get_free_entry(void) > +{ > + unsigned int ref; > + unsigned long flags; > + > + local_irq_save(flags); > + ref = gnttab_list[0]; > + BUG_ON(ref < NR_RESERVED_ENTRIES || ref >= NR_GRANT_ENTRIES); > + gnttab_list[0] = gnttab_list[ref]; > + local_irq_restore(flags); > + return ref; > +} > + > +grant_ref_t gnttab_grant_access(domid_t domid, unsigned long frame, int readonly) > +{ > + grant_ref_t ref; > + > + ref = get_free_entry(); > + gnttab_table[ref].frame = frame; > + gnttab_table[ref].domid = domid; > + wmb(); > + readonly *= GTF_readonly; > + gnttab_table[ref].flags = GTF_permit_access | readonly; > + > + return ref; > +} > + > +grant_ref_t gnttab_grant_transfer(domid_t domid, unsigned long pfn) It is not possible to transfer grant on Arm. So I would suggest to remove the code related to it. [...] > +unsigned long gnttab_end_transfer(grant_ref_t ref) likewise. > +{ > + unsigned long frame; > + u16 flags; > + > + BUG_ON(ref >= NR_GRANT_ENTRIES || ref < NR_RESERVED_ENTRIES); > + > + while (!((flags = gnttab_table[ref].flags) & GTF_transfer_committed)) { > + if (synch_cmpxchg(&gnttab_table[ref].flags, flags, 0) == flags) { > + printf("Release unused transfer grant.\n"); > + put_free_entry(ref); > + return 0; > + } > + } > + > + /* If a transfer is in progress then wait until it is completed. */ > + while (!(flags & GTF_transfer_completed)) > + flags = gnttab_table[ref].flags; > + > + /* Read the frame number /after/ reading completion status. */ > + rmb(); > + frame = gnttab_table[ref].frame; > + > + put_free_entry(ref); > + > + return frame; > +} > + > +grant_ref_t gnttab_alloc_and_grant(void **map) > +{ > + unsigned long mfn; > + grant_ref_t gref; > + > + *map = (void *)memalign(PAGE_SIZE, PAGE_SIZE); > + mfn = virt_to_mfn(*map); > + gref = gnttab_grant_access(0, mfn, 0); > + return gref; > +} > + > +static const char * const gnttabop_error_msgs[] = GNTTABOP_error_msgs; > + > +const char *gnttabop_error(int16_t status) > +{ > + status = -status; > + if (status < 0 || status >= ARRAY_SIZE(gnttabop_error_msgs)) > + return "bad status"; > + else > + return gnttabop_error_msgs[status]; > +} > + > +/* Get Xen's suggested physical page assignments for the grant table. */ > +void get_gnttab_base(phys_addr_t *gnttab_base, phys_size_t *gnttab_sz) > +{ > + const void *blob = gd->fdt_blob; > + struct fdt_resource res; > + int mem; > + > + mem = fdt_node_offset_by_compatible(blob, -1, "xen,xen"); > + if (mem < 0) { > + printf("No xen,xen compatible found\n"); > + BUG(); > + } > + > + mem = fdt_get_resource(blob, mem, "reg", 0, &res); > + if (mem == -FDT_ERR_NOTFOUND) { > + printf("No grant table base in the device tree\n"); > + BUG(); > + } > + > + *gnttab_base = (phys_addr_t)res.start; > + if (gnttab_sz) > + *gnttab_sz = (phys_size_t)(res.end - res.start + 1); > + > + debug("FDT suggests grant table base at %llx\n", > + *gnttab_base); > +} > + > +void init_gnttab(void) > +{ > + struct xen_add_to_physmap xatp; > + struct gnttab_setup_table setup; > + xen_pfn_t frames[NR_GRANT_FRAMES]; > + int i, rc; > + > + debug("%s\n", __func__); > + > + for (i = NR_RESERVED_ENTRIES; i < NR_GRANT_ENTRIES; i++) > + put_free_entry(i); > + > + get_gnttab_base((phys_addr_t *)&gnttab_table, NULL); > + > + for (i = 0; i < NR_GRANT_FRAMES; i++) { > + xatp.domid = DOMID_SELF; > + xatp.size = 0; > + xatp.space = XENMAPSPACE_grant_table; > + xatp.idx = i; > + xatp.gpfn = PFN_DOWN((unsigned long)gnttab_table) + i; > + rc = HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp); > + if (rc) > + printf("XENMEM_add_to_physmap failed; status = %d\n", > + rc); > + BUG_ON(rc != 0); > + } > + > + setup.dom = DOMID_SELF; > + setup.nr_frames = NR_GRANT_FRAMES; > + set_xen_guest_handle(setup.frame_list, frames); > + rc = HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1); > + if (rc || setup.status) { > + printf("GNTTABOP_setup_table failed; status = %s\n", > + gnttabop_error(setup.status)); > + BUG(); > + } GNTTAOP_grant_table_op is not needed on Arm. > +} > + > +void fini_gnttab(void) > +{ > + struct xen_remove_from_physmap xrtp; > + struct gnttab_setup_table setup; > + int i, rc; > + > + debug("%s\n", __func__); > + > + for (i = 0; i < NR_GRANT_FRAMES; i++) { > + xrtp.domid = DOMID_SELF; > + xrtp.gpfn = PFN_DOWN((unsigned long)gnttab_table) + i; > + rc = HYPERVISOR_memory_op(XENMEM_remove_from_physmap, &xrtp); > + if (rc) > + printf("XENMEM_remove_from_physmap failed; status = %d\n", > + rc); > + BUG_ON(rc != 0); > + } > + > + setup.dom = DOMID_SELF; > + setup.nr_frames = 0; > + > + HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1); > + if (setup.status) { > + printf("GNTTABOP_setup_table failed; status = %s\n", > + gnttabop_error(setup.status)); > + BUG(); > + } The hypercall doesn't do any clean-up in Xen. So why are you calling this from fini_gnttab()? Cheers,
Hi Julien, On Wed, 2020-07-01 at 17:59 +0100, Julien Grall wrote: > > On 01/07/2020 17:29, Anastasiia Lukianenko wrote: > > From: Oleksandr Andrushchenko <oleksandr_andrushchenko at epam.com> > > > > Make required updates to run on u-boot. > > > > Signed-off-by: Oleksandr Andrushchenko < > > oleksandr_andrushchenko at epam.com> > > Signed-off-by: Anastasiia Lukianenko < > > anastasiia_lukianenko at epam.com> > > --- > > board/xen/xenguest_arm64/xenguest_arm64.c | 13 ++ > > drivers/xen/Makefile | 1 + > > drivers/xen/gnttab.c | 258 > > ++++++++++++++++++++++ > > drivers/xen/hypervisor.c | 2 + > > include/xen/gnttab.h | 25 +++ > > 5 files changed, 299 insertions(+) > > create mode 100644 drivers/xen/gnttab.c > > create mode 100644 include/xen/gnttab.h > > > > diff --git a/board/xen/xenguest_arm64/xenguest_arm64.c > > b/board/xen/xenguest_arm64/xenguest_arm64.c > > index e8621f7174..b4e1650f99 100644 > > --- a/board/xen/xenguest_arm64/xenguest_arm64.c > > +++ b/board/xen/xenguest_arm64/xenguest_arm64.c > > @@ -22,6 +22,7 @@ > > > > #include <linux/compiler.h> > > > > +#include <xen/gnttab.h> > > #include <xen/hvm.h> > > > > DECLARE_GLOBAL_DATA_PTR; > > @@ -64,6 +65,8 @@ static int setup_mem_map(void) > > struct fdt_resource res; > > const void *blob = gd->fdt_blob; > > u64 gfn; > > + phys_addr_t gnttab_base; > > + phys_size_t gnttab_sz; > > > > /* > > * Add "magic" region which is used by Xen to provide some > > essentials > > @@ -97,6 +100,16 @@ static int setup_mem_map(void) > > PTE_BLOCK_INNER_SHARE); > > i++; > > > > + /* Get Xen's suggested physical page assignments for the grant > > table. */ > > + get_gnttab_base(&gnttab_base, &gnttab_sz); > > + > > + xen_mem_map[i].virt = gnttab_base; > > + xen_mem_map[i].phys = gnttab_base; > > + xen_mem_map[i].size = gnttab_sz; > > + xen_mem_map[i].attrs = (PTE_BLOCK_MEMTYPE(MT_NORMAL) | > > + PTE_BLOCK_INNER_SHARE); > > + i++; > > + > > mem = get_next_memory_node(blob, -1); > > if (mem < 0) { > > printf("%s: Missing /memory node\n", __func__); > > diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile > > index 9d0f604aaa..243b13277a 100644 > > --- a/drivers/xen/Makefile > > +++ b/drivers/xen/Makefile > > @@ -5,3 +5,4 @@ > > obj-y += hypervisor.o > > obj-y += events.o > > obj-y += xenbus.o > > +obj-y += gnttab.o > > diff --git a/drivers/xen/gnttab.c b/drivers/xen/gnttab.c > > new file mode 100644 > > index 0000000000..b18102e329 > > --- /dev/null > > +++ b/drivers/xen/gnttab.c > > @@ -0,0 +1,258 @@ > > +/* > > + > > ******************************************************************* > > ********* > > + * (C) 2006 - Cambridge University > > + * (C) 2020 - EPAM Systems Inc. > > + > > ******************************************************************* > > ********* > > + * > > + * File: gnttab.c > > + * Author: Steven Smith (sos22 at cam.ac.uk) > > + * Changes: Grzegorz Milos (gm281 at cam.ac.uk) > > + * > > + * Date: July 2006 > > + * > > + * Environment: Xen Minimal OS > > + * Description: Simple grant tables implementation. About as > > stupid as it's > > + * possible to be and still work. > > + * > > + > > ******************************************************************* > > ********* > > + */ > > +#include <common.h> > > +#include <linux/compiler.h> > > +#include <log.h> > > +#include <malloc.h> > > + > > +#include <asm/armv8/mmu.h> > > +#include <asm/io.h> > > +#include <asm/xen/system.h> > > + > > +#include <linux/bug.h> > > + > > +#include <xen/gnttab.h> > > +#include <xen/hvm.h> > > + > > +#include <xen/interface/memory.h> > > + > > +DECLARE_GLOBAL_DATA_PTR; > > + > > +#define NR_RESERVED_ENTRIES 8 > > + > > +/* NR_GRANT_FRAMES must be less than or equal to that configured > > in Xen */ > > +#define NR_GRANT_FRAMES 1 > > +#define NR_GRANT_ENTRIES (NR_GRANT_FRAMES * PAGE_SIZE / > > sizeof(struct grant_entry_v1)) > > + > > +static struct grant_entry_v1 *gnttab_table; > > +static grant_ref_t gnttab_list[NR_GRANT_ENTRIES]; > > + > > +static void put_free_entry(grant_ref_t ref) > > +{ > > + unsigned long flags; > > + > > + local_irq_save(flags); > > + gnttab_list[ref] = gnttab_list[0]; > > + gnttab_list[0] = ref; > > + local_irq_restore(flags); > > +} > > + > > +static grant_ref_t get_free_entry(void) > > +{ > > + unsigned int ref; > > + unsigned long flags; > > + > > + local_irq_save(flags); > > + ref = gnttab_list[0]; > > + BUG_ON(ref < NR_RESERVED_ENTRIES || ref >= NR_GRANT_ENTRIES); > > + gnttab_list[0] = gnttab_list[ref]; > > + local_irq_restore(flags); > > + return ref; > > +} > > + > > +grant_ref_t gnttab_grant_access(domid_t domid, unsigned long > > frame, int readonly) > > +{ > > + grant_ref_t ref; > > + > > + ref = get_free_entry(); > > + gnttab_table[ref].frame = frame; > > + gnttab_table[ref].domid = domid; > > + wmb(); > > + readonly *= GTF_readonly; > > + gnttab_table[ref].flags = GTF_permit_access | readonly; > > + > > + return ref; > > +} > > + > > +grant_ref_t gnttab_grant_transfer(domid_t domid, unsigned long > > pfn) > > It is not possible to transfer grant on Arm. So I would suggest to > remove the code related to it. > > [...] Makes sense, will remove. > > > +unsigned long gnttab_end_transfer(grant_ref_t ref) > > likewise. Same above. > > > +{ > > + unsigned long frame; > > + u16 flags; > > + > > + BUG_ON(ref >= NR_GRANT_ENTRIES || ref < NR_RESERVED_ENTRIES); > > + > > + while (!((flags = gnttab_table[ref].flags) & > > GTF_transfer_committed)) { > > + if (synch_cmpxchg(&gnttab_table[ref].flags, flags, 0) > > == flags) { > > + printf("Release unused transfer grant.\n"); > > + put_free_entry(ref); > > + return 0; > > + } > > + } > > + > > + /* If a transfer is in progress then wait until it is > > completed. */ > > + while (!(flags & GTF_transfer_completed)) > > + flags = gnttab_table[ref].flags; > > + > > + /* Read the frame number /after/ reading completion status. */ > > + rmb(); > > + frame = gnttab_table[ref].frame; > > + > > + put_free_entry(ref); > > + > > + return frame; > > +} > > + > > +grant_ref_t gnttab_alloc_and_grant(void **map) > > +{ > > + unsigned long mfn; > > + grant_ref_t gref; > > + > > + *map = (void *)memalign(PAGE_SIZE, PAGE_SIZE); > > + mfn = virt_to_mfn(*map); > > + gref = gnttab_grant_access(0, mfn, 0); > > + return gref; > > +} > > + > > +static const char * const gnttabop_error_msgs[] = > > GNTTABOP_error_msgs; > > + > > +const char *gnttabop_error(int16_t status) > > +{ > > + status = -status; > > + if (status < 0 || status >= ARRAY_SIZE(gnttabop_error_msgs)) > > + return "bad status"; > > + else > > + return gnttabop_error_msgs[status]; > > +} > > + > > +/* Get Xen's suggested physical page assignments for the grant > > table. */ > > +void get_gnttab_base(phys_addr_t *gnttab_base, phys_size_t > > *gnttab_sz) > > +{ > > + const void *blob = gd->fdt_blob; > > + struct fdt_resource res; > > + int mem; > > + > > + mem = fdt_node_offset_by_compatible(blob, -1, "xen,xen"); > > + if (mem < 0) { > > + printf("No xen,xen compatible found\n"); > > + BUG(); > > + } > > + > > + mem = fdt_get_resource(blob, mem, "reg", 0, &res); > > + if (mem == -FDT_ERR_NOTFOUND) { > > + printf("No grant table base in the device tree\n"); > > + BUG(); > > + } > > + > > + *gnttab_base = (phys_addr_t)res.start; > > + if (gnttab_sz) > > + *gnttab_sz = (phys_size_t)(res.end - res.start + 1); > > + > > + debug("FDT suggests grant table base at %llx\n", > > + *gnttab_base); > > +} > > + > > +void init_gnttab(void) > > +{ > > + struct xen_add_to_physmap xatp; > > + struct gnttab_setup_table setup; > > + xen_pfn_t frames[NR_GRANT_FRAMES]; > > + int i, rc; > > + > > + debug("%s\n", __func__); > > + > > + for (i = NR_RESERVED_ENTRIES; i < NR_GRANT_ENTRIES; i++) > > + put_free_entry(i); > > + > > + get_gnttab_base((phys_addr_t *)&gnttab_table, NULL); > > + > > + for (i = 0; i < NR_GRANT_FRAMES; i++) { > > + xatp.domid = DOMID_SELF; > > + xatp.size = 0; > > + xatp.space = XENMAPSPACE_grant_table; > > + xatp.idx = i; > > + xatp.gpfn = PFN_DOWN((unsigned long)gnttab_table) + i; > > + rc = HYPERVISOR_memory_op(XENMEM_add_to_physmap, > > &xatp); > > + if (rc) > > + printf("XENMEM_add_to_physmap failed; status = > > %d\n", > > + rc); > > + BUG_ON(rc != 0); > > + } > > + > > + setup.dom = DOMID_SELF; > > + setup.nr_frames = NR_GRANT_FRAMES; > > + set_xen_guest_handle(setup.frame_list, frames); > > + rc = HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, > > 1); > > + if (rc || setup.status) { > > + printf("GNTTABOP_setup_table failed; status = %s\n", > > + gnttabop_error(setup.status)); > > + BUG(); > > + } > > GNTTAOP_grant_table_op is not needed on Arm. > Ok, will remove. > > +} > > + > > +void fini_gnttab(void) > > +{ > > + struct xen_remove_from_physmap xrtp; > > + struct gnttab_setup_table setup; > > + int i, rc; > > + > > + debug("%s\n", __func__); > > + > > + for (i = 0; i < NR_GRANT_FRAMES; i++) { > > + xrtp.domid = DOMID_SELF; > > + xrtp.gpfn = PFN_DOWN((unsigned long)gnttab_table) + i; > > + rc = HYPERVISOR_memory_op(XENMEM_remove_from_physmap, > > &xrtp); > > + if (rc) > > + printf("XENMEM_remove_from_physmap failed; > > status = %d\n", > > + rc); > > + BUG_ON(rc != 0); > > + } > > + > > + setup.dom = DOMID_SELF; > > + setup.nr_frames = 0; > > + > > + HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1); > > + if (setup.status) { > > + printf("GNTTABOP_setup_table failed; status = %s\n", > > + gnttabop_error(setup.status)); > > + BUG(); > > + } > > The hypercall doesn't do any clean-up in Xen. So why are you calling > this from fini_gnttab()? Will remove. > > Cheers, > Best regards, Anastasiia
diff --git a/board/xen/xenguest_arm64/xenguest_arm64.c b/board/xen/xenguest_arm64/xenguest_arm64.c index e8621f7174..b4e1650f99 100644 --- a/board/xen/xenguest_arm64/xenguest_arm64.c +++ b/board/xen/xenguest_arm64/xenguest_arm64.c @@ -22,6 +22,7 @@ #include <linux/compiler.h> +#include <xen/gnttab.h> #include <xen/hvm.h> DECLARE_GLOBAL_DATA_PTR; @@ -64,6 +65,8 @@ static int setup_mem_map(void) struct fdt_resource res; const void *blob = gd->fdt_blob; u64 gfn; + phys_addr_t gnttab_base; + phys_size_t gnttab_sz; /* * Add "magic" region which is used by Xen to provide some essentials @@ -97,6 +100,16 @@ static int setup_mem_map(void) PTE_BLOCK_INNER_SHARE); i++; + /* Get Xen's suggested physical page assignments for the grant table. */ + get_gnttab_base(&gnttab_base, &gnttab_sz); + + xen_mem_map[i].virt = gnttab_base; + xen_mem_map[i].phys = gnttab_base; + xen_mem_map[i].size = gnttab_sz; + xen_mem_map[i].attrs = (PTE_BLOCK_MEMTYPE(MT_NORMAL) | + PTE_BLOCK_INNER_SHARE); + i++; + mem = get_next_memory_node(blob, -1); if (mem < 0) { printf("%s: Missing /memory node\n", __func__); diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile index 9d0f604aaa..243b13277a 100644 --- a/drivers/xen/Makefile +++ b/drivers/xen/Makefile @@ -5,3 +5,4 @@ obj-y += hypervisor.o obj-y += events.o obj-y += xenbus.o +obj-y += gnttab.o diff --git a/drivers/xen/gnttab.c b/drivers/xen/gnttab.c new file mode 100644 index 0000000000..b18102e329 --- /dev/null +++ b/drivers/xen/gnttab.c @@ -0,0 +1,258 @@ +/* + **************************************************************************** + * (C) 2006 - Cambridge University + * (C) 2020 - EPAM Systems Inc. + **************************************************************************** + * + * File: gnttab.c + * Author: Steven Smith (sos22 at cam.ac.uk) + * Changes: Grzegorz Milos (gm281 at cam.ac.uk) + * + * Date: July 2006 + * + * Environment: Xen Minimal OS + * Description: Simple grant tables implementation. About as stupid as it's + * possible to be and still work. + * + **************************************************************************** + */ +#include <common.h> +#include <linux/compiler.h> +#include <log.h> +#include <malloc.h> + +#include <asm/armv8/mmu.h> +#include <asm/io.h> +#include <asm/xen/system.h> + +#include <linux/bug.h> + +#include <xen/gnttab.h> +#include <xen/hvm.h> + +#include <xen/interface/memory.h> + +DECLARE_GLOBAL_DATA_PTR; + +#define NR_RESERVED_ENTRIES 8 + +/* NR_GRANT_FRAMES must be less than or equal to that configured in Xen */ +#define NR_GRANT_FRAMES 1 +#define NR_GRANT_ENTRIES (NR_GRANT_FRAMES * PAGE_SIZE / sizeof(struct grant_entry_v1)) + +static struct grant_entry_v1 *gnttab_table; +static grant_ref_t gnttab_list[NR_GRANT_ENTRIES]; + +static void put_free_entry(grant_ref_t ref) +{ + unsigned long flags; + + local_irq_save(flags); + gnttab_list[ref] = gnttab_list[0]; + gnttab_list[0] = ref; + local_irq_restore(flags); +} + +static grant_ref_t get_free_entry(void) +{ + unsigned int ref; + unsigned long flags; + + local_irq_save(flags); + ref = gnttab_list[0]; + BUG_ON(ref < NR_RESERVED_ENTRIES || ref >= NR_GRANT_ENTRIES); + gnttab_list[0] = gnttab_list[ref]; + local_irq_restore(flags); + return ref; +} + +grant_ref_t gnttab_grant_access(domid_t domid, unsigned long frame, int readonly) +{ + grant_ref_t ref; + + ref = get_free_entry(); + gnttab_table[ref].frame = frame; + gnttab_table[ref].domid = domid; + wmb(); + readonly *= GTF_readonly; + gnttab_table[ref].flags = GTF_permit_access | readonly; + + return ref; +} + +grant_ref_t gnttab_grant_transfer(domid_t domid, unsigned long pfn) +{ + grant_ref_t ref; + + ref = get_free_entry(); + gnttab_table[ref].frame = pfn; + gnttab_table[ref].domid = domid; + wmb(); + gnttab_table[ref].flags = GTF_accept_transfer; + + return ref; +} + +int gnttab_end_access(grant_ref_t ref) +{ + u16 flags, nflags; + + BUG_ON(ref >= NR_GRANT_ENTRIES || ref < NR_RESERVED_ENTRIES); + + nflags = gnttab_table[ref].flags; + do { + if ((flags = nflags) & (GTF_reading | GTF_writing)) { + printf("WARNING: g.e. still in use! (%x)\n", flags); + return 0; + } + } while ((nflags = synch_cmpxchg(&gnttab_table[ref].flags, flags, 0)) != + flags); + + put_free_entry(ref); + return 1; +} + +unsigned long gnttab_end_transfer(grant_ref_t ref) +{ + unsigned long frame; + u16 flags; + + BUG_ON(ref >= NR_GRANT_ENTRIES || ref < NR_RESERVED_ENTRIES); + + while (!((flags = gnttab_table[ref].flags) & GTF_transfer_committed)) { + if (synch_cmpxchg(&gnttab_table[ref].flags, flags, 0) == flags) { + printf("Release unused transfer grant.\n"); + put_free_entry(ref); + return 0; + } + } + + /* If a transfer is in progress then wait until it is completed. */ + while (!(flags & GTF_transfer_completed)) + flags = gnttab_table[ref].flags; + + /* Read the frame number /after/ reading completion status. */ + rmb(); + frame = gnttab_table[ref].frame; + + put_free_entry(ref); + + return frame; +} + +grant_ref_t gnttab_alloc_and_grant(void **map) +{ + unsigned long mfn; + grant_ref_t gref; + + *map = (void *)memalign(PAGE_SIZE, PAGE_SIZE); + mfn = virt_to_mfn(*map); + gref = gnttab_grant_access(0, mfn, 0); + return gref; +} + +static const char * const gnttabop_error_msgs[] = GNTTABOP_error_msgs; + +const char *gnttabop_error(int16_t status) +{ + status = -status; + if (status < 0 || status >= ARRAY_SIZE(gnttabop_error_msgs)) + return "bad status"; + else + return gnttabop_error_msgs[status]; +} + +/* Get Xen's suggested physical page assignments for the grant table. */ +void get_gnttab_base(phys_addr_t *gnttab_base, phys_size_t *gnttab_sz) +{ + const void *blob = gd->fdt_blob; + struct fdt_resource res; + int mem; + + mem = fdt_node_offset_by_compatible(blob, -1, "xen,xen"); + if (mem < 0) { + printf("No xen,xen compatible found\n"); + BUG(); + } + + mem = fdt_get_resource(blob, mem, "reg", 0, &res); + if (mem == -FDT_ERR_NOTFOUND) { + printf("No grant table base in the device tree\n"); + BUG(); + } + + *gnttab_base = (phys_addr_t)res.start; + if (gnttab_sz) + *gnttab_sz = (phys_size_t)(res.end - res.start + 1); + + debug("FDT suggests grant table base at %llx\n", + *gnttab_base); +} + +void init_gnttab(void) +{ + struct xen_add_to_physmap xatp; + struct gnttab_setup_table setup; + xen_pfn_t frames[NR_GRANT_FRAMES]; + int i, rc; + + debug("%s\n", __func__); + + for (i = NR_RESERVED_ENTRIES; i < NR_GRANT_ENTRIES; i++) + put_free_entry(i); + + get_gnttab_base((phys_addr_t *)&gnttab_table, NULL); + + for (i = 0; i < NR_GRANT_FRAMES; i++) { + xatp.domid = DOMID_SELF; + xatp.size = 0; + xatp.space = XENMAPSPACE_grant_table; + xatp.idx = i; + xatp.gpfn = PFN_DOWN((unsigned long)gnttab_table) + i; + rc = HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp); + if (rc) + printf("XENMEM_add_to_physmap failed; status = %d\n", + rc); + BUG_ON(rc != 0); + } + + setup.dom = DOMID_SELF; + setup.nr_frames = NR_GRANT_FRAMES; + set_xen_guest_handle(setup.frame_list, frames); + rc = HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1); + if (rc || setup.status) { + printf("GNTTABOP_setup_table failed; status = %s\n", + gnttabop_error(setup.status)); + BUG(); + } +} + +void fini_gnttab(void) +{ + struct xen_remove_from_physmap xrtp; + struct gnttab_setup_table setup; + int i, rc; + + debug("%s\n", __func__); + + for (i = 0; i < NR_GRANT_FRAMES; i++) { + xrtp.domid = DOMID_SELF; + xrtp.gpfn = PFN_DOWN((unsigned long)gnttab_table) + i; + rc = HYPERVISOR_memory_op(XENMEM_remove_from_physmap, &xrtp); + if (rc) + printf("XENMEM_remove_from_physmap failed; status = %d\n", + rc); + BUG_ON(rc != 0); + } + + setup.dom = DOMID_SELF; + setup.nr_frames = 0; + + HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1); + if (setup.status) { + printf("GNTTABOP_setup_table failed; status = %s\n", + gnttabop_error(setup.status)); + BUG(); + } +} + diff --git a/drivers/xen/hypervisor.c b/drivers/xen/hypervisor.c index d7fbacb08e..f3c2504d72 100644 --- a/drivers/xen/hypervisor.c +++ b/drivers/xen/hypervisor.c @@ -38,6 +38,7 @@ #include <xen/hvm.h> #include <xen/events.h> +#include <xen/gnttab.h> #include <xen/xenbus.h> #include <xen/interface/memory.h> @@ -275,5 +276,6 @@ void xen_init(void) map_shared_info(NULL); init_events(); init_xenbus(); + init_gnttab(); } diff --git a/include/xen/gnttab.h b/include/xen/gnttab.h new file mode 100644 index 0000000000..7e0f6db83e --- /dev/null +++ b/include/xen/gnttab.h @@ -0,0 +1,25 @@ +/* + * SPDX-License-Identifier: GPL-2.0 + * + * (C) 2006, Steven Smith <sos22 at cam.ac.uk> + * (C) 2006, Grzegorz Milos <gm281 at cam.ac.uk> + * (C) 2020, EPAM Systems Inc. + */ +#ifndef __GNTTAB_H__ +#define __GNTTAB_H__ + +#include <xen/interface/grant_table.h> + +void init_gnttab(void); +void fini_gnttab(void); + +grant_ref_t gnttab_alloc_and_grant(void **map); +grant_ref_t gnttab_grant_access(domid_t domid, unsigned long frame, + int readonly); +grant_ref_t gnttab_grant_transfer(domid_t domid, unsigned long pfn); +int gnttab_end_access(grant_ref_t ref); +const char *gnttabop_error(int16_t status); + +void get_gnttab_base(phys_addr_t *gnttab_base, phys_size_t *gnttab_sz); + +#endif /* !__GNTTAB_H__ */