On Wed, May 31, 2017 at 01:15:38PM +0200, Thomas Huth wrote: > RTAS tokens can have any value, also 0xffffffff is theoretically > allowed (which is currently used for the RTAS_UNKNOWN_SERVICE error > code). Thus we should not mix error codes and tokens in the return > value here and return the token value via a pointer parameter > instead. > > This patch also adds a check to rtas_token() to test whether the device > tree is available at all. This fixes a possible endless loop that > happens without device tree, spamming the console with "rtas_node: > /rtas: FDT_ERR_BADMAGIC" messages: Somewhere the code calls abort() > due to the missing device tree, and abort() calls exit() which in > turn tries to shut down the VM with rtas_power_off(). rtas_power_off() > needs the device tree again to look up the right RTAS token, where we > then end up in the next iteration. > > Signed-off-by: Thomas Huth <thuth@xxxxxxxxxx> > --- > lib/powerpc/asm/rtas.h | 2 +- > lib/powerpc/rtas.c | 30 ++++++++++++++++++++++-------- > lib/powerpc/smp.c | 11 ++++++----- > powerpc/rtas.c | 24 +++++++++++++----------- > 4 files changed, 42 insertions(+), 25 deletions(-) > > diff --git a/lib/powerpc/asm/rtas.h b/lib/powerpc/asm/rtas.h > index 9012a1e..6fb407a 100644 > --- a/lib/powerpc/asm/rtas.h > +++ b/lib/powerpc/asm/rtas.h > @@ -21,7 +21,7 @@ struct rtas_args { > }; > > extern void rtas_init(void); > -extern int rtas_token(const char *service); > +extern int rtas_token(const char *service, uint32_t *token); > extern int rtas_call(int token, int nargs, int nret, int *outputs, ...); > > extern void rtas_power_off(void); > diff --git a/lib/powerpc/rtas.c b/lib/powerpc/rtas.c > index 3407e25..2e7e0da 100644 > --- a/lib/powerpc/rtas.c > +++ b/lib/powerpc/rtas.c > @@ -69,17 +69,22 @@ void rtas_init(void) > } > } > > -int rtas_token(const char *service) > +int rtas_token(const char *service, uint32_t *token) > { > const struct fdt_property *prop; > - u32 *token; > + u32 *data; > + > + if (!dt_available()) > + return RTAS_UNKNOWN_SERVICE; > > prop = fdt_get_property(dt_fdt(), rtas_node(), service, NULL); > - if (prop) { > - token = (u32 *)prop->data; > - return fdt32_to_cpu(*token); > - } > - return RTAS_UNKNOWN_SERVICE; > + if (!prop) > + return RTAS_UNKNOWN_SERVICE; > + > + data = (u32 *)prop->data; > + *token = fdt32_to_cpu(*data); > + > + return 0; > } > > int rtas_call(int token, int nargs, int nret, int *outputs, ...) > @@ -116,6 +121,15 @@ int rtas_call(int token, int nargs, int nret, int *outputs, ...) > > void rtas_power_off(void) > { > - int ret = rtas_call(rtas_token("power-off"), 2, 1, NULL, -1, -1); > + uint32_t token; > + int ret; > + > + ret = rtas_token("power-off", &token); > + if (ret) { > + puts("RTAS power-off not available\n"); > + return; > + } > + > + ret = rtas_call(token, 2, 1, NULL, -1, -1); > printf("RTAS power-off returned %d\n", ret); > } > diff --git a/lib/powerpc/smp.c b/lib/powerpc/smp.c > index e18894b..afe4361 100644 > --- a/lib/powerpc/smp.c > +++ b/lib/powerpc/smp.c > @@ -27,12 +27,13 @@ struct secondary_entry_data { > */ > int start_thread(int cpu_id, secondary_entry_fn entry, uint32_t r3) > { > - int query_token, start_token, outputs[1], ret; > + uint32_t query_token, start_token; > + int outputs[1], ret; > > - query_token = rtas_token("query-cpu-stopped-state"); > - start_token = rtas_token("start-cpu"); > - assert(query_token != RTAS_UNKNOWN_SERVICE && > - start_token != RTAS_UNKNOWN_SERVICE); > + ret = rtas_token("query-cpu-stopped-state", &query_token); > + assert(ret == 0); > + ret = rtas_token("start-cpu", &start_token); > + assert(ret == 0); > > ret = rtas_call(query_token, 1, 2, outputs, cpu_id); > if (ret) { > diff --git a/powerpc/rtas.c b/powerpc/rtas.c > index 1b1e9c7..5d43f33 100644 > --- a/powerpc/rtas.c > +++ b/powerpc/rtas.c > @@ -39,14 +39,14 @@ static unsigned long mktime(int year, int month, int day, > > static void check_get_time_of_day(unsigned long start) > { > - int token; > + uint32_t token; > int ret; > int now[8]; > unsigned long t1, t2, count; > > - token = rtas_token("get-time-of-day"); > - report("token available", token != RTAS_UNKNOWN_SERVICE); > - if (token == RTAS_UNKNOWN_SERVICE) > + ret = rtas_token("get-time-of-day", &token); > + report("token available", ret == 0); > + if (ret) > return; > > ret = rtas_call(token, 0, 8, now); > @@ -74,23 +74,25 @@ static void check_get_time_of_day(unsigned long start) > > static void check_set_time_of_day(void) > { > - int token; > + uint32_t stod_token, gtod_token; > int ret; > int date[8]; > unsigned long t1, t2, count; > > - token = rtas_token("set-time-of-day"); > - report("token available", token != RTAS_UNKNOWN_SERVICE); > - if (token == RTAS_UNKNOWN_SERVICE) > + ret = rtas_token("set-time-of-day", &stod_token); > + report("token available", ret == 0); > + if (ret) > return; > > /* 23:59:59 28/2/2000 */ > > - ret = rtas_call(token, 7, 1, NULL, 2000, 2, 28, 23, 59, 59); > + ret = rtas_call(stod_token, 7, 1, NULL, 2000, 2, 28, 23, 59, 59); > report("execution", ret == 0); > > /* check it has worked */ > - ret = rtas_call(rtas_token("get-time-of-day"), 0, 8, date); > + ret = rtas_token("get-time-of-day", >od_token); > + assert(ret == 0); > + ret = rtas_call(gtod_token, 0, 8, date); > report("re-read", ret == 0); > t1 = mktime(2000, 2, 28, 23, 59, 59); > t2 = mktime(date[0], date[1], date[2], > @@ -100,7 +102,7 @@ static void check_set_time_of_day(void) > /* check it is running */ > count = 0; > do { > - ret = rtas_call(rtas_token("get-time-of-day"), 0, 8, date); > + ret = rtas_call(gtod_token, 0, 8, date); > t2 = mktime(date[0], date[1], date[2], > date[3], date[4], date[5]); > count++; > -- > 1.8.3.1 > Reviewed-by: Andrew Jones <drjones@xxxxxxxxxx>