1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
| ENTRY(__asm_copy_to_user) ENTRY(__asm_copy_from_user)
/* Enable access to user memory */ li t6, SR_SUM csrs CSR_STATUS, t6
/* 如上,a0是用户态目的地址,a1是内核buffer的地址, a2是要copy的size,a3是源数据buffer的结尾 */ add a3, a1, a2 /* Use word-oriented copy only if low-order bits match */ /* 64bit的系统,SZREG是8,t0得到目的地址的低3bit,t1得到源地址的低3bit */ andi t0, a0, SZREG-1 andi t1, a1, SZREG-1 /* * 目的地址和源地址低3bit不相等的时候,跳到label 2,有数据要拷贝的时候, * 会直接跳到label 5, label 5本来是拷贝非8Byte数据的,但是,在源数据buffer * 和目的数据buffer地址不对应的情况,直接在label 5用单Byte拷贝的方式复制 * 整段内存。 */ bne t0, t1, 2f
/* * 对于源数据buffer,下面每一段表示8B,那么t0和t1的志向的位置如下: * * | 8B | | | | | * +-------+-------+-------+-------+-------+ * | ^ | | | ^ | | * | | * +------------------------+ * | ^ ^ | 源数据buffer * | | * a1 a3 * t0 t1 * * 如下这块代码的逻辑是找到源数据buffer中整8Byte的部分,t0指向起始地址, * t1指向结尾地址。 */ addi t0, a1, SZREG-1 andi t1, a3, ~(SZREG-1) andi t0, t0, ~(SZREG-1) /* * a3: terminal address of source region * t0: lowest XLEN-aligned address in source * t1: highest XLEN-aligned address in source */ /* * t0 >= t1是一些边角的情况,跳到label 2,有数据要拷贝的时候,再跳到label 5 * 做单Byte拷贝。过了这个点后,下面是拷贝算法的主题逻辑。 */ bgeu t0, t1, 2f /* a1 < t0说明有t0前面多出来的那一截,跳到label 4,单Byte拷贝结尾这段非对齐数据 */ bltu a1, t0, 4f 1: /* * fixup宏的定义是: * * .macro fixup op reg addr lbl * 100: * \op \reg, \addr * .section __ex_table,"a" * .balign RISCV_SZPTR * RISCV_PTR 100b, \lbl * .previous * .endm * * 这个宏生成了一个指令,上下文看来,一般是生成load或者store指令,然后在 * __ex_table这个段生成一个dword大小(8B)的数据,这个数据的格式是低4B是之前 * 生成指令的地址,高4B是一个跳转的label。当load/store有异常发生的时候, * 异常处理函数在__ex_table中找到对应的地址,高32bit保存就是要继续跳转的 * 地址,这里是继续跳转到label 10的地方,函数返回值配置成数据搬移的size, * 然后函数返回。 * * 相关的流程是:各种访存异常处理函数(e.g. do_trap_load_misaligned)->do_trap_error->fixup_exception * 在fixup_exception里配置regs->epc为fixup代码地址(label 10地址),然后调用 * sret跳到对应地址执行。这里怎么和异常恢复结合起来?还会有什么异常? */ fixup REG_L, t2, (a1), 10f fixup REG_S, t2, (a0), 10f addi a1, a1, SZREG addi a0, a0, SZREG bltu a1, t1, 1b 2: bltu a1, a3, 5f
3: /* Disable access to user memory */ csrc CSR_STATUS, t6 li a0, 0 ret 4: /* Edge case: unalignment */ fixup lbu, t2, (a1), 10f fixup sb, t2, (a0), 10f addi a1, a1, 1 addi a0, a0, 1 bltu a1, t0, 4b /* 拷贝完前面一截非8Byte对齐的数据,跳到label 1以8Byte为单位复制数据 */ j 1b 5: /* Edge case: remainder */ fixup lbu, t2, (a1), 10f fixup sb, t2, (a0), 10f addi a1, a1, 1 addi a0, a0, 1 bltu a1, a3, 5b j 3b ENDPROC(__asm_copy_to_user) ENDPROC(__asm_copy_from_user) EXPORT_SYMBOL(__asm_copy_to_user) EXPORT_SYMBOL(__asm_copy_from_user) [...] 10: /* Disable access to user memory */ csrs CSR_STATUS, t6 mv a0, a2 ret
|