在 2024/7/29 上午11:57, Richard Henderson 写道:
On 7/29/24 11:39, Song Gao wrote:
/* Mapped address */
- return loongarch_map_address(env, physical, prot, address,
- access_type, mmu_idx);
+ ret = loongarch_map_address(env, physical, prot, address,
+ access_type, mmu_idx);
+#ifdef CONFIG_TCG
+ if (!FIELD_EX32(env->cpucfg[2], CPUCFG2, HPTW)) {
+ return ret;
+ }
+
+ if (!FIELD_EX32(env->CSR_PWCH, CSR_PWCH, HPTW_EN)) {
+ return ret;
+ }
+
+ if (do_page_walk(env, address, access_type, ret)) {
When called from loongarch_cpu_get_phys_page_debug, you do not want ...
+ index = get_random_tlb_index(env, tlbehi, ps);
+ invalidate_tlb(env, index);
+ do_fill_tlb_entry(env, vppn, entrylo0, entrylo1, index, ps);
... to modify the TLB. This will cause gdbstub to modify the
behaviour of the guest, which you do not want.
Hi, sorry for the late reply. I'm very busy recently.
How about adding a variable to determine if tlb needs to be modified?
like this:
@@ -248,7 +250,7 @@ hwaddr loongarch_cpu_get_phys_page_debug(CPUState
*cs, vaddr addr)
int prot;
if (get_physical_address(env, &phys_addr, &prot, addr, MMU_DATA_LOAD,
- cpu_mmu_index(cs, false)) != 0) {
+ cpu_mmu_index(cs, false) != 0, false)) {
return -1;
}
[..]
@@ -233,9 +233,11 @@ int get_physical_address(CPULoongArchState *env,
hwaddr *physical,
return ret;
}
- if (do_page_walk(env, address, access_type, ret)) {
- ret = loongarch_map_address(env, physical, prot, address,
- access_type, mmu_idx);
+ if (do_page_walk(env, address, access_type, ret, physical,
is_modify)) {
+ if (is_modify) {
+ ret = loongarch_map_address(env, physical, prot, address,
+ access_type, mmu_idx);
+ }
}
bool do_page_walk(CPULoongArchState *env, vaddr address,
- MMUAccessType access_type, int tlb_error)
+ MMUAccessType access_type, int tlb_error,
+ hwaddr *physical, bool is_modify)
{
CPUState *cs = env_cpu(env);
target_ulong base, ps, tmp0, tmp1, ptindex, ptoffset, entry;
@@ -705,9 +706,21 @@ bool do_page_walk(CPULoongArchState *env, vaddr
address,
entrylo1 = tmp1;
tlbehi = address & (TARGET_PAGE_MASK << 1);
vppn = FIELD_EX64(tlbehi, CSR_TLBEHI_64, VPPN);
- index = get_random_tlb_index(env, tlbehi, ps);
- invalidate_tlb(env, index);
- do_fill_tlb_entry(env, vppn, entrylo0, entrylo1, index, ps);
+
+ if (is_modify) {
+ index = get_random_tlb_index(env, tlbehi, ps);
+ invalidate_tlb(env, index);
+ do_fill_tlb_entry(env, vppn, entrylo0, entrylo1, index, ps);
+ } else {
+ uint64_t tlb_entry, tlb_ppn;
+ uint8_t n;
+ n = (address >> ps) & 0x1;
+
+ tlb_entry = n ? entrylo1 : entrylo0;
+ tlb_ppn = FIELD_EX64(tlb_entry, TLBENTRY_64, PPN);
+ tlb_ppn = tlb_ppn & ~(((0x1UL << (ps - 12)) -1));
+ *physical = (tlb_ppn << R_TLBENTRY_64_PPN_SHIFT) | (address
& MAKE_64BIT_MASK(0, ps));
+ }
ret = true;
break;
+ entry = ldq_phys(cs->as, tmp0) & TARGET_PHYS_MASK;
+
+ if (entry == 0) {
+ return ret;
+ }
+
+ /* Check entry, and do tlb modify. */
+ if ((tlb_error == TLBRET_INVALID) &&
+ (access_type == MMU_DATA_LOAD ||
+ access_type == MMU_INST_FETCH )) {
+ if (!(FIELD_EX64(entry, TLBENTRY, PRESENT))) {
+ break;
+ }
+ entry = FIELD_DP64(entry, TLBENTRY, V, 1);
+ } else if ((tlb_error == TLBRET_INVALID) &&
+ access_type == MMU_DATA_STORE) {
+ if (!((FIELD_EX64(entry, TLBENTRY, PRESENT) &&
+ (FIELD_EX64(entry, TLBENTRY, WRITE))))){
+ break;
+ }
+ entry = FIELD_DP64(entry, TLBENTRY, V, 1);
+ entry = FIELD_DP64(entry, TLBENTRY, D, 1);
+ } else if (tlb_error == TLBRET_DIRTY) {
+ if (!(FIELD_EX64(entry, TLBENTRY, WRITE))) {
+ break;
+ }
+ entry = FIELD_DP64(entry, TLBENTRY, D, 1);
+ entry = FIELD_DP64(entry, TLBENTRY, V, 1);
+ }
+ stq_phys(cs->as, tmp0, entry);
You certainly want to use a compare and swap here, restarting if the
compare fails.
Sorry , I don't understand here, could you explain it in detail?
Thanks.
Song Gao
r~