[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] [POWERPC][XEN] Set up an RTAS node for dom0 and proxy methods
# HG changeset patch # User Jimi Xenidis <jimix@xxxxxxxxxxxxxx> # Date 1181074198 14400 # Node ID 6750b1320159458c15fed78ba26d202ada818e57 # Parent 06a32f040d64a9e26d29f97bd0c48cf25724788a [POWERPC][XEN] Set up an RTAS node for dom0 and proxy methods If real FW supplies an RTAS layer then pass thru the methods Xen will proxy for Dom0. - NVRAM read/write methods work, see nvsetenv(8) or nvram(8). - Firmware flash methods exist, but currently "chicken switched" off for further testing. Signed-off-by: Jimi Xenidis <jimix@xxxxxxxxxxxxxx> --- xen/arch/powerpc/Makefile | 2 xen/arch/powerpc/ofd_fixup.c | 37 +------- xen/arch/powerpc/oftree.h | 4 xen/arch/powerpc/rtas.c | 151 ++++++++++++++++++++++++++++------ xen/arch/powerpc/rtas.h | 31 +++++++ xen/arch/powerpc/rtas_flash.c | 182 ++++++++++++++++++++++++++++++++++++++++++ xen/arch/powerpc/rtas_nvram.c | 129 +++++++++++++++++++++++++++++ 7 files changed, 477 insertions(+), 59 deletions(-) diff -r 06a32f040d64 -r 6750b1320159 xen/arch/powerpc/Makefile --- a/xen/arch/powerpc/Makefile Sun Jun 03 10:39:31 2007 -0400 +++ b/xen/arch/powerpc/Makefile Tue Jun 05 16:09:58 2007 -0400 @@ -35,6 +35,8 @@ obj-y += physdev.o obj-y += physdev.o obj-y += platform.o obj-y += rtas.o +obj-y += rtas_nvram.o +obj-y += rtas_flash.o obj-y += setup.o obj-y += shadow.o obj-y += smp.o diff -r 06a32f040d64 -r 6750b1320159 xen/arch/powerpc/ofd_fixup.c --- a/xen/arch/powerpc/ofd_fixup.c Sun Jun 03 10:39:31 2007 -0400 +++ b/xen/arch/powerpc/ofd_fixup.c Tue Jun 05 16:09:58 2007 -0400 @@ -26,8 +26,6 @@ #include "of-devtree.h" #include "oftree.h" #include "rtas.h" - -#undef RTAS ofdn_t ofd_boot_cpu; @@ -307,26 +305,6 @@ static ofdn_t ofd_chosen_props(void *m, return n; } -#ifdef RTAS -static ofdn_t ofd_rtas_props(void *m) -{ - static const char path[] = "/rtas"; - static const char hypertas[] = "dummy"; - ofdn_t p; - ofdn_t n; - - /* just enough to make linux think its on LPAR */ - - p = ofd_node_find(m, "/"); - - n = ofd_node_add(m, p, path, sizeof(path)); - ofd_prop_add(m, n, "name", &path[1], sizeof (path) - 1); - ofd_prop_add(m, n, "ibm,hypertas-functions", hypertas, sizeof (hypertas)); - - return n; -} -#endif - static ofdn_t ofd_xen_props(void *m, struct domain *d, ulong shared_info) { ofdn_t n; @@ -382,8 +360,8 @@ static ofdn_t ofd_xen_props(void *m, str return n; } -int ofd_dom0_fixup(struct domain *d, ulong mem, const char *cmdline, - ulong shared_info) +ulong ofd_dom0_fixup(struct domain *d, ulong mem, const char *cmdline, + ulong shared_info) { void *m; const ofdn_t n = OFD_ROOT; @@ -423,11 +401,8 @@ int ofd_dom0_fixup(struct domain *d, ulo printk("Remove original /rtas\n"); ofd_prune_path(m, "/rtas"); -#ifdef RTAS - printk("Create a new RTAS with just enough stuff to convince " - "Linux that its on LPAR\n"); - ofd_rtas_props(m); -#endif + rtas_proxy_init(m); + #ifdef FIX_COMPAT const char compat[] = "Hypervisor,Maple"; r = ofd_prop_add(m, n, "compatible", compat, sizeof (compat)); @@ -446,5 +421,5 @@ int ofd_dom0_fixup(struct domain *d, ulo #ifdef DEBUG ofd_walk(m, __func__, OFD_ROOT, ofd_dump_props, OFD_DUMP_ALL); #endif - return 1; -} + return ofd_size(m); +} diff -r 06a32f040d64 -r 6750b1320159 xen/arch/powerpc/oftree.h --- a/xen/arch/powerpc/oftree.h Sun Jun 03 10:39:31 2007 -0400 +++ b/xen/arch/powerpc/oftree.h Tue Jun 05 16:09:58 2007 -0400 @@ -28,8 +28,8 @@ extern ulong oftree_end; extern ulong oftree_end; extern ofdn_t ofd_boot_cpu; -extern int ofd_dom0_fixup(struct domain *d, ulong mem, const char *cmdline, - ulong shared_info); +extern ulong ofd_dom0_fixup(struct domain *d, ulong mem, const char *cmdline, + ulong shared_info); extern void ofd_memory_props(void *m, struct domain *d); extern int firmware_image_start[0]; diff -r 06a32f040d64 -r 6750b1320159 xen/arch/powerpc/rtas.c --- a/xen/arch/powerpc/rtas.c Sun Jun 03 10:39:31 2007 -0400 +++ b/xen/arch/powerpc/rtas.c Tue Jun 05 16:09:58 2007 -0400 @@ -13,7 +13,7 @@ * along with this program; if not, write to the Free Software * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * Copyright (C) IBM Corp. 2006 + * Copyright (C) IBM Corp. 2006, 2007 * * Authors: Jimi Xenidis <jimix@xxxxxxxxxxxxxx> */ @@ -22,24 +22,16 @@ #include <xen/init.h> #include <xen/lib.h> #include <xen/errno.h> +#include <xen/sched.h> #include "of-devtree.h" #include "rtas.h" -static int rtas_halt_token = -1; -static int rtas_reboot_token = -1; int rtas_entry; unsigned long rtas_msr; unsigned long rtas_base; unsigned long rtas_end; -struct rtas_args { - int ra_token; - int ra_nargs; - int ra_nrets; - int ra_args[10]; -} __attribute__ ((aligned(8))); - -static int rtas_call(struct rtas_args *r) +int rtas_call(void *r) { if (rtas_entry == 0) return -ENOSYS; @@ -47,11 +39,51 @@ static int rtas_call(struct rtas_args *r return prom_call(r, rtas_base, rtas_entry, rtas_msr); } +/* rtas always uses physical address */ +void *rtas_remote_addr(ulong addr, ulong length) +{ + struct vcpu *v = get_current(); + struct domain *d = v->domain; + ulong mfn; + ulong mfn_end; + + mfn = gmfn_to_mfn(d, addr >> PAGE_SHIFT); + if (mfn == INVALID_MFN) + return NULL; + + /* a little paranoid since almost everyone will pass us page + * bounded thingies, but just in case */ + mfn_end = gmfn_to_mfn(d, (addr + length) >> PAGE_SHIFT); + if (mfn_end == INVALID_MFN) + return NULL; + + return (void *)((mfn << PAGE_SHIFT) | (addr & (PAGE_SIZE - 1))); +} + +/* these do not proxy */ +#define RTAS_HALT 0 +#define RTAS_REBOOT 1 + +struct rtas_token rt_power_off = { .name = "power-off", .token = -1, }; +struct rtas_token rt_system_reboot = { .name = "system-reboot", .token = -1}; + +static struct rtas_token *tokens[] = { + /* these do not proxy */ + [RTAS_HALT] = &rt_power_off, + [RTAS_REBOOT] = &rt_system_reboot, + &rt_nvram_store, + &rt_nvram_fetch, + &rt_manage_flash, + &rt_validate_flash, + &rt_update_reboot_flash +}; + +static int rtas_proxy; + int __init rtas_init(void *m) { - static const char halt[] = "power-off"; - static const char reboot[] = "system-reboot"; ofdn_t n; + int i; if (rtas_entry == 0) return -ENOSYS; @@ -60,22 +92,87 @@ int __init rtas_init(void *m) if (n <= 0) return -ENOSYS; - ofd_getprop(m, n, halt, - &rtas_halt_token, sizeof (rtas_halt_token)); - ofd_getprop(m, n, reboot, - &rtas_reboot_token, sizeof (rtas_reboot_token)); + for (i = 0; i < ARRAY_SIZE(tokens); i++) { + ofd_getprop(m, n, tokens[i]->name, + &tokens[i]->token, sizeof (tokens[i]->token)); + if (!rtas_proxy && tokens[i]->proxy && tokens[i]->token != -1) + rtas_proxy = 1; + } return 1; +} + +int rtas_proxy_init(void *m) +{ + static const char path[] = "/rtas"; + ofdn_t p; + ofdn_t n; + int i; + + if (!rtas_proxy) + return -1; + + printk("Create a new /rtas with tokens Xen is willing to proxy\n"); + + p = ofd_node_find(m, "/"); + + n = ofd_node_add(m, p, path, sizeof(path)); + ofd_prop_add(m, n, "name", &path[1], sizeof (path) - 1); + + /* and the tokens for proxy */ + for (i = 0; i < ARRAY_SIZE(tokens); i++) { + if (tokens[i]->proxy && tokens[i]->token != -1) + ofd_prop_add(m, n, tokens[i]->name, &i, sizeof (i)); + } + return n; +} + +int do_rtas_proxy(ulong arg) +{ + struct rtas_args *r; + unsigned i; + int token; + ulong sz; + + if (!IS_PRIV(current->domain)) + return -EPERM; + if (!rtas_proxy) + return -ENOSYS; + + /* has to be at least 5 words */ + sz = (3 + 1 + 1) * sizeof (int); + r = rtas_remote_addr(arg, sz); + if (r == NULL) { + /* this is about all we can do at this point */ + return -1; + } + /* make sure we can deal with everything */ + sz = (3 + r->ra_nargs + r->ra_nrets) * sizeof (int); + if (rtas_remote_addr(arg, sz) == NULL) { + r->ra_args[r->ra_nargs] = RTAS_HW; + return -1; + } + + i = r->ra_token; + token = tokens[i]->token; + + if (i < ARRAY_SIZE(tokens) && + tokens[i]->proxy != NULL && + token != -1) + return tokens[i]->proxy(token, r); + + return -1; } int rtas_halt(void) { struct rtas_args r; - - if (rtas_halt_token == -1) - return -1; - - r.ra_token = rtas_halt_token; + int token = tokens[RTAS_HALT]->token; + + if (token == -1) + return -1; + + r.ra_token = token; r.ra_nargs = 2; r.ra_nrets = 1; r.ra_args[0] = 0; @@ -89,10 +186,12 @@ rtas_reboot(void) { struct rtas_args r; - if (rtas_reboot_token == -1) - return -ENOSYS; - - r.ra_token = rtas_reboot_token; + int token = tokens[RTAS_REBOOT]->token; + + if (token == -1) + return -1; + + r.ra_token = token; r.ra_nargs = 2; r.ra_nrets = 1; r.ra_args[0] = 0; diff -r 06a32f040d64 -r 6750b1320159 xen/arch/powerpc/rtas.h --- a/xen/arch/powerpc/rtas.h Sun Jun 03 10:39:31 2007 -0400 +++ b/xen/arch/powerpc/rtas.h Tue Jun 05 16:09:58 2007 -0400 @@ -26,9 +26,40 @@ extern unsigned long rtas_base; extern unsigned long rtas_base; extern unsigned long rtas_end; +struct rtas_args { + int ra_token; + int ra_nargs; + int ra_nrets; + int ra_args[10]; +} __attribute__ ((aligned(8))); + +struct rtas_token { + char *name; + int (*proxy)(int token, struct rtas_args *r); + int token; +}; + +extern struct rtas_token rt_power_off; +extern struct rtas_token rt_system_reboot; +extern struct rtas_token rt_nvram_fetch; +extern struct rtas_token rt_nvram_store; +extern struct rtas_token rt_manage_flash; +extern struct rtas_token rt_validate_flash; +extern struct rtas_token rt_update_reboot_flash; + +/* RTAS errors */ +#define RTAS_HW -1 +#define RTAS_BUSY -2 +#define RTAS_PARAMETER -3 + + extern int prom_call(void *arg, unsigned base, unsigned long func, unsigned long msr); extern int rtas_init(void *); extern int rtas_halt(void); extern int rtas_reboot(void); +extern int rtas_proxy_init(void *m); +extern int do_rtas_proxy(ulong arg); +extern void *rtas_remote_addr(ulong addr, ulong length); +extern int rtas_call(void *r); #endif diff -r 06a32f040d64 -r 6750b1320159 xen/arch/powerpc/rtas_flash.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/arch/powerpc/rtas_flash.c Tue Jun 05 16:09:58 2007 -0400 @@ -0,0 +1,182 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright (C) IBM Corp. 2007 + * + * Authors: Jimi Xenidis <jimix@xxxxxxxxxxxxxx> + */ + +#include <xen/config.h> +#include <xen/init.h> +#include <xen/lib.h> +#include <xen/sched.h> +#include "rtas.h" + +static int rtas_manage_flash(int token, struct rtas_args *ra) +{ + struct rtas_args r; + ulong sz = (3 + ra->ra_nargs + ra->ra_nrets) * sizeof (int); + int ret; + + if (ra->ra_nargs != 1 || ra->ra_nrets != 1) { + ra->ra_args[ra->ra_nargs] = RTAS_PARAMETER; + return -1; + } + memcpy(&r, ra, sz); + r.ra_token = token; + + ret = rtas_call(&r); + ra->ra_args[ra->ra_nargs] = r.ra_args[r.ra_nargs]; + return ret; +} +struct rtas_token rt_manage_flash = { + .name = "ibm,manage-flash-image", + .proxy = rtas_manage_flash, + .token = -1 +}; + +static int rtas_validate_flash(int token, struct rtas_args *ra) +{ + ulong length = ra->ra_args[1]; + char *buffer; + char *local; + struct rtas_args r; + ulong sz = (3 + ra->ra_nargs + ra->ra_nrets) * sizeof (int); + int ret; + + if (ra->ra_nargs != 2 || ra->ra_nrets != 2) { + ra->ra_args[ra->ra_nargs] = RTAS_PARAMETER; + return -1; + } + + /* the original pointer can be in memory that is too high so we + * need to do it locally */ + buffer = rtas_remote_addr(ra->ra_args[0], length); + if (buffer == NULL) { + ra->ra_args[ra->ra_nargs] = RTAS_PARAMETER; + return -1; + } + + local = xmalloc_bytes(length); + if (local == NULL) { + printk("%s: could not allocate local buffer size: 0x%lx\n", + __func__, length); + ra->ra_args[ra->ra_nargs] = RTAS_HW; + return -1; + } + /* RTAS is 32bits so we need to make sure that that local + * buffer is in that range */ + BUG_ON(((ulong)local + length) & ~0xffffffffUL); + + /* copy the remote buffer to the local one */ + memcpy(local, buffer, length); + + memcpy(&r, ra, sz); + r.ra_token = token; + r.ra_args[0] = (unsigned)(ulong)local; + ret = rtas_call(&r); + ra->ra_args[ra->ra_nargs] = r.ra_args[r.ra_nargs]; + ra->ra_args[ra->ra_nargs + 1] = r.ra_args[r.ra_nargs + 1]; + xfree(local); + return ret; +} + +struct rtas_token rt_validate_flash = { + .name = "ibm,validate-flash-image", + .proxy = rtas_validate_flash, + .token = -1 +}; + +/* flash data structs */ +struct flash_block { + u64 addr; + u64 length; +}; +struct flash_block_list { + struct { + u64 ver:8; + u64 bytes:56; + } header; + u64 *next; + struct flash_block blocks[0]; +}; + +static int safe_to_flash; +static int rtas_update_reboot_flash(int token, struct rtas_args *ra) +{ + struct rtas_args r; + ulong sz = (3 + ra->ra_nargs + ra->ra_nrets) * sizeof (int); + int ret; + void *local; + struct flash_block_list *l; + ulong blocks; + + if (ra->ra_nargs != 1 || ra->ra_nrets != 1) { + ra->ra_args[ra->ra_nargs] = RTAS_PARAMETER; + return -1; + } + + if (!safe_to_flash) { + printk("%s: this has not been fully tested yet\n", __func__); + ra->ra_args[ra->ra_nargs] = RTAS_HW; + return -1; + } + + /* we only need to relocate the first block address to 4G, for now + * lets just bug on that */ + local = rtas_remote_addr(ra->ra_args[0], 16); + BUG_ON((ulong)local & ~0xffffffffUL); + + /* now we run through the block list and translate base addresses */ + l = (struct flash_block_list *)local; + + /* header and next count as one block */ + blocks = (l->header.bytes / sizeof (struct flash_block)) - 1; + if (blocks == 0) { + ra->ra_args[ra->ra_nargs] = RTAS_PARAMETER; + return -1; + } + + /* go thru the block lists */ + do { + int i = 0; + + /* go thru the block in the list */ + for (i = 0; i < blocks; i++) { + void *addr; + + addr = rtas_remote_addr(l->blocks[i].addr, l->blocks[i].length); + BUG_ON(addr == NULL); + l->blocks[i].addr = (u64)addr; + } + l = (struct flash_block_list *)l->next; + } while (l != NULL); + + memcpy(&r, ra, sz); + r.ra_token = token; + + /* this arguement is a pointer to a block list */ + r.ra_args[0] = (unsigned)(ulong)local; + + ret = rtas_call(&r); + ra->ra_args[ra->ra_nargs] = r.ra_args[r.ra_nargs]; + return ret; +} + +struct rtas_token rt_update_reboot_flash = { + .name = "ibm,update-flash-64-and-reboot", + .proxy = rtas_update_reboot_flash, + .token = -1 +}; diff -r 06a32f040d64 -r 6750b1320159 xen/arch/powerpc/rtas_nvram.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/arch/powerpc/rtas_nvram.c Tue Jun 05 16:09:58 2007 -0400 @@ -0,0 +1,129 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright (C) IBM Corp. 2007 + * + * Authors: Jimi Xenidis <jimix@xxxxxxxxxxxxxx> + */ + +#include <xen/config.h> +#include <xen/init.h> +#include <xen/lib.h> +#include <xen/sched.h> +#include "rtas.h" + +static int rtas_nvram_store(int token, struct rtas_args *ra) +{ + ulong length = ra->ra_args[2]; + char *buffer; + char *local; + struct rtas_args r; + ulong sz = (3 + ra->ra_nargs + ra->ra_nrets) * sizeof (int); + int ret; + + if (ra->ra_nargs != 3 || ra->ra_nrets != 2) { + ra->ra_args[ra->ra_nargs] = RTAS_PARAMETER; + return -1; + } + + /* the original pointer can be in memory that is too high so we + * need to do it locally */ + buffer = rtas_remote_addr(ra->ra_args[1], length); + if (buffer == NULL) { + ra->ra_args[ra->ra_nargs] = RTAS_PARAMETER; + return -1; + } + + local = xmalloc_bytes(length); + if (local == NULL) { + printk("%s: could not allocate local buffer size: 0x%lx\n", + __func__, length); + ra->ra_args[ra->ra_nargs] = RTAS_HW; + return -1; + } + /* RTAS is 32bits so we need to make sure that that local + * buffer is in that range */ + BUG_ON(((ulong)local + length) & ~0xffffffffUL); + + /* copy the remote buffer to the local one */ + memcpy(local, buffer, length); + + memcpy(&r, ra, sz); + r.ra_token = token; + r.ra_args[1] = (unsigned)(ulong)local; + + ret = rtas_call(&r); + ra->ra_args[ra->ra_nargs] = r.ra_args[r.ra_nargs]; + ra->ra_args[ra->ra_nargs + 1] = r.ra_args[r.ra_nargs + 1]; + xfree(local); + return ret; +} + +struct rtas_token rt_nvram_store = { + .name = "nvram-store", + .proxy = rtas_nvram_store, + .token = -1 +}; + +static int rtas_nvram_fetch(int token, struct rtas_args *ra) +{ + ulong length = ra->ra_args[2]; + char *buffer; + char *local; + struct rtas_args r; + ulong sz = (3 + ra->ra_nargs + ra->ra_nrets) * sizeof (int); + int ret; + + if (ra->ra_nargs != 3 || ra->ra_nrets != 2) { + ra->ra_args[ra->ra_nargs] = RTAS_PARAMETER; + return -1; + } + /* the original pointer can be in ememory that is too high so + * we need to do it locally */ + buffer = rtas_remote_addr(ra->ra_args[1], length); + + local = xmalloc_bytes(length); + if (local == NULL) { + printk("%s: could not allocate local buffer size: 0x%lx\n", + __func__, length); + ra->ra_args[ra->ra_nargs] = RTAS_HW; + return -1; + } + /* RTAS is 32bits so we need to make sure that that local + * buffer is in that range */ + BUG_ON(((ulong)local + length) & ~0xffffffffUL); + + memcpy(&r, ra, sz); + r.ra_token = token; + r.ra_args[1] = (unsigned)(ulong)local; + + ret = rtas_call(&r); + ra->ra_args[ra->ra_nargs] = r.ra_args[r.ra_nargs]; + ra->ra_args[ra->ra_nargs + 1] = r.ra_args[r.ra_nargs + 1]; + if (r.ra_args[r.ra_nargs] >= 0) { + /* copy from local to remote */ + sz = r.ra_args[r.ra_nargs + 1]; + memcpy(buffer, local, sz); + } + xfree(local); + return ret; +} + +struct rtas_token rt_nvram_fetch = { + .name = "nvram-fetch", + .proxy = rtas_nvram_fetch, + .token = -1 +}; + _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |