Message ID | 4f856a5ea2c039c6639df875d11b5bff1bf7ecd2.1567326213.git.noring@nocrew.org (mailing list archive) |
---|---|
State | RFC |
Headers | show |
Series | Linux for the PlayStation 2 | expand |
On Sun, 1 Sep 2019, Fredrik Noring wrote: > CONFIG_DEFAULT_MMAP_MIN_ADDR must not be less than PAGE_SIZE to reliably > trap and emulate RDHWR, so this is made a BUILD_BUG_ON for the R5900. I think a more complex solution is required as the value can be changed at run time, via /proc/sys/vm/mmap_min_addr, defeating this protection. E.g. by introducing an ARCH_MIN_MMAP_MIN_ADDR minimum value, by default 0 unless overridden by the architecture selected, and then using it for both the default DEFAULT_MMAP_MIN_ADDR value and the minimum accepted via /proc/sys/vm/mmap_min_addr. > diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c > index 92bd2b0f0548..f490944d73cf 100644 > --- a/arch/mips/kernel/unaligned.c > +++ b/arch/mips/kernel/unaligned.c > @@ -1342,6 +1375,7 @@ static void emulate_load_store_insn(struct pt_regs *regs, > cu2_notifier_call_chain(CU2_SDC2_OP, regs); > break; > #endif > + > default: > /* > * Pheeee... We encountered an yet unknown instruction or Extraneous change. Maciej
Hi Fredrik, Cc'ing glibc folks in case... On 9/1/19 5:36 PM, Fredrik Noring wrote: > On the R5900, the RDHWR instruction is interpreted as the R5900 specific > SQ instruction[1] that traps into a zero page address exception. Hence > RDHWR can be emulated by emulate_load_store_insn(). Please bare with me because this is not my area, but this does not look the correct way to fix this problem to me. The R5900 is a MIPS-III, so I don't understand why we have to care about RDHWR. IIRC MIPS TLS support has been added in glibc with MIPS32 ISA in mind in 2005: https://sourceware.org/git/?p=glibc.git;a=commit;h=f850220be6 MIPS16 is handled differently: https://sourceware.org/git/?p=glibc.git;a=blobdiff;f=ports/sysdeps/mips/tls-macros.h;h=3e87e42ea;hp=8fe2e4a150d;hb=43301bd3c2;hpb=85bd816a60 Shouldn't we have a similar set of macros for the R5900? The problem I have is this break running the binaries built by the Sony Linux Toolkit for Playstation 2 which use the LQ/SQ instruction: 1b00d5c: 0c6c00d4 jal 0x1b00350 1b00d60: 7fa90020 sq t1,32(sp) 1b00d64: a2710000 sb s1,0(s3) 1b00d68: 26730001 addiu s3,s3,1 1b00d6c: 10000004 b 0x1b00d80 1b00d70: 7ba90020 lq t1,32(sp) 1b00d74: 00000000 nop 1b00d78: 2617ffff addiu s7,s0,-1 1b00d7c: 25360001 addiu s6,t1,1 1b00d80: 91220000 lbu v0,0(t1) 1b00d84: 02e0802d move s0,s7 1b00d88: 02c0482d move t1,s6 1b00d8c: a2620000 sb v0,0(s3) 1b00d90: 1600fff9 bnez s0,0x1b00d78 1b00d94: 26730001 addiu s3,s3,1 1b00d98: 10000003 b 0x1b00da8 1b00d9c: 01342026 xor a0,t1,s4 1b00da0: 253e0003 addiu s8,t1,3 1b00da4: 01342026 xor a0,t1,s4 1b00da8: 7fa90020 sq t1,32(sp) 1b00dac: 2c840001 sltiu a0,a0,1 1b00db0: 0c6c00d4 jal 0x1b00350 What do you think? Regards, Phil. > CONFIG_DEFAULT_MMAP_MIN_ADDR must not be less than PAGE_SIZE to reliably > trap and emulate RDHWR, so this is made a BUILD_BUG_ON for the R5900. > > References: > > [1] "TX System RISC TX79 Core Architecture" manual, revision 2.0, > Toshiba Corporation, p. B-162, https://wiki.qemu.org/File:C790.pdf > > Signed-off-by: Fredrik Noring <noring@nocrew.org> > --- > arch/mips/include/asm/traps.h | 2 ++ > arch/mips/kernel/traps.c | 2 +- > arch/mips/kernel/unaligned.c | 36 ++++++++++++++++++++++++++++++++++- > 3 files changed, 38 insertions(+), 2 deletions(-) > > diff --git a/arch/mips/include/asm/traps.h b/arch/mips/include/asm/traps.h > index 6a0864bb604d..ed6449f2967b 100644 > --- a/arch/mips/include/asm/traps.h > +++ b/arch/mips/include/asm/traps.h > @@ -35,4 +35,6 @@ extern int register_nmi_notifier(struct notifier_block *nb); > register_nmi_notifier(&fn##_nb); \ > }) > > +int simulate_rdhwr(struct pt_regs *regs, int rd, int rt); > + > #endif /* _ASM_TRAPS_H */ > diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c > index 342e41de9d64..9423b9a2eb67 100644 > --- a/arch/mips/kernel/traps.c > +++ b/arch/mips/kernel/traps.c > @@ -625,7 +625,7 @@ static int simulate_llsc(struct pt_regs *regs, unsigned int opcode) > * Simulate trapping 'rdhwr' instructions to provide user accessible > * registers not implemented in hardware. > */ > -static int simulate_rdhwr(struct pt_regs *regs, int rd, int rt) > +int simulate_rdhwr(struct pt_regs *regs, int rd, int rt) > { > struct thread_info *ti = task_thread_info(current); > > diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c > index 92bd2b0f0548..f490944d73cf 100644 > --- a/arch/mips/kernel/unaligned.c > +++ b/arch/mips/kernel/unaligned.c > @@ -90,6 +90,7 @@ > #include <asm/fpu_emulator.h> > #include <asm/inst.h> > #include <asm/mmu_context.h> > +#include <asm/traps.h> > #include <linux/uaccess.h> > > #define STR(x) __STR(x) > @@ -934,7 +935,39 @@ static void emulate_load_store_insn(struct pt_regs *regs, > * interest. > */ > case spec3_op: > - if (insn.dsp_format.func == lx_op) { > + if (IS_ENABLED(CONFIG_CPU_R5900)) { > + /* > + * On the R5900, the RDHWR instruction > + * > + * +--------+-------+----+----+-------+--------+ > + * | 011111 | 00000 | rt | rd | 00000 | 111011 | > + * +--------+-------+----+----+-------+--------+ > + * 6 5 5 5 5 6 > + * > + * is interpreted as the R5900 specific SQ instruction > + * > + * +--------+-------+----+---------------------+ > + * | 011111 | base | rt | offset | > + * +--------+-------+----+---------------------+ > + * 6 5 5 16 > + * > + * that asserts a zero page address exception. Hence > + * RDHWR can be trapped and emulated here, provided > + * DEFAULT_MMAP_MIN_ADDR isn't zero. > + */ > + BUILD_BUG_ON(IS_ENABLED(CONFIG_CPU_R5900) && > + CONFIG_DEFAULT_MMAP_MIN_ADDR < PAGE_SIZE); > + if (insn.r_format.func == rdhwr_op && > + insn.r_format.rs == 0 && > + insn.r_format.re == 0) { > + if (compute_return_epc(regs) < 0 || > + simulate_rdhwr(regs, insn.r_format.rd, > + insn.r_format.rt) < 0) > + goto sigill; > + return; > + } > + goto sigbus; > + } else if (insn.dsp_format.func == lx_op) { > switch (insn.dsp_format.op) { > case lwx_op: > if (!access_ok(addr, 4)) > @@ -1342,6 +1375,7 @@ static void emulate_load_store_insn(struct pt_regs *regs, > cu2_notifier_call_chain(CU2_SDC2_OP, regs); > break; > #endif > + > default: > /* > * Pheeee... We encountered an yet unknown instruction or >
On Thu, 19 Nov 2020, Philippe Mathieu-Daudé wrote: > > On the R5900, the RDHWR instruction is interpreted as the R5900 specific > > SQ instruction[1] that traps into a zero page address exception. Hence > > RDHWR can be emulated by emulate_load_store_insn(). > > Please bare with me because this is not my area, but this does > not look the correct way to fix this problem to me. > > The R5900 is a MIPS-III, so I don't understand why we have to care > about RDHWR. The use of RDHWR, actual or emulated, is a part of the MIPS TLS psABI, see: <https://www.linux-mips.org/wiki/NPTL>, in particular starting from: <https://www.linux-mips.org/wiki/NPTL#Design_Choices> and throughout (the expired certificate of the web site is a known issue, but there is currently no way to get it fixed as nobody knows where Ralf Baechle has gone). > IIRC MIPS TLS support has been added in glibc with MIPS32 ISA in > mind in 2005: > https://sourceware.org/git/?p=glibc.git;a=commit;h=f850220be6 > > MIPS16 is handled differently: > https://sourceware.org/git/?p=glibc.git;a=blobdiff;f=ports/sysdeps/mips/tls-macros.h;h=3e87e42ea;hp=8fe2e4a150d;hb=43301bd3c2;hpb=85bd816a60 > > Shouldn't we have a similar set of macros for the R5900? The macros are there to support different instructions used to access data within TLS. However the TLS pointer still has to be fetched with RDHWR, and READ_THREAD_POINTER does exactly that, by calling the `__builtin_thread_pointer' intrinsic in the MIPS16 case. How it works is explained in GCC sources, in gcc/config/mips/mips.md: ;; In MIPS16 mode, the TLS base pointer is accessed by a ;; libgcc helper function __mips16_rdhwr(), as 'rdhwr' is not ;; accessible in MIPS16. ;; ;; This is not represented as a call insn, to avoid the ;; unnecesarry clobbering of caller-save registers by a ;; function consisting only of: "rdhwr $3,$29; j $31; nop;" ;; ;; A $25 clobber is added to cater for a $25 load stub added by the ;; linker to __mips16_rdhwr when the call is made from non-PIC code. -- that is a small piece of regular MIPS code is called, which executes RDHWR. > The problem I have is this break running the binaries built > by the Sony Linux Toolkit for Playstation 2 which use the > LQ/SQ instruction: > > 1b00d5c: 0c6c00d4 jal 0x1b00350 > 1b00d60: 7fa90020 sq t1,32(sp) > 1b00d64: a2710000 sb s1,0(s3) > 1b00d68: 26730001 addiu s3,s3,1 > 1b00d6c: 10000004 b 0x1b00d80 > 1b00d70: 7ba90020 lq t1,32(sp) > 1b00d74: 00000000 nop > 1b00d78: 2617ffff addiu s7,s0,-1 > 1b00d7c: 25360001 addiu s6,t1,1 > 1b00d80: 91220000 lbu v0,0(t1) > 1b00d84: 02e0802d move s0,s7 > 1b00d88: 02c0482d move t1,s6 > 1b00d8c: a2620000 sb v0,0(s3) > 1b00d90: 1600fff9 bnez s0,0x1b00d78 > 1b00d94: 26730001 addiu s3,s3,1 > 1b00d98: 10000003 b 0x1b00da8 > 1b00d9c: 01342026 xor a0,t1,s4 > 1b00da0: 253e0003 addiu s8,t1,3 > 1b00da4: 01342026 xor a0,t1,s4 > 1b00da8: 7fa90020 sq t1,32(sp) > 1b00dac: 2c840001 sltiu a0,a0,1 > 1b00db0: 0c6c00d4 jal 0x1b00350 Where exactly do you see a problem, what are the symptoms? A bug in the emulation cannot be ruled out of course. While there indeed is an unfortunate opcode overlap between RDHWR and SQ, the encoding of the specific operands chosen for TLS pointer access is luckily guaranteed to always trap in the user mode, because the address requested when the encoding is interpreted as SQ rather than RDHWR is within the kernel KSEG2 segment: $ cat rdhwr.s rdhwr $3, $29 $ gcc -march=mips32r2 -c rdhwr.s $ objdump -d rdhwr.o rdhwr.o: file format elf32-tradlittlemips Disassembly of section .text: 00000000 <.text>: 0: 7c03e83b rdhwr v1,$29 ... $ objdump -m mips:5900 -d rdhwr.o rdhwr.o: file format elf32-tradlittlemips Disassembly of section .text: 00000000 <.text>: 0: 7c03e83b sq v1,-6085(zero) ... $ This is because the HWR read is encoded in bits 15:11 of the instruction word and $29 has the highest bit set, which lands in bit 15 of the instruction word, meaning that the offset encoded in bits 15:0 used where the instruction word is interpreted as SQ is negative. And then bits 25:21 are hardwired to 0 in the encoding of RDHWR and they correspond to the base register encoding with SQ, meaning that it will be interpreted as $zero. So the address ultimately requested is -6085 => 0xffffffffffffe83b (the R5900 uses 32-bit addressing and ignores address bits 63:32, but that does not matter here; this is KSEG2 either way). Consequently an AdES exception is triggered which we can trap and handle, reinterpreting the encoding according to our needs and return the TLS pointer in $v1 rather than issuing a SIGBUS. So you are not expected to see any issue unless there is a security erratum in the R5900 as well and the encoding does not cause an exception for some reason. This of course disagrees with what Fredrik wrote in the quotation above, as it's the last page rather than the zeroth that is accessed, but the net effect is the same, or even better. Maciej
On Thu, 19 Nov 2020, Maciej W. Rozycki wrote: > Consequently an AdES exception is triggered which we can trap and handle, > reinterpreting the encoding according to our needs and return the TLS > pointer in $v1 rather than issuing a SIGBUS. ... while keeping regular SQ instruction use intact, I should have added. Maciej
Hi Maciej, On Thu, Nov 19, 2020 at 01:28:00PM +0000, Maciej W. Rozycki wrote: > The use of RDHWR, actual or emulated, is a part of the MIPS TLS psABI, > see: <https://www.linux-mips.org/wiki/NPTL>, in particular starting from: > <https://www.linux-mips.org/wiki/NPTL#Design_Choices> and throughout (the > expired certificate of the web site is a known issue, but there is > currently no way to get it fixed as nobody knows where Ralf Baechle has > gone). Can the site be wrapped up and published elsewhere? > While there indeed is an unfortunate opcode overlap between RDHWR and SQ, > the encoding of the specific operands chosen for TLS pointer access is > luckily guaranteed to always trap in the user mode, because the address > requested when the encoding is interpreted as SQ rather than RDHWR is > within the kernel KSEG2 segment: > > $ cat rdhwr.s > rdhwr $3, $29 > $ gcc -march=mips32r2 -c rdhwr.s > $ objdump -d rdhwr.o > rdhwr.o: file format elf32-tradlittlemips > > > Disassembly of section .text: > > 00000000 <.text>: > 0: 7c03e83b rdhwr v1,$29 > ... > $ objdump -m mips:5900 -d rdhwr.o > > rdhwr.o: file format elf32-tradlittlemips > > > Disassembly of section .text: > > 00000000 <.text>: > 0: 7c03e83b sq v1,-6085(zero) > ... > $ > > This is because the HWR read is encoded in bits 15:11 of the instruction > word and $29 has the highest bit set, which lands in bit 15 of the > instruction word, meaning that the offset encoded in bits 15:0 used where > the instruction word is interpreted as SQ is negative. And then bits > 25:21 are hardwired to 0 in the encoding of RDHWR and they correspond to > the base register encoding with SQ, meaning that it will be interpreted as > $zero. So the address ultimately requested is -6085 => 0xffffffffffffe83b > (the R5900 uses 32-bit addressing and ignores address bits 63:32, but that > does not matter here; this is KSEG2 either way). > > Consequently an AdES exception is triggered which we can trap and handle, > reinterpreting the encoding according to our needs and return the TLS > pointer in $v1 rather than issuing a SIGBUS. So you are not expected to > see any issue unless there is a security erratum in the R5900 as well and > the encoding does not cause an exception for some reason. > > This of course disagrees with what Fredrik wrote in the quotation above, > as it's the last page rather than the zeroth that is accessed, but the net > effect is the same, or even better. The first page could be mapped by the application itself, but what about RDHWR registers $0-$3 having mnemonics CPUNum, SYNC1_Step, CC and CCRes[1], or in Linux /* RDHWR register numbers */ #define MIPS_HWR_CPUNUM 0 /* CPU number */ #define MIPS_HWR_SYNCISTEP 1 /* SYNCI step size */ #define MIPS_HWR_CC 2 /* Cycle counter */ #define MIPS_HWR_CCRES 3 /* Cycle counter resolution */ #define MIPS_HWR_ULR 29 /* UserLocal */ #define MIPS_HWR_IMPL1 30 /* Implementation dependent */ #define MIPS_HWR_IMPL2 31 /* Implementation dependent */ in arch/mips/include/asm/mipsregs.h? They land on the first page, no? Fredrik References: [1] "MIPS Architecture for programmers Volume II-A: The MIPS32 Instruction Set", revision 5.04, 11 December 2013, p. 248.
On Sat, 12 Dec 2020, Fredrik Noring wrote: > > The use of RDHWR, actual or emulated, is a part of the MIPS TLS psABI, > > see: <https://www.linux-mips.org/wiki/NPTL>, in particular starting from: > > <https://www.linux-mips.org/wiki/NPTL#Design_Choices> and throughout (the > > expired certificate of the web site is a known issue, but there is > > currently no way to get it fixed as nobody knows where Ralf Baechle has > > gone). > > Can the site be wrapped up and published elsewhere? Well if someone does that, sure! I guess archive.org will have it too. > > This of course disagrees with what Fredrik wrote in the quotation above, > > as it's the last page rather than the zeroth that is accessed, but the net > > effect is the same, or even better. > > The first page could be mapped by the application itself, but what about It doesn't matter given that `rdhwr $3, $29' maps to an R5900 instruction that does not access it. > RDHWR registers $0-$3 having mnemonics CPUNum, SYNC1_Step, CC and CCRes[1], > or in Linux > > /* RDHWR register numbers */ > #define MIPS_HWR_CPUNUM 0 /* CPU number */ > #define MIPS_HWR_SYNCISTEP 1 /* SYNCI step size */ > #define MIPS_HWR_CC 2 /* Cycle counter */ > #define MIPS_HWR_CCRES 3 /* Cycle counter resolution */ > #define MIPS_HWR_ULR 29 /* UserLocal */ > #define MIPS_HWR_IMPL1 30 /* Implementation dependent */ > #define MIPS_HWR_IMPL2 31 /* Implementation dependent */ > > in arch/mips/include/asm/mipsregs.h? They land on the first page, no? Unlike TLS pointer access, specifically using $3 as rt, which has been made a part of the Linux ABI, they're not supposed to be referred with pre-R2 code. After all RDHWR was only introduced with R2. Indeed there's emulation code in the kernel for those encodings even with pre-R2 hardware, but it is not guaranteed to give sensible results, and given the circumstances I'm not sure what it really is for, e.g. what is SYNCI_Step for with processors that do not implement SYNCI? The cycle counter register may be absent too, so even emulated accesses will return rubbish; gettimeofday(2) is the standard interface. So I think we can safely ignore them, just as we can any ULR access with rt != $3. Unlike standardised TLS pointer accesses such instructions won't appear in compiler-generated code and whoever uses them in handcoded assembly or otherwise generated machine code will have to make sure they make sense for their application (yes, there's rubbish code out there, e.g. Firefox has a JIT that unconditionally produces MIPS R2 code even if the piece of software has been compiled for an older ISA revision, and having not verified that the CPU it runs on actually supports the R2 ISA, but that's just the usual imperfection of the world; you just can't fix it all). Maciej
On Sat, Dec 12, 2020 at 11:36:35AM +0000, Maciej W. Rozycki wrote: > Unlike TLS pointer access, specifically using $3 as rt, which has been > made a part of the Linux ABI, they're not supposed to be referred with > pre-R2 code. After all RDHWR was only introduced with R2. > > Indeed there's emulation code in the kernel for those encodings even with > pre-R2 hardware, but it is not guaranteed to give sensible results, and > given the circumstances I'm not sure what it really is for, e.g. what is > SYNCI_Step for with processors that do not implement SYNCI? The cycle > counter register may be absent too, so even emulated accesses will return > rubbish; gettimeofday(2) is the standard interface. > > So I think we can safely ignore them, just as we can any ULR access with > rt != $3. Unlike standardised TLS pointer accesses such instructions > won't appear in compiler-generated code and whoever uses them in handcoded > assembly or otherwise generated machine code will have to make sure they > make sense for their application (yes, there's rubbish code out there, > e.g. Firefox has a JIT that unconditionally produces MIPS R2 code even if > the piece of software has been compiled for an older ISA revision, and > having not verified that the CPU it runs on actually supports the R2 ISA, > but that's just the usual imperfection of the world; you just can't fix it > all). Many thanks, that resolves it! I'll write it up in the commit message. Fredrik
> So I think we can safely ignore them, just as we can any ULR access with > rt != $3. The comment is corrected and the conditions on rd and rt are now strict, as shown in the patch below. Fredrik diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c index 92bd2b0f0548..89ce42c60c6f 100644 --- a/arch/mips/kernel/unaligned.c +++ b/arch/mips/kernel/unaligned.c @@ -90,6 +90,7 @@ #include <asm/fpu_emulator.h> #include <asm/inst.h> #include <asm/mmu_context.h> +#include <asm/traps.h> #include <linux/uaccess.h> #define STR(x) __STR(x) @@ -934,7 +935,46 @@ static void emulate_load_store_insn(struct pt_regs *regs, * interest. */ case spec3_op: - if (insn.dsp_format.func == lx_op) { + if (IS_ENABLED(CONFIG_CPU_R5900)) { + /* + * On the R5900, a valid RDHWR instruction + * + * +--------+-------+----+----+-------+--------+ + * | 011111 | 00000 | rt | rd | 00000 | 111011 | + * +--------+-------+----+----+-------+--------+ + * 6 5 5 5 5 6 + * + * having rt $3 (v1) and rd $29 (MIPS_HWR_ULR) is + * interpreted as the R5900 specific SQ instruction + * + * +--------+-------+----+---------------------+ + * | 011111 | base | rt | offset | + * +--------+-------+----+---------------------+ + * 6 5 5 16 + * + * with + * + * sq v1,-6085(zero) + * + * that asserts an address exception since -6085(zero) + * always resolves to 0xffffe83b in 32-bit KSEG2. + * + * Other legacy values of rd, such as MIPS_HWR_CPUNUM, + * are ignored. + */ + if (insn.r_format.func == rdhwr_op && + insn.r_format.rd == MIPS_HWR_ULR && + insn.r_format.rt == 3 && + insn.r_format.rs == 0 && + insn.r_format.re == 0) { + if (compute_return_epc(regs) < 0 || + simulate_rdhwr(regs, insn.r_format.rd, + insn.r_format.rt) < 0) + goto sigill; + return; + } + goto sigbus; + } else if (insn.dsp_format.func == lx_op) { switch (insn.dsp_format.op) { case lwx_op: if (!access_ok(addr, 4))
diff --git a/arch/mips/include/asm/traps.h b/arch/mips/include/asm/traps.h index 6a0864bb604d..ed6449f2967b 100644 --- a/arch/mips/include/asm/traps.h +++ b/arch/mips/include/asm/traps.h @@ -35,4 +35,6 @@ extern int register_nmi_notifier(struct notifier_block *nb); register_nmi_notifier(&fn##_nb); \ }) +int simulate_rdhwr(struct pt_regs *regs, int rd, int rt); + #endif /* _ASM_TRAPS_H */ diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 342e41de9d64..9423b9a2eb67 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -625,7 +625,7 @@ static int simulate_llsc(struct pt_regs *regs, unsigned int opcode) * Simulate trapping 'rdhwr' instructions to provide user accessible * registers not implemented in hardware. */ -static int simulate_rdhwr(struct pt_regs *regs, int rd, int rt) +int simulate_rdhwr(struct pt_regs *regs, int rd, int rt) { struct thread_info *ti = task_thread_info(current); diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c index 92bd2b0f0548..f490944d73cf 100644 --- a/arch/mips/kernel/unaligned.c +++ b/arch/mips/kernel/unaligned.c @@ -90,6 +90,7 @@ #include <asm/fpu_emulator.h> #include <asm/inst.h> #include <asm/mmu_context.h> +#include <asm/traps.h> #include <linux/uaccess.h> #define STR(x) __STR(x) @@ -934,7 +935,39 @@ static void emulate_load_store_insn(struct pt_regs *regs, * interest. */ case spec3_op: - if (insn.dsp_format.func == lx_op) { + if (IS_ENABLED(CONFIG_CPU_R5900)) { + /* + * On the R5900, the RDHWR instruction + * + * +--------+-------+----+----+-------+--------+ + * | 011111 | 00000 | rt | rd | 00000 | 111011 | + * +--------+-------+----+----+-------+--------+ + * 6 5 5 5 5 6 + * + * is interpreted as the R5900 specific SQ instruction + * + * +--------+-------+----+---------------------+ + * | 011111 | base | rt | offset | + * +--------+-------+----+---------------------+ + * 6 5 5 16 + * + * that asserts a zero page address exception. Hence + * RDHWR can be trapped and emulated here, provided + * DEFAULT_MMAP_MIN_ADDR isn't zero. + */ + BUILD_BUG_ON(IS_ENABLED(CONFIG_CPU_R5900) && + CONFIG_DEFAULT_MMAP_MIN_ADDR < PAGE_SIZE); + if (insn.r_format.func == rdhwr_op && + insn.r_format.rs == 0 && + insn.r_format.re == 0) { + if (compute_return_epc(regs) < 0 || + simulate_rdhwr(regs, insn.r_format.rd, + insn.r_format.rt) < 0) + goto sigill; + return; + } + goto sigbus; + } else if (insn.dsp_format.func == lx_op) { switch (insn.dsp_format.op) { case lwx_op: if (!access_ok(addr, 4)) @@ -1342,6 +1375,7 @@ static void emulate_load_store_insn(struct pt_regs *regs, cu2_notifier_call_chain(CU2_SDC2_OP, regs); break; #endif + default: /* * Pheeee... We encountered an yet unknown instruction or
On the R5900, the RDHWR instruction is interpreted as the R5900 specific SQ instruction[1] that traps into a zero page address exception. Hence RDHWR can be emulated by emulate_load_store_insn(). CONFIG_DEFAULT_MMAP_MIN_ADDR must not be less than PAGE_SIZE to reliably trap and emulate RDHWR, so this is made a BUILD_BUG_ON for the R5900. References: [1] "TX System RISC TX79 Core Architecture" manual, revision 2.0, Toshiba Corporation, p. B-162, https://wiki.qemu.org/File:C790.pdf Signed-off-by: Fredrik Noring <noring@nocrew.org> --- arch/mips/include/asm/traps.h | 2 ++ arch/mips/kernel/traps.c | 2 +- arch/mips/kernel/unaligned.c | 36 ++++++++++++++++++++++++++++++++++- 3 files changed, 38 insertions(+), 2 deletions(-)