Paul Mackerras | a6ef351 | 2005-04-22 23:08:43 -0700 | [diff] [blame] | 1 | /* |
| 2 | * SHA-1 implementation for PowerPC. |
| 3 | * |
| 4 | * Copyright (C) 2005 Paul Mackerras <paulus@samba.org> |
| 5 | */ |
Paul Mackerras | a6ef351 | 2005-04-22 23:08:43 -0700 | [diff] [blame] | 6 | |
| 7 | /* |
Unknown | 8470299 | 2006-06-24 02:31:20 -0700 | [diff] [blame] | 8 | * PowerPC calling convention: |
| 9 | * %r0 - volatile temp |
| 10 | * %r1 - stack pointer. |
| 11 | * %r2 - reserved |
| 12 | * %r3-%r12 - Incoming arguments & return values; volatile. |
| 13 | * %r13-%r31 - Callee-save registers |
| 14 | * %lr - Return address, volatile |
| 15 | * %ctr - volatile |
| 16 | * |
| 17 | * Register usage in this routine: |
| 18 | * %r0 - temp |
| 19 | * %r3 - argument (pointer to 5 words of SHA state) |
| 20 | * %r4 - argument (pointer to data to hash) |
Pavel Roskin | 3dff537 | 2007-02-03 23:49:16 -0500 | [diff] [blame] | 21 | * %r5 - Constant K in SHA round (initially number of blocks to hash) |
Unknown | 8470299 | 2006-06-24 02:31:20 -0700 | [diff] [blame] | 22 | * %r6-%r10 - Working copies of SHA variables A..E (actually E..A order) |
| 23 | * %r11-%r26 - Data being hashed W[]. |
| 24 | * %r27-%r31 - Previous copies of A..E, for final add back. |
| 25 | * %ctr - loop count |
Paul Mackerras | a6ef351 | 2005-04-22 23:08:43 -0700 | [diff] [blame] | 26 | */ |
Paul Mackerras | a6ef351 | 2005-04-22 23:08:43 -0700 | [diff] [blame] | 27 | |
Paul Mackerras | a6ef351 | 2005-04-22 23:08:43 -0700 | [diff] [blame] | 28 | |
Unknown | 8470299 | 2006-06-24 02:31:20 -0700 | [diff] [blame] | 29 | /* |
| 30 | * We roll the registers for A, B, C, D, E around on each |
| 31 | * iteration; E on iteration t is D on iteration t+1, and so on. |
| 32 | * We use registers 6 - 10 for this. (Registers 27 - 31 hold |
| 33 | * the previous values.) |
| 34 | */ |
| 35 | #define RA(t) (((t)+4)%5+6) |
| 36 | #define RB(t) (((t)+3)%5+6) |
| 37 | #define RC(t) (((t)+2)%5+6) |
| 38 | #define RD(t) (((t)+1)%5+6) |
| 39 | #define RE(t) (((t)+0)%5+6) |
Paul Mackerras | a6ef351 | 2005-04-22 23:08:43 -0700 | [diff] [blame] | 40 | |
Unknown | 8470299 | 2006-06-24 02:31:20 -0700 | [diff] [blame] | 41 | /* We use registers 11 - 26 for the W values */ |
| 42 | #define W(t) ((t)%16+11) |
Paul Mackerras | a6ef351 | 2005-04-22 23:08:43 -0700 | [diff] [blame] | 43 | |
Unknown | 8470299 | 2006-06-24 02:31:20 -0700 | [diff] [blame] | 44 | /* Register 5 is used for the constant k */ |
Paul Mackerras | a6ef351 | 2005-04-22 23:08:43 -0700 | [diff] [blame] | 45 | |
Unknown | 8470299 | 2006-06-24 02:31:20 -0700 | [diff] [blame] | 46 | /* |
| 47 | * The basic SHA-1 round function is: |
| 48 | * E += ROTL(A,5) + F(B,C,D) + W[i] + K; B = ROTL(B,30) |
| 49 | * Then the variables are renamed: (A,B,C,D,E) = (E,A,B,C,D). |
| 50 | * |
Pavel Roskin | 3dff537 | 2007-02-03 23:49:16 -0500 | [diff] [blame] | 51 | * Every 20 rounds, the function F() and the constant K changes: |
Unknown | 8470299 | 2006-06-24 02:31:20 -0700 | [diff] [blame] | 52 | * - 20 rounds of f0(b,c,d) = "bit wise b ? c : d" = (^b & d) + (b & c) |
| 53 | * - 20 rounds of f1(b,c,d) = b^c^d = (b^d)^c |
| 54 | * - 20 rounds of f2(b,c,d) = majority(b,c,d) = (b&d) + ((b^d)&c) |
| 55 | * - 20 more rounds of f1(b,c,d) |
| 56 | * |
| 57 | * These are all scheduled for near-optimal performance on a G4. |
| 58 | * The G4 is a 3-issue out-of-order machine with 3 ALUs, but it can only |
| 59 | * *consider* starting the oldest 3 instructions per cycle. So to get |
Pavel Roskin | 3dff537 | 2007-02-03 23:49:16 -0500 | [diff] [blame] | 60 | * maximum performance out of it, you have to treat it as an in-order |
Unknown | 8470299 | 2006-06-24 02:31:20 -0700 | [diff] [blame] | 61 | * machine. Which means interleaving the computation round t with the |
| 62 | * computation of W[t+4]. |
| 63 | * |
| 64 | * The first 16 rounds use W values loaded directly from memory, while the |
Pavel Roskin | 82e5a82 | 2006-07-10 01:50:18 -0400 | [diff] [blame] | 65 | * remaining 64 use values computed from those first 16. We preload |
Unknown | 8470299 | 2006-06-24 02:31:20 -0700 | [diff] [blame] | 66 | * 4 values before starting, so there are three kinds of rounds: |
| 67 | * - The first 12 (all f0) also load the W values from memory. |
| 68 | * - The next 64 compute W(i+4) in parallel. 8*f0, 20*f1, 20*f2, 16*f1. |
| 69 | * - The last 4 (all f1) do not do anything with W. |
| 70 | * |
| 71 | * Therefore, we have 6 different round functions: |
| 72 | * STEPD0_LOAD(t,s) - Perform round t and load W(s). s < 16 |
| 73 | * STEPD0_UPDATE(t,s) - Perform round t and compute W(s). s >= 16. |
| 74 | * STEPD1_UPDATE(t,s) |
| 75 | * STEPD2_UPDATE(t,s) |
| 76 | * STEPD1(t) - Perform round t with no load or update. |
| 77 | * |
| 78 | * The G5 is more fully out-of-order, and can find the parallelism |
| 79 | * by itself. The big limit is that it has a 2-cycle ALU latency, so |
| 80 | * even though it's 2-way, the code has to be scheduled as if it's |
| 81 | * 4-way, which can be a limit. To help it, we try to schedule the |
| 82 | * read of RA(t) as late as possible so it doesn't stall waiting for |
| 83 | * the previous round's RE(t-1), and we try to rotate RB(t) as early |
| 84 | * as possible while reading RC(t) (= RB(t-1)) as late as possible. |
| 85 | */ |
Paul Mackerras | a6ef351 | 2005-04-22 23:08:43 -0700 | [diff] [blame] | 86 | |
Unknown | 8470299 | 2006-06-24 02:31:20 -0700 | [diff] [blame] | 87 | /* the initial loads. */ |
| 88 | #define LOADW(s) \ |
| 89 | lwz W(s),(s)*4(%r4) |
Paul Mackerras | a6ef351 | 2005-04-22 23:08:43 -0700 | [diff] [blame] | 90 | |
Unknown | 8470299 | 2006-06-24 02:31:20 -0700 | [diff] [blame] | 91 | /* |
| 92 | * Perform a step with F0, and load W(s). Uses W(s) as a temporary |
| 93 | * before loading it. |
| 94 | * This is actually 10 instructions, which is an awkward fit. |
| 95 | * It can execute grouped as listed, or delayed one instruction. |
| 96 | * (If delayed two instructions, there is a stall before the start of the |
| 97 | * second line.) Thus, two iterations take 7 cycles, 3.5 cycles per round. |
| 98 | */ |
| 99 | #define STEPD0_LOAD(t,s) \ |
| 100 | add RE(t),RE(t),W(t); andc %r0,RD(t),RB(t); and W(s),RC(t),RB(t); \ |
| 101 | add RE(t),RE(t),%r0; rotlwi %r0,RA(t),5; rotlwi RB(t),RB(t),30; \ |
| 102 | add RE(t),RE(t),W(s); add %r0,%r0,%r5; lwz W(s),(s)*4(%r4); \ |
| 103 | add RE(t),RE(t),%r0 |
Paul Mackerras | a6ef351 | 2005-04-22 23:08:43 -0700 | [diff] [blame] | 104 | |
Unknown | 8470299 | 2006-06-24 02:31:20 -0700 | [diff] [blame] | 105 | /* |
| 106 | * This is likewise awkward, 13 instructions. However, it can also |
| 107 | * execute starting with 2 out of 3 possible moduli, so it does 2 rounds |
| 108 | * in 9 cycles, 4.5 cycles/round. |
| 109 | */ |
| 110 | #define STEPD0_UPDATE(t,s,loadk...) \ |
| 111 | add RE(t),RE(t),W(t); andc %r0,RD(t),RB(t); xor W(s),W((s)-16),W((s)-3); \ |
| 112 | add RE(t),RE(t),%r0; and %r0,RC(t),RB(t); xor W(s),W(s),W((s)-8); \ |
| 113 | add RE(t),RE(t),%r0; rotlwi %r0,RA(t),5; xor W(s),W(s),W((s)-14); \ |
| 114 | add RE(t),RE(t),%r5; loadk; rotlwi RB(t),RB(t),30; rotlwi W(s),W(s),1; \ |
| 115 | add RE(t),RE(t),%r0 |
Paul Mackerras | a6ef351 | 2005-04-22 23:08:43 -0700 | [diff] [blame] | 116 | |
Unknown | 8470299 | 2006-06-24 02:31:20 -0700 | [diff] [blame] | 117 | /* Nicely optimal. Conveniently, also the most common. */ |
| 118 | #define STEPD1_UPDATE(t,s,loadk...) \ |
| 119 | add RE(t),RE(t),W(t); xor %r0,RD(t),RB(t); xor W(s),W((s)-16),W((s)-3); \ |
| 120 | add RE(t),RE(t),%r5; loadk; xor %r0,%r0,RC(t); xor W(s),W(s),W((s)-8); \ |
| 121 | add RE(t),RE(t),%r0; rotlwi %r0,RA(t),5; xor W(s),W(s),W((s)-14); \ |
| 122 | add RE(t),RE(t),%r0; rotlwi RB(t),RB(t),30; rotlwi W(s),W(s),1 |
| 123 | |
| 124 | /* |
| 125 | * The naked version, no UPDATE, for the last 4 rounds. 3 cycles per. |
| 126 | * We could use W(s) as a temp register, but we don't need it. |
| 127 | */ |
| 128 | #define STEPD1(t) \ |
| 129 | add RE(t),RE(t),W(t); xor %r0,RD(t),RB(t); \ |
| 130 | rotlwi RB(t),RB(t),30; add RE(t),RE(t),%r5; xor %r0,%r0,RC(t); \ |
| 131 | add RE(t),RE(t),%r0; rotlwi %r0,RA(t),5; /* spare slot */ \ |
| 132 | add RE(t),RE(t),%r0 |
| 133 | |
| 134 | /* |
| 135 | * 14 instructions, 5 cycles per. The majority function is a bit |
| 136 | * awkward to compute. This can execute with a 1-instruction delay, |
| 137 | * but it causes a 2-instruction delay, which triggers a stall. |
| 138 | */ |
| 139 | #define STEPD2_UPDATE(t,s,loadk...) \ |
| 140 | add RE(t),RE(t),W(t); and %r0,RD(t),RB(t); xor W(s),W((s)-16),W((s)-3); \ |
| 141 | add RE(t),RE(t),%r0; xor %r0,RD(t),RB(t); xor W(s),W(s),W((s)-8); \ |
| 142 | add RE(t),RE(t),%r5; loadk; and %r0,%r0,RC(t); xor W(s),W(s),W((s)-14); \ |
| 143 | add RE(t),RE(t),%r0; rotlwi %r0,RA(t),5; rotlwi W(s),W(s),1; \ |
| 144 | add RE(t),RE(t),%r0; rotlwi RB(t),RB(t),30 |
| 145 | |
| 146 | #define STEP0_LOAD4(t,s) \ |
| 147 | STEPD0_LOAD(t,s); \ |
| 148 | STEPD0_LOAD((t+1),(s)+1); \ |
| 149 | STEPD0_LOAD((t)+2,(s)+2); \ |
| 150 | STEPD0_LOAD((t)+3,(s)+3) |
| 151 | |
| 152 | #define STEPUP4(fn, t, s, loadk...) \ |
| 153 | STEP##fn##_UPDATE(t,s,); \ |
| 154 | STEP##fn##_UPDATE((t)+1,(s)+1,); \ |
| 155 | STEP##fn##_UPDATE((t)+2,(s)+2,); \ |
| 156 | STEP##fn##_UPDATE((t)+3,(s)+3,loadk) |
| 157 | |
| 158 | #define STEPUP20(fn, t, s, loadk...) \ |
| 159 | STEPUP4(fn, t, s,); \ |
| 160 | STEPUP4(fn, (t)+4, (s)+4,); \ |
| 161 | STEPUP4(fn, (t)+8, (s)+8,); \ |
| 162 | STEPUP4(fn, (t)+12, (s)+12,); \ |
| 163 | STEPUP4(fn, (t)+16, (s)+16, loadk) |
Paul Mackerras | a6ef351 | 2005-04-22 23:08:43 -0700 | [diff] [blame] | 164 | |
Nicolas Pitre | 9126f00 | 2008-10-01 14:05:20 -0400 | [diff] [blame] | 165 | .globl ppc_sha1_core |
| 166 | ppc_sha1_core: |
Unknown | 8470299 | 2006-06-24 02:31:20 -0700 | [diff] [blame] | 167 | stwu %r1,-80(%r1) |
| 168 | stmw %r13,4(%r1) |
Paul Mackerras | a6ef351 | 2005-04-22 23:08:43 -0700 | [diff] [blame] | 169 | |
| 170 | /* Load up A - E */ |
Unknown | 8470299 | 2006-06-24 02:31:20 -0700 | [diff] [blame] | 171 | lmw %r27,0(%r3) |
Paul Mackerras | a6ef351 | 2005-04-22 23:08:43 -0700 | [diff] [blame] | 172 | |
| 173 | mtctr %r5 |
| 174 | |
Unknown | 8470299 | 2006-06-24 02:31:20 -0700 | [diff] [blame] | 175 | 1: |
| 176 | LOADW(0) |
| 177 | lis %r5,0x5a82 |
| 178 | mr RE(0),%r31 |
Paul Mackerras | a6ef351 | 2005-04-22 23:08:43 -0700 | [diff] [blame] | 179 | LOADW(1) |
Unknown | 8470299 | 2006-06-24 02:31:20 -0700 | [diff] [blame] | 180 | mr RD(0),%r30 |
| 181 | mr RC(0),%r29 |
Paul Mackerras | a6ef351 | 2005-04-22 23:08:43 -0700 | [diff] [blame] | 182 | LOADW(2) |
Unknown | 8470299 | 2006-06-24 02:31:20 -0700 | [diff] [blame] | 183 | ori %r5,%r5,0x7999 /* K0-19 */ |
| 184 | mr RB(0),%r28 |
Paul Mackerras | a6ef351 | 2005-04-22 23:08:43 -0700 | [diff] [blame] | 185 | LOADW(3) |
Unknown | 8470299 | 2006-06-24 02:31:20 -0700 | [diff] [blame] | 186 | mr RA(0),%r27 |
Paul Mackerras | a6ef351 | 2005-04-22 23:08:43 -0700 | [diff] [blame] | 187 | |
Unknown | 8470299 | 2006-06-24 02:31:20 -0700 | [diff] [blame] | 188 | STEP0_LOAD4(0, 4) |
| 189 | STEP0_LOAD4(4, 8) |
| 190 | STEP0_LOAD4(8, 12) |
| 191 | STEPUP4(D0, 12, 16,) |
| 192 | STEPUP4(D0, 16, 20, lis %r5,0x6ed9) |
Paul Mackerras | a6ef351 | 2005-04-22 23:08:43 -0700 | [diff] [blame] | 193 | |
Unknown | 8470299 | 2006-06-24 02:31:20 -0700 | [diff] [blame] | 194 | ori %r5,%r5,0xeba1 /* K20-39 */ |
| 195 | STEPUP20(D1, 20, 24, lis %r5,0x8f1b) |
Paul Mackerras | a6ef351 | 2005-04-22 23:08:43 -0700 | [diff] [blame] | 196 | |
Unknown | 8470299 | 2006-06-24 02:31:20 -0700 | [diff] [blame] | 197 | ori %r5,%r5,0xbcdc /* K40-59 */ |
| 198 | STEPUP20(D2, 40, 44, lis %r5,0xca62) |
Paul Mackerras | a6ef351 | 2005-04-22 23:08:43 -0700 | [diff] [blame] | 199 | |
Unknown | 8470299 | 2006-06-24 02:31:20 -0700 | [diff] [blame] | 200 | ori %r5,%r5,0xc1d6 /* K60-79 */ |
| 201 | STEPUP4(D1, 60, 64,) |
| 202 | STEPUP4(D1, 64, 68,) |
| 203 | STEPUP4(D1, 68, 72,) |
| 204 | STEPUP4(D1, 72, 76,) |
| 205 | addi %r4,%r4,64 |
Paul Mackerras | a6ef351 | 2005-04-22 23:08:43 -0700 | [diff] [blame] | 206 | STEPD1(76) |
| 207 | STEPD1(77) |
| 208 | STEPD1(78) |
| 209 | STEPD1(79) |
| 210 | |
Unknown | 8470299 | 2006-06-24 02:31:20 -0700 | [diff] [blame] | 211 | /* Add results to original values */ |
| 212 | add %r31,%r31,RE(0) |
| 213 | add %r30,%r30,RD(0) |
| 214 | add %r29,%r29,RC(0) |
| 215 | add %r28,%r28,RB(0) |
| 216 | add %r27,%r27,RA(0) |
Paul Mackerras | a6ef351 | 2005-04-22 23:08:43 -0700 | [diff] [blame] | 217 | |
Paul Mackerras | a6ef351 | 2005-04-22 23:08:43 -0700 | [diff] [blame] | 218 | bdnz 1b |
| 219 | |
Unknown | 8470299 | 2006-06-24 02:31:20 -0700 | [diff] [blame] | 220 | /* Save final hash, restore registers, and return */ |
| 221 | stmw %r27,0(%r3) |
| 222 | lmw %r13,4(%r1) |
| 223 | addi %r1,%r1,80 |
Paul Mackerras | a6ef351 | 2005-04-22 23:08:43 -0700 | [diff] [blame] | 224 | blr |