Mon Jul 19 22:21:36 2021 UTC ()
- In unaligned_fixup(), use defined constants for opcodes, not magic numbers.

- In handle_opdec(), use ufetch_int() to fetch the instruction and
  _u{fetch,store}_{8,16}() when emulating BWX instructions rather
  than copyin() / copyout() (they're faster).

- Add event counters for BWX instruction emulation.


(thorpej)
diff -r1.135 -r1.136 src/sys/arch/alpha/alpha/trap.c

cvs diff -r1.135 -r1.136 src/sys/arch/alpha/alpha/trap.c (expand / switch to unified diff)

--- src/sys/arch/alpha/alpha/trap.c 2019/11/21 19:23:58 1.135
+++ src/sys/arch/alpha/alpha/trap.c 2021/07/19 22:21:36 1.136
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: trap.c,v 1.135 2019/11/21 19:23:58 ad Exp $ */ 1/* $NetBSD: trap.c,v 1.136 2021/07/19 22:21:36 thorpej Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc. 4 * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to The NetBSD Foundation 7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9 * NASA Ames Research Center, by Charles M. Hannum, and by Ross Harvey. 9 * NASA Ames Research Center, by Charles M. Hannum, and by Ross Harvey.
10 * 10 *
11 * Redistribution and use in source and binary forms, with or without 11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions 12 * modification, are permitted provided that the following conditions
13 * are met: 13 * are met:
14 * 1. Redistributions of source code must retain the above copyright 14 * 1. Redistributions of source code must retain the above copyright
@@ -77,33 +77,35 @@ @@ -77,33 +77,35 @@
77 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 77 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
78 * 78 *
79 * Carnegie Mellon requests users of this software to return to 79 * Carnegie Mellon requests users of this software to return to
80 * 80 *
81 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 81 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
82 * School of Computer Science 82 * School of Computer Science
83 * Carnegie Mellon University 83 * Carnegie Mellon University
84 * Pittsburgh PA 15213-3890 84 * Pittsburgh PA 15213-3890
85 * 85 *
86 * any improvements or extensions that they make and grant Carnegie the 86 * any improvements or extensions that they make and grant Carnegie the
87 * rights to redistribute these changes. 87 * rights to redistribute these changes.
88 */ 88 */
89 89
 90#define __UFETCHSTORE_PRIVATE /* see handle_opdec() */
 91
90#include "opt_fix_unaligned_vax_fp.h" 92#include "opt_fix_unaligned_vax_fp.h"
91#include "opt_ddb.h" 93#include "opt_ddb.h"
92#include "opt_multiprocessor.h" 94#include "opt_multiprocessor.h"
93 95
94#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */ 96#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
95 97
96__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.135 2019/11/21 19:23:58 ad Exp $"); 98__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.136 2021/07/19 22:21:36 thorpej Exp $");
97 99
98#include <sys/param.h> 100#include <sys/param.h>
99#include <sys/systm.h> 101#include <sys/systm.h>
100#include <sys/proc.h> 102#include <sys/proc.h>
101#include <sys/syscall.h> 103#include <sys/syscall.h>
102#include <sys/buf.h> 104#include <sys/buf.h>
103#include <sys/kauth.h> 105#include <sys/kauth.h>
104#include <sys/kmem.h> 106#include <sys/kmem.h>
105#include <sys/cpu.h> 107#include <sys/cpu.h>
106#include <sys/atomic.h> 108#include <sys/atomic.h>
107 109
108#include <uvm/uvm_extern.h> 110#include <uvm/uvm_extern.h>
109 111
@@ -865,109 +867,131 @@ unaligned_fixup(u_long va, u_long opcode @@ -865,109 +867,131 @@ unaligned_fixup(u_long va, u_long opcode
865 * 867 *
866 * We never allow bad data to be unknowingly used by the user process. 868 * We never allow bad data to be unknowingly used by the user process.
867 * That is, if we can't access the address needed to fix up the trap, 869 * That is, if we can't access the address needed to fix up the trap,
868 * we cause a SIGSEGV rather than letting the user process go on 870 * we cause a SIGSEGV rather than letting the user process go on
869 * without warning. 871 * without warning.
870 * 872 *
871 * If we're trying to do a fixup, we assume that things 873 * If we're trying to do a fixup, we assume that things
872 * will be botched. If everything works out OK, 874 * will be botched. If everything works out OK,
873 * unaligned_{load,store}_* clears the signal flag. 875 * unaligned_{load,store}_* clears the signal flag.
874 */ 876 */
875 signo = SIGSEGV; 877 signo = SIGSEGV;
876 if (dofix && selected_tab->fixable) { 878 if (dofix && selected_tab->fixable) {
877 switch (opcode) { 879 switch (opcode) {
878 case 0x0c: /* ldwu */ 880 case op_ldwu:
879 /* XXX ONLY WORKS ON LITTLE-ENDIAN ALPHA */ 881 /* XXX ONLY WORKS ON LITTLE-ENDIAN ALPHA */
880 unaligned_load_integer(worddata); 882 unaligned_load_integer(worddata);
881 break; 883 break;
882 884
883 case 0x0d: /* stw */ 885 case op_stw:
884 /* XXX ONLY WORKS ON LITTLE-ENDIAN ALPHA */ 886 /* XXX ONLY WORKS ON LITTLE-ENDIAN ALPHA */
885 unaligned_store_integer(worddata); 887 unaligned_store_integer(worddata);
886 break; 888 break;
887 889
888#ifdef FIX_UNALIGNED_VAX_FP 890#ifdef FIX_UNALIGNED_VAX_FP
889 case 0x20: /* ldf */ 891 case op_ldf:
890 unaligned_load_floating(intdata, Ffloat_to_reg); 892 unaligned_load_floating(intdata, Ffloat_to_reg);
891 break; 893 break;
892 894
893 case 0x21: /* ldg */ 895 case op_ldg:
894 unaligned_load_floating(longdata, Gfloat_reg_cvt); 896 unaligned_load_floating(longdata, Gfloat_reg_cvt);
895 break; 897 break;
896#endif 898#endif
897 899
898 case 0x22: /* lds */ 900 case op_lds:
899 unaligned_load_floating(intdata, Sfloat_to_reg); 901 unaligned_load_floating(intdata, Sfloat_to_reg);
900 break; 902 break;
901 903
902 case 0x23: /* ldt */ 904 case op_ldt:
903 unaligned_load_floating(longdata, Tfloat_reg_cvt); 905 unaligned_load_floating(longdata, Tfloat_reg_cvt);
904 break; 906 break;
905 907
906#ifdef FIX_UNALIGNED_VAX_FP 908#ifdef FIX_UNALIGNED_VAX_FP
907 case 0x24: /* stf */ 909 case op_stf:
908 unaligned_store_floating(intdata, reg_to_Ffloat); 910 unaligned_store_floating(intdata, reg_to_Ffloat);
909 break; 911 break;
910 912
911 case 0x25: /* stg */ 913 case op_stg:
912 unaligned_store_floating(longdata, Gfloat_reg_cvt); 914 unaligned_store_floating(longdata, Gfloat_reg_cvt);
913 break; 915 break;
914#endif 916#endif
915 917
916 case 0x26: /* sts */ 918 case op_sts:
917 unaligned_store_floating(intdata, reg_to_Sfloat); 919 unaligned_store_floating(intdata, reg_to_Sfloat);
918 break; 920 break;
919 921
920 case 0x27: /* stt */ 922 case op_stt:
921 unaligned_store_floating(longdata, Tfloat_reg_cvt); 923 unaligned_store_floating(longdata, Tfloat_reg_cvt);
922 break; 924 break;
923 925
924 case 0x28: /* ldl */ 926 case op_ldl:
925 unaligned_load_integer(intdata); 927 unaligned_load_integer(intdata);
926 break; 928 break;
927 929
928 case 0x29: /* ldq */ 930 case op_ldq:
929 unaligned_load_integer(longdata); 931 unaligned_load_integer(longdata);
930 break; 932 break;
931 933
932 case 0x2c: /* stl */ 934 case op_stl:
933 unaligned_store_integer(intdata); 935 unaligned_store_integer(intdata);
934 break; 936 break;
935 937
936 case 0x2d: /* stq */ 938 case op_stq:
937 unaligned_store_integer(longdata); 939 unaligned_store_integer(longdata);
938 break; 940 break;
939 941
940#ifdef DIAGNOSTIC 942#ifdef DIAGNOSTIC
941 default: 943 default:
942 panic("unaligned_fixup: can't get here"); 944 panic("unaligned_fixup: can't get here");
943#endif 945#endif
944 } 946 }
945 } 947 }
946 948
947 /* 949 /*
948 * Force SIGBUS if requested. 950 * Force SIGBUS if requested.
949 */ 951 */
950 if (dosigbus) 952 if (dosigbus)
951 signo = SIGBUS; 953 signo = SIGBUS;
952 954
953 /* 955 /*
954 * Write back USP. 956 * Write back USP.
955 */ 957 */
956 alpha_pal_wrusp(l->l_md.md_tf->tf_regs[FRAME_SP]); 958 alpha_pal_wrusp(l->l_md.md_tf->tf_regs[FRAME_SP]);
957 959
958 return (signo); 960 return (signo);
959} 961}
960 962
 963static struct evcnt emul_bwx_ldbu =
 964 EVCNT_INITIALIZER(EVCNT_TYPE_TRAP, NULL, "emul bwx", "ldbu");
 965static struct evcnt emul_bwx_ldwu =
 966 EVCNT_INITIALIZER(EVCNT_TYPE_TRAP, NULL, "emul bwx", "ldwu");
 967static struct evcnt emul_bwx_stb =
 968 EVCNT_INITIALIZER(EVCNT_TYPE_TRAP, NULL, "emul bwx", "stb");
 969static struct evcnt emul_bwx_stw =
 970 EVCNT_INITIALIZER(EVCNT_TYPE_TRAP, NULL, "emul bwx", "stw");
 971static struct evcnt emul_bwx_sextb =
 972 EVCNT_INITIALIZER(EVCNT_TYPE_TRAP, NULL, "emul bwx", "sextb");
 973static struct evcnt emul_bwx_sextw =
 974 EVCNT_INITIALIZER(EVCNT_TYPE_TRAP, NULL, "emul bwx", "sextw");
 975
 976EVCNT_ATTACH_STATIC(emul_bwx_ldbu);
 977EVCNT_ATTACH_STATIC(emul_bwx_ldwu);
 978EVCNT_ATTACH_STATIC(emul_bwx_stb);
 979EVCNT_ATTACH_STATIC(emul_bwx_stw);
 980EVCNT_ATTACH_STATIC(emul_bwx_sextb);
 981EVCNT_ATTACH_STATIC(emul_bwx_sextw);
 982
 983#define EMUL_COUNT(ev) atomic_inc_64(&(ev).ev_count)
 984
961/* 985/*
962 * Reserved/unimplemented instruction (opDec fault) handler 986 * Reserved/unimplemented instruction (opDec fault) handler
963 * 987 *
964 * Argument is the process that caused it. No useful information 988 * Argument is the process that caused it. No useful information
965 * is passed to the trap handler other than the fault type. The 989 * is passed to the trap handler other than the fault type. The
966 * address of the instruction that caused the fault is 4 less than 990 * address of the instruction that caused the fault is 4 less than
967 * the PC stored in the trap frame. 991 * the PC stored in the trap frame.
968 * 992 *
969 * If the instruction is emulated successfully, this function returns 0. 993 * If the instruction is emulated successfully, this function returns 0.
970 * Otherwise, this function returns the signal to deliver to the process, 994 * Otherwise, this function returns the signal to deliver to the process,
971 * and fills in *ucodep with the code to be delivered. 995 * and fills in *ucodep with the code to be delivered.
972 */ 996 */
973int 997int
@@ -976,117 +1000,131 @@ handle_opdec(struct lwp *l, u_long *ucod @@ -976,117 +1000,131 @@ handle_opdec(struct lwp *l, u_long *ucod
976 alpha_instruction inst; 1000 alpha_instruction inst;
977 register_t *regptr, memaddr; 1001 register_t *regptr, memaddr;
978 uint64_t inst_pc; 1002 uint64_t inst_pc;
979 int sig; 1003 int sig;
980 1004
981 /* 1005 /*
982 * Read USP into frame in case it's going to be used or modified. 1006 * Read USP into frame in case it's going to be used or modified.
983 * This keeps us from having to check for it in lots of places 1007 * This keeps us from having to check for it in lots of places
984 * later. 1008 * later.
985 */ 1009 */
986 l->l_md.md_tf->tf_regs[FRAME_SP] = alpha_pal_rdusp(); 1010 l->l_md.md_tf->tf_regs[FRAME_SP] = alpha_pal_rdusp();
987 1011
988 inst_pc = memaddr = l->l_md.md_tf->tf_regs[FRAME_PC] - 4; 1012 inst_pc = memaddr = l->l_md.md_tf->tf_regs[FRAME_PC] - 4;
989 if (copyin((void *)inst_pc, &inst, sizeof (inst)) != 0) { 1013 if (ufetch_int((void *)inst_pc, &inst.bits) != 0) {
990 /* 1014 /*
991 * really, this should never happen, but in case it 1015 * really, this should never happen, but in case it
992 * does we handle it. 1016 * does we handle it.
993 */ 1017 */
994 printf("WARNING: handle_opdec() couldn't fetch instruction\n"); 1018 printf("WARNING: handle_opdec() couldn't fetch instruction\n");
995 goto sigsegv; 1019 goto sigsegv;
996 } 1020 }
997 1021
998 switch (inst.generic_format.opcode) { 1022 switch (inst.generic_format.opcode) {
999 case op_ldbu: 1023 case op_ldbu:
1000 case op_ldwu: 1024 case op_ldwu:
1001 case op_stw: 1025 case op_stw:
1002 case op_stb: 1026 case op_stb:
1003 regptr = irp(l, inst.mem_format.rb); 1027 regptr = irp(l, inst.mem_format.rb);
1004 if (regptr != NULL) 1028 if (regptr != NULL)
1005 memaddr = *regptr; 1029 memaddr = *regptr;
1006 else 1030 else
1007 memaddr = 0; 1031 memaddr = 0;
1008 memaddr += inst.mem_format.displacement; 1032 memaddr += inst.mem_format.displacement;
1009 1033
1010 regptr = irp(l, inst.mem_format.ra); 1034 regptr = irp(l, inst.mem_format.ra);
1011 1035
1012 if (inst.mem_format.opcode == op_ldwu || 1036 if (inst.mem_format.opcode == op_ldwu ||
1013 inst.mem_format.opcode == op_stw) { 1037 inst.mem_format.opcode == op_stw) {
1014 if (memaddr & 0x01) { 1038 if (memaddr & 0x01) {
 1039 if (inst.mem_format.opcode == op_ldwu) {
 1040 EMUL_COUNT(emul_bwx_ldwu);
 1041 } else {
 1042 EMUL_COUNT(emul_bwx_stw);
 1043 }
1015 sig = unaligned_fixup(memaddr, 1044 sig = unaligned_fixup(memaddr,
1016 inst.mem_format.opcode, 1045 inst.mem_format.opcode,
1017 inst.mem_format.ra, l); 1046 inst.mem_format.ra, l);
1018 if (sig) 1047 if (sig)
1019 goto unaligned_fixup_sig; 1048 goto unaligned_fixup_sig;
1020 break; 1049 break;
1021 } 1050 }
1022 } 1051 }
1023 1052
 1053 /*
 1054 * We know the addresses are aligned, so it's safe to
 1055 * use _u{fetch,store}_{8,16}(). Note, these are
 1056 * __UFETCHSTORE_PRIVATE, but this is MD code, and
 1057 * we know the details of the alpha implementation.
 1058 */
 1059
1024 if (inst.mem_format.opcode == op_ldbu) { 1060 if (inst.mem_format.opcode == op_ldbu) {
1025 uint8_t b; 1061 uint8_t b;
1026 1062
1027 /* XXX ONLY WORKS ON LITTLE-ENDIAN ALPHA */ 1063 EMUL_COUNT(emul_bwx_ldbu);
1028 if (copyin((void *)memaddr, &b, sizeof (b)) != 0) 1064 if (_ufetch_8((void *)memaddr, &b) != 0)
1029 goto sigsegv; 1065 goto sigsegv;
1030 if (regptr != NULL) 1066 if (regptr != NULL)
1031 *regptr = b; 1067 *regptr = b;
1032 } else if (inst.mem_format.opcode == op_ldwu) { 1068 } else if (inst.mem_format.opcode == op_ldwu) {
1033 uint16_t w; 1069 uint16_t w;
1034 1070
1035 /* XXX ONLY WORKS ON LITTLE-ENDIAN ALPHA */ 1071 EMUL_COUNT(emul_bwx_ldwu);
1036 if (copyin((void *)memaddr, &w, sizeof (w)) != 0) 1072 if (_ufetch_16((void *)memaddr, &w) != 0)
1037 goto sigsegv; 1073 goto sigsegv;
1038 if (regptr != NULL) 1074 if (regptr != NULL)
1039 *regptr = w; 1075 *regptr = w;
1040 } else if (inst.mem_format.opcode == op_stw) { 1076 } else if (inst.mem_format.opcode == op_stw) {
1041 uint16_t w; 1077 uint16_t w;
1042 1078
1043 /* XXX ONLY WORKS ON LITTLE-ENDIAN ALPHA */ 1079 EMUL_COUNT(emul_bwx_stw);
1044 w = (regptr != NULL) ? *regptr : 0; 1080 w = (regptr != NULL) ? *regptr : 0;
1045 if (copyout(&w, (void *)memaddr, sizeof (w)) != 0) 1081 if (_ustore_16((void *)memaddr, w) != 0)
1046 goto sigsegv; 1082 goto sigsegv;
1047 } else if (inst.mem_format.opcode == op_stb) { 1083 } else if (inst.mem_format.opcode == op_stb) {
1048 uint8_t b; 1084 uint8_t b;
1049 1085
1050 /* XXX ONLY WORKS ON LITTLE-ENDIAN ALPHA */ 1086 EMUL_COUNT(emul_bwx_stb);
1051 b = (regptr != NULL) ? *regptr : 0; 1087 b = (regptr != NULL) ? *regptr : 0;
1052 if (copyout(&b, (void *)memaddr, sizeof (b)) != 0) 1088 if (_ustore_8((void *)memaddr, b) != 0)
1053 goto sigsegv; 1089 goto sigsegv;
1054 } 1090 }
1055 break; 1091 break;
1056 1092
1057 case op_intmisc: 1093 case op_intmisc:
1058 if (inst.operate_generic_format.function == op_sextb && 1094 if (inst.operate_generic_format.function == op_sextb &&
1059 inst.operate_generic_format.ra == 31) { 1095 inst.operate_generic_format.ra == 31) {
1060 int8_t b; 1096 int8_t b;
1061 1097
 1098 EMUL_COUNT(emul_bwx_sextb);
1062 if (inst.operate_generic_format.is_lit) { 1099 if (inst.operate_generic_format.is_lit) {
1063 b = inst.operate_lit_format.literal; 1100 b = inst.operate_lit_format.literal;
1064 } else { 1101 } else {
1065 if (inst.operate_reg_format.sbz != 0) 1102 if (inst.operate_reg_format.sbz != 0)
1066 goto sigill; 1103 goto sigill;
1067 regptr = irp(l, inst.operate_reg_format.rb); 1104 regptr = irp(l, inst.operate_reg_format.rb);
1068 b = (regptr != NULL) ? *regptr : 0; 1105 b = (regptr != NULL) ? *regptr : 0;
1069 } 1106 }
1070 1107
1071 regptr = irp(l, inst.operate_generic_format.rc); 1108 regptr = irp(l, inst.operate_generic_format.rc);
1072 if (regptr != NULL) 1109 if (regptr != NULL)
1073 *regptr = b; 1110 *regptr = b;
1074 break; 1111 break;
1075 } 1112 }
1076 if (inst.operate_generic_format.function == op_sextw && 1113 if (inst.operate_generic_format.function == op_sextw &&
1077 inst.operate_generic_format.ra == 31) { 1114 inst.operate_generic_format.ra == 31) {
1078 int16_t w; 1115 int16_t w;
1079 1116
 1117 EMUL_COUNT(emul_bwx_sextw);
1080 if (inst.operate_generic_format.is_lit) { 1118 if (inst.operate_generic_format.is_lit) {
1081 w = inst.operate_lit_format.literal; 1119 w = inst.operate_lit_format.literal;
1082 } else { 1120 } else {
1083 if (inst.operate_reg_format.sbz != 0) 1121 if (inst.operate_reg_format.sbz != 0)
1084 goto sigill; 1122 goto sigill;
1085 regptr = irp(l, inst.operate_reg_format.rb); 1123 regptr = irp(l, inst.operate_reg_format.rb);
1086 w = (regptr != NULL) ? *regptr : 0; 1124 w = (regptr != NULL) ? *regptr : 0;
1087 } 1125 }
1088 1126
1089 regptr = irp(l, inst.operate_generic_format.rc); 1127 regptr = irp(l, inst.operate_generic_format.rc);
1090 if (regptr != NULL) 1128 if (regptr != NULL)
1091 *regptr = w; 1129 *regptr = w;
1092 break; 1130 break;