diff -r bbf2db4ddf54 arch/powerpc/platforms/xen/gnttab.c --- a/arch/powerpc/platforms/xen/gnttab.c Tue Dec 19 09:22:37 2006 -0500 +++ b/arch/powerpc/platforms/xen/gnttab.c Thu Jan 11 11:42:57 2007 -0600 @@ -264,7 +264,8 @@ int HYPERVISOR_grant_table_op(unsigned i argsize = sizeof(setup); frame_list = xencomm_create_inline( - xen_guest_handle(setup.frame_list)); + xen_guest_handle(setup.frame_list), + (sizeof(ulong) * setup.nr_frames)); set_xen_guest_handle(setup.frame_list, frame_list); memcpy(op, &setup, sizeof(setup)); @@ -286,7 +287,7 @@ int HYPERVISOR_grant_table_op(unsigned i return -ENOSYS; } - desc = xencomm_create_inline(op); + desc = xencomm_create_inline(op, argsize); ret = plpar_hcall_norets(XEN_MARK(__HYPERVISOR_grant_table_op), cmd, desc, count); diff -r bbf2db4ddf54 arch/powerpc/platforms/xen/hcall.c --- a/arch/powerpc/platforms/xen/hcall.c Tue Dec 19 09:22:37 2006 -0500 +++ b/arch/powerpc/platforms/xen/hcall.c Thu Jan 11 11:50:19 2007 -0600 @@ -50,11 +50,31 @@ * In general, we need a xencomm descriptor to cover the top-level data * structure (e.g. the domctl op), plus another for every embedded pointer to * another data structure (i.e. for every GUEST_HANDLE). + * + * Some hypercalls are made before the memory subsystem is up, so instead of + * calling xencomm_create(), we allocate XENCOMM_MINI_AREA bytes from the stack + * to hold the xencomm descriptor. */ int HYPERVISOR_console_io(int cmd, int count, char *str) { - void *desc = xencomm_create_inline(str); + char xc_area[XENCOMM_MINI_AREA]; + struct xencomm_desc *desc; + int rc; + + desc = xencomm_create_inline(str, count); + + if (desc == NULL) { + rc = xencomm_create_mini(xc_area, XENCOMM_MINI_AREA, str, count, + &desc); + if (rc) + return rc; + + rc = plpar_hcall_norets(XEN_MARK(__HYPERVISOR_console_io), + cmd, count, __pa(desc)); + + return rc; + } return plpar_hcall_norets(XEN_MARK(__HYPERVISOR_console_io), cmd, count, desc); @@ -63,7 +83,22 @@ EXPORT_SYMBOL(HYPERVISOR_console_io); int HYPERVISOR_event_channel_op(int cmd, void *op) { - void *desc = xencomm_create_inline(op); + char xc_area[XENCOMM_MINI_AREA]; + struct xencomm_desc *desc; + int rc; + + desc = xencomm_create_inline(op, sizeof(evtchn_op_t)); + + if (desc == NULL) { + rc = xencomm_create_mini(xc_area, XENCOMM_MINI_AREA, + op, sizeof(evtchn_op_t), &desc); + if (rc) + return rc; + + rc = plpar_hcall_norets(XEN_MARK(__HYPERVISOR_event_channel_op), + cmd, __pa(desc)); + return rc; + } return plpar_hcall_norets(XEN_MARK(__HYPERVISOR_event_channel_op), cmd, desc); @@ -121,7 +156,7 @@ int HYPERVISOR_xen_version(int cmd, void int HYPERVISOR_xen_version(int cmd, void *arg) { if (is_kernel_addr((unsigned long)arg)) { - void *desc = xencomm_create_inline(arg); + void *desc = xencomm_create_inline(arg, sizeof(__u64)); return plpar_hcall_norets(XEN_MARK(__HYPERVISOR_xen_version), cmd, desc); } return HYPERVISOR_xen_version_userspace(cmd, arg); @@ -129,7 +164,7 @@ int HYPERVISOR_xen_version(int cmd, void int HYPERVISOR_physdev_op(int cmd, void *op) { - void *desc = xencomm_create_inline(op); + void *desc = xencomm_create_inline(op, sizeof(physdev_op_t)); return plpar_hcall_norets(XEN_MARK(__HYPERVISOR_physdev_op), cmd, desc); @@ -139,6 +174,7 @@ int HYPERVISOR_sched_op(int cmd, void *a int HYPERVISOR_sched_op(int cmd, void *arg) { struct xencomm_desc *desc; + int argsize = 0; switch (cmd) { case SCHEDOP_yield: @@ -151,24 +187,29 @@ int HYPERVISOR_sched_op(int cmd, void *a evtchn_port_t *ports; struct sched_poll sched_poll; + argsize = sizeof(struct sched_poll); + memcpy(&sched_poll, arg, sizeof(sched_poll)); ports = xencomm_create_inline( - xen_guest_handle(sched_poll.ports)); + xen_guest_handle(sched_poll.ports), + (sizeof(evtchn_port_t) * sched_poll.nr_ports)); set_xen_guest_handle(sched_poll.ports, ports); memcpy(arg, &sched_poll, sizeof(sched_poll)); - + } break; case SCHEDOP_shutdown: + argsize = sizeof(struct sched_shutdown); case SCHEDOP_remote_shutdown: + argsize = sizeof(struct sched_remote_shutdown); break; default: printk(KERN_ERR "%s: unknown sched op %d\n", __func__, cmd); return -ENOSYS; } - desc = xencomm_create_inline(arg); + desc = xencomm_create_inline(arg, argsize); return plpar_hcall_norets(XEN_MARK(__HYPERVISOR_sched_op), cmd, desc); diff -r bbf2db4ddf54 drivers/xen/core/xencomm.c --- a/drivers/xen/core/xencomm.c Tue Dec 19 09:22:37 2006 -0500 +++ b/drivers/xen/core/xencomm.c Wed Jan 10 14:29:17 2007 -0600 @@ -119,13 +119,59 @@ int xencomm_create(void *buffer, unsigne return 0; } -void *xencomm_create_inline(void *ptr) +void *xencomm_create_inline(void *ptr, unsigned long bytes) { unsigned long paddr; + unsigned long first_page; + unsigned long last_page; - BUG_ON(!is_kernel_addr((unsigned long)ptr)); + first_page = xencomm_vtop(ptr) & PAGE_MASK; + last_page = xencomm_vtop(ptr + bytes) & PAGE_MASK; + + if (first_page != last_page) + return NULL; paddr = (unsigned long)xencomm_pa(ptr); BUG_ON(paddr & XENCOMM_INLINE_FLAG); return (void *)(paddr | XENCOMM_INLINE_FLAG); } + +/* "mini" routines, for stack-based communications: */ +static void *xencomm_alloc_mini(void *area, int arealen) +{ + unsigned long base = (unsigned long)area; + unsigned int left_in_page; + + left_in_page = PAGE_SIZE - base % PAGE_SIZE; + + /* we probably fit right at the front of area */ + if (left_in_page >= sizeof(struct xencomm_mini)) { + return area; + } + + /* if not, see if area is big enough to advance to the next page */ + if ((arealen - left_in_page) >= sizeof(struct xencomm_mini)) + return (void *)(base + left_in_page); + + /* area was too small */ + return NULL; +} + +int xencomm_create_mini(void *area, int arealen, void *buffer, + unsigned long bytes, struct xencomm_desc **ret) +{ + struct xencomm_desc *desc; + int rc; + + desc = xencomm_alloc_mini(area, arealen); + if (!desc) + return -ENOMEM; + desc->nr_addrs = XENCOMM_MINI_ADDRS; + + rc = xencomm_init(desc, buffer, bytes); + if (rc) + return rc; + + *ret = desc; + return 0; +} diff -r bbf2db4ddf54 include/xen/xencomm.h --- a/include/xen/xencomm.h Tue Dec 19 09:22:37 2006 -0500 +++ b/include/xen/xencomm.h Tue Jan 09 16:07:21 2007 -0600 @@ -23,10 +23,19 @@ #include +#define XENCOMM_MINI_ADDRS 3 +struct xencomm_mini { + struct xencomm_desc _desc; + uint64_t address[XENCOMM_MINI_ADDRS]; +}; +#define XENCOMM_MINI_AREA (sizeof(struct xencomm_mini) * 2) + extern int xencomm_create(void *buffer, unsigned long bytes, struct xencomm_desc **desc, gfp_t type); extern void xencomm_free(struct xencomm_desc *desc); -extern void *xencomm_create_inline(void *ptr); +extern void *xencomm_create_inline(void *ptr, unsigned long bytes); +extern int xencomm_create_mini(void *area, int arealen, void *buffer, + unsigned long bytes, struct xencomm_desc **ret); /* provided by architecture code: */ extern unsigned long xencomm_vtop(unsigned long vaddr);