@@ -515,28 +515,47 @@ void read_simd_reg(int reg, u64 dst[2]){
515515 kernel_neon_end ();
516516}
517517
518+
519+ void write_simd_reg (int reg , u64 src [2 ]){
520+
521+ if (!may_use_simd ()){
522+ printk ("may_use_simd returned false!\n" );
523+ }
524+ kernel_neon_begin ();
525+ if (current -> thread .sve_state ){
526+ printk ("SVE state is not NULL!\n" );
527+ }
528+
529+ * ((u64 * )(& current -> thread .uw .fpsimd_state .vregs [reg ])) = src [0 ];
530+ * (((u64 * )(& current -> thread .uw .fpsimd_state .vregs [reg ])) + 1 ) = src [1 ];
531+
532+ kernel_neon_end ();
533+ }
534+
518535int do_ls_fixup (u32 instr , struct pt_regs * regs , struct fixupDescription * desc ){
519536 int r ;
520- u64 data1 [2 ];
521- u64 data2 [2 ];
537+ u64 data1 [2 ] = { 0 , 0 } ;
538+ u64 data2 [2 ] = { 0 , 0 } ;
522539
523540 // the reg indices have to always be valid, even if the reg isn't being used
524- if (desc -> simd ){
525- // At least currently, there aren't any simd instructions supported that use more than one data register
526- //__uint128_t tmp;
527-
528- // probably better for performance to read both registers with one function to kernel_neon_* doesn't have to be called more than once
529- read_simd_reg (desc -> reg1 , data1 );
530- read_simd_reg (desc -> reg2 , data2 );
531- //data1[0] = tmp;
532- //data1[1] = *(((u64*)&tmp) + 1);
533- ///printk("SIMD: storing 0x%llx %llx (%d bits) at 0x%px", data1[1], data1[0], desc->width, desc->addr);
534- if (desc -> width < 128 ){
535- return -1 ;
541+ if (!desc -> load ){
542+ if (desc -> simd ){
543+ // At least currently, there aren't any simd instructions supported that use more than one data register
544+ //__uint128_t tmp;
545+
546+ // probably better for performance to read both registers with one function to kernel_neon_* doesn't have to be called more than once
547+ read_simd_reg (desc -> reg1 , data1 );
548+ read_simd_reg (desc -> reg2 , data2 );
549+ //data1[0] = tmp;
550+ //data1[1] = *(((u64*)&tmp) + 1);
551+ ///printk("SIMD: storing 0x%llx %llx (%d bits) at 0x%px", data1[1], data1[0], desc->width, desc->addr);
552+ /*if(desc->width < 128){
553+ return -1;
554+ }*/
555+ } else {
556+ data1 [0 ] = regs -> regs [desc -> reg1 ];
557+ data2 [0 ] = regs -> regs [desc -> reg2 ];
536558 }
537- } else {
538- data1 [0 ] = regs -> regs [desc -> reg1 ];
539- data2 [0 ] = regs -> regs [desc -> reg2 ];
540559 }
541560
542561 /*if(desc->width > 64){
@@ -573,8 +592,54 @@ int do_ls_fixup(u32 instr, struct pt_regs *regs, struct fixupDescription* desc){
573592 }
574593 arm64_skip_faulting_instruction (regs , 4 );
575594 } else {
576- printk ("Loading is currently not implemented (addr 0x%px)\n" , desc -> addr );
577- return -1 ;
595+ //printk("Loading is currently not implemented (addr 0x%px)\n", desc->addr);
596+
597+ uint8_t * addr = desc -> addr ;
598+ int bcount = desc -> width / 8 ; // since the field stores the width in bits. Honestly, there's no particular reason for that
599+
600+ //printk("Storing %d bytes (pair: %d) to 0x%llx",bcount, desc->pair, desc->addr);
601+ int addrIt = 0 ;
602+ for (int i = 0 ; i < bcount ; i ++ ){
603+ uint8_t val ;
604+ if ((r = get_user ( val , (uint8_t __user * )addr ))){
605+ printk ("Failed to write data at 0x%px (base was 0x%px)\n" , addr , desc -> addr );
606+ return r ;
607+ }
608+ * (((uint8_t * )data1 ) + addrIt ) = val ;
609+ //desc->data1 >>= 8;
610+ addrIt ++ ;
611+ addr ++ ;
612+ }
613+
614+ if (desc -> simd ){
615+ write_simd_reg (desc -> reg1 , data1 );
616+ } else {
617+ regs -> regs [desc -> reg1 ] = data1 [0 ];
618+ }
619+
620+ addrIt = 0 ;
621+ if (desc -> pair ){
622+ for (int i = 0 ; i < bcount ; i ++ ){
623+ uint8_t val ;
624+ if ((r = get_user (val , (uint8_t __user * )addr ))){
625+ printk ("Failed to write data at 0x%px (base was 0x%px)\n" , addr , desc -> addr );
626+ return r ;
627+ }
628+ * (((uint8_t * )data2 ) + addrIt ) = val ;
629+ //desc->data2 >>= 8;
630+ addrIt ++ ;
631+ addr ++ ;
632+ }
633+
634+ if (desc -> simd ){
635+ write_simd_reg (desc -> reg2 , data1 );
636+ } else {
637+ regs -> regs [desc -> reg2 ] = data1 [0 ];
638+ }
639+ }
640+ arm64_skip_faulting_instruction (regs , 4 );
641+
642+
578643 }
579644 return 0 ;
580645}
@@ -734,7 +799,7 @@ int ls_reg_unsigned_imm(u32 instr, struct pt_regs *regs, struct fixupDescription
734799 if ((size & 1 ) && simd && (opc & 2 )){
735800 return 1 ;
736801 }
737-
802+ desc -> load = load ;
738803 desc -> reg1 = Rt ;
739804 desc -> simd = simd ;
740805 desc -> extendSign = extend_sign ;
@@ -850,9 +915,10 @@ int lsr_unscaled_immediate_fixup(u32 instr, struct pt_regs *regs, struct fixupDe
850915 desc -> pair = 0 ;
851916
852917 int load = opc & 1 ;
853- if (load ){
918+ desc -> load = load ;
919+ /*if(load){
854920 return 1;
855- }
921+ }*/
856922 desc -> reg1 = Rt ;
857923 if (simd ){
858924 desc -> simd = 1 ;
@@ -863,6 +929,10 @@ int lsr_unscaled_immediate_fixup(u32 instr, struct pt_regs *regs, struct fixupDe
863929 desc->data1 = tmp;
864930 desc->data1_simd = *(((u64*)&tmp) + 1);*/
865931 return do_ls_fixup (instr , regs , desc );
932+ } else {
933+ desc -> simd = 0 ;
934+ desc -> width = 8 << size ;
935+ return do_ls_fixup (instr , regs , desc );
866936 }
867937 ///printk("SIMD: %d\n", simd);
868938 return 1 ;
0 commit comments