* Re: Re: [PATCH] accel/tcg: fix self-modify-code problem when modify code in a single tb loop
@ 2025-09-23 2:04 李威威
0 siblings, 0 replies; 2+ messages in thread
From: 李威威 @ 2025-09-23 2:04 UTC (permalink / raw)
To: Richard Henderson, pbonzini, qemu-devel
Cc: kasperl, 王俊强, Wei Wu, liwei1518
[-- Attachment #1: Type: text/plain, Size: 1643 bytes --]
Richard Henderson <richard.henderson@linaro.org> 于2025年9月23日周二 07:22写道:
>
> On 9/17/25 05:47, liweiwei@kubuds.cn wrote:
> > From: Weiwei Li <liweiwei@kubuds.cn>
> >
> > The problem is triggered in following conditions:
> > - thread 1:
> > run spin loop(ended with a direct jump) like "0x0000006f, // jal zero, #0"
> > - thread 2:
> > do something, and then modify the loop code of thread 1 to nop isntruction,
> > finally wait thread 1 exit.
> >
> > The loop tb which is patched to jump to itself, will not be updated in this case
> > and will never exit.
> >
> > Signed-off-by: Weiwei Li <liweiwei@kubuds.cn>
> > ---
> > accel/tcg/cpu-exec.c | 8 ++++++--
> > 1 file changed, 6 insertions(+), 2 deletions(-)
>
> If there's a problem with 1 tb, there's also a problem with 2 tb like
>
> jal zero, #4
> jal zero, #-4
>
I tried this case. And it didn't have this problem.
This problem seems only existed in single tb loop.
>
> But unlinking the tb should be part of invalidation, so I don't quite see where the
> problem is. You need to expand on the description of the problem.
>
I think the problem is the single tb is always in use when the single tb is linked with itself,
and it cannot be updated when we update the code。
Regards,
Weiwei Li
>
> r~
[-- Attachment #2: Type: text/html, Size: 2376 bytes --]
^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: Re: [PATCH] accel/tcg: fix self-modify-code problem when modify code in a single tb loop
@ 2025-09-23 7:35 李威威
0 siblings, 0 replies; 2+ messages in thread
From: 李威威 @ 2025-09-23 7:35 UTC (permalink / raw)
To: Richard Henderson, pbonzini, qemu-devel
Cc: kasperl, 王俊强, Wei Wu, liwei1518
[-- Attachment #1: Type: text/plain, Size: 6691 bytes --]
Richard Henderson <richard.henderson@linaro.org> 于2025年9月23日周二 10:10写道:
>
> On 9/22/25 19:04, 李威威 wrote:
> > > If there's a problem with 1 tb, there's also a problem with 2 tb like
> > >
> > > jal zero, #4
> > > jal zero, #-4
> > >
> >
> > I tried this case. And it didn't have this problem.
> > This problem seems only existed in single tb loop.
> >
> > >
> > > But unlinking the tb should be part of invalidation, so I don't quite see where the
> > > problem is. You need to expand on the description of the problem.
> > >
> >
> > I think the problem is the single tb is always in use when the single tb is linked with
> > itself,
> > and it cannot be updated when we update the code。
>
> There's no use count for tb's, so that explanation doesn't make sense.
> Can you please share a testcase for this?
I think the problem is here:
/*
* Invalidate all TBs which intersect with the target address range.
* Called with mmap_lock held for user-mode emulation.
* NOTE: this function must not be called while a TB is running.
*/
void tb_invalidate_phys_range(CPUState *cpu, tb_page_addr_t start,
tb_page_addr_t last)
{
TranslationBlock *tb;
PageForEachNext n;
assert_memory_lock();
PAGE_FOR_EACH_TB(start, last, unused, tb, n) {
tb_phys_invalidate__locked(tb);
}
}
Only un-running tb will be invalidated.
This problem is found after a recent change in V8. Following is an example built by Kasper Land:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h> // For mmap, mprotect, munmap.
#include <pthread.h> // For pthread functions.
#include <stdint.h> // For intptr_t, uint32_t.
#include <unistd.h> // For sleep.
// This program is specific to the RISC-V architecture.
#if !defined(__riscv)
#error "This code is intended for RISC-V architectures only."
#endif
// Define a function pointer type that takes no arguments and returns an int.
typedef int (*jit_func)();
/**
* @brief The function that will be executed by the new thread.
* * @param arg A pointer to the JIT-compiled function.
* @return void* The integer result from the JIT function, cast to a void pointer.
*/
void* thread_runner(void* arg) {
// Cast the argument back to our function pointer type.
jit_func func = (jit_func)arg;
printf(" [Thread] Executing JIT'ed code...\n");
int result = func();
printf(" [Thread] JIT'ed code returned: %d\n", result);
// To return a simple integer value from a thread, it's safe to cast it
// through intptr_t, which is an integer type guaranteed to be able to hold a pointer.
return (void*)(intptr_t)result;
}
int main() {
// ## 1. RISC-V machine code.
// Assembly:
// L: j L ; Jump to self (spin).
// li a0, 42 ; Place 42 into the return value register a0.
// ret ; Return to caller.
uint32_t machine_code[] = {
0x0000006f, // jal zero, #0
0x02a00513, // addi a0, zero, 42
0x00008067 // jalr zero, ra, 0
};
size_t code_size = sizeof(machine_code);
// ## 2. Allocate executable memory.
void* buffer = mmap(
NULL,
code_size,
PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_PRIVATE | MAP_ANONYMOUS,
-1, 0
);
if (buffer == MAP_FAILED) {
perror("mmap failed");
return 1;
}
// ## 3. Copy machine code into buffer.
memcpy(buffer, machine_code, code_size);
printf("[Main] Successfully generated machine code at address: %p\n", buffer);
// ## 4. Execute the code in a separate thread.
pthread_t thread_id;
void* thread_return_value;
// The JIT'ed code is now ready to be run.
jit_func func_to_run = (jit_func)buffer;
printf("[Main] Creating a new thread to run the JIT code...\n");
if (pthread_create(&thread_id, NULL, thread_runner, func_to_run) != 0) {
perror("pthread_create failed");
munmap(buffer, code_size);
return 1;
}
// Wait a second and then try to patch the generated code
// to get the runner thread to get unstuck by patching the
// spin jump.
sleep(1);
printf("[Main] Patching spin jump to nop...\n");
uint32_t* patchable = (uint32_t*) buffer;
patchable[0] = 0x00000013; // nop
printf("[Main] Flush icache...\n");
__builtin___clear_cache((char*) patchable, (char*) &patchable[1]);
printf("[Main] Waiting for the thread to finish...\n");
if (pthread_join(thread_id, &thread_return_value) != 0) {
perror("pthread_join failed");
munmap(buffer, code_size);
return 1;
}
int result = (int)(intptr_t)thread_return_value;
printf("[Main] The JIT'ed function (run in a thread) returned: %d\n", result);
printf("[Main] Execution successful!\n");
// ## 6. Clean Up.
munmap(buffer, code_size);
return 0;
}
>
> For extra kudos, a small assembly test for tests/tcg/loongarch64/system/, so that we have
> a regression test for the issue. :-)
>
>
> r~
[-- Attachment #2: Type: text/html, Size: 7453 bytes --]
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2025-09-23 7:37 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-09-23 7:35 Re: [PATCH] accel/tcg: fix self-modify-code problem when modify code in a single tb loop 李威威
-- strict thread matches above, loose matches on Subject: below --
2025-09-23 2:04 李威威
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).