NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
port-arm/54720: pagein problem by prefetching Thumb 32bit instruction on a page boundary
>Number: 54720
>Category: port-arm
>Synopsis: cannot pagein by prefetching Thumb 32bit instruction on a page boundary
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: port-arm-maintainer
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Mon Nov 25 19:25:00 +0000 2019
>Originator: Ryo Shimizu
>Release: NetBSD 9.99.18
>Organization:
>Environment:
System: NetBSD max 9.99.18 NetBSD 9.99.18 (NITROGEN6MAX) #24: Mon Nov 25 20:31:25 JST 2019 ryo@phenomena:/src/cvs/NetBSD/sys/arch/evbarm/compile/NITROGEN6MAX evbarm
Architecture: earmv7hf
Machine: evbarm
>Description:
A 32bit Thumb instruction is located on the page boundaries, and the second page is unmap,
prefetch-abort is endlessly occured, and the process goes into a busyloop.
>How-To-Repeat:
execute below test program (shar)
% cc -Wall -mthumb -c -O -fomit-frame-pointer thumb.c
% cc -Wall -static -o pagein_test -O main.c thumb.o
% ./pagein_test
pagesize=8192
thumb_nop = 0x14000
execute thumb "nop.w" code on page boundary
ok
% ./pagein_test pageout
pagesize=8192
thumb_nop = 0x14000
0x15fe0: 00 bf 00 bf 00 bf 00 bf 00 bf 00 bf 00 bf 00 bf
0x15ff0: 00 bf 00 bf 00 bf 00 bf 00 bf 00 bf 00 bf af f3
0x16000: 00 80 00 bf 00 bf 00 bf 00 bf 00 bf 00 bf 00 bf
0x16010: 00 bf 00 bf 00 bf 00 bf 00 bf 00 bf 00 bf 00 bf
pageout 0x16000-0x17fff
execute thumb "nop.w" code on page boundary
[ 21620.9678153] load: 0.27 cmd: pagein_test 1588 [0x15ffe/0] 0.15u 2.97s 13% 744k
[ 21623.0878012] load: 0.33 cmd: pagein_test 1588 [0x15ffe/0] 0.22u 5.02s 21% 744k
[ 21624.5777914] load: 0.33 cmd: pagein_test 1588 [0x15ffe/0] 0.32u 6.41s 25% 744k
[ 21625.0277890] load: 0.33 cmd: pagein_test 1588 [0x15ffe/0] 0.34u 6.84s 28% 744k
^C
- page 0x14000-15fff is mapped
- page 0x16000-17fff is not mapped (paged out)
- "00 bf" is Thumb-16bit nop
- "af f3 00 80" is Thumb-32bit nop.w (at 0x15ffe).
# This is a shell archive. Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file". Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
# main.c
# thumb.c
# Makefile
#
echo x - main.c
sed 's/^X//' >main.c << 'END-of-main.c'
X#include <stdio.h>
X#include <stdlib.h>
X#include <string.h>
X#include <stdbool.h>
X#include <sys/mman.h>
X
Xvoid thumb_nop(void);
X
Xstatic void
Xdumpstr(const unsigned char *data, int len)
X{
X for (int i = 0; i < len; i++) {
X if ((i & 15) == 0)
X printf("%p:", data);
X printf(" %02x", *data++);
X if ((i & 15) == 15)
X printf("\n");
X }
X}
X
Xint
Xmain(int argc, char *argv[])
X{
X int pagesize = 8192; // XXX
X void *thumb_nop_addr;
X bool do_pageout = false;
X
X if (argc == 2 && strcmp(argv[1], "pageout") == 0)
X do_pageout = true;
X else if (argc != 1) {
X fprintf(stderr, "usage: pagein_test [pageout]\n");
X exit(1);
X }
X
X
X setbuf(stdout, NULL);
X printf("pagesize=%d\n", pagesize);
X
X thumb_nop_addr = (void *)((uintptr_t)thumb_nop & -2);
X printf("thumb_nop = %p\n\n", thumb_nop_addr);
X
X if (do_pageout) {
X /* dump around page boundary */
X dumpstr(thumb_nop_addr + pagesize - 32, 64);
X printf("\n");
X
X /* pageout last half of thumb_nop()) */
X printf("pageout %p-%p\n", thumb_nop_addr + pagesize, thumb_nop_addr + pagesize * 2 - 1);
X madvise(thumb_nop_addr + pagesize, pagesize, MADV_DONTNEED);
X madvise(thumb_nop_addr + pagesize, pagesize, MADV_FREE);
X printf("\n");
X }
X
X printf("execute thumb \"nop.w\" code on page boundary\n");
X thumb_nop();
X printf("ok\n");
X}
END-of-main.c
echo x - thumb.c
sed 's/^X//' >thumb.c << 'END-of-thumb.c'
X#include <sys/cdefs.h>
X
X __aligned(8192) /* 0x2000 */
Xvoid
Xthumb_nop(void)
X{
X // at +0x00000
X asm(".rept 4095; nop; .endr");
X
X // at +0x01ffe
X asm("nop.w");
X
X // at +0x02002
X asm(".rept 4095; nop; .endr");
X}
END-of-thumb.c
echo x - Makefile
sed 's/^X//' >Makefile << 'END-of-Makefile'
X
Xmcr_test: main.c thumb.c
X cc -Wall -mthumb -c -O -fomit-frame-pointer thumb.c
X cc -Wall -static -o pagein_test -O main.c thumb.o
X
Xclean:
X rm -f pagein_test thumb.o
END-of-Makefile
exit
>Fix:
Index: sys/arch/arm/arm32/fault.c
===================================================================
RCS file: /src/cvs/cvsroot-netbsd/src/sys/arch/arm/arm32/fault.c,v
retrieving revision 1.108
diff -u -r1.108 fault.c
--- sys/arch/arm/arm32/fault.c 6 Apr 2019 03:06:25 -0000 1.108
+++ sys/arch/arm/arm32/fault.c 25 Nov 2019 17:58:04 -0000
@@ -838,6 +838,9 @@
UVMHIST_LOG(maphist, " (pc=0x%jx, l=0x%#jx, tf=0x%#jx)",
fault_pc, (uintptr_t)l, (uintptr_t)tf, 0);
+#ifdef THUMB_CODE
+ recheck:
+#endif
/* Ok validate the address, can only execute in USER space */
if (__predict_false(fault_pc >= VM_MAXUSER_ADDRESS ||
(fault_pc < VM_MIN_ADDRESS && vector_page == ARM_VECTORS_LOW))) {
@@ -897,6 +900,18 @@
call_trapsignal(l, tf, &ksi);
out:
+
+#ifdef THUMB_CODE
+#define THUMB_32BIT(hi) (((hi) & 0xe000) == 0xe000 && ((hi) & 0x1800))
+ /* thumb-32 instruction was located on page boundary? */
+ if ((tf->tf_spsr & PSR_T_bit) &&
+ ((fault_pc & PAGE_MASK) == (PAGE_SIZE - THUMB_INSN_SIZE)) &&
+ THUMB_32BIT(*(uint16_t *)tf->tf_pc)) {
+ fault_pc = tf->tf_pc + THUMB_INSN_SIZE;
+ goto recheck;
+ }
+#endif /* THUMB_CODE */
+
KASSERT(!TRAP_USERMODE(tf) || VALID_R15_PSR(tf->tf_pc, tf->tf_spsr));
userret(l);
}
Home |
Main Index |
Thread Index |
Old Index