2133 lines · 57.1 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-or-later/* * * Procedures for interfacing to the RTAS on CHRP machines. * * Peter Bergner, IBM	March 2001. * Copyright (C) 2001 IBM. */ #define pr_fmt(fmt)	"rtas: " fmt #include <linux/bsearch.h>#include <linux/capability.h>#include <linux/delay.h>#include <linux/export.h>#include <linux/init.h>#include <linux/kconfig.h>#include <linux/kernel.h>#include <linux/lockdep.h>#include <linux/memblock.h>#include <linux/mutex.h>#include <linux/nospec.h>#include <linux/of.h>#include <linux/of_fdt.h>#include <linux/reboot.h>#include <linux/sched.h>#include <linux/security.h>#include <linux/slab.h>#include <linux/spinlock.h>#include <linux/stdarg.h>#include <linux/syscalls.h>#include <linux/types.h>#include <linux/uaccess.h>#include <linux/xarray.h> #include <asm/delay.h>#include <asm/firmware.h>#include <asm/interrupt.h>#include <asm/machdep.h>#include <asm/mmu.h>#include <asm/page.h>#include <asm/rtas-work-area.h>#include <asm/rtas.h>#include <asm/time.h>#include <asm/trace.h>#include <asm/udbg.h> struct rtas_filter {	/* Indexes into the args buffer, -1 if not used */	const int buf_idx1;	const int size_idx1;	const int buf_idx2;	const int size_idx2;	/*	 * Assumed buffer size per the spec if the function does not	 * have a size parameter, e.g. ibm,errinjct. 0 if unused.	 */	const int fixed_size;}; /** * struct rtas_function - Descriptor for RTAS functions. * * @token: Value of @name if it exists under the /rtas node. * @name: Function name. * @filter: If non-NULL, invoking this function via the rtas syscall is *          generally allowed, and @filter describes constraints on the *          arguments. See also @banned_for_syscall_on_le. * @banned_for_syscall_on_le: Set when call via sys_rtas is generally allowed *                            but specifically restricted on ppc64le. Such *                            functions are believed to have no users on *                            ppc64le, and we want to keep it that way. It does *                            not make sense for this to be set when @filter *                            is NULL. * @lock: Pointer to an optional dedicated per-function mutex. This *        should be set for functions that require multiple calls in *        sequence to complete a single operation, and such sequences *        will disrupt each other if allowed to interleave. Users of *        this function are required to hold the associated lock for *        the duration of the call sequence. Add an explanatory *        comment to the function table entry if setting this member. */struct rtas_function {	s32 token;	const bool banned_for_syscall_on_le:1;	const char * const name;	const struct rtas_filter *filter;	struct mutex *lock;}; /* * Per-function locks for sequence-based RTAS functions. */static DEFINE_MUTEX(rtas_ibm_activate_firmware_lock);static DEFINE_MUTEX(rtas_ibm_lpar_perftools_lock);DEFINE_MUTEX(rtas_ibm_physical_attestation_lock);DEFINE_MUTEX(rtas_ibm_get_vpd_lock);DEFINE_MUTEX(rtas_ibm_get_indices_lock);DEFINE_MUTEX(rtas_ibm_set_dynamic_indicator_lock);DEFINE_MUTEX(rtas_ibm_get_dynamic_sensor_state_lock);DEFINE_MUTEX(rtas_ibm_receive_hvpipe_msg_lock);DEFINE_MUTEX(rtas_ibm_send_hvpipe_msg_lock); static struct rtas_function rtas_function_table[] __ro_after_init = {	[RTAS_FNIDX__CHECK_EXCEPTION] = {		.name = "check-exception",	},	[RTAS_FNIDX__DISPLAY_CHARACTER] = {		.name = "display-character",		.filter = &(const struct rtas_filter) {			.buf_idx1 = -1, .size_idx1 = -1,			.buf_idx2 = -1, .size_idx2 = -1,		},	},	[RTAS_FNIDX__EVENT_SCAN] = {		.name = "event-scan",	},	[RTAS_FNIDX__FREEZE_TIME_BASE] = {		.name = "freeze-time-base",	},	[RTAS_FNIDX__GET_POWER_LEVEL] = {		.name = "get-power-level",		.filter = &(const struct rtas_filter) {			.buf_idx1 = -1, .size_idx1 = -1,			.buf_idx2 = -1, .size_idx2 = -1,		},	},	[RTAS_FNIDX__GET_SENSOR_STATE] = {		.name = "get-sensor-state",		.filter = &(const struct rtas_filter) {			.buf_idx1 = -1, .size_idx1 = -1,			.buf_idx2 = -1, .size_idx2 = -1,		},	},	[RTAS_FNIDX__GET_TERM_CHAR] = {		.name = "get-term-char",	},	[RTAS_FNIDX__GET_TIME_OF_DAY] = {		.name = "get-time-of-day",		.filter = &(const struct rtas_filter) {			.buf_idx1 = -1, .size_idx1 = -1,			.buf_idx2 = -1, .size_idx2 = -1,		},	},	[RTAS_FNIDX__IBM_ACTIVATE_FIRMWARE] = {		.name = "ibm,activate-firmware",		.filter = &(const struct rtas_filter) {			.buf_idx1 = -1, .size_idx1 = -1,			.buf_idx2 = -1, .size_idx2 = -1,		},		/*		 * PAPR+ as of v2.13 doesn't explicitly impose any		 * restriction, but this typically requires multiple		 * calls before success, and there's no reason to		 * allow sequences to interleave.		 */		.lock = &rtas_ibm_activate_firmware_lock,	},	[RTAS_FNIDX__IBM_CBE_START_PTCAL] = {		.name = "ibm,cbe-start-ptcal",	},	[RTAS_FNIDX__IBM_CBE_STOP_PTCAL] = {		.name = "ibm,cbe-stop-ptcal",	},	[RTAS_FNIDX__IBM_CHANGE_MSI] = {		.name = "ibm,change-msi",	},	[RTAS_FNIDX__IBM_CLOSE_ERRINJCT] = {		.name = "ibm,close-errinjct",		.filter = &(const struct rtas_filter) {			.buf_idx1 = -1, .size_idx1 = -1,			.buf_idx2 = -1, .size_idx2 = -1,		},	},	[RTAS_FNIDX__IBM_CONFIGURE_BRIDGE] = {		.name = "ibm,configure-bridge",	},	[RTAS_FNIDX__IBM_CONFIGURE_CONNECTOR] = {		.name = "ibm,configure-connector",		.filter = &(const struct rtas_filter) {			.buf_idx1 = 0, .size_idx1 = -1,			.buf_idx2 = 1, .size_idx2 = -1,			.fixed_size = 4096,		},	},	[RTAS_FNIDX__IBM_CONFIGURE_KERNEL_DUMP] = {		.name = "ibm,configure-kernel-dump",	},	[RTAS_FNIDX__IBM_CONFIGURE_PE] = {		.name = "ibm,configure-pe",	},	[RTAS_FNIDX__IBM_CREATE_PE_DMA_WINDOW] = {		.name = "ibm,create-pe-dma-window",	},	[RTAS_FNIDX__IBM_DISPLAY_MESSAGE] = {		.name = "ibm,display-message",		.filter = &(const struct rtas_filter) {			.buf_idx1 = 0, .size_idx1 = -1,			.buf_idx2 = -1, .size_idx2 = -1,		},	},	[RTAS_FNIDX__IBM_ERRINJCT] = {		.name = "ibm,errinjct",		.filter = &(const struct rtas_filter) {			.buf_idx1 = 2, .size_idx1 = -1,			.buf_idx2 = -1, .size_idx2 = -1,			.fixed_size = 1024,		},	},	[RTAS_FNIDX__IBM_EXTI2C] = {		.name = "ibm,exti2c",	},	[RTAS_FNIDX__IBM_GET_CONFIG_ADDR_INFO] = {		.name = "ibm,get-config-addr-info",	},	[RTAS_FNIDX__IBM_GET_CONFIG_ADDR_INFO2] = {		.name = "ibm,get-config-addr-info2",		.filter = &(const struct rtas_filter) {			.buf_idx1 = -1, .size_idx1 = -1,			.buf_idx2 = -1, .size_idx2 = -1,		},	},	[RTAS_FNIDX__IBM_GET_DYNAMIC_SENSOR_STATE] = {		.name = "ibm,get-dynamic-sensor-state",		.filter = &(const struct rtas_filter) {			.buf_idx1 = 1, .size_idx1 = -1,			.buf_idx2 = -1, .size_idx2 = -1,		},		/*		 * PAPR+ v2.13 R1–7.3.19–3 is explicit that the OS		 * must not call ibm,get-dynamic-sensor-state with		 * different inputs until a non-retry status has been		 * returned.		 */		.lock = &rtas_ibm_get_dynamic_sensor_state_lock,	},	[RTAS_FNIDX__IBM_GET_INDICES] = {		.name = "ibm,get-indices",		.filter = &(const struct rtas_filter) {			.buf_idx1 = 2, .size_idx1 = 3,			.buf_idx2 = -1, .size_idx2 = -1,		},		/*		 * PAPR+ v2.13 R1–7.3.17–2 says that the OS must not		 * interleave ibm,get-indices call sequences with		 * different inputs.		 */		.lock = &rtas_ibm_get_indices_lock,	},	[RTAS_FNIDX__IBM_GET_RIO_TOPOLOGY] = {		.name = "ibm,get-rio-topology",	},	[RTAS_FNIDX__IBM_GET_SYSTEM_PARAMETER] = {		.name = "ibm,get-system-parameter",		.filter = &(const struct rtas_filter) {			.buf_idx1 = 1, .size_idx1 = 2,			.buf_idx2 = -1, .size_idx2 = -1,		},	},	[RTAS_FNIDX__IBM_GET_VPD] = {		.name = "ibm,get-vpd",		.filter = &(const struct rtas_filter) {			.buf_idx1 = 0, .size_idx1 = -1,			.buf_idx2 = 1, .size_idx2 = 2,		},		/*		 * PAPR+ v2.13 R1–7.3.20–4 indicates that sequences		 * should not be allowed to interleave.		 */		.lock = &rtas_ibm_get_vpd_lock,	},	[RTAS_FNIDX__IBM_GET_XIVE] = {		.name = "ibm,get-xive",	},	[RTAS_FNIDX__IBM_INT_OFF] = {		.name = "ibm,int-off",	},	[RTAS_FNIDX__IBM_INT_ON] = {		.name = "ibm,int-on",	},	[RTAS_FNIDX__IBM_IO_QUIESCE_ACK] = {		.name = "ibm,io-quiesce-ack",	},	[RTAS_FNIDX__IBM_LPAR_PERFTOOLS] = {		.name = "ibm,lpar-perftools",		.filter = &(const struct rtas_filter) {			.buf_idx1 = 2, .size_idx1 = 3,			.buf_idx2 = -1, .size_idx2 = -1,		},		/*		 * PAPR+ v2.13 R1–7.3.26–6 says the OS should allow		 * only one call sequence in progress at a time.		 */		.lock = &rtas_ibm_lpar_perftools_lock,	},	[RTAS_FNIDX__IBM_MANAGE_FLASH_IMAGE] = {		.name = "ibm,manage-flash-image",	},	[RTAS_FNIDX__IBM_MANAGE_STORAGE_PRESERVATION] = {		.name = "ibm,manage-storage-preservation",	},	[RTAS_FNIDX__IBM_NMI_INTERLOCK] = {		.name = "ibm,nmi-interlock",	},	[RTAS_FNIDX__IBM_NMI_REGISTER] = {		.name = "ibm,nmi-register",	},	[RTAS_FNIDX__IBM_OPEN_ERRINJCT] = {		.name = "ibm,open-errinjct",		.filter = &(const struct rtas_filter) {			.buf_idx1 = -1, .size_idx1 = -1,			.buf_idx2 = -1, .size_idx2 = -1,		},	},	[RTAS_FNIDX__IBM_OPEN_SRIOV_ALLOW_UNFREEZE] = {		.name = "ibm,open-sriov-allow-unfreeze",	},	[RTAS_FNIDX__IBM_OPEN_SRIOV_MAP_PE_NUMBER] = {		.name = "ibm,open-sriov-map-pe-number",	},	[RTAS_FNIDX__IBM_OS_TERM] = {		.name = "ibm,os-term",	},	[RTAS_FNIDX__IBM_PARTNER_CONTROL] = {		.name = "ibm,partner-control",	},	[RTAS_FNIDX__IBM_PHYSICAL_ATTESTATION] = {		.name = "ibm,physical-attestation",		.filter = &(const struct rtas_filter) {			.buf_idx1 = 0, .size_idx1 = 1,			.buf_idx2 = -1, .size_idx2 = -1,		},		/*		 * This follows a sequence-based pattern similar to		 * ibm,get-vpd et al. Since PAPR+ restricts		 * interleaving call sequences for other functions of		 * this style, assume the restriction applies here,		 * even though it's not explicit in the spec.		 */		.lock = &rtas_ibm_physical_attestation_lock,	},	[RTAS_FNIDX__IBM_PLATFORM_DUMP] = {		.name = "ibm,platform-dump",		.filter = &(const struct rtas_filter) {			.buf_idx1 = 4, .size_idx1 = 5,			.buf_idx2 = -1, .size_idx2 = -1,		},		/*		 * PAPR+ v2.13 7.3.3.4.1 indicates that concurrent		 * sequences of ibm,platform-dump are allowed if they		 * are operating on different dump tags. So leave the		 * lock pointer unset for now. This may need		 * reconsideration if kernel-internal users appear.		 */	},	[RTAS_FNIDX__IBM_POWER_OFF_UPS] = {		.name = "ibm,power-off-ups",	},	[RTAS_FNIDX__IBM_QUERY_INTERRUPT_SOURCE_NUMBER] = {		.name = "ibm,query-interrupt-source-number",	},	[RTAS_FNIDX__IBM_QUERY_PE_DMA_WINDOW] = {		.name = "ibm,query-pe-dma-window",	},	[RTAS_FNIDX__IBM_READ_PCI_CONFIG] = {		.name = "ibm,read-pci-config",	},	[RTAS_FNIDX__IBM_READ_SLOT_RESET_STATE] = {		.name = "ibm,read-slot-reset-state",		.filter = &(const struct rtas_filter) {			.buf_idx1 = -1, .size_idx1 = -1,			.buf_idx2 = -1, .size_idx2 = -1,		},	},	[RTAS_FNIDX__IBM_READ_SLOT_RESET_STATE2] = {		.name = "ibm,read-slot-reset-state2",	},	[RTAS_FNIDX__IBM_RECEIVE_HVPIPE_MSG] {		.name = "ibm,receive-hvpipe-msg",		.filter = &(const struct rtas_filter) {			.buf_idx1 = 0, .size_idx1 = 1,			.buf_idx2 = -1, .size_idx2 = -1,		},		/*		 * PAPR+ v2.13 R1–7.3.32.1		 */		.lock = &rtas_ibm_receive_hvpipe_msg_lock,	},	[RTAS_FNIDX__IBM_REMOVE_PE_DMA_WINDOW] = {		.name = "ibm,remove-pe-dma-window",	},	[RTAS_FNIDX__IBM_RESET_PE_DMA_WINDOW] = {		/*		 * Note: PAPR+ v2.13 7.3.31.4.1 spells this as		 * "ibm,reset-pe-dma-windows" (plural), but RTAS		 * implementations use the singular form in practice.		 */		.name = "ibm,reset-pe-dma-window",	},	[RTAS_FNIDX__IBM_SCAN_LOG_DUMP] = {		.name = "ibm,scan-log-dump",		.filter = &(const struct rtas_filter) {			.buf_idx1 = 0, .size_idx1 = 1,			.buf_idx2 = -1, .size_idx2 = -1,		},	},	[RTAS_FNIDX__IBM_SEND_HVPIPE_MSG] {		.name = "ibm,send-hvpipe-msg",		.filter = &(const struct rtas_filter) {			.buf_idx1 = 1, .size_idx1 = -1,			.buf_idx2 = -1, .size_idx2 = -1,		},		/*		 * PAPR+ v2.13 R1–7.3.32.2		 */		.lock = &rtas_ibm_send_hvpipe_msg_lock,	},	[RTAS_FNIDX__IBM_SET_DYNAMIC_INDICATOR] = {		.name = "ibm,set-dynamic-indicator",		.filter = &(const struct rtas_filter) {			.buf_idx1 = 2, .size_idx1 = -1,			.buf_idx2 = -1, .size_idx2 = -1,		},		/*		 * PAPR+ v2.13 R1–7.3.18–3 says the OS must not call		 * this function with different inputs until a		 * non-retry status has been returned.		 */		.lock = &rtas_ibm_set_dynamic_indicator_lock,	},	[RTAS_FNIDX__IBM_SET_EEH_OPTION] = {		.name = "ibm,set-eeh-option",		.filter = &(const struct rtas_filter) {			.buf_idx1 = -1, .size_idx1 = -1,			.buf_idx2 = -1, .size_idx2 = -1,		},	},	[RTAS_FNIDX__IBM_SET_SLOT_RESET] = {		.name = "ibm,set-slot-reset",	},	[RTAS_FNIDX__IBM_SET_SYSTEM_PARAMETER] = {		.name = "ibm,set-system-parameter",		.filter = &(const struct rtas_filter) {			.buf_idx1 = 1, .size_idx1 = -1,			.buf_idx2 = -1, .size_idx2 = -1,		},	},	[RTAS_FNIDX__IBM_SET_XIVE] = {		.name = "ibm,set-xive",	},	[RTAS_FNIDX__IBM_SLOT_ERROR_DETAIL] = {		.name = "ibm,slot-error-detail",	},	[RTAS_FNIDX__IBM_SUSPEND_ME] = {		.name = "ibm,suspend-me",		.banned_for_syscall_on_le = true,		.filter = &(const struct rtas_filter) {			.buf_idx1 = -1, .size_idx1 = -1,			.buf_idx2 = -1, .size_idx2 = -1,		},	},	[RTAS_FNIDX__IBM_TUNE_DMA_PARMS] = {		.name = "ibm,tune-dma-parms",	},	[RTAS_FNIDX__IBM_UPDATE_FLASH_64_AND_REBOOT] = {		.name = "ibm,update-flash-64-and-reboot",	},	[RTAS_FNIDX__IBM_UPDATE_NODES] = {		.name = "ibm,update-nodes",		.banned_for_syscall_on_le = true,		.filter = &(const struct rtas_filter) {			.buf_idx1 = 0, .size_idx1 = -1,			.buf_idx2 = -1, .size_idx2 = -1,			.fixed_size = 4096,		},	},	[RTAS_FNIDX__IBM_UPDATE_PROPERTIES] = {		.name = "ibm,update-properties",		.banned_for_syscall_on_le = true,		.filter = &(const struct rtas_filter) {			.buf_idx1 = 0, .size_idx1 = -1,			.buf_idx2 = -1, .size_idx2 = -1,			.fixed_size = 4096,		},	},	[RTAS_FNIDX__IBM_VALIDATE_FLASH_IMAGE] = {		.name = "ibm,validate-flash-image",	},	[RTAS_FNIDX__IBM_WRITE_PCI_CONFIG] = {		.name = "ibm,write-pci-config",	},	[RTAS_FNIDX__NVRAM_FETCH] = {		.name = "nvram-fetch",	},	[RTAS_FNIDX__NVRAM_STORE] = {		.name = "nvram-store",	},	[RTAS_FNIDX__POWER_OFF] = {		.name = "power-off",	},

Lines 1–500 of 2133.