qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH V3 1/1] target/loongarch: Fixed tlb huge page loading issue


From: lixianglai
Subject: Re: [PATCH V3 1/1] target/loongarch: Fixed tlb huge page loading issue
Date: Tue, 12 Mar 2024 11:35:29 +0800
User-agent: Mozilla/5.0 (X11; Linux loongarch64; rv:68.0) Gecko/20100101 Thunderbird/68.7.0

Hi Richard:

@@ -495,30 +508,10 @@ target_ulong helper_lddir(CPULoongArchState *env, target_ulong base,
      shift = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTEWIDTH);
      shift = (shift + 1) * 3;
  -    if (huge) {
-        return base;
-    }
-    switch (level) {
-    case 1:
-        dir_base = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR1_BASE);
-        dir_width = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR1_WIDTH);
-        break;
-    case 2:
-        dir_base = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR2_BASE);
-        dir_width = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR2_WIDTH);
-        break;
-    case 3:
-        dir_base = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR3_BASE);
-        dir_width = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR3_WIDTH);
-        break;
-    case 4:
-        dir_base = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR4_BASE);
-        dir_width = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR4_WIDTH);
-        break;
-    default:
-        do_raise_exception(env, EXCCODE_INE, GETPC());
+    if (get_dir_base_width(env, &dir_base, &dir_width, level) != 0) {
          return 0;
      }

I believe that we should not raise an exception here at all.  This illegal instruction exception is based on the LDDIR immediate operand, so we should have diagnosed this error and raised an exception in trans_lddir().

After consulting the hardware technician, when the level value is greater than 4,

the hardware does not report an exception, we can check the level in helper_lddir,

if the parameter is not valid, we will directly return to base,

and it is not reasonable to check the validity of the immediate number in trans_lddir.

The actual action should be implemented in the instruction simulation,and the log should be printed and recorded,

like this:

target_ulong helper_lddir( )

{

    if ((level == 0) || (level > 4)) {

       qemu_log_mask(LOG_GUEST_ERROR, "Illegal instruction level %lu\n",  level);

        return base;

    }

......

}


Therefore the default label should use only g_assert_not_reached(), and there need not be a error return from get_dir_base_width at all.


@@ -534,17 +527,38 @@ void helper_ldpte(CPULoongArchState *env, target_ulong base, target_ulong odd,
      bool huge = (base >> LOONGARCH_PAGE_HUGE_SHIFT) & 0x1;
      uint64_t ptbase = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTBASE);
      uint64_t ptwidth = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTWIDTH);
+    uint64_t dir_base, dir_width;
+    uint64_t huge_page_level;
        base = base & TARGET_PHYS_MASK;
        if (huge) {
-        /* Huge Page. base is paddr */
+        /*
+         * Gets the huge page level
+         * Clears the huge page level information in the address
+         * Clears huge page bit
+         * Gets huge page size
+         */
+        huge_page_level = (base & HUGE_PAGE_LEVEL_MASK) >>
+                          HUGE_PAGE_LEVEL_SHIFT;
+
+        base &= ~HUGE_PAGE_LEVEL_MASK;
+
          tmp0 = base ^ (1 << LOONGARCH_PAGE_HUGE_SHIFT);
          /* Move Global bit */
          tmp0 = ((tmp0 & (1 << LOONGARCH_HGLOBAL_SHIFT))  >>
                  LOONGARCH_HGLOBAL_SHIFT) << R_TLBENTRY_G_SHIFT |
                  (tmp0 & (~(1 << LOONGARCH_HGLOBAL_SHIFT)));
-        ps = ptbase + ptwidth - 1;
+
+        huge_page_level++;

Why are you incrementing the level?

level plus 1 is to obtain the dir_base of the upper level,

because I directly use the dir_base of the upper level as the size of the huge page when calculating the page size,

this practice is different from the hardware implementation,

the hardware implementation is explained below,

the next version I will refer to the hardware implementation method to calculate the size of the huge page.


I think you want

    level = MIN(level, 1);

Google translates the documentation for LDPTE as "bits [14:13] ... should be a non-zero value".  I don't know if "should" is precisely correct here (english technical documents prefer "shall" or "may" to indicate a hard requirement vs optional behaviour). The document does not appear to say what happens if the value is zero.


After consulting hardware technicians, LDPTE uses dir_base + dir_width corresponding to [14..13]bits as the page size,

and when [14..13]bits is 0, the page size should be PTbase + PTwidth.

So [14..13]bits can be zero and we should revise the manual.

And The get_dir_base_width function plans to add the handling of case 0,

so that get_dir_base_width will not receive illegal level arguments when ldpte,

and because of the validity of the level at the entry of the lddir function,

the get_dir_base_width function will not receive illegal level arguments.

So you will not receive level == 0 and level > 4:


static void get_dir_base_width(CPULoongArchState *env, uint64_t *dir_base,
                               uint64_t *dir_width, target_ulong level)
{
    switch (level) {
    case 0:
        *dir_base = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTBASE);
        *dir_width = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTWIDTH);
        break;
    case 1:
        *dir_base = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR1_BASE);
        *dir_width = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR1_WIDTH);
        break;
    case 2:
        *dir_base = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR2_BASE);
        *dir_width = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR2_WIDTH);
        break;
    case 3:
        *dir_base = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR3_BASE);
        *dir_width = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR3_WIDTH);
        break;
    case 4:
        *dir_base = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR4_BASE);
        *dir_width = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR4_WIDTH);
        break;
    default:
        g_assert_not_reached();
    }
}


Since an earlier version of the specification did not have bits [14:13], my suspicion is that the the current version of the specification is intended to be compatible, which would map [14:13] == 0 to level == 1.

In any case, incrementing the level such that [14:13] == 1 -> level == 2 definitely seems wrong.


r~




reply via email to

[Prev in Thread] Current Thread [Next in Thread]