Something went wrong. Try again.
(I'm so sorry!) Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582/* SPDX-License-Identifier: GPL-2.0 *//* * Copyright (C) 2026 ARM Ltd. */
#ifndef __LINUX_ARM_RMI_CMDS_H_#define __LINUX_ARM_RMI_CMDS_H_
#include <linux/arm-smccc-rmi.h>#include <linux/bug.h>#include <linux/gfp.h>#include <linux/processor.h>#include <linux/string.h>#include <linux/types.h>
#define RMI_MAX_ADDR_LIST 256
struct rmi_sro_state { struct arm_smccc_1_2_regs regs; int addr_count; unsigned long addr_list[RMI_MAX_ADDR_LIST];};
#define RMM_BLOCKED_RETRY_COUNT 2/* * rmi_smccc_invoke: Invoke the RMI call and return the results, retrying the * command when status is RMI_BUSY. If we encounter RMI_BLOCKED, we retry * it one more time before we give up. The caller is supposed to handle the * result and reissue if required. * * We don't expect to see RMI_BLOCKED on a practical system, except when * there are parallel requests that results in long standing operation, * with one blocking the other. * * @regs: Input parameters filled in. Updated with the output results * after the call. */static inline void rmi_smccc_invoke(struct arm_smccc_1_2_regs *regs){ struct arm_smccc_1_2_regs args = *regs; long status; int i = 0;
while (i < RMM_BLOCKED_RETRY_COUNT) { arm_smccc_1_2_smc(&args, regs);
status = RMI_RESULT_STATUS(regs->a0); if (status != RMI_BUSY && status != RMI_BLOCKED) break; if (status == RMI_BLOCKED) i++; cpu_relax(); }}
/* * rmi_smccc_invoke_once: Invoke the RMI call and return the results. Do not * retry the command. Let the caller deal with RMI_BUSY or RMI_BLOCKED. * * @regs: Input parameters filled in. Updated with the output results * after the call. */static __always_inline void rmi_smccc_invoke_once(struct arm_smccc_1_2_regs *regs){ arm_smccc_1_2_smc(regs, regs);}
unsigned long rmi_feat_reg(unsigned int index);
int rmi_delegate_range(phys_addr_t phys, unsigned long size, phys_addr_t *out_phys);int rmi_undelegate_range(phys_addr_t phys, unsigned long size);int rmi_free_delegated_page(phys_addr_t phys);
static inline int rmi_delegate_page(phys_addr_t phys){ return rmi_delegate_range(phys, PAGE_SIZE, NULL);}
static inline int rmi_undelegate_page(phys_addr_t phys){ return rmi_undelegate_range(phys, PAGE_SIZE);}
long rmi_sro_memxfer_execute(struct rmi_sro_state *sro, gfp_t gfp);void rmi_sro_free(struct rmi_sro_state *sro);long rmi_sro_execute(struct arm_smccc_1_2_regs *regs);
/* * Resetting the addr_count is sufficient to ignore the addr_list contents. */#define rmi_sro_memxfer_cmd(sro, gfp, ...) ({ \ struct rmi_sro_state *__sro = (sro); \ __sro->addr_count = 0; \ __sro->regs = (struct arm_smccc_1_2_regs){ __VA_ARGS__ }; \ long __ret = rmi_sro_memxfer_execute(__sro, gfp); \ rmi_sro_free(__sro); \ __ret; \})
#ifdef CONFIG_ARM_RMM_RMI
bool is_rmm_active(void);bool is_rmi_available(void);
#else
static inline bool is_rmm_active(void){ return false;}
static inline bool is_rmi_available(void){ return false;}#endif /* CONFIG_ARM_RMM_RMI */
/** * rmi_rtt_data_map_init() - Create a mapping at protected IPA, copying contents * from a given non-secure source granule. * @rd: PA of the RD * @data: PA of the target granule mapped in the guest * @ipa: IPA at which the granule @data will be mapped in the guest * @src: PA of the source granule with contents * @flags: RMI_MEASURE_CONTENT if the contents should be measured * * Create a mapping from Protected IPA space to conventional memory, copying * contents from a Non-secure Granule provided by the caller. * * Return: 0 on success, positive RMI result code or negative Linux error code */static inline long rmi_rtt_data_map_init(unsigned long rd, unsigned long data, unsigned long ipa, unsigned long src, unsigned long flags){ struct arm_smccc_1_2_regs regs = { SMC_RMI_RTT_DATA_MAP_INIT, rd, data, ipa, src, flags };
return rmi_sro_execute(®s);}
/** * rmi_rtt_data_map() - Create mappings in protected IPA range with unknown contents * @rd: PA of the RD * @base: Base of the target IPA range * @top: Top of the target IPA range * @flags: Flags * @oaddr: Output address set descriptor * @out_top: Top address of range which was processed. * * Return: 0 on success, positive RMI result code or negative Linux error code. * NOTE: out_top is only valid with ret == RMI_SUCCESS */static inline long rmi_rtt_data_map(unsigned long rd, unsigned long base, unsigned long top, unsigned long flags, unsigned long oaddr, unsigned long *out_top){ struct arm_smccc_1_2_regs regs = { SMC_RMI_RTT_DATA_MAP, rd, base, top, flags, oaddr }; long ret;
ret = rmi_sro_execute(®s);
if (ret == RMI_SUCCESS && out_top) *out_top = regs.a1;
return ret;}
/** * rmi_rtt_data_unmap() - Remove mappings to conventional memory at a protected * IPA range * @rd: PA of the RD * @base: Base of the target IPA range * @top: Top of the target IPA range * @flags: Flags * @oaddr: Output address set descriptor * @out_top: Returns top IPA of range which has been unmapped * @out_range: Output address range * @out_count: Number of entries in output address list * * Removes mappings to convention memory with a target Protected IPA range. * * Return: 0 on success, positive RMI result code or negative Linux error code * NOTE: out_top is only valid with ret == RMI_SUCCESS */static inline long rmi_rtt_data_unmap(unsigned long rd, unsigned long base, unsigned long top, unsigned long flags, unsigned long oaddr, unsigned long *out_top, unsigned long *out_range, unsigned long *out_count){ struct arm_smccc_1_2_regs regs = { SMC_RMI_RTT_DATA_UNMAP, rd, base, top, flags, oaddr }; long ret;
ret = rmi_sro_execute(®s);
if (ret != RMI_SUCCESS) return ret;
if (out_top) *out_top = regs.a1; if (out_range) *out_range = regs.a2; if (out_count) *out_count = regs.a3;
return RMI_SUCCESS;}
/** * rmi_psci_complete() - Complete pending PSCI command * @calling_rec: PA of the calling REC * @status: Status of the PSCI request * * Completes a pending PSCI command. * * Return: RMI return code */static inline long rmi_psci_complete(unsigned long calling_rec, unsigned long status){ struct arm_smccc_1_2_regs regs = { SMC_RMI_PSCI_COMPLETE, calling_rec, status, };
rmi_smccc_invoke(®s); return regs.a0;}
/** * rmi_realm_activate() - Activate a realm * @rd: PA of the RD * * Mark a realm as Active, signalling that creation is completed, allowing * execution of the realm. * * Return: RMI return code */static inline long rmi_realm_activate(unsigned long rd){ struct arm_smccc_1_2_regs regs = { SMC_RMI_REALM_ACTIVATE, rd, };
rmi_smccc_invoke(®s); return regs.a0;}
/** * rmi_realm_create() - Create a realm * @rd: PA of the RD * @params: PA of realm parameters * @sro: Preallocated SRO context * * Create a new realm using the given parameters. * * Return: 0 on success, positive RMI result code or negative Linux error code */static inline long rmi_realm_create(unsigned long rd, unsigned long params, struct rmi_sro_state *sro){ return rmi_sro_memxfer_cmd(sro, GFP_KERNEL, SMC_RMI_REALM_CREATE, rd, params);}
/** * rmi_realm_terminate() - Terminate a realm * @rd: PA of the RD * @sro: Preallocated SRO context * * Terminates a realm, moving it into a ZOMBIE state * * Return: 0 on success, positive RMI result code or negative Linux error code */static inline long rmi_realm_terminate(unsigned long rd, struct rmi_sro_state *sro){ return rmi_sro_memxfer_cmd(sro, GFP_KERNEL, SMC_RMI_REALM_TERMINATE, rd);}
/** * rmi_realm_destroy() - Destroy a realm * @rd: PA of the RD * @sro: Preallocated SRO context * * Destroys a realm, all objects belonging to the realm must be destroyed first. * * Return: 0 on success, positive RMI result code or negative Linux error code */static inline long rmi_realm_destroy(unsigned long rd, struct rmi_sro_state *sro){ return rmi_sro_memxfer_cmd(sro, GFP_KERNEL, SMC_RMI_REALM_DESTROY, rd);}
/** * rmi_rec_create() - Create a REC * @rd: PA of the RD * @rec: PA of the target REC * @params: PA of REC parameters * @sro: Allocated SRO context to be used * * Create a REC using the parameters specified in the struct rec_params pointed * to by @params. * * Return: 0 on success, positive RMI result code or negative Linux error code */static inline long rmi_rec_create(unsigned long rd, unsigned long rec, unsigned long params, struct rmi_sro_state *sro){ return rmi_sro_memxfer_cmd(sro, GFP_KERNEL, SMC_RMI_REC_CREATE, rd, rec, params);}
/** * rmi_rec_destroy() - Destroy a REC * @rec: PA of the target REC * @sro: Allocated SRO context to be used * * Destroys a REC. The REC must not be running. * * Return: 0 on success, positive RMI result code or negative Linux error code */static __always_inline long rmi_rec_destroy(unsigned long rec, struct rmi_sro_state *sro){ return rmi_sro_memxfer_cmd(sro, GFP_KERNEL, SMC_RMI_REC_DESTROY, rec);}
/** * rmi_rec_enter() - Enter a REC * @rec: PA of the target REC * @run_ptr: PA of RecRun structure * * Starts (or continues) execution within a REC. * * Return: RMI result */static __always_inline long rmi_rec_enter(unsigned long rec, unsigned long run_ptr){ struct arm_smccc_1_2_regs regs = { SMC_RMI_REC_ENTER, rec, run_ptr, };
rmi_smccc_invoke_once(®s); return regs.a0;}
/** * rmi_rtt_create() - Creates an RTT * @rd: PA of the RD * @rtt: PA of the target RTT * @ipa: Base of the IPA range described by the RTT * @level: Depth of the RTT within the tree * * Creates an RTT (Realm Translation Table) at the specified level for the * translation of the specified address within the realm. * * Return: 0 on success, positive RMI result code or negative Linux error code */static inline long rmi_rtt_create(unsigned long rd, unsigned long rtt, unsigned long ipa, long level){ struct arm_smccc_1_2_regs regs = { SMC_RMI_RTT_CREATE, rd, rtt, ipa, level };
return rmi_sro_execute(®s);}
/** * rmi_rtt_destroy() - Destroy an RTT * @rd: PA of the RD * @ipa: Base of the IPA range described by the RTT * @level: RTT level * @out_rtt: Pointer to write the PA of the RTT which was destroyed * @out_top: Pointer to write the top IPA of non-live RTT entries, from entry * at which the RTT walk terminated. * * Destroys an RTT. The RTT must be non-live, i.e. none of the entries in the * table are in ASSIGNED or TABLE state. * * Return: 0 on success, positive RMI result code or negative Linux error code. */static inline long rmi_rtt_destroy(unsigned long rd, unsigned long ipa, long level, unsigned long *out_rtt, unsigned long *out_top){ struct arm_smccc_1_2_regs regs = { SMC_RMI_RTT_DESTROY, rd, ipa, level }; long ret = rmi_sro_execute(®s);
switch (RMI_RESULT_STATUS(ret)) { case RMI_SUCCESS: if (out_rtt) *out_rtt = regs.a1; fallthrough; case RMI_ERROR_RTT: if (out_top) *out_top = regs.a2; break; default: break; }
return ret;}
/** * rmi_rtt_fold() - Fold an RTT * @rd: PA of the RD * @ipa: Base of the IPA range described by the RTT * @level: Depth of the RTT within the tree * @out_rtt: Pointer to write the PA of the RTT which was destroyed * * Folds an RTT. If all entries with the RTT are 'homogeneous' the RTT can be * folded into the parent and the RTT destroyed. * * Return: 0 on success, positive RMI result code or negative Linux error code */static inline long rmi_rtt_fold(unsigned long rd, unsigned long ipa, long level, unsigned long *out_rtt){ struct arm_smccc_1_2_regs regs = { SMC_RMI_RTT_FOLD, rd, ipa, level }; long ret = rmi_sro_execute(®s);
if (ret == RMI_SUCCESS && out_rtt) *out_rtt = regs.a1;
return ret;}
/** * rmi_rtt_init_ripas() - Set RIPAS for new realm * @rd: PA of the RD * @base: Base of target IPA region * @top: Top of target IPA region * @out_top: Top IPA of range whose RIPAS was modified * * Sets the RIPAS of a target IPA range to RAM, for a realm in the NEW state. * * Return: 0 on success, positive RMI result code or negative Linux error code */static inline long rmi_rtt_init_ripas(unsigned long rd, unsigned long base, unsigned long top, unsigned long *out_top){ struct arm_smccc_1_2_regs regs = { SMC_RMI_RTT_INIT_RIPAS, rd, base, top }; long ret = rmi_sro_execute(®s);
if (ret == RMI_SUCCESS && out_top) *out_top = regs.a1;
return ret;}
/** * rmi_rtt_unprot_map() - Map unprotected granules into a realm * @rd: PA of the RD * @base: Base IPA of the mapping * @top: Top of the target IPA range * @flags: Flags * @oaddr: Output address set descriptor * @out_top: Top IPA of range which has been mapped * * Create mappings to memory within a target unprotected IPA range. * * Return: 0 on success, positive RMI result code or negative Linux error code */static inline long rmi_rtt_unprot_map(unsigned long rd, unsigned long base, unsigned long top, unsigned long flags, unsigned long oaddr, unsigned long *out_top){ struct arm_smccc_1_2_regs regs = { SMC_RMI_RTT_UNPROT_MAP, rd, base, top, flags, oaddr }; long ret = rmi_sro_execute(®s);
if (ret == RMI_SUCCESS && out_top) *out_top = regs.a1;
return ret;}
/** * rmi_rtt_set_ripas() - Set RIPAS for an running realm * @rd: PA of the RD * @rec: PA of the REC making the request * @base: Base of target IPA region * @top: Top of target IPA region * @out_top: Pointer to write top IPA of range whose RIPAS was modified * * Completes a request made by the realm to change the RIPAS of a target IPA * range. * * Return: 0 on success, positive RMI result code or negative Linux error code */static inline long rmi_rtt_set_ripas(unsigned long rd, unsigned long rec, unsigned long base, unsigned long top, unsigned long *out_top){ struct arm_smccc_1_2_regs regs = { SMC_RMI_RTT_SET_RIPAS, rd, rec, base, top }; long ret = rmi_sro_execute(®s);
if (ret == RMI_SUCCESS && out_top) *out_top = regs.a1;
return ret;}
/** * rmi_rtt_unprot_unmap() - Remove mappings within an unprotected IPA range * @rd: PA of the RD * @base: Base IPA of the mapping * @top: Top of the target IPA range * @flags: Flags * @oaddr: Output address set descriptor * @out_top: Top IPA which has been unmapped * @out_range: Output address range * @out_count: Number of entries in output address list * * Removes mappings to memory within a target unprotected IPA range. * * Return: 0 on success, positive RMI result code or negative Linux error code * NOTE: out_top is only valid with ret == RMI_SUCCESS. */static inline long rmi_rtt_unprot_unmap(unsigned long rd, unsigned long base, unsigned long top, unsigned long flags, unsigned long oaddr, unsigned long *out_top, unsigned long *out_range, unsigned long *out_count){ struct arm_smccc_1_2_regs regs = { SMC_RMI_RTT_UNPROT_UNMAP, rd, base, top, flags, oaddr }; long ret = rmi_sro_execute(®s);
if (ret != RMI_SUCCESS) return ret;
if (out_top) *out_top = regs.a1; if (out_range) *out_range = regs.a2; if (out_count) *out_count = regs.a3;
return RMI_SUCCESS;}
#endif /* __LINUX_ARM_RMI_CMDS_H_ */