Skip to content

Commit ad8261f

Browse files
Coreforgegeerlingguy
authored andcommitted
ldr, DOOM Eternal now works
1 parent f630721 commit ad8261f

File tree

1 file changed

+92
-22
lines changed

1 file changed

+92
-22
lines changed

arch/arm64/kernel/compat_alignment.c

Lines changed: 92 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -513,28 +513,47 @@ void read_simd_reg(int reg, u64 dst[2]){
513513
kernel_neon_end();
514514
}
515515

516+
517+
void write_simd_reg(int reg, u64 src[2]){
518+
519+
if(!may_use_simd()){
520+
printk("may_use_simd returned false!\n");
521+
}
522+
kernel_neon_begin();
523+
if(current->thread.sve_state){
524+
printk("SVE state is not NULL!\n");
525+
}
526+
527+
*((u64*)(&current->thread.uw.fpsimd_state.vregs[reg])) = src[0];
528+
*(((u64*)(&current->thread.uw.fpsimd_state.vregs[reg])) + 1) = src[1];
529+
530+
kernel_neon_end();
531+
}
532+
516533
int do_ls_fixup(u32 instr, struct pt_regs *regs, struct fixupDescription* desc){
517534
int r;
518-
u64 data1[2];
519-
u64 data2[2];
535+
u64 data1[2] = {0,0};
536+
u64 data2[2] = {0,0};
520537

521538
// the reg indices have to always be valid, even if the reg isn't being used
522-
if(desc->simd){
523-
// At least currently, there aren't any simd instructions supported that use more than one data register
524-
//__uint128_t tmp;
525-
526-
// probably better for performance to read both registers with one function to kernel_neon_* doesn't have to be called more than once
527-
read_simd_reg(desc->reg1, data1);
528-
read_simd_reg(desc->reg2, data2);
529-
//data1[0] = tmp;
530-
//data1[1] = *(((u64*)&tmp) + 1);
531-
///printk("SIMD: storing 0x%llx %llx (%d bits) at 0x%px", data1[1], data1[0], desc->width, desc->addr);
532-
if(desc->width < 128){
533-
return -1;
539+
if(!desc->load){
540+
if(desc->simd){
541+
// At least currently, there aren't any simd instructions supported that use more than one data register
542+
//__uint128_t tmp;
543+
544+
// probably better for performance to read both registers with one function to kernel_neon_* doesn't have to be called more than once
545+
read_simd_reg(desc->reg1, data1);
546+
read_simd_reg(desc->reg2, data2);
547+
//data1[0] = tmp;
548+
//data1[1] = *(((u64*)&tmp) + 1);
549+
///printk("SIMD: storing 0x%llx %llx (%d bits) at 0x%px", data1[1], data1[0], desc->width, desc->addr);
550+
/*if(desc->width < 128){
551+
return -1;
552+
}*/
553+
} else {
554+
data1[0] = regs->regs[desc->reg1];
555+
data2[0] = regs->regs[desc->reg2];
534556
}
535-
} else {
536-
data1[0] = regs->regs[desc->reg1];
537-
data2[0] = regs->regs[desc->reg2];
538557
}
539558

540559
/*if(desc->width > 64){
@@ -571,8 +590,54 @@ int do_ls_fixup(u32 instr, struct pt_regs *regs, struct fixupDescription* desc){
571590
}
572591
arm64_skip_faulting_instruction(regs, 4);
573592
} else {
574-
printk("Loading is currently not implemented (addr 0x%px)\n", desc->addr);
575-
return -1;
593+
//printk("Loading is currently not implemented (addr 0x%px)\n", desc->addr);
594+
595+
uint8_t* addr = desc->addr;
596+
int bcount = desc->width / 8; // since the field stores the width in bits. Honestly, there's no particular reason for that
597+
598+
//printk("Storing %d bytes (pair: %d) to 0x%llx",bcount, desc->pair, desc->addr);
599+
int addrIt = 0;
600+
for(int i = 0; i < bcount; i++){
601+
uint8_t val;
602+
if((r=get_user( val, (uint8_t __user *)addr))){
603+
printk("Failed to write data at 0x%px (base was 0x%px)\n", addr, desc->addr);
604+
return r;
605+
}
606+
*(((uint8_t*)data1) + addrIt) = val;
607+
//desc->data1 >>= 8;
608+
addrIt++;
609+
addr++;
610+
}
611+
612+
if(desc->simd){
613+
write_simd_reg(desc->reg1, data1);
614+
} else {
615+
regs->regs[desc->reg1] = data1[0];
616+
}
617+
618+
addrIt = 0;
619+
if(desc->pair){
620+
for(int i = 0; i < bcount; i++){
621+
uint8_t val;
622+
if((r=get_user(val, (uint8_t __user *)addr))){
623+
printk("Failed to write data at 0x%px (base was 0x%px)\n", addr, desc->addr);
624+
return r;
625+
}
626+
*(((uint8_t*)data2) + addrIt) = val;
627+
//desc->data2 >>= 8;
628+
addrIt++;
629+
addr++;
630+
}
631+
632+
if(desc->simd){
633+
write_simd_reg(desc->reg2, data1);
634+
} else {
635+
regs->regs[desc->reg2] = data1[0];
636+
}
637+
}
638+
arm64_skip_faulting_instruction(regs, 4);
639+
640+
576641
}
577642
return 0;
578643
}
@@ -732,7 +797,7 @@ int ls_reg_unsigned_imm(u32 instr, struct pt_regs *regs, struct fixupDescription
732797
if((size & 1) && simd && (opc & 2)){
733798
return 1;
734799
}
735-
800+
desc->load = load;
736801
desc->reg1 = Rt;
737802
desc->simd = simd;
738803
desc->extendSign = extend_sign;
@@ -848,9 +913,10 @@ int lsr_unscaled_immediate_fixup(u32 instr, struct pt_regs *regs, struct fixupDe
848913
desc->pair = 0;
849914

850915
int load = opc & 1;
851-
if(load){
916+
desc->load = load;
917+
/*if(load){
852918
return 1;
853-
}
919+
}*/
854920
desc->reg1 = Rt;
855921
if(simd){
856922
desc->simd = 1;
@@ -861,6 +927,10 @@ int lsr_unscaled_immediate_fixup(u32 instr, struct pt_regs *regs, struct fixupDe
861927
desc->data1 = tmp;
862928
desc->data1_simd = *(((u64*)&tmp) + 1);*/
863929
return do_ls_fixup(instr, regs, desc);
930+
} else {
931+
desc->simd = 0;
932+
desc->width = 8 << size;
933+
return do_ls_fixup(instr, regs, desc);
864934
}
865935
///printk("SIMD: %d\n", simd);
866936
return 1;

0 commit comments

Comments
 (0)