brintos

brintos / linux-shallow public Read only

0
0
Text · 3.4 KiB · 8c48bcf Raw
99 lines · plain
1.. SPDX-License-Identifier: GPL-2.02 3==============================================================================4Concurrent Modification and Execution of Instructions (CMODX) for RISC-V Linux5==============================================================================6 7CMODX is a programming technique where a program executes instructions that were8modified by the program itself. Instruction storage and the instruction cache9(icache) are not guaranteed to be synchronized on RISC-V hardware. Therefore, the10program must enforce its own synchronization with the unprivileged fence.i11instruction.12 13However, the default Linux ABI prohibits the use of fence.i in userspace14applications. At any point the scheduler may migrate a task onto a new hart. If15migration occurs after the userspace synchronized the icache and instruction16storage with fence.i, the icache on the new hart will no longer be clean. This17is due to the behavior of fence.i only affecting the hart that it is called on.18Thus, the hart that the task has been migrated to may not have synchronized19instruction storage and icache.20 21There are two ways to solve this problem: use the riscv_flush_icache() syscall,22or use the ``PR_RISCV_SET_ICACHE_FLUSH_CTX`` prctl() and emit fence.i in23userspace. The syscall performs a one-off icache flushing operation. The prctl24changes the Linux ABI to allow userspace to emit icache flushing operations.25 26As an aside, "deferred" icache flushes can sometimes be triggered in the kernel.27At the time of writing, this only occurs during the riscv_flush_icache() syscall28and when the kernel uses copy_to_user_page(). These deferred flushes happen only29when the memory map being used by a hart changes. If the prctl() context caused30an icache flush, this deferred icache flush will be skipped as it is redundant.31Therefore, there will be no additional flush when using the riscv_flush_icache()32syscall inside of the prctl() context.33 34prctl() Interface35---------------------36 37Call prctl() with ``PR_RISCV_SET_ICACHE_FLUSH_CTX`` as the first argument. The38remaining arguments will be delegated to the riscv_set_icache_flush_ctx39function detailed below.40 41.. kernel-doc:: arch/riscv/mm/cacheflush.c42	:identifiers: riscv_set_icache_flush_ctx43 44Example usage:45 46The following files are meant to be compiled and linked with each other. The47modify_instruction() function replaces an add with 0 with an add with one,48causing the instruction sequence in get_value() to change from returning a zero49to returning a one.50 51cmodx.c::52 53	#include <stdio.h>54	#include <sys/prctl.h>55 56	extern int get_value();57	extern void modify_instruction();58 59	int main()60	{61		int value = get_value();62		printf("Value before cmodx: %d\n", value);63 64		// Call prctl before first fence.i is called inside modify_instruction65		prctl(PR_RISCV_SET_ICACHE_FLUSH_CTX, PR_RISCV_CTX_SW_FENCEI_ON, PR_RISCV_SCOPE_PER_PROCESS);66		modify_instruction();67		// Call prctl after final fence.i is called in process68		prctl(PR_RISCV_SET_ICACHE_FLUSH_CTX, PR_RISCV_CTX_SW_FENCEI_OFF, PR_RISCV_SCOPE_PER_PROCESS);69 70		value = get_value();71		printf("Value after cmodx: %d\n", value);72		return 0;73	}74 75cmodx.S::76 77	.option norvc78 79	.text80	.global modify_instruction81	modify_instruction:82	lw a0, new_insn83	lui a5,%hi(old_insn)84	sw  a0,%lo(old_insn)(a5)85	fence.i86	ret87 88	.section modifiable, "awx"89	.global get_value90	get_value:91	li a0, 092	old_insn:93	addi a0, a0, 094	ret95 96	.data97	new_insn:98	addi a0, a0, 199