Message ID | 1602831120-3377-2-git-send-email-chenhc@lemote.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | mips: Add Loongson-3 machine support | expand |
On 10/16/20 8:51 AM, Huacai Chen wrote: > From: Jiaxun Yang <jiaxun.yang@flygoat.com> > > Our current code assumed the target page size is always 4k > when handling PageMask and VPN2, however, variable page size > was just added to mips target and that's no longer true. > > Fixes: ee3863b9d414 ("target/mips: Support variable page size") > Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com> > Signed-off-by: Huacai Chen <chenhc@lemote.com> > --- > target/mips/cp0_helper.c | 36 +++++++++++++++++++++++++++++------- > target/mips/cpu.h | 1 + > 2 files changed, 30 insertions(+), 7 deletions(-) > > diff --git a/target/mips/cp0_helper.c b/target/mips/cp0_helper.c > index de64add038..f3478d826b 100644 > --- a/target/mips/cp0_helper.c > +++ b/target/mips/cp0_helper.c > @@ -867,13 +867,35 @@ void helper_mtc0_memorymapid(CPUMIPSState *env, target_ulong arg1) > > void update_pagemask(CPUMIPSState *env, target_ulong arg1, int32_t *pagemask) > { > - uint64_t mask = arg1 >> (TARGET_PAGE_BITS + 1); > - if (!(env->insn_flags & ISA_MIPS32R6) || (arg1 == ~0) || > - (mask == 0x0000 || mask == 0x0003 || mask == 0x000F || > - mask == 0x003F || mask == 0x00FF || mask == 0x03FF || > - mask == 0x0FFF || mask == 0x3FFF || mask == 0xFFFF)) { > - env->CP0_PageMask = arg1 & (0x1FFFFFFF & (TARGET_PAGE_MASK << 1)); > + unsigned long mask; > + int maskbits; > + > + if (env->insn_flags & ISA_MIPS32R6) { > + return; > + } > + /* Don't care MASKX as we don't support 1KB page */ > + mask = extract32((uint32_t)arg1, CP0PM_MASK, 16); > + maskbits = find_first_zero_bit(&mask, 32); > + > + /* Ensure no more set bit after first zero */ > + if (mask >> maskbits) { > + goto invalid; > + } > + /* We don't support VTLB entry smaller than target page */ > + if ((maskbits + 12) < TARGET_PAGE_BITS) { > + goto invalid; > } > + env->CP0_PageMask = mask << CP0PM_MASK; > + > + return; > + > +invalid: > + /* > + * When invalid, ensure the value is bigger than or equal to > + * the minimal but smaller than or equal to the maxium. > + */ > + maskbits = MIN(16, MAX(maskbits, TARGET_PAGE_BITS - 12)); > + env->CP0_PageMask = ((1 << (16 + 1)) - 1) << CP0PM_MASK; > } > > void helper_mtc0_pagemask(CPUMIPSState *env, target_ulong arg1) > @@ -1104,7 +1126,7 @@ void helper_mthc0_saar(CPUMIPSState *env, target_ulong arg1) > void helper_mtc0_entryhi(CPUMIPSState *env, target_ulong arg1) > { > target_ulong old, val, mask; > - mask = (TARGET_PAGE_MASK << 1) | env->CP0_EntryHi_ASID_mask; > + mask = ~((1 << 14) - 1) | env->CP0_EntryHi_ASID_mask; > if (((env->CP0_Config4 >> CP0C4_IE) & 0x3) >= 2) { > mask |= 1 << CP0EnHi_EHINV; > } > diff --git a/target/mips/cpu.h b/target/mips/cpu.h > index 7cf7f5239f..9c8bb23807 100644 > --- a/target/mips/cpu.h > +++ b/target/mips/cpu.h > @@ -618,6 +618,7 @@ struct CPUMIPSState { > * CP0 Register 5 > */ > int32_t CP0_PageMask; > +#define CP0PM_MASK 13 > int32_t CP0_PageGrain_rw_bitmask; > int32_t CP0_PageGrain; > #define CP0PG_RIE 31 > Malta test failing: [ 0.000000] Linux version 4.5.0-2-4kc-malta (debian-kernel@lists.debian.org) (gcc version 5.3.1 20160519 (Debian 5.3.1-20) ) #1 Debian 4.5.5-1 (2016-05-29) [ 0.000000] earlycon: Early serial console at I/O port 0x3f8 (options '38400n8') [ 0.000000] bootconsole [uart0] enabled [ 0.000000] CPU0 revision is: 00019300 (MIPS 24Kc) [ 0.000000] FPU revision is: 00739300 [ 0.000000] MIPS: machine is mti,malta [...] Freeing unused kernel memory: 412K (80979000 - 809e0000) do_page_fault(): sending SIGSEGV to mount for invalid write access to 0018a000 epc = 77848a54 in libc-2.27.so[7782f000+177000] ra = 779d0618 in ld-2.27.so[779bf000+24000] do_page_fault(): sending SIGSEGV to ln for invalid write access to 0018a000 epc = 778d4a54 in libc-2.27.so[778bb000+177000] ra = 77a5c618 in ld-2.27.so[77a4b000+24000] do_page_fault(): sending SIGSEGV to S01logging for invalid write access to 0018a000 epc = 77d08a54 in libc-2.27.so[77cef000+177000] ra = 77e90618 in ld-2.27.so[77e7f000+24000] do_page_fault(): sending SIGSEGV to S20urandom for invalid write access to 0018a000 epc = 76ee4a54 in libc-2.27.so[76ecb000+177000] ra = 7706c618 in ld-2.27.so[7705b000+24000] do_page_fault(): sending SIGSEGV to ifup for invalid write access to 0018a000 epc = 77974a54 in libc-2.27.so[7795b000+177000] ra = 77afc618 in ld-2.27.so[77aeb000+24000] do_page_fault(): sending SIGSEGV to awk for invalid read access from 00000000 epc = 00000000 in busybox[400000+d8000] ra = 77248110 in libc-2.27.so[770fb000+177000] do_page_fault(): sending SIGSEGV to cat for invalid write access to 0018a000 epc = 77484a54 in libc-2.27.so[7746b000+177000] ra = 7760c618 in ld-2.27.so[775fb000+24000] do_page_fault(): sending SIGSEGV to run.sh for invalid write access to 0018a000 epc = 76e88a54 in libc-2.27.so[76e6f000+177000] ra = 77010618 in ld-2.27.so[76fff000+24000] qemu-system-mips: terminating on signal 2 Please run the QEMU tests. The easiest way is to push your series on GitLab. Regards, Phil.
Hi, Philippe, On Fri, Oct 16, 2020 at 11:15 PM Philippe Mathieu-Daudé <f4bug@amsat.org> wrote: > > On 10/16/20 8:51 AM, Huacai Chen wrote: > > From: Jiaxun Yang <jiaxun.yang@flygoat.com> > > > > Our current code assumed the target page size is always 4k > > when handling PageMask and VPN2, however, variable page size > > was just added to mips target and that's no longer true. > > > > Fixes: ee3863b9d414 ("target/mips: Support variable page size") > > Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com> > > Signed-off-by: Huacai Chen <chenhc@lemote.com> > > --- > > target/mips/cp0_helper.c | 36 +++++++++++++++++++++++++++++------- > > target/mips/cpu.h | 1 + > > 2 files changed, 30 insertions(+), 7 deletions(-) > > > > diff --git a/target/mips/cp0_helper.c b/target/mips/cp0_helper.c > > index de64add038..f3478d826b 100644 > > --- a/target/mips/cp0_helper.c > > +++ b/target/mips/cp0_helper.c > > @@ -867,13 +867,35 @@ void helper_mtc0_memorymapid(CPUMIPSState *env, target_ulong arg1) > > > > void update_pagemask(CPUMIPSState *env, target_ulong arg1, int32_t *pagemask) > > { > > - uint64_t mask = arg1 >> (TARGET_PAGE_BITS + 1); > > - if (!(env->insn_flags & ISA_MIPS32R6) || (arg1 == ~0) || > > - (mask == 0x0000 || mask == 0x0003 || mask == 0x000F || > > - mask == 0x003F || mask == 0x00FF || mask == 0x03FF || > > - mask == 0x0FFF || mask == 0x3FFF || mask == 0xFFFF)) { > > - env->CP0_PageMask = arg1 & (0x1FFFFFFF & (TARGET_PAGE_MASK << 1)); > > + unsigned long mask; > > + int maskbits; > > + > > + if (env->insn_flags & ISA_MIPS32R6) { > > + return; > > + } > > + /* Don't care MASKX as we don't support 1KB page */ > > + mask = extract32((uint32_t)arg1, CP0PM_MASK, 16); > > + maskbits = find_first_zero_bit(&mask, 32); > > + > > + /* Ensure no more set bit after first zero */ > > + if (mask >> maskbits) { > > + goto invalid; > > + } > > + /* We don't support VTLB entry smaller than target page */ > > + if ((maskbits + 12) < TARGET_PAGE_BITS) { > > + goto invalid; > > } > > + env->CP0_PageMask = mask << CP0PM_MASK; > > + > > + return; > > + > > +invalid: > > + /* > > + * When invalid, ensure the value is bigger than or equal to > > + * the minimal but smaller than or equal to the maxium. > > + */ > > + maskbits = MIN(16, MAX(maskbits, TARGET_PAGE_BITS - 12)); > > + env->CP0_PageMask = ((1 << (16 + 1)) - 1) << CP0PM_MASK; > > } > > > > void helper_mtc0_pagemask(CPUMIPSState *env, target_ulong arg1) > > @@ -1104,7 +1126,7 @@ void helper_mthc0_saar(CPUMIPSState *env, target_ulong arg1) > > void helper_mtc0_entryhi(CPUMIPSState *env, target_ulong arg1) > > { > > target_ulong old, val, mask; > > - mask = (TARGET_PAGE_MASK << 1) | env->CP0_EntryHi_ASID_mask; > > + mask = ~((1 << 14) - 1) | env->CP0_EntryHi_ASID_mask; > > if (((env->CP0_Config4 >> CP0C4_IE) & 0x3) >= 2) { > > mask |= 1 << CP0EnHi_EHINV; > > } > > diff --git a/target/mips/cpu.h b/target/mips/cpu.h > > index 7cf7f5239f..9c8bb23807 100644 > > --- a/target/mips/cpu.h > > +++ b/target/mips/cpu.h > > @@ -618,6 +618,7 @@ struct CPUMIPSState { > > * CP0 Register 5 > > */ > > int32_t CP0_PageMask; > > +#define CP0PM_MASK 13 > > int32_t CP0_PageGrain_rw_bitmask; > > int32_t CP0_PageGrain; > > #define CP0PG_RIE 31 > > > > Malta test failing: > > [ 0.000000] Linux version 4.5.0-2-4kc-malta > (debian-kernel@lists.debian.org) (gcc version 5.3.1 20160519 (Debian > 5.3.1-20) ) #1 Debian 4.5.5-1 (2016-05-29) > [ 0.000000] earlycon: Early serial console at I/O port 0x3f8 (options > '38400n8') > [ 0.000000] bootconsole [uart0] enabled > [ 0.000000] CPU0 revision is: 00019300 (MIPS 24Kc) > [ 0.000000] FPU revision is: 00739300 > [ 0.000000] MIPS: machine is mti,malta > [...] > Freeing unused kernel memory: 412K (80979000 - 809e0000) > do_page_fault(): sending SIGSEGV to mount for invalid write access to > 0018a000 > epc = 77848a54 in libc-2.27.so[7782f000+177000] > ra = 779d0618 in ld-2.27.so[779bf000+24000] > do_page_fault(): sending SIGSEGV to ln for invalid write access to 0018a000 > epc = 778d4a54 in libc-2.27.so[778bb000+177000] > ra = 77a5c618 in ld-2.27.so[77a4b000+24000] > do_page_fault(): sending SIGSEGV to S01logging for invalid write access > to 0018a000 > epc = 77d08a54 in libc-2.27.so[77cef000+177000] > ra = 77e90618 in ld-2.27.so[77e7f000+24000] > do_page_fault(): sending SIGSEGV to S20urandom for invalid write access > to 0018a000 > epc = 76ee4a54 in libc-2.27.so[76ecb000+177000] > ra = 7706c618 in ld-2.27.so[7705b000+24000] > do_page_fault(): sending SIGSEGV to ifup for invalid write access to > 0018a000 > epc = 77974a54 in libc-2.27.so[7795b000+177000] > ra = 77afc618 in ld-2.27.so[77aeb000+24000] > do_page_fault(): sending SIGSEGV to awk for invalid read access from > 00000000 > epc = 00000000 in busybox[400000+d8000] > ra = 77248110 in libc-2.27.so[770fb000+177000] > do_page_fault(): sending SIGSEGV to cat for invalid write access to 0018a000 > epc = 77484a54 in libc-2.27.so[7746b000+177000] > ra = 7760c618 in ld-2.27.so[775fb000+24000] > do_page_fault(): sending SIGSEGV to run.sh for invalid write access to > 0018a000 > epc = 76e88a54 in libc-2.27.so[76e6f000+177000] > ra = 77010618 in ld-2.27.so[76fff000+24000] > qemu-system-mips: terminating on signal 2 > > Please run the QEMU tests. OK, we are investigating. > > The easiest way is to push your series on GitLab. > > Regards, > > Phil.
diff --git a/target/mips/cp0_helper.c b/target/mips/cp0_helper.c index de64add038..f3478d826b 100644 --- a/target/mips/cp0_helper.c +++ b/target/mips/cp0_helper.c @@ -867,13 +867,35 @@ void helper_mtc0_memorymapid(CPUMIPSState *env, target_ulong arg1) void update_pagemask(CPUMIPSState *env, target_ulong arg1, int32_t *pagemask) { - uint64_t mask = arg1 >> (TARGET_PAGE_BITS + 1); - if (!(env->insn_flags & ISA_MIPS32R6) || (arg1 == ~0) || - (mask == 0x0000 || mask == 0x0003 || mask == 0x000F || - mask == 0x003F || mask == 0x00FF || mask == 0x03FF || - mask == 0x0FFF || mask == 0x3FFF || mask == 0xFFFF)) { - env->CP0_PageMask = arg1 & (0x1FFFFFFF & (TARGET_PAGE_MASK << 1)); + unsigned long mask; + int maskbits; + + if (env->insn_flags & ISA_MIPS32R6) { + return; + } + /* Don't care MASKX as we don't support 1KB page */ + mask = extract32((uint32_t)arg1, CP0PM_MASK, 16); + maskbits = find_first_zero_bit(&mask, 32); + + /* Ensure no more set bit after first zero */ + if (mask >> maskbits) { + goto invalid; + } + /* We don't support VTLB entry smaller than target page */ + if ((maskbits + 12) < TARGET_PAGE_BITS) { + goto invalid; } + env->CP0_PageMask = mask << CP0PM_MASK; + + return; + +invalid: + /* + * When invalid, ensure the value is bigger than or equal to + * the minimal but smaller than or equal to the maxium. + */ + maskbits = MIN(16, MAX(maskbits, TARGET_PAGE_BITS - 12)); + env->CP0_PageMask = ((1 << (16 + 1)) - 1) << CP0PM_MASK; } void helper_mtc0_pagemask(CPUMIPSState *env, target_ulong arg1) @@ -1104,7 +1126,7 @@ void helper_mthc0_saar(CPUMIPSState *env, target_ulong arg1) void helper_mtc0_entryhi(CPUMIPSState *env, target_ulong arg1) { target_ulong old, val, mask; - mask = (TARGET_PAGE_MASK << 1) | env->CP0_EntryHi_ASID_mask; + mask = ~((1 << 14) - 1) | env->CP0_EntryHi_ASID_mask; if (((env->CP0_Config4 >> CP0C4_IE) & 0x3) >= 2) { mask |= 1 << CP0EnHi_EHINV; } diff --git a/target/mips/cpu.h b/target/mips/cpu.h index 7cf7f5239f..9c8bb23807 100644 --- a/target/mips/cpu.h +++ b/target/mips/cpu.h @@ -618,6 +618,7 @@ struct CPUMIPSState { * CP0 Register 5 */ int32_t CP0_PageMask; +#define CP0PM_MASK 13 int32_t CP0_PageGrain_rw_bitmask; int32_t CP0_PageGrain; #define CP0PG_RIE 31