€•K€Œsphinx.addnodes”Œdocument”“”)”}”(Œ rawsource”Œ”Œchildren”]”(Œ translations”Œ LanguagesNode”“”)”}”(hhh]”(hŒ pending_xref”“”)”}”(hhh]”Œdocutils.nodes”ŒText”“”ŒChinese (Simplified)”…””}”Œparent”hsbaŒ attributes”}”(Œids”]”Œclasses”]”Œnames”]”Œdupnames”]”Œbackrefs”]”Œ refdomain”Œstd”Œreftype”Œdoc”Œ reftarget”Œ$/translations/zh_CN/arch/riscv/cmodx”Œmodname”NŒ classname”NŒ refexplicit”ˆuŒtagname”hhh ubh)”}”(hhh]”hŒChinese (Traditional)”…””}”hh2sbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ$/translations/zh_TW/arch/riscv/cmodx”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒItalian”…””}”hhFsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ$/translations/it_IT/arch/riscv/cmodx”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒJapanese”…””}”hhZsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ$/translations/ja_JP/arch/riscv/cmodx”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒKorean”…””}”hhnsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ$/translations/ko_KR/arch/riscv/cmodx”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒPortuguese (Brazilian)”…””}”hh‚sbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ$/translations/pt_BR/arch/riscv/cmodx”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒSpanish”…””}”hh–sbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ$/translations/sp_SP/arch/riscv/cmodx”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubeh}”(h]”h ]”h"]”h$]”h&]”Œcurrent_language”ŒEnglish”uh1h hhŒ _document”hŒsource”NŒline”NubhŒcomment”“”)”}”(hŒ SPDX-License-Identifier: GPL-2.0”h]”hŒ SPDX-License-Identifier: GPL-2.0”…””}”hh·sbah}”(h]”h ]”h"]”h$]”h&]”Œ xml:space”Œpreserve”uh1hµhhh²hh³Œ>/var/lib/git/docbuild/linux/Documentation/arch/riscv/cmodx.rst”h´KubhŒsection”“”)”}”(hhh]”(hŒtitle”“”)”}”(hŒNConcurrent Modification and Execution of Instructions (CMODX) for RISC-V Linux”h]”hŒNConcurrent Modification and Execution of Instructions (CMODX) for RISC-V Linux”…””}”(hhÏh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhhÊh²hh³hÇh´KubhŒ paragraph”“”)”}”(hXHCMODX is a programming technique where a program executes instructions that were modified by the program itself. Instruction storage and the instruction cache (icache) are not guaranteed to be synchronized on RISC-V hardware. Therefore, the program must enforce its own synchronization with the unprivileged fence.i instruction.”h]”hXHCMODX is a programming technique where a program executes instructions that were modified by the program itself. Instruction storage and the instruction cache (icache) are not guaranteed to be synchronized on RISC-V hardware. Therefore, the program must enforce its own synchronization with the unprivileged fence.i instruction.”…””}”(hhßh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´KhhÊh²hubhÉ)”}”(hhh]”hÎ)”}”(hŒCMODX in the Kernel Space”h]”hŒCMODX in the Kernel Space”…””}”(hhðh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhhíh²hh³hÇh´Kubah}”(h]”Œcmodx-in-the-kernel-space”ah ]”h"]”Œcmodx in the kernel space”ah$]”h&]”uh1hÈhhÊh²hh³hÇh´KubhÉ)”}”(hhh]”(hÎ)”}”(hŒDynamic ftrace”h]”hŒDynamic ftrace”…””}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhjh²hh³hÇh´KubhÞ)”}”(hXaEssentially, dynamic ftrace directs the control flow by inserting a function call at each patchable function entry, and patches it dynamically at runtime to enable or disable the redirection. In the case of RISC-V, 2 instructions, AUIPC + JALR, are required to compose a function call. However, it is impossible to patch 2 instructions and expect that a concurrent read-side executes them without a race condition. This series makes atmoic code patching possible in RISC-V ftrace. Kernel preemption makes things even worse as it allows the old state to persist across the patching process with stop_machine().”h]”hXaEssentially, dynamic ftrace directs the control flow by inserting a function call at each patchable function entry, and patches it dynamically at runtime to enable or disable the redirection. In the case of RISC-V, 2 instructions, AUIPC + JALR, are required to compose a function call. However, it is impossible to patch 2 instructions and expect that a concurrent read-side executes them without a race condition. This series makes atmoic code patching possible in RISC-V ftrace. Kernel preemption makes things even worse as it allows the old state to persist across the patching process with stop_machine().”…””}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´Khjh²hubhÞ)”}”(hXžIn order to get rid of stop_machine() and run dynamic ftrace with full kernel preemption, we partially initialize each patchable function entry at boot-time, setting the first instruction to AUIPC, and the second to NOP. Now, atmoic patching is possible because the kernel only has to update one instruction. According to Ziccif, as long as an instruction is naturally aligned, the ISA guarantee an atomic update.”h]”hXžIn order to get rid of stop_machine() and run dynamic ftrace with full kernel preemption, we partially initialize each patchable function entry at boot-time, setting the first instruction to AUIPC, and the second to NOP. Now, atmoic patching is possible because the kernel only has to update one instruction. According to Ziccif, as long as an instruction is naturally aligned, the ISA guarantee an atomic update.”…””}”(hj%h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´Khjh²hubhÞ)”}”(hX¸By fixing down the first instruction, AUIPC, the range of the ftrace trampoline is limited to +-2K from the predetermined target, ftrace_caller, due to the lack of immediate encoding space in RISC-V. To address the issue, we introduce CALL_OPS, where an 8B naturally align metadata is added in front of each pacthable function. The metadata is resolved at the first trampoline, then the execution can be derect to another custom trampoline.”h]”hX¸By fixing down the first instruction, AUIPC, the range of the ftrace trampoline is limited to +-2K from the predetermined target, ftrace_caller, due to the lack of immediate encoding space in RISC-V. To address the issue, we introduce CALL_OPS, where an 8B naturally align metadata is added in front of each pacthable function. The metadata is resolved at the first trampoline, then the execution can be derect to another custom trampoline.”…””}”(hj3h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´K#hjh²hubeh}”(h]”Œdynamic-ftrace”ah ]”h"]”Œdynamic ftrace”ah$]”h&]”uh1hÈhhÊh²hh³hÇh´KubhÉ)”}”(hhh]”(hÎ)”}”(hŒCMODX in the User Space”h]”hŒCMODX in the User Space”…””}”(hjLh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhjIh²hh³hÇh´K+ubhÞ)”}”(hXThough fence.i is an unprivileged instruction, the default Linux ABI prohibits the use of fence.i in userspace applications. At any point the scheduler may migrate a task onto a new hart. If migration occurs after the userspace synchronized the icache and instruction storage with fence.i, the icache on the new hart will no longer be clean. This is due to the behavior of fence.i only affecting the hart that it is called on. Thus, the hart that the task has been migrated to may not have synchronized instruction storage and icache.”h]”hXThough fence.i is an unprivileged instruction, the default Linux ABI prohibits the use of fence.i in userspace applications. At any point the scheduler may migrate a task onto a new hart. If migration occurs after the userspace synchronized the icache and instruction storage with fence.i, the icache on the new hart will no longer be clean. This is due to the behavior of fence.i only affecting the hart that it is called on. Thus, the hart that the task has been migrated to may not have synchronized instruction storage and icache.”…””}”(hjZh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´K-hjIh²hubhÞ)”}”(hX4There are two ways to solve this problem: use the riscv_flush_icache() syscall, or use the ``PR_RISCV_SET_ICACHE_FLUSH_CTX`` prctl() and emit fence.i in userspace. The syscall performs a one-off icache flushing operation. The prctl changes the Linux ABI to allow userspace to emit icache flushing operations.”h]”(hŒ[There are two ways to solve this problem: use the riscv_flush_icache() syscall, or use the ”…””}”(hjhh²hh³Nh´NubhŒliteral”“”)”}”(hŒ!``PR_RISCV_SET_ICACHE_FLUSH_CTX``”h]”hŒPR_RISCV_SET_ICACHE_FLUSH_CTX”…””}”(hjrh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jphjhubhŒ¸ prctl() and emit fence.i in userspace. The syscall performs a one-off icache flushing operation. The prctl changes the Linux ABI to allow userspace to emit icache flushing operations.”…””}”(hjhh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´K5hjIh²hubhÞ)”}”(hX As an aside, "deferred" icache flushes can sometimes be triggered in the kernel. At the time of writing, this only occurs during the riscv_flush_icache() syscall and when the kernel uses copy_to_user_page(). These deferred flushes happen only when the memory map being used by a hart changes. If the prctl() context caused an icache flush, this deferred icache flush will be skipped as it is redundant. Therefore, there will be no additional flush when using the riscv_flush_icache() syscall inside of the prctl() context.”h]”hXAs an aside, “deferred†icache flushes can sometimes be triggered in the kernel. At the time of writing, this only occurs during the riscv_flush_icache() syscall and when the kernel uses copy_to_user_page(). These deferred flushes happen only when the memory map being used by a hart changes. If the prctl() context caused an icache flush, this deferred icache flush will be skipped as it is redundant. Therefore, there will be no additional flush when using the riscv_flush_icache() syscall inside of the prctl() context.”…””}”(hjŠh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´K:hjIh²hubeh}”(h]”Œcmodx-in-the-user-space”ah ]”h"]”Œcmodx in the user space”ah$]”h&]”uh1hÈhhÊh²hh³hÇh´K+ubhÉ)”}”(hhh]”(hÎ)”}”(hŒprctl() Interface”h]”hŒprctl() Interface”…””}”(hj£h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhj h²hh³hÇh´KCubhÞ)”}”(hŒ¯Call prctl() with ``PR_RISCV_SET_ICACHE_FLUSH_CTX`` as the first argument. The remaining arguments will be delegated to the riscv_set_icache_flush_ctx function detailed below.”h]”(hŒCall prctl() with ”…””}”(hj±h²hh³Nh´Nubjq)”}”(hŒ!``PR_RISCV_SET_ICACHE_FLUSH_CTX``”h]”hŒPR_RISCV_SET_ICACHE_FLUSH_CTX”…””}”(hj¹h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jphj±ubhŒ| as the first argument. The remaining arguments will be delegated to the riscv_set_icache_flush_ctx function detailed below.”…””}”(hj±h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´KEhj h²hubhŒindex”“”)”}”(hhh]”h}”(h]”h ]”h"]”h$]”h&]”Œentries”]”(Œsingle”Œ'riscv_set_icache_flush_ctx (C function)”Œc.riscv_set_icache_flush_ctx”hNt”auh1jÑhj h²hh³Nh´NubhŒdesc”“”)”}”(hhh]”(hŒdesc_signature”“”)”}”(hŒGint riscv_set_icache_flush_ctx (unsigned long ctx, unsigned long scope)”h]”hŒdesc_signature_line”“”)”}”(hŒFint riscv_set_icache_flush_ctx(unsigned long ctx, unsigned long scope)”h]”(hŒdesc_sig_keyword_type”“”)”}”(hŒint”h]”hŒint”…””}”(hjõh²hh³Nh´Nubah}”(h]”h ]”Œkt”ah"]”h$]”h&]”uh1jóhjïh²hh³Œ[/var/lib/git/docbuild/linux/Documentation/arch/riscv/cmodx:73: ./arch/riscv/mm/cacheflush.c”h´KÊubhŒdesc_sig_space”“”)”}”(hŒ ”h]”hŒ ”…””}”(hjh²hh³Nh´Nubah}”(h]”h ]”Œw”ah"]”h$]”h&]”uh1jhjïh²hh³jh´KÊubhŒ desc_name”“”)”}”(hŒriscv_set_icache_flush_ctx”h]”hŒ desc_sig_name”“”)”}”(hŒriscv_set_icache_flush_ctx”h]”hŒriscv_set_icache_flush_ctx”…””}”(hjh²hh³Nh´Nubah}”(h]”h ]”Œn”ah"]”h$]”h&]”uh1jhjubah}”(h]”h ]”(Œsig-name”Œdescname”eh"]”h$]”h&]”hÅhÆuh1jhjïh²hh³jh´KÊubhŒdesc_parameterlist”“”)”}”(hŒ((unsigned long ctx, unsigned long scope)”h]”(hŒdesc_parameter”“”)”}”(hŒunsigned long ctx”h]”(jô)”}”(hŒunsigned”h]”hŒunsigned”…””}”(hjAh²hh³Nh´Nubah}”(h]”h ]”jah"]”h$]”h&]”uh1jóhj=ubj)”}”(hŒ ”h]”hŒ ”…””}”(hjOh²hh³Nh´Nubah}”(h]”h ]”jah"]”h$]”h&]”uh1jhj=ubjô)”}”(hŒlong”h]”hŒlong”…””}”(hj]h²hh³Nh´Nubah}”(h]”h ]”jah"]”h$]”h&]”uh1jóhj=ubj)”}”(hŒ ”h]”hŒ ”…””}”(hjkh²hh³Nh´Nubah}”(h]”h ]”jah"]”h$]”h&]”uh1jhj=ubj)”}”(hŒctx”h]”hŒctx”…””}”(hjyh²hh³Nh´Nubah}”(h]”h ]”j)ah"]”h$]”h&]”uh1jhj=ubeh}”(h]”h ]”h"]”h$]”h&]”Œnoemph”ˆhÅhÆuh1j;hj7ubj<)”}”(hŒunsigned long scope”h]”(jô)”}”(hŒunsigned”h]”hŒunsigned”…””}”(hj’h²hh³Nh´Nubah}”(h]”h ]”jah"]”h$]”h&]”uh1jóhjŽubj)”}”(hŒ ”h]”hŒ ”…””}”(hj h²hh³Nh´Nubah}”(h]”h ]”jah"]”h$]”h&]”uh1jhjŽubjô)”}”(hŒlong”h]”hŒlong”…””}”(hj®h²hh³Nh´Nubah}”(h]”h ]”jah"]”h$]”h&]”uh1jóhjŽubj)”}”(hŒ ”h]”hŒ ”…””}”(hj¼h²hh³Nh´Nubah}”(h]”h ]”jah"]”h$]”h&]”uh1jhjŽubj)”}”(hŒscope”h]”hŒscope”…””}”(hjÊh²hh³Nh´Nubah}”(h]”h ]”j)ah"]”h$]”h&]”uh1jhjŽubeh}”(h]”h ]”h"]”h$]”h&]”Œnoemph”ˆhÅhÆuh1j;hj7ubeh}”(h]”h ]”h"]”h$]”h&]”hÅhÆuh1j5hjïh²hh³jh´KÊubeh}”(h]”h ]”h"]”h$]”h&]”hÅhÆŒ add_permalink”ˆuh1jíŒsphinx_line_type”Œ declarator”hjéh²hh³jh´KÊubah}”(h]”jàah ]”(Œsig”Œ sig-object”eh"]”h$]”h&]”Œ is_multiline”ˆŒ _toc_parts”)Œ _toc_name”huh1jçh³jh´KÊhjäh²hubhŒ desc_content”“”)”}”(hhh]”hÞ)”}”(hŒ9Enable/disable icache flushing instructions in userspace.”h]”hŒ9Enable/disable icache flushing instructions in userspace.”…””}”(hjþh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³Œ[/var/lib/git/docbuild/linux/Documentation/arch/riscv/cmodx:73: ./arch/riscv/mm/cacheflush.c”h´KÊhjûh²hubah}”(h]”h ]”h"]”h$]”h&]”uh1jùhjäh²hh³jh´KÊubeh}”(h]”h ]”(Œc”Œfunction”eh"]”h$]”h&]”Œdomain”jŒobjtype”jŒdesctype”jŒnoindex”‰Œ noindexentry”‰Œnocontentsentry”‰uh1jâh²hhj h³Nh´NubhŒ container”“”)”}”(hX***Parameters** ``unsigned long ctx`` Set the type of icache flushing instructions permitted/prohibited in userspace. Supported values described below. ``unsigned long scope`` Set scope of where icache flushing instructions are allowed to be emitted. Supported values described below. **Description** Supported values for ctx: * ``PR_RISCV_CTX_SW_FENCEI_ON``: Allow fence.i in user space. * ``PR_RISCV_CTX_SW_FENCEI_OFF``: Disallow fence.i in user space. All threads in a process will be affected when ``scope == PR_RISCV_SCOPE_PER_PROCESS``. Therefore, caution must be taken; use this flag only when you can guarantee that no thread in the process will emit fence.i from this point onward. Supported values for scope: * ``PR_RISCV_SCOPE_PER_PROCESS``: Ensure the icache of any thread in this process is coherent with instruction storage upon migration. * ``PR_RISCV_SCOPE_PER_THREAD``: Ensure the icache of the current thread is coherent with instruction storage upon migration. When ``scope == PR_RISCV_SCOPE_PER_PROCESS``, all threads in the process are permitted to emit icache flushing instructions. Whenever any thread in the process is migrated, the corresponding hart's icache will be guaranteed to be consistent with instruction storage. This does not enforce any guarantees outside of migration. If a thread modifies an instruction that another thread may attempt to execute, the other thread must still emit an icache flushing instruction before attempting to execute the potentially modified instruction. This must be performed by the user-space program. In per-thread context (eg. ``scope == PR_RISCV_SCOPE_PER_THREAD``) only the thread calling this function is permitted to emit icache flushing instructions. When the thread is migrated, the corresponding hart's icache will be guaranteed to be consistent with instruction storage. On kernels configured without SMP, this function is a nop as migrations across harts will not occur.”h]”(hÞ)”}”(hŒ**Parameters**”h]”hŒstrong”“”)”}”(hj)h]”hŒ Parameters”…””}”(hj-h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j+hj'ubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³Œ[/var/lib/git/docbuild/linux/Documentation/arch/riscv/cmodx:73: ./arch/riscv/mm/cacheflush.c”h´KÎhj#ubhŒdefinition_list”“”)”}”(hhh]”(hŒdefinition_list_item”“”)”}”(hŒˆ``unsigned long ctx`` Set the type of icache flushing instructions permitted/prohibited in userspace. Supported values described below. ”h]”(hŒterm”“”)”}”(hŒ``unsigned long ctx``”h]”jq)”}”(hjPh]”hŒunsigned long ctx”…””}”(hjRh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jphjNubah}”(h]”h ]”h"]”h$]”h&]”uh1jLh³Œ[/var/lib/git/docbuild/linux/Documentation/arch/riscv/cmodx:73: ./arch/riscv/mm/cacheflush.c”h´KÍhjHubhŒ definition”“”)”}”(hhh]”hÞ)”}”(hŒqSet the type of icache flushing instructions permitted/prohibited in userspace. Supported values described below.”h]”hŒqSet the type of icache flushing instructions permitted/prohibited in userspace. Supported values described below.”…””}”(hjkh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³Œ[/var/lib/git/docbuild/linux/Documentation/arch/riscv/cmodx:73: ./arch/riscv/mm/cacheflush.c”h´KÌhjhubah}”(h]”h ]”h"]”h$]”h&]”uh1jfhjHubeh}”(h]”h ]”h"]”h$]”h&]”uh1jFh³jeh´KÍhjCubjG)”}”(hŒ…``unsigned long scope`` Set scope of where icache flushing instructions are allowed to be emitted. Supported values described below. ”h]”(jM)”}”(hŒ``unsigned long scope``”h]”jq)”}”(hjŒh]”hŒunsigned long scope”…””}”(hjŽh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jphjŠubah}”(h]”h ]”h"]”h$]”h&]”uh1jLh³Œ[/var/lib/git/docbuild/linux/Documentation/arch/riscv/cmodx:73: ./arch/riscv/mm/cacheflush.c”h´KÙhj†ubjg)”}”(hhh]”hÞ)”}”(hŒlSet scope of where icache flushing instructions are allowed to be emitted. Supported values described below.”h]”hŒlSet scope of where icache flushing instructions are allowed to be emitted. Supported values described below.”…””}”(hj¥h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³Œ[/var/lib/git/docbuild/linux/Documentation/arch/riscv/cmodx:73: ./arch/riscv/mm/cacheflush.c”h´KØhj¢ubah}”(h]”h ]”h"]”h$]”h&]”uh1jfhj†ubeh}”(h]”h ]”h"]”h$]”h&]”uh1jFh³j¡h´KÙhjCubeh}”(h]”h ]”h"]”h$]”h&]”uh1jAhj#ubhÞ)”}”(hŒ**Description**”h]”j,)”}”(hjÈh]”hŒ Description”…””}”(hjÊh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j+hjÆubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³Œ[/var/lib/git/docbuild/linux/Documentation/arch/riscv/cmodx:73: ./arch/riscv/mm/cacheflush.c”h´KÛhj#ubhÞ)”}”(hŒSupported values for ctx:”h]”hŒSupported values for ctx:”…””}”(hjÞh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³Œ[/var/lib/git/docbuild/linux/Documentation/arch/riscv/cmodx:73: ./arch/riscv/mm/cacheflush.c”h´KÎhj#ubhŒ bullet_list”“”)”}”(hhh]”(hŒ list_item”“”)”}”(hŒ<``PR_RISCV_CTX_SW_FENCEI_ON``: Allow fence.i in user space. ”h]”hÞ)”}”(hŒ;``PR_RISCV_CTX_SW_FENCEI_ON``: Allow fence.i in user space.”h]”(jq)”}”(hŒ``PR_RISCV_CTX_SW_FENCEI_ON``”h]”hŒPR_RISCV_CTX_SW_FENCEI_ON”…””}”(hjüh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jphjøubhŒ: Allow fence.i in user space.”…””}”(hjøh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³Œ[/var/lib/git/docbuild/linux/Documentation/arch/riscv/cmodx:73: ./arch/riscv/mm/cacheflush.c”h´KÐhjôubah}”(h]”h ]”h"]”h$]”h&]”uh1jòhjïubjó)”}”(hX-``PR_RISCV_CTX_SW_FENCEI_OFF``: Disallow fence.i in user space. All threads in a process will be affected when ``scope == PR_RISCV_SCOPE_PER_PROCESS``. Therefore, caution must be taken; use this flag only when you can guarantee that no thread in the process will emit fence.i from this point onward. ”h]”hÞ)”}”(hX+``PR_RISCV_CTX_SW_FENCEI_OFF``: Disallow fence.i in user space. All threads in a process will be affected when ``scope == PR_RISCV_SCOPE_PER_PROCESS``. Therefore, caution must be taken; use this flag only when you can guarantee that no thread in the process will emit fence.i from this point onward.”h]”(jq)”}”(hŒ``PR_RISCV_CTX_SW_FENCEI_OFF``”h]”hŒPR_RISCV_CTX_SW_FENCEI_OFF”…””}”(hj#h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jphjubhŒQ: Disallow fence.i in user space. All threads in a process will be affected when ”…””}”(hjh²hh³Nh´Nubjq)”}”(hŒ'``scope == PR_RISCV_SCOPE_PER_PROCESS``”h]”hŒ#scope == PR_RISCV_SCOPE_PER_PROCESS”…””}”(hj5h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jphjubhŒ•. Therefore, caution must be taken; use this flag only when you can guarantee that no thread in the process will emit fence.i from this point onward.”…””}”(hjh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³Œ[/var/lib/git/docbuild/linux/Documentation/arch/riscv/cmodx:73: ./arch/riscv/mm/cacheflush.c”h´KÒhjubah}”(h]”h ]”h"]”h$]”h&]”uh1jòhjïubeh}”(h]”h ]”h"]”h$]”h&]”Œbullet”Œ*”uh1jíh³jh´KÐhj#ubhÞ)”}”(hŒSupported values for scope:”h]”hŒSupported values for scope:”…””}”(hj\h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³Œ[/var/lib/git/docbuild/linux/Documentation/arch/riscv/cmodx:73: ./arch/riscv/mm/cacheflush.c”h´KØhj#ubjî)”}”(hhh]”(jó)”}”(hŒ½``PR_RISCV_SCOPE_PER_PROCESS``: Ensure the icache of any thread in this process is coherent with instruction storage upon migration. ”h]”jB)”}”(hhh]”jG)”}”(hŒ…``PR_RISCV_SCOPE_PER_PROCESS``: Ensure the icache of any thread in this process is coherent with instruction storage upon migration. ”h]”(jM)”}”(hŒO``PR_RISCV_SCOPE_PER_PROCESS``: Ensure the icache of any thread in this process”h]”(jq)”}”(hŒ``PR_RISCV_SCOPE_PER_PROCESS``”h]”hŒPR_RISCV_SCOPE_PER_PROCESS”…””}”(hj}h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jphjyubhŒ1: Ensure the icache of any thread in this process”…””}”(hjyh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1jLh³Œ[/var/lib/git/docbuild/linux/Documentation/arch/riscv/cmodx:73: ./arch/riscv/mm/cacheflush.c”h´KÜhjuubjg)”}”(hhh]”hÞ)”}”(hŒ4is coherent with instruction storage upon migration.”h]”hŒ4is coherent with instruction storage upon migration.”…””}”(hj™h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³Œ[/var/lib/git/docbuild/linux/Documentation/arch/riscv/cmodx:73: ./arch/riscv/mm/cacheflush.c”h´KÛhj–ubah}”(h]”h ]”h"]”h$]”h&]”uh1jfhjuubeh}”(h]”h ]”h"]”h$]”h&]”uh1jFh³j•h´KÜhjrubah}”(h]”h ]”h"]”h$]”h&]”uh1jAhjnubah}”(h]”h ]”h"]”h$]”h&]”uh1jòhjkubjó)”}”(hŒ²``PR_RISCV_SCOPE_PER_THREAD``: Ensure the icache of the current thread is coherent with instruction storage upon migration. ”h]”jB)”}”(hhh]”jG)”}”(hŒ|``PR_RISCV_SCOPE_PER_THREAD``: Ensure the icache of the current thread is coherent with instruction storage upon migration. ”h]”(jM)”}”(hŒI``PR_RISCV_SCOPE_PER_THREAD``: Ensure the icache of the current thread is”h]”(jq)”}”(hŒ``PR_RISCV_SCOPE_PER_THREAD``”h]”hŒPR_RISCV_SCOPE_PER_THREAD”…””}”(hjÏh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jphjËubhŒ,: Ensure the icache of the current thread is”…””}”(hjËh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1jLh³Œ[/var/lib/git/docbuild/linux/Documentation/arch/riscv/cmodx:73: ./arch/riscv/mm/cacheflush.c”h´KàhjÇubjg)”}”(hhh]”hÞ)”}”(hŒ1coherent with instruction storage upon migration.”h]”hŒ1coherent with instruction storage upon migration.”…””}”(hjëh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³Œ[/var/lib/git/docbuild/linux/Documentation/arch/riscv/cmodx:73: ./arch/riscv/mm/cacheflush.c”h´Kßhjèubah}”(h]”h ]”h"]”h$]”h&]”uh1jfhjÇubeh}”(h]”h ]”h"]”h$]”h&]”uh1jFh³jçh´KàhjÄubah}”(h]”h ]”h"]”h$]”h&]”uh1jAhjÀubah}”(h]”h ]”h"]”h$]”h&]”uh1jòhjkubeh}”(h]”h ]”h"]”h$]”h&]”jZj[uh1jíh³Œ[/var/lib/git/docbuild/linux/Documentation/arch/riscv/cmodx:73: ./arch/riscv/mm/cacheflush.c”h´KÚhj#ubhÞ)”}”(hXJWhen ``scope == PR_RISCV_SCOPE_PER_PROCESS``, all threads in the process are permitted to emit icache flushing instructions. Whenever any thread in the process is migrated, the corresponding hart's icache will be guaranteed to be consistent with instruction storage. This does not enforce any guarantees outside of migration. If a thread modifies an instruction that another thread may attempt to execute, the other thread must still emit an icache flushing instruction before attempting to execute the potentially modified instruction. This must be performed by the user-space program.”h]”(hŒWhen ”…””}”(hjh²hh³Nh´Nubjq)”}”(hŒ'``scope == PR_RISCV_SCOPE_PER_PROCESS``”h]”hŒ#scope == PR_RISCV_SCOPE_PER_PROCESS”…””}”(hj!h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jphjubhX , all threads in the process are permitted to emit icache flushing instructions. Whenever any thread in the process is migrated, the corresponding hart’s icache will be guaranteed to be consistent with instruction storage. This does not enforce any guarantees outside of migration. If a thread modifies an instruction that another thread may attempt to execute, the other thread must still emit an icache flushing instruction before attempting to execute the potentially modified instruction. This must be performed by the user-space program.”…””}”(hjh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³Œ[/var/lib/git/docbuild/linux/Documentation/arch/riscv/cmodx:73: ./arch/riscv/mm/cacheflush.c”h´Kâhj#ubhÞ)”}”(hXIn per-thread context (eg. ``scope == PR_RISCV_SCOPE_PER_THREAD``) only the thread calling this function is permitted to emit icache flushing instructions. When the thread is migrated, the corresponding hart's icache will be guaranteed to be consistent with instruction storage.”h]”(hŒIn per-thread context (eg. ”…””}”(hj:h²hh³Nh´Nubjq)”}”(hŒ&``scope == PR_RISCV_SCOPE_PER_THREAD``”h]”hŒ"scope == PR_RISCV_SCOPE_PER_THREAD”…””}”(hjBh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jphj:ubhŒ×) only the thread calling this function is permitted to emit icache flushing instructions. When the thread is migrated, the corresponding hart’s icache will be guaranteed to be consistent with instruction storage.”…””}”(hj:h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³Œ[/var/lib/git/docbuild/linux/Documentation/arch/riscv/cmodx:73: ./arch/riscv/mm/cacheflush.c”h´Këhj#ubhÞ)”}”(hŒdOn kernels configured without SMP, this function is a nop as migrations across harts will not occur.”h]”hŒdOn kernels configured without SMP, this function is a nop as migrations across harts will not occur.”…””}”(hj[h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³Œ[/var/lib/git/docbuild/linux/Documentation/arch/riscv/cmodx:73: ./arch/riscv/mm/cacheflush.c”h´Kðhj#ubeh}”(h]”h ]”Œ kernelindent”ah"]”h$]”h&]”uh1j!hj h²hh³Nh´NubhÞ)”}”(hŒExample usage:”h]”hŒExample usage:”…””}”(hjqh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´KLhj h²hubhÞ)”}”(hŒûThe following files are meant to be compiled and linked with each other. The modify_instruction() function replaces an add with 0 with an add with one, causing the instruction sequence in get_value() to change from returning a zero to returning a one.”h]”hŒûThe following files are meant to be compiled and linked with each other. The modify_instruction() function replaces an add with 0 with an add with one, causing the instruction sequence in get_value() to change from returning a zero to returning a one.”…””}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´KNhj h²hubhÞ)”}”(hŒ cmodx.c::”h]”hŒcmodx.c:”…””}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´KShj h²hubhŒ literal_block”“”)”}”(hX¢#include #include extern int get_value(); extern void modify_instruction(); int main() { int value = get_value(); printf("Value before cmodx: %d\n", value); // Call prctl before first fence.i is called inside modify_instruction prctl(PR_RISCV_SET_ICACHE_FLUSH_CTX, PR_RISCV_CTX_SW_FENCEI_ON, PR_RISCV_SCOPE_PER_PROCESS); modify_instruction(); // Call prctl after final fence.i is called in process prctl(PR_RISCV_SET_ICACHE_FLUSH_CTX, PR_RISCV_CTX_SW_FENCEI_OFF, PR_RISCV_SCOPE_PER_PROCESS); value = get_value(); printf("Value after cmodx: %d\n", value); return 0; }”h]”hX¢#include #include extern int get_value(); extern void modify_instruction(); int main() { int value = get_value(); printf("Value before cmodx: %d\n", value); // Call prctl before first fence.i is called inside modify_instruction prctl(PR_RISCV_SET_ICACHE_FLUSH_CTX, PR_RISCV_CTX_SW_FENCEI_ON, PR_RISCV_SCOPE_PER_PROCESS); modify_instruction(); // Call prctl after final fence.i is called in process prctl(PR_RISCV_SET_ICACHE_FLUSH_CTX, PR_RISCV_CTX_SW_FENCEI_OFF, PR_RISCV_SCOPE_PER_PROCESS); value = get_value(); printf("Value after cmodx: %d\n", value); return 0; }”…””}”hjsbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆuh1j›h³hÇh´KUhj h²hubhÞ)”}”(hŒ cmodx.S::”h]”hŒcmodx.S:”…””}”(hj«h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´Kkhj h²hubjœ)”}”(hX .option norvc .text .global modify_instruction modify_instruction: lw a0, new_insn lui a5,%hi(old_insn) sw a0,%lo(old_insn)(a5) fence.i ret .section modifiable, "awx" .global get_value get_value: li a0, 0 old_insn: addi a0, a0, 0 ret .data new_insn: addi a0, a0, 1”h]”hX .option norvc .text .global modify_instruction modify_instruction: lw a0, new_insn lui a5,%hi(old_insn) sw a0,%lo(old_insn)(a5) fence.i ret .section modifiable, "awx" .global get_value get_value: li a0, 0 old_insn: addi a0, a0, 0 ret .data new_insn: addi a0, a0, 1”…””}”hj¹sbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆuh1j›h³hÇh´Kmhj h²hubeh}”(h]”Œprctl-interface”ah ]”h"]”Œprctl() interface”ah$]”h&]”uh1hÈhhÊh²hh³hÇh´KCubeh}”(h]”ŒLconcurrent-modification-and-execution-of-instructions-cmodx-for-risc-v-linux”ah ]”h"]”ŒNconcurrent modification and execution of instructions (cmodx) for risc-v linux”ah$]”h&]”uh1hÈhhh²hh³hÇh´Kubeh}”(h]”h ]”h"]”h$]”h&]”Œsource”hÇuh1hŒcurrent_source”NŒ current_line”NŒsettings”Œdocutils.frontend”ŒValues”“”)”}”(hÍNŒ generator”NŒ datestamp”NŒ source_link”NŒ source_url”NŒ toc_backlinks”Œentry”Œfootnote_backlinks”KŒ sectnum_xform”KŒstrip_comments”NŒstrip_elements_with_classes”NŒ strip_classes”NŒ report_level”KŒ halt_level”KŒexit_status_level”KŒdebug”NŒwarning_stream”NŒ traceback”ˆŒinput_encoding”Œ utf-8-sig”Œinput_encoding_error_handler”Œstrict”Œoutput_encoding”Œutf-8”Œoutput_encoding_error_handler”júŒerror_encoding”Œutf-8”Œerror_encoding_error_handler”Œbackslashreplace”Œ language_code”Œen”Œrecord_dependencies”NŒconfig”NŒ id_prefix”hŒauto_id_prefix”Œid”Œ dump_settings”NŒdump_internals”NŒdump_transforms”NŒdump_pseudo_xml”NŒexpose_internals”NŒstrict_visitor”NŒ_disable_config”NŒ_source”hÇŒ _destination”NŒ _config_files”]”Œ7/var/lib/git/docbuild/linux/Documentation/docutils.conf”aŒfile_insertion_enabled”ˆŒ raw_enabled”KŒline_length_limit”M'Œpep_references”NŒ pep_base_url”Œhttps://peps.python.org/”Œpep_file_url_template”Œpep-%04d”Œrfc_references”NŒ rfc_base_url”Œ&https://datatracker.ietf.org/doc/html/”Œ tab_width”KŒtrim_footnote_reference_space”‰Œsyntax_highlight”Œlong”Œ smart_quotes”ˆŒsmartquotes_locales”]”Œcharacter_level_inline_markup”‰Œdoctitle_xform”‰Œ docinfo_xform”KŒsectsubtitle_xform”‰Œ image_loading”Œlink”Œembed_stylesheet”‰Œcloak_email_addresses”ˆŒsection_self_link”‰Œenv”NubŒreporter”NŒindirect_targets”]”Œsubstitution_defs”}”Œsubstitution_names”}”Œrefnames”}”Œrefids”}”Œnameids”}”(jÔjÑjjjFjCjjšjÌjÉuŒ nametypes”}”(jÔ‰j‰jF‰j‰j̉uh}”(jÑhÊjhíjCjjšjIjÉj jàjéuŒ footnote_refs”}”Œ citation_refs”}”Œ autofootnotes”]”Œautofootnote_refs”]”Œsymbol_footnotes”]”Œsymbol_footnote_refs”]”Œ footnotes”]”Œ citations”]”Œautofootnote_start”KŒsymbol_footnote_start”KŒ id_counter”Œ collections”ŒCounter”“”}”…”R”Œparse_messages”]”Œtransform_messages”]”Œ transformer”NŒ include_log”]”Œ decoration”Nh²hub.