Commit 08273c9f authored by Nathan Lynch's avatar Nathan Lynch Committed by Michael Ellerman
Browse files

powerpc/rtas: arch-wide function token lookup conversions



With the tokens for all implemented RTAS functions now available via
rtas_function_token(), which is optimal and safe for arbitrary
contexts, there is no need to use rtas_token() or cache its result.

Most conversions are trivial, but a few are worth describing in more
detail:

* Error injection token comparisons for lockdown purposes are
  consolidated into a simple predicate: token_is_restricted_errinjct().

* A couple of special cases in block_rtas_call() do not use
  rtas_token() but perform string comparisons against names in the
  function table. These are converted to compare against token values
  instead, which is logically equivalent but less expensive.

* The lookup for the ibm,os-term token can be deferred until needed,
  instead of caching it at boot to avoid device tree traversal during
  panic.

* Since rtas_function_token() accesses a read-only data structure
  without taking any locks, xmon's lookup of set-indicator can be
  performed as needed instead of cached at startup.

Signed-off-by: default avatarNathan Lynch <nathanl@linux.ibm.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20230125-b4-powerpc-rtas-queue-v3-20-26929c8cce78@linux.ibm.com
parent 716bfc97
Loading
Loading
Loading
Loading
+12 −12
Original line number Diff line number Diff line
@@ -287,7 +287,7 @@ static ssize_t ppc_rtas_poweron_write(struct file *file,

	rtc_time64_to_tm(nowtime, &tm);

	error = rtas_call(rtas_token("set-time-for-power-on"), 7, 1, NULL, 
	error = rtas_call(rtas_function_token(RTAS_FN_SET_TIME_FOR_POWER_ON), 7, 1, NULL,
			  tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
			  tm.tm_hour, tm.tm_min, tm.tm_sec, 0 /* nano */);
	if (error)
@@ -350,7 +350,7 @@ static ssize_t ppc_rtas_clock_write(struct file *file,
		return error;

	rtc_time64_to_tm(nowtime, &tm);
	error = rtas_call(rtas_token("set-time-of-day"), 7, 1, NULL, 
	error = rtas_call(rtas_function_token(RTAS_FN_SET_TIME_OF_DAY), 7, 1, NULL,
			  tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
			  tm.tm_hour, tm.tm_min, tm.tm_sec, 0);
	if (error)
@@ -362,7 +362,7 @@ static ssize_t ppc_rtas_clock_write(struct file *file,
static int ppc_rtas_clock_show(struct seq_file *m, void *v)
{
	int ret[8];
	int error = rtas_call(rtas_token("get-time-of-day"), 0, 8, ret);
	int error = rtas_call(rtas_function_token(RTAS_FN_GET_TIME_OF_DAY), 0, 8, ret);

	if (error) {
		printk(KERN_WARNING "error: reading the clock returned: %s\n", 
@@ -385,7 +385,7 @@ static int ppc_rtas_sensors_show(struct seq_file *m, void *v)
{
	int i,j;
	int state, error;
	int get_sensor_state = rtas_token("get-sensor-state");
	int get_sensor_state = rtas_function_token(RTAS_FN_GET_SENSOR_STATE);

	seq_printf(m, "RTAS (RunTime Abstraction Services) Sensor Information\n");
	seq_printf(m, "Sensor\t\tValue\t\tCondition\tLocation\n");
@@ -708,7 +708,7 @@ static ssize_t ppc_rtas_tone_freq_write(struct file *file,
		return error;

	rtas_tone_frequency = freq; /* save it for later */
	error = rtas_call(rtas_token("set-indicator"), 3, 1, NULL,
	error = rtas_call(rtas_function_token(RTAS_FN_SET_INDICATOR), 3, 1, NULL,
			  TONE_FREQUENCY, 0, freq);
	if (error)
		printk(KERN_WARNING "error: setting tone frequency returned: %s\n", 
@@ -736,7 +736,7 @@ static ssize_t ppc_rtas_tone_volume_write(struct file *file,
		volume = 100;
	
        rtas_tone_volume = volume; /* save it for later */
	error = rtas_call(rtas_token("set-indicator"), 3, 1, NULL,
	error = rtas_call(rtas_function_token(RTAS_FN_SET_INDICATOR), 3, 1, NULL,
			  TONE_VOLUME, 0, volume);
	if (error)
		printk(KERN_WARNING "error: setting tone volume returned: %s\n", 
+3 −3
Original line number Diff line number Diff line
@@ -21,7 +21,7 @@ time64_t __init rtas_get_boot_time(void)

	max_wait_tb = get_tb() + tb_ticks_per_usec * 1000 * MAX_RTC_WAIT;
	do {
		error = rtas_call(rtas_token("get-time-of-day"), 0, 8, ret);
		error = rtas_call(rtas_function_token(RTAS_FN_GET_TIME_OF_DAY), 0, 8, ret);

		wait_time = rtas_busy_delay_time(error);
		if (wait_time) {
@@ -53,7 +53,7 @@ void rtas_get_rtc_time(struct rtc_time *rtc_tm)

	max_wait_tb = get_tb() + tb_ticks_per_usec * 1000 * MAX_RTC_WAIT;
	do {
		error = rtas_call(rtas_token("get-time-of-day"), 0, 8, ret);
		error = rtas_call(rtas_function_token(RTAS_FN_GET_TIME_OF_DAY), 0, 8, ret);

		wait_time = rtas_busy_delay_time(error);
		if (wait_time) {
@@ -90,7 +90,7 @@ int rtas_set_rtc_time(struct rtc_time *tm)

	max_wait_tb = get_tb() + tb_ticks_per_usec * 1000 * MAX_RTC_WAIT;
	do {
	        error = rtas_call(rtas_token("set-time-of-day"), 7, 1, NULL,
		error = rtas_call(rtas_function_token(RTAS_FN_SET_TIME_OF_DAY), 7, 1, NULL,
				  tm->tm_year + 1900, tm->tm_mon + 1,
				  tm->tm_mday, tm->tm_hour, tm->tm_min,
				  tm->tm_sec, 0);
+38 −41
Original line number Diff line number Diff line
@@ -782,8 +782,8 @@ void rtas_progress(char *s, unsigned short hex)
					"ibm,display-truncation-length", NULL);
			of_node_put(root);
		}
		display_character = rtas_token("display-character");
		set_indicator = rtas_token("set-indicator");
		display_character = rtas_function_token(RTAS_FN_DISPLAY_CHARACTER);
		set_indicator = rtas_function_token(RTAS_FN_SET_INDICATOR);
	}

	if (display_character == RTAS_UNKNOWN_SERVICE) {
@@ -937,7 +937,6 @@ static void __init init_error_log_max(void)


static char rtas_err_buf[RTAS_ERROR_LOG_MAX];
static int rtas_last_error_token;

/** Return a copy of the detailed error text associated with the
 *  most recent failed call to rtas.  Because the error text
@@ -947,16 +946,17 @@ static int rtas_last_error_token;
 */
static char *__fetch_rtas_last_error(char *altbuf)
{
	const s32 token = rtas_function_token(RTAS_FN_RTAS_LAST_ERROR);
	struct rtas_args err_args, save_args;
	u32 bufsz;
	char *buf = NULL;

	if (rtas_last_error_token == -1)
	if (token == -1)
		return NULL;

	bufsz = rtas_get_error_log_max();

	err_args.token = cpu_to_be32(rtas_last_error_token);
	err_args.token = cpu_to_be32(token);
	err_args.nargs = cpu_to_be32(2);
	err_args.nret = cpu_to_be32(1);
	err_args.args[0] = cpu_to_be32(__pa(rtas_err_buf));
@@ -1025,8 +1025,11 @@ void rtas_call_unlocked(struct rtas_args *args, int token, int nargs, int nret,
	va_end(list);
}

static int ibm_open_errinjct_token;
static int ibm_errinjct_token;
static bool token_is_restricted_errinjct(s32 token)
{
	return token == rtas_function_token(RTAS_FN_IBM_OPEN_ERRINJCT) ||
	       token == rtas_function_token(RTAS_FN_IBM_ERRINJCT);
}

/**
 * rtas_call() - Invoke an RTAS firmware function.
@@ -1098,7 +1101,7 @@ int rtas_call(int token, int nargs, int nret, int *outputs, ...)
	if (!rtas.entry || token == RTAS_UNKNOWN_SERVICE)
		return -1;

	if (token == ibm_open_errinjct_token || token == ibm_errinjct_token) {
	if (token_is_restricted_errinjct(token)) {
		/*
		 * It would be nicer to not discard the error value
		 * from security_locked_down(), but callers expect an
@@ -1330,7 +1333,7 @@ static int rtas_error_rc(int rtas_rc)

int rtas_get_power_level(int powerdomain, int *level)
{
	int token = rtas_token("get-power-level");
	int token = rtas_function_token(RTAS_FN_GET_POWER_LEVEL);
	int rc;

	if (token == RTAS_UNKNOWN_SERVICE)
@@ -1347,7 +1350,7 @@ EXPORT_SYMBOL_GPL(rtas_get_power_level);

int rtas_set_power_level(int powerdomain, int level, int *setlevel)
{
	int token = rtas_token("set-power-level");
	int token = rtas_function_token(RTAS_FN_SET_POWER_LEVEL);
	int rc;

	if (token == RTAS_UNKNOWN_SERVICE)
@@ -1365,7 +1368,7 @@ EXPORT_SYMBOL_GPL(rtas_set_power_level);

int rtas_get_sensor(int sensor, int index, int *state)
{
	int token = rtas_token("get-sensor-state");
	int token = rtas_function_token(RTAS_FN_GET_SENSOR_STATE);
	int rc;

	if (token == RTAS_UNKNOWN_SERVICE)
@@ -1383,7 +1386,7 @@ EXPORT_SYMBOL_GPL(rtas_get_sensor);

int rtas_get_sensor_fast(int sensor, int index, int *state)
{
	int token = rtas_token("get-sensor-state");
	int token = rtas_function_token(RTAS_FN_GET_SENSOR_STATE);
	int rc;

	if (token == RTAS_UNKNOWN_SERVICE)
@@ -1425,7 +1428,7 @@ bool rtas_indicator_present(int token, int *maxindex)

int rtas_set_indicator(int indicator, int index, int new_value)
{
	int token = rtas_token("set-indicator");
	int token = rtas_function_token(RTAS_FN_SET_INDICATOR);
	int rc;

	if (token == RTAS_UNKNOWN_SERVICE)
@@ -1446,8 +1449,8 @@ EXPORT_SYMBOL_GPL(rtas_set_indicator);
 */
int rtas_set_indicator_fast(int indicator, int index, int new_value)
{
	int token = rtas_function_token(RTAS_FN_SET_INDICATOR);
	int rc;
	int token = rtas_token("set-indicator");

	if (token == RTAS_UNKNOWN_SERVICE)
		return -ENOENT;
@@ -1489,10 +1492,11 @@ int rtas_set_indicator_fast(int indicator, int index, int new_value)
 */
int rtas_ibm_suspend_me(int *fw_status)
{
	int token = rtas_function_token(RTAS_FN_IBM_SUSPEND_ME);
	int fwrc;
	int ret;

	fwrc = rtas_call(rtas_token("ibm,suspend-me"), 0, 1, NULL);
	fwrc = rtas_call(token, 0, 1, NULL);

	switch (fwrc) {
	case 0:
@@ -1525,7 +1529,7 @@ void __noreturn rtas_restart(char *cmd)
	if (rtas_flash_term_hook)
		rtas_flash_term_hook(SYS_RESTART);
	pr_emerg("system-reboot returned %d\n",
		 rtas_call(rtas_token("system-reboot"), 0, 1, NULL));
		 rtas_call(rtas_function_token(RTAS_FN_SYSTEM_REBOOT), 0, 1, NULL));
	for (;;);
}

@@ -1535,7 +1539,7 @@ void rtas_power_off(void)
		rtas_flash_term_hook(SYS_POWER_OFF);
	/* allow power on only with power button press */
	pr_emerg("power-off returned %d\n",
		 rtas_call(rtas_token("power-off"), 2, 1, NULL, -1, -1));
		 rtas_call(rtas_function_token(RTAS_FN_POWER_OFF), 2, 1, NULL, -1, -1));
	for (;;);
}

@@ -1545,16 +1549,17 @@ void __noreturn rtas_halt(void)
		rtas_flash_term_hook(SYS_HALT);
	/* allow power on only with power button press */
	pr_emerg("power-off returned %d\n",
		 rtas_call(rtas_token("power-off"), 2, 1, NULL, -1, -1));
		 rtas_call(rtas_function_token(RTAS_FN_POWER_OFF), 2, 1, NULL, -1, -1));
	for (;;);
}

/* Must be in the RMO region, so we place it here */
static char rtas_os_term_buf[2048];
static s32 ibm_os_term_token = RTAS_UNKNOWN_SERVICE;
static bool ibm_extended_os_term;

void rtas_os_term(char *str)
{
	s32 token = rtas_function_token(RTAS_FN_IBM_OS_TERM);
	int status;

	/*
@@ -1563,7 +1568,8 @@ void rtas_os_term(char *str)
	 * this property may terminate the partition which we want to avoid
	 * since it interferes with panic_timeout.
	 */
	if (ibm_os_term_token == RTAS_UNKNOWN_SERVICE)

	if (token == RTAS_UNKNOWN_SERVICE || !ibm_extended_os_term)
		return;

	snprintf(rtas_os_term_buf, 2048, "OS panic: %s", str);
@@ -1574,8 +1580,7 @@ void rtas_os_term(char *str)
	 * schedules.
	 */
	do {
		status = rtas_call(ibm_os_term_token, 1, 1, NULL,
				   __pa(rtas_os_term_buf));
		status = rtas_call(token, 1, 1, NULL, __pa(rtas_os_term_buf));
	} while (rtas_busy_delay_time(status));

	if (status != 0)
@@ -1595,10 +1600,9 @@ void rtas_os_term(char *str)
 */
void rtas_activate_firmware(void)
{
	int token;
	int token = rtas_function_token(RTAS_FN_IBM_ACTIVATE_FIRMWARE);
	int fwrc;

	token = rtas_token("ibm,activate-firmware");
	if (token == RTAS_UNKNOWN_SERVICE) {
		pr_notice("ibm,activate-firmware method unavailable\n");
		return;
@@ -1684,6 +1688,8 @@ static bool block_rtas_call(int token, int nargs,
{
	const struct rtas_function *func;
	const struct rtas_filter *f;
	const bool is_platform_dump = token == rtas_function_token(RTAS_FN_IBM_PLATFORM_DUMP);
	const bool is_config_conn = token == rtas_function_token(RTAS_FN_IBM_CONFIGURE_CONNECTOR);
	u32 base, size, end;

	/*
@@ -1720,8 +1726,7 @@ static bool block_rtas_call(int token, int nargs,
		 * Special case for ibm,platform-dump - NULL buffer
		 * address is used to indicate end of dump processing
		 */
		if (!strcmp(func->name, "ibm,platform-dump") &&
		    base == 0)
		if (is_platform_dump && base == 0)
			return false;

		if (!in_rmo_buf(base, end))
@@ -1742,8 +1747,7 @@ static bool block_rtas_call(int token, int nargs,
		 * Special case for ibm,configure-connector where the
		 * address can be 0
		 */
		if (!strcmp(func->name, "ibm,configure-connector") &&
		    base == 0)
		if (is_config_conn && base == 0)
			return false;

		if (!in_rmo_buf(base, end))
@@ -1798,7 +1802,7 @@ SYSCALL_DEFINE1(rtas, struct rtas_args __user *, uargs)
	if (block_rtas_call(token, nargs, &args))
		return -EINVAL;

	if (token == ibm_open_errinjct_token || token == ibm_errinjct_token) {
	if (token_is_restricted_errinjct(token)) {
		int err;

		err = security_locked_down(LOCKDOWN_RTAS_ERROR_INJECTION);
@@ -1807,7 +1811,7 @@ SYSCALL_DEFINE1(rtas, struct rtas_args __user *, uargs)
	}

	/* Need to handle ibm,suspend_me call specially */
	if (token == rtas_token("ibm,suspend-me")) {
	if (token == rtas_function_token(RTAS_FN_IBM_SUSPEND_ME)) {

		/*
		 * rtas_ibm_suspend_me assumes the streamid handle is in cpu
@@ -1942,11 +1946,10 @@ void __init rtas_initialize(void)
	rtas_function_table_init();

	/*
	 * Discover these now to avoid device tree lookups in the
	 * Discover this now to avoid a device tree lookup in the
	 * panic path.
	 */
	if (of_property_read_bool(rtas.dev, "ibm,extended-os-term"))
		ibm_os_term_token = rtas_token("ibm,os-term");
	ibm_extended_os_term = of_property_read_bool(rtas.dev, "ibm,extended-os-term");

	/* If RTAS was found, allocate the RMO buffer for it and look for
	 * the stop-self token if any
@@ -1961,12 +1964,6 @@ void __init rtas_initialize(void)
		panic("ERROR: RTAS: Failed to allocate %lx bytes below %pa\n",
		      PAGE_SIZE, &rtas_region);

#ifdef CONFIG_RTAS_ERROR_LOGGING
	rtas_last_error_token = rtas_token("rtas-last-error");
#endif
	ibm_open_errinjct_token = rtas_token("ibm,open-errinjct");
	ibm_errinjct_token = rtas_token("ibm,errinjct");

	rtas_work_area_reserve_arena(rtas_region);
}

@@ -2022,13 +2019,13 @@ void rtas_give_timebase(void)

	raw_spin_lock_irqsave(&timebase_lock, flags);
	hard_irq_disable();
	rtas_call(rtas_token("freeze-time-base"), 0, 1, NULL);
	rtas_call(rtas_function_token(RTAS_FN_FREEZE_TIME_BASE), 0, 1, NULL);
	timebase = get_tb();
	raw_spin_unlock(&timebase_lock);

	while (timebase)
		barrier();
	rtas_call(rtas_token("thaw-time-base"), 0, 1, NULL);
	rtas_call(rtas_function_token(RTAS_FN_THAW_TIME_BASE), 0, 1, NULL);
	local_irq_restore(flags);
}

+10 −11
Original line number Diff line number Diff line
@@ -376,7 +376,7 @@ static void manage_flash(struct rtas_manage_flash_t *args_buf, unsigned int op)
	s32 rc;

	do {
		rc = rtas_call(rtas_token("ibm,manage-flash-image"), 1, 1,
		rc = rtas_call(rtas_function_token(RTAS_FN_IBM_MANAGE_FLASH_IMAGE), 1, 1,
			       NULL, op);
	} while (rtas_busy_delay(rc));

@@ -444,7 +444,7 @@ static ssize_t manage_flash_write(struct file *file, const char __user *buf,
 */
static void validate_flash(struct rtas_validate_flash_t *args_buf)
{
	int token = rtas_token("ibm,validate-flash-image");
	int token = rtas_function_token(RTAS_FN_IBM_VALIDATE_FLASH_IMAGE);
	int update_results;
	s32 rc;	

@@ -570,7 +570,7 @@ static void rtas_flash_firmware(int reboot_type)
		return;
	}

	update_token = rtas_token("ibm,update-flash-64-and-reboot");
	update_token = rtas_function_token(RTAS_FN_IBM_UPDATE_FLASH_64_AND_REBOOT);
	if (update_token == RTAS_UNKNOWN_SERVICE) {
		printk(KERN_ALERT "FLASH: ibm,update-flash-64-and-reboot "
		       "is not available -- not a service partition?\n");
@@ -653,7 +653,7 @@ static void rtas_flash_firmware(int reboot_type)
 */
struct rtas_flash_file {
	const char *filename;
	const char *rtas_call_name;
	const rtas_fn_handle_t handle;
	int *status;
	const struct proc_ops ops;
};
@@ -661,7 +661,7 @@ struct rtas_flash_file {
static const struct rtas_flash_file rtas_flash_files[] = {
	{
		.filename	= "powerpc/rtas/" FIRMWARE_FLASH_NAME,
		.rtas_call_name	= "ibm,update-flash-64-and-reboot",
		.handle		= RTAS_FN_IBM_UPDATE_FLASH_64_AND_REBOOT,
		.status		= &rtas_update_flash_data.status,
		.ops.proc_read	= rtas_flash_read_msg,
		.ops.proc_write	= rtas_flash_write,
@@ -670,7 +670,7 @@ static const struct rtas_flash_file rtas_flash_files[] = {
	},
	{
		.filename	= "powerpc/rtas/" FIRMWARE_UPDATE_NAME,
		.rtas_call_name	= "ibm,update-flash-64-and-reboot",
		.handle		= RTAS_FN_IBM_UPDATE_FLASH_64_AND_REBOOT,
		.status		= &rtas_update_flash_data.status,
		.ops.proc_read	= rtas_flash_read_num,
		.ops.proc_write	= rtas_flash_write,
@@ -679,7 +679,7 @@ static const struct rtas_flash_file rtas_flash_files[] = {
	},
	{
		.filename	= "powerpc/rtas/" VALIDATE_FLASH_NAME,
		.rtas_call_name	= "ibm,validate-flash-image",
		.handle		= RTAS_FN_IBM_VALIDATE_FLASH_IMAGE,
		.status		= &rtas_validate_flash_data.status,
		.ops.proc_read	= validate_flash_read,
		.ops.proc_write	= validate_flash_write,
@@ -688,7 +688,7 @@ static const struct rtas_flash_file rtas_flash_files[] = {
	},
	{
		.filename	= "powerpc/rtas/" MANAGE_FLASH_NAME,
		.rtas_call_name	= "ibm,manage-flash-image",
		.handle		= RTAS_FN_IBM_MANAGE_FLASH_IMAGE,
		.status		= &rtas_manage_flash_data.status,
		.ops.proc_read	= manage_flash_read,
		.ops.proc_write	= manage_flash_write,
@@ -700,8 +700,7 @@ static int __init rtas_flash_init(void)
{
	int i;

	if (rtas_token("ibm,update-flash-64-and-reboot") ==
		       RTAS_UNKNOWN_SERVICE) {
	if (rtas_function_token(RTAS_FN_IBM_UPDATE_FLASH_64_AND_REBOOT) == RTAS_UNKNOWN_SERVICE) {
		pr_info("rtas_flash: no firmware flash support\n");
		return -EINVAL;
	}
@@ -730,7 +729,7 @@ static int __init rtas_flash_init(void)
		 * This code assumes that the status int is the first member of the
		 * struct
		 */
		token = rtas_token(f->rtas_call_name);
		token = rtas_function_token(f->handle);
		if (token == RTAS_UNKNOWN_SERVICE)
			*f->status = FLASH_AUTH;
		else
+4 −4
Original line number Diff line number Diff line
@@ -191,10 +191,10 @@ static void python_countermeasures(struct device_node *dev)

void __init init_pci_config_tokens(void)
{
	read_pci_config = rtas_token("read-pci-config");
	write_pci_config = rtas_token("write-pci-config");
	ibm_read_pci_config = rtas_token("ibm,read-pci-config");
	ibm_write_pci_config = rtas_token("ibm,write-pci-config");
	read_pci_config = rtas_function_token(RTAS_FN_READ_PCI_CONFIG);
	write_pci_config = rtas_function_token(RTAS_FN_WRITE_PCI_CONFIG);
	ibm_read_pci_config = rtas_function_token(RTAS_FN_IBM_READ_PCI_CONFIG);
	ibm_write_pci_config = rtas_function_token(RTAS_FN_IBM_WRITE_PCI_CONFIG);
}

unsigned long get_phb_buid(struct device_node *phb)
Loading