@@ -414,6 +414,7 @@ potentially also ldur q0, [x1, #32] and ldur q1, [x1, #48]
414414 */
415415
416416#include <linux/timekeeping.h>
417+ #include <generated/asm/sysreg-defs.h>
417418
418419struct fixupDescription {
419420 void * addr ;
@@ -756,6 +757,38 @@ __attribute__((always_inline)) inline int get_data(int size, uint8_t* data, void
756757 return r ;
757758}
758759
760+ int memset_io_user (uint64_t size , uint8_t c , void * addr ){
761+ int r = 0 ;
762+ uint64_t pattern = c ;
763+ pattern |= pattern << 8 ;
764+ pattern |= pattern << 16 ;
765+ pattern |= pattern << 32 ;
766+ uint64_t cnt = 0 ;
767+ while (cnt < size ){
768+ if ((uint64_t )(addr + cnt ) % 8 ){
769+ if ((r = put_user (c , (uint8_t __user * ) addr ))){
770+ printk ("Failed to write data at 0x%px (%d)(base was 0x%px)\n" , addr + cnt , r , addr );
771+ return r ;
772+ }
773+ cnt ++ ;
774+ } else if (size - cnt >= 8 ){
775+ if ((r = put_user (pattern , (uint64_t __user * ) addr ))){
776+ printk ("Failed to write data at 0x%px (%d)(base was 0x%px)\n" , addr + cnt , r , addr );
777+ return r ;
778+ }
779+ cnt += 8 ;
780+ } else {
781+ if ((r = put_user (c , (uint8_t __user * ) addr ))){
782+ printk ("Failed to write data at 0x%px (%d)(base was 0x%px)\n" , addr + cnt , r , addr );
783+ return r ;
784+ }
785+ cnt ++ ;
786+ }
787+
788+ }
789+ return r ;
790+ }
791+
759792int do_ls_fixup (u32 instr , struct pt_regs * regs , struct fixupDescription * desc ){
760793 int r ;
761794 u64 data1 [2 ] = {0 ,0 };
@@ -1216,6 +1249,60 @@ __attribute__((always_inline)) inline int ls_fixup(u32 instr, struct pt_regs *re
12161249 return r ;
12171250}
12181251
1252+ __attribute__((always_inline )) inline int system_fixup (u32 instr , struct pt_regs * regs , struct fixupDescription * desc ){
1253+ uint8_t op1 ;
1254+ uint8_t op2 ;
1255+ uint8_t CRn ;
1256+ uint8_t CRm ;
1257+ uint8_t Rt ;
1258+ bool L ;
1259+ int r = 0 ;
1260+
1261+ op1 = (instr >> 16 ) & 0x7 ;
1262+ op2 = (instr >> 5 ) & 0x7 ;
1263+ CRn = (instr >> 12 ) & 0xf ;
1264+ CRm = (instr >> 8 ) & 0xf ;
1265+ L = (instr >> 21 ) & 1 ;
1266+ Rt = instr & 0x1f ;
1267+
1268+ if (!L ){
1269+ // SYS
1270+ // proper decoding would be nicer here, but I don't expect to see too many system instructions
1271+ if ((op1 == 0x3 ) && (op2 == 1 ) && (CRn = 0x7 ) && (CRm == 4 )){
1272+ // dc zva
1273+ uint64_t dczid_el0 = read_sysreg_s (SYS_DCZID_EL0 );
1274+ if (!((dczid_el0 >> DCZID_EL0_DZP_SHIFT ) & 1 )){
1275+ uint16_t blksize = 4 << (dczid_el0 & 0xf );
1276+ r = memset_io_user (blksize , 0 , regs -> user_regs .regs [Rt ]);
1277+ arm64_skip_faulting_instruction (regs , 4 );
1278+ return r ;
1279+ } else {
1280+ printk ("DC ZVA is not allowed!\n" );
1281+ return 1 ;
1282+ }
1283+ }
1284+ }
1285+
1286+ printk ("Unhandled system instruction. op1=0x%x op2=0x%x CRn=0x%x CRm=0x%x\n" , op1 , op2 , CRn , CRm );
1287+ return 1 ;
1288+ }
1289+
1290+ __attribute__((always_inline )) inline int branch_except_system_fixup (u32 instr , struct pt_regs * regs , struct fixupDescription * desc ){
1291+ uint8_t op0 ;
1292+ uint32_t op1 ;
1293+ uint8_t op2 ;
1294+
1295+ op0 = (instr >> 29 ) & 0x7 ;
1296+ op1 = (instr >> 5 ) & 0x1fffff ;
1297+ op2 = instr & 0x1f ;
1298+
1299+ if ((op0 == 0x6 ) && (op1 & 0x1ec000 ) == 0x84000 ){
1300+ return system_fixup (instr , regs , desc );
1301+ }
1302+ printk ("Unhandled Branch/Exception generating/System instruction. op0=0x%x op1=0x%x op2=0x%x\n" , op0 , op1 , op2 );
1303+ return 1 ;
1304+ }
1305+
12191306uint32_t * seenCMDs ;
12201307size_t seenCMDCount = 0 ;
12211308size_t seenCMDSize = 0 ;
@@ -1277,8 +1364,11 @@ int do_alignment_fixup(unsigned long addr, struct pt_regs *regs){
12771364 }
12781365
12791366 return r ;
1280- } else {
1281- printk ("Not handling instruction with op0 0x%x " ,op0 );
1367+ } else if ((op0 & 0xe ) == 0xa ){
1368+ // System instructions, needed for dc zva
1369+ return branch_except_system_fixup (instr , regs , & desc );
1370+ }else {
1371+ printk ("Not handling instruction with op0 0x%x (instruction is 0x%08x)" ,op0 , instr );
12821372 }
12831373 return -1 ;
12841374}
0 commit comments