Commit | Line | Data |
---|---|---|
a09dac63 PMF |
1 | /* Copyright (C) 2009 Pierre-Marc Fournier |
2 | * | |
3 | * This library is free software; you can redistribute it and/or | |
4 | * modify it under the terms of the GNU Lesser General Public | |
5 | * License as published by the Free Software Foundation; either | |
6 | * version 2.1 of the License, or (at your option) any later version. | |
7 | * | |
8 | * This library is distributed in the hope that it will be useful, | |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
11 | * Lesser General Public License for more details. | |
12 | * | |
13 | * You should have received a copy of the GNU Lesser General Public | |
14 | * License along with this library; if not, write to the Free Software | |
15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
16 | */ | |
17 | ||
5af57e62 PMF |
18 | #ifndef UST_PROCESSOR_H |
19 | #define UST_PROCESSOR_H | |
d98a01c6 PMF |
20 | |
21 | #include <stddef.h> | |
636ca5d6 PMF |
22 | #include <string.h> |
23 | ||
24 | extern __thread long ust_reg_stack[500]; | |
25 | extern volatile __thread long *ust_reg_stack_ptr; | |
26 | ||
6fa0d97f | 27 | #ifdef __i386 |
d98a01c6 PMF |
28 | |
29 | struct registers { | |
7756d65a PMF |
30 | short ss; |
31 | short cs; | |
d98a01c6 | 32 | long esi; |
7756d65a PMF |
33 | long ebp; |
34 | long edx; | |
d98a01c6 | 35 | long edi; |
f2496f58 | 36 | long ecx; |
7756d65a PMF |
37 | long ebx; |
38 | long eax; | |
d98a01c6 | 39 | long eflags; |
7756d65a | 40 | long esp; |
d98a01c6 PMF |
41 | }; |
42 | ||
6fa0d97f PMF |
43 | static inline int fls(int x) |
44 | { | |
45 | int r; | |
46 | asm("bsrl %1,%0\n\t" | |
47 | "cmovzl %2,%0" | |
48 | : "=&r" (r) : "rm" (x), "rm" (-1)); | |
49 | return r + 1; | |
50 | } | |
51 | ||
e003d6ee | 52 | #ifdef CONFIG_UST_GDB_INTEGRATION |
defa46a7 | 53 | |
55c5b393 PMF |
54 | /* save_registers - saves most of the processor's registers so |
55 | * they are available to the probe. gdb uses this to give the | |
56 | * value of local variables. | |
57 | * | |
58 | * Saving all registers without losing any of their values is | |
59 | * tricky. | |
60 | * | |
61 | * We cannot pass to the asm stub the address of a registers structure | |
62 | * on the stack, because it will use a register and override its value. | |
63 | * | |
64 | * We don't want to use a stub to push the regs on the stack and then | |
65 | * another stub to copy them to a structure because changing %sp in asm | |
66 | * and then returning to C (even briefly) can have unexpected results. | |
67 | * Also, gcc might modify %sp between the stubs in reaction to the | |
68 | * register needs of the second stub that needs to know where to copy | |
69 | * the register values. | |
70 | * | |
71 | * So the chosen approach is to use another stack, declared in thread- | |
72 | * local storage, to push the registers. They are subsequently copied | |
73 | * to the stack, by C code. | |
74 | */ | |
7756d65a PMF |
75 | |
76 | #define save_registers(regsptr) \ | |
77 | asm volatile ( \ | |
78 | /* save original esp */ \ | |
79 | "pushl %%esp\n\t" \ | |
80 | /* push original eflags */ \ | |
81 | "pushfl\n\t" \ | |
82 | /* eax will hold the ptr to the private stack bottom */ \ | |
83 | "pushl %%eax\n\t" \ | |
f2496f58 | 84 | /* ebx is used for TLS access */ \ |
7756d65a | 85 | "pushl %%ebx\n\t" \ |
55c5b393 PMF |
86 | /* ecx will be used to temporarily hold the stack bottom addr */\ |
87 | "pushl %%ecx\n\t" \ | |
88 | /* rdi is the input to __tls_get_addr, and also a temp var */ \ | |
89 | "pushl %%edi\n\t" \ | |
90 | /* For TLS access, we have to do function calls. However, \ | |
91 | * we must not lose the original value of: \ | |
92 | * esp, eflags, eax, ebx, ecx, edx, esi, edi, ebp, cs, ss \ | |
93 | * \ | |
94 | * Some registers' original values have already been saved: \ | |
95 | * esp, eflags, eax, ebx, ecx, edi \ | |
96 | * \ | |
97 | * In addition, the i386 ABI says the following registers belong\ | |
98 | * to the caller function: \ | |
99 | * esp, ebp, esi, edi, ebx \ | |
100 | * \ | |
101 | * The following registers should not be changed by the callee: \ | |
102 | * cs, ss \ | |
103 | * \ | |
104 | * Therefore, the following registers must be explicitly \ | |
105 | * preserved: \ | |
106 | * edx \ | |
107 | */ \ | |
108 | "pushl %%edx\n\t" \ | |
f2496f58 PMF |
109 | /* Get GOT address */ \ |
110 | "call __i686.get_pc_thunk.bx\n\t" \ | |
111 | "addl $_GLOBAL_OFFSET_TABLE_, %%ebx\n\t" \ | |
7756d65a PMF |
112 | /* Start TLS access of private reg stack pointer */ \ |
113 | "leal ust_reg_stack_ptr@tlsgd(,%%ebx,1),%%eax\n\t" \ | |
114 | "call ___tls_get_addr@plt\n\t" \ | |
115 | /* --- End TLS access */ \ | |
116 | /* check if ust_reg_stack_ptr has been initialized */ \ | |
f2496f58 PMF |
117 | "movl (%%eax),%%ecx\n\t" \ |
118 | "testl %%ecx,%%ecx\n\t" \ | |
7756d65a | 119 | "jne 1f\n\t" \ |
f2496f58 | 120 | "movl %%eax,%%ecx\n\t" \ |
55c5b393 | 121 | /* Save ecx because we are using it. */ \ |
f2496f58 | 122 | "pushl %%ecx\n\t" \ |
7756d65a PMF |
123 | /* Start TLS access of private reg stack */ \ |
124 | "leal ust_reg_stack@tlsgd(,%%ebx,1),%%eax\n\t" \ | |
125 | "call ___tls_get_addr@plt\n\t" \ | |
126 | /* --- End TLS access */ \ | |
f2496f58 | 127 | "popl %%ecx\n\t" \ |
7756d65a | 128 | "addl $500,%%eax\n\t" \ |
f2496f58 PMF |
129 | "movl %%eax,(%%ecx)\n\t" \ |
130 | "movl %%ecx,%%eax\n\t" \ | |
7756d65a PMF |
131 | /* now the pointer to the private stack is in eax. \ |
132 | must add stack size so the ptr points to the stack bottom. */ \ | |
133 | "1:\n\t" \ | |
55c5b393 PMF |
134 | /* edx was pushed for function calls */ \ |
135 | "popl %%edx\n\t" \ | |
7756d65a PMF |
136 | /* Manually push esp to private stack */ \ |
137 | "addl $-4,(%%eax)\n\t" \ | |
f2496f58 | 138 | "movl 20(%%esp), %%edi\n\t" \ |
7756d65a PMF |
139 | "movl (%%eax), %%ebx\n\t" \ |
140 | "movl %%edi, (%%ebx)\n\t" \ | |
141 | /* Manually push eflags to private stack */ \ | |
142 | "addl $-4,(%%eax)\n\t" \ | |
f2496f58 | 143 | "movl 16(%%esp), %%edi\n\t" \ |
7756d65a PMF |
144 | "movl (%%eax), %%ebx\n\t" \ |
145 | "movl %%edi, (%%ebx)\n\t" \ | |
146 | /* Manually push eax to private stack */ \ | |
147 | "addl $-4,(%%eax)\n\t" \ | |
f2496f58 | 148 | "movl 12(%%esp), %%edi\n\t" \ |
7756d65a PMF |
149 | "movl (%%eax), %%ebx\n\t" \ |
150 | "movl %%edi, (%%ebx)\n\t" \ | |
151 | /* Manually push ebx to private stack */ \ | |
152 | "addl $-4,(%%eax)\n\t" \ | |
f2496f58 PMF |
153 | "movl 8(%%esp), %%edi\n\t" \ |
154 | "movl (%%eax), %%ebx\n\t" \ | |
155 | "movl %%edi, (%%ebx)\n\t" \ | |
156 | /* Manually push ecx to private stack */ \ | |
157 | "addl $-4,(%%eax)\n\t" \ | |
7756d65a PMF |
158 | "movl 4(%%esp), %%edi\n\t" \ |
159 | "movl (%%eax), %%ebx\n\t" \ | |
160 | "movl %%edi, (%%ebx)\n\t" \ | |
161 | /* Manually push edi to private stack */ \ | |
162 | "addl $-4,(%%eax)\n\t" \ | |
163 | "movl 0(%%esp), %%edi\n\t" \ | |
164 | "movl (%%eax), %%ebx\n\t" \ | |
165 | "movl %%edi, (%%ebx)\n\t" \ | |
166 | /* now push regs to tls */ \ | |
167 | /* -- esp already pushed -- */ \ | |
168 | /* -- eax already pushed -- */ \ | |
169 | /* -- ebx already pushed -- */ \ | |
f2496f58 | 170 | /* -- ecx already pushed -- */ \ |
7756d65a PMF |
171 | /* -- edi already pushed -- */ \ |
172 | "addl $-4,(%%eax)\n\t" \ | |
173 | "movl (%%eax), %%ebx\n\t" \ | |
7756d65a PMF |
174 | "movl %%edx,(%%ebx)\n\t" \ |
175 | "addl $-4,(%%eax)\n\t" \ | |
176 | "movl (%%eax), %%ebx\n\t" \ | |
177 | "movl %%ebp,(%%ebx)\n\t" \ | |
178 | "addl $-4,(%%eax)\n\t" \ | |
179 | "movl (%%eax), %%ebx\n\t" \ | |
180 | "movl %%esi,(%%ebx)\n\t" \ | |
181 | /* push cs */ \ | |
182 | "addl $-2,(%%eax)\n\t" \ | |
183 | "movl (%%eax), %%ebx\n\t" \ | |
184 | "movw %%cs, (%%ebx)\n\t" \ | |
185 | /* push ss */ \ | |
186 | "addl $-2,(%%eax)\n\t" \ | |
187 | "movl (%%eax), %%ebx\n\t" \ | |
188 | "movw %%ss, (%%ebx)\n\t" \ | |
189 | /* restore original values of regs that were used internally */ \ | |
190 | "popl %%edi\n\t" \ | |
f2496f58 | 191 | "popl %%ecx\n\t" \ |
7756d65a PMF |
192 | "popl %%ebx\n\t" \ |
193 | "popl %%eax\n\t" \ | |
194 | /* cancel push of rsp */ \ | |
195 | "addl $4,%%esp\n\t" \ | |
196 | /* cancel push of eflags */ \ | |
197 | "addl $4,%%esp\n\t" \ | |
198 | ::: "memory"); \ | |
199 | memcpy(regsptr, (void *)ust_reg_stack_ptr, sizeof(struct registers)); \ | |
200 | ust_reg_stack_ptr = (void *)(((long)ust_reg_stack_ptr) + sizeof(struct registers)); | |
defa46a7 | 201 | |
e003d6ee | 202 | #else /* CONFIG_UST_GDB_INTEGRATION */ |
defa46a7 | 203 | |
defa46a7 PMF |
204 | #define save_registers(a) |
205 | ||
e003d6ee | 206 | #endif /* CONFIG_UST_GDB_INTEGRATION */ |
d98a01c6 | 207 | |
9e8f4f52 PMF |
208 | #define RELATIVE_ADDRESS(__rel_label__) __rel_label__ |
209 | ||
6fa0d97f | 210 | #define ARCH_COPY_ADDR(dst) "lea 2b," dst "\n\t" |
9692fa18 | 211 | |
9e8f4f52 PMF |
212 | #define _ASM_PTR ".long " |
213 | ||
6fa0d97f PMF |
214 | #endif /* below is code for x86-64 */ |
215 | ||
216 | #ifdef __x86_64 | |
d98a01c6 PMF |
217 | |
218 | struct registers { | |
636ca5d6 PMF |
219 | int padding; /* 4 bytes */ |
220 | short ss; | |
221 | short cs; | |
636ca5d6 PMF |
222 | unsigned long r15; |
223 | unsigned long r14; | |
224 | unsigned long r13; | |
225 | unsigned long r12; | |
226 | unsigned long r11; | |
227 | unsigned long r10; | |
228 | unsigned long r9; | |
229 | unsigned long r8; | |
d98a01c6 | 230 | unsigned long rsi; |
636ca5d6 PMF |
231 | unsigned long rbp; |
232 | unsigned long rdx; | |
233 | unsigned long rcx; | |
d98a01c6 | 234 | unsigned long rdi; |
636ca5d6 PMF |
235 | unsigned long rbx; |
236 | unsigned long rax; | |
a5850bc4 | 237 | unsigned long rflags; |
636ca5d6 | 238 | unsigned long rsp; |
d98a01c6 PMF |
239 | }; |
240 | ||
6fa0d97f PMF |
241 | static inline int fls(int x) |
242 | { | |
243 | int r; | |
244 | asm("bsrl %1,%0\n\t" | |
245 | "cmovzl %2,%0" | |
246 | : "=&r" (r) : "rm" (x), "rm" (-1)); | |
247 | return r + 1; | |
248 | } | |
249 | ||
e003d6ee | 250 | #ifdef CONFIG_UST_GDB_INTEGRATION |
defa46a7 | 251 | |
8524c98d | 252 | #define save_registers(regsptr) \ |
636ca5d6 PMF |
253 | asm volatile ( \ |
254 | /* save original rsp */ \ | |
255 | "pushq %%rsp\n\t" \ | |
a5850bc4 PMF |
256 | /* push original rflags */ \ |
257 | "pushfq\n\t" \ | |
636ca5d6 PMF |
258 | /* rax will hold the ptr to the private stack bottom */ \ |
259 | "pushq %%rax\n\t" \ | |
260 | /* rbx will be used to temporarily hold the stack bottom addr */ \ | |
261 | "pushq %%rbx\n\t" \ | |
262 | /* rdi is the input to __tls_get_addr, and also a temp var */ \ | |
263 | "pushq %%rdi\n\t" \ | |
55c5b393 PMF |
264 | /* For TLS access, we have to do function calls. However, \ |
265 | * we must not lose the original value of: \ | |
266 | * rsp, rflags, rax, rbx, rcx, rdx, rsi, rdi, rbp, r8, r9 \ | |
267 | * r10, r11, r12, r13, r14, r15, cs, ss \ | |
268 | * \ | |
269 | * Some registers' original values have already been saved: \ | |
270 | * rsp, rflags, rax, rbx, rdi \ | |
271 | * \ | |
272 | * In addition, the x86-64 ABI says the following registers \ | |
273 | * belong to the caller function: \ | |
274 | * rbp, rbx, r12, r13, r14, r15 \ | |
275 | * \ | |
276 | * The following registers should not be changed by the callee: \ | |
277 | * cs, ss \ | |
278 | * \ | |
279 | * Therefore, the following registers must be explicitly \ | |
280 | * preserved: \ | |
281 | * rcx, rdx, rsi, r8, r9, r10, r11 \ | |
282 | */ \ | |
283 | "pushq %%rcx\n\t" \ | |
284 | "pushq %%rdx\n\t" \ | |
285 | "pushq %%rsi\n\t" \ | |
286 | "pushq %%r8\n\t" \ | |
287 | "pushq %%r9\n\t" \ | |
288 | "pushq %%r10\n\t" \ | |
289 | "pushq %%r11\n\t" \ | |
a5850bc4 | 290 | /* Start TLS access of private reg stack pointer */ \ |
636ca5d6 PMF |
291 | ".byte 0x66\n\t" \ |
292 | "leaq ust_reg_stack_ptr@tlsgd(%%rip), %%rdi\n\t" \ | |
293 | ".word 0x6666\n\t" \ | |
294 | "rex64\n\t" \ | |
295 | "call __tls_get_addr@plt\n\t" \ | |
296 | /* --- End TLS access */ \ | |
a5850bc4 PMF |
297 | /* check if ust_reg_stack_ptr has been initialized */ \ |
298 | "movq (%%rax),%%rbx\n\t" \ | |
299 | "testq %%rbx,%%rbx\n\t" \ | |
300 | "jne 1f\n\t" \ | |
301 | "movq %%rax,%%rbx\n\t" \ | |
302 | /* Start TLS access of private reg stack */ \ | |
303 | ".byte 0x66\n\t" \ | |
304 | "leaq ust_reg_stack@tlsgd(%%rip), %%rdi\n\t" \ | |
305 | ".word 0x6666\n\t" \ | |
306 | "rex64\n\t" \ | |
307 | "call __tls_get_addr@plt\n\t" \ | |
308 | /* --- End TLS access */ \ | |
309 | "addq $500,%%rax\n\t" \ | |
310 | "movq %%rax,(%%rbx)\n\t" \ | |
311 | "movq %%rbx,%%rax\n\t" \ | |
312 | /* now the pointer to the private stack is in rax. | |
313 | must add stack size so the ptr points to the stack bottom. */ \ | |
314 | "1:\n\t" \ | |
55c5b393 PMF |
315 | /* Pop regs that were pushed for function calls */ \ |
316 | "popq %%r11\n\t" \ | |
317 | "popq %%r10\n\t" \ | |
318 | "popq %%r9\n\t" \ | |
319 | "popq %%r8\n\t" \ | |
320 | "popq %%rsi\n\t" \ | |
321 | "popq %%rdx\n\t" \ | |
322 | "popq %%rcx\n\t" \ | |
636ca5d6 PMF |
323 | /* Manually push rsp to private stack */ \ |
324 | "addq $-8,(%%rax)\n\t" \ | |
a5850bc4 PMF |
325 | "movq 32(%%rsp), %%rdi\n\t" \ |
326 | "movq (%%rax), %%rbx\n\t" \ | |
327 | "movq %%rdi, (%%rbx)\n\t" \ | |
328 | /* Manually push eflags to private stack */ \ | |
329 | "addq $-8,(%%rax)\n\t" \ | |
636ca5d6 PMF |
330 | "movq 24(%%rsp), %%rdi\n\t" \ |
331 | "movq (%%rax), %%rbx\n\t" \ | |
332 | "movq %%rdi, (%%rbx)\n\t" \ | |
333 | /* Manually push rax to private stack */ \ | |
334 | "addq $-8,(%%rax)\n\t" \ | |
335 | "movq 16(%%rsp), %%rdi\n\t" \ | |
336 | "movq (%%rax), %%rbx\n\t" \ | |
337 | "movq %%rdi, (%%rbx)\n\t" \ | |
338 | /* Manually push rbx to private stack */ \ | |
339 | "addq $-8,(%%rax)\n\t" \ | |
340 | "movq 8(%%rsp), %%rdi\n\t" \ | |
341 | "movq (%%rax), %%rbx\n\t" \ | |
342 | "movq %%rdi, (%%rbx)\n\t" \ | |
343 | /* Manually push rdi to private stack */ \ | |
344 | "addq $-8,(%%rax)\n\t" \ | |
345 | "movq 0(%%rsp), %%rdi\n\t" \ | |
346 | "movq (%%rax), %%rbx\n\t" \ | |
347 | "movq %%rdi, (%%rbx)\n\t" \ | |
348 | /* now push regs to tls */ \ | |
349 | /* -- rsp already pushed -- */ \ | |
350 | /* -- rax already pushed -- */ \ | |
351 | /* -- rbx already pushed -- */ \ | |
352 | /* -- rdi already pushed -- */ \ | |
353 | "addq $-8,(%%rax)\n\t" \ | |
354 | "movq (%%rax), %%rbx\n\t" \ | |
355 | "movq %%rcx,(%%rbx)\n\t" \ | |
356 | "addq $-8,(%%rax)\n\t" \ | |
357 | "movq (%%rax), %%rbx\n\t" \ | |
358 | "movq %%rdx,(%%rbx)\n\t" \ | |
359 | "addq $-8,(%%rax)\n\t" \ | |
360 | "movq (%%rax), %%rbx\n\t" \ | |
361 | "movq %%rbp,(%%rbx)\n\t" \ | |
362 | "addq $-8,(%%rax)\n\t" \ | |
363 | "movq (%%rax), %%rbx\n\t" \ | |
364 | "movq %%rsi,(%%rbx)\n\t" \ | |
365 | "addq $-8,(%%rax)\n\t" \ | |
366 | "movq (%%rax), %%rbx\n\t" \ | |
367 | "movq %%r8,(%%rbx)\n\t" \ | |
368 | "addq $-8,(%%rax)\n\t" \ | |
369 | "movq (%%rax), %%rbx\n\t" \ | |
370 | "movq %%r9,(%%rbx)\n\t" \ | |
371 | "addq $-8,(%%rax)\n\t" \ | |
372 | "movq (%%rax), %%rbx\n\t" \ | |
373 | "movq %%r10,(%%rbx)\n\t" \ | |
374 | "addq $-8,(%%rax)\n\t" \ | |
375 | "movq (%%rax), %%rbx\n\t" \ | |
376 | "movq %%r11,(%%rbx)\n\t" \ | |
377 | "addq $-8,(%%rax)\n\t" \ | |
378 | "movq (%%rax), %%rbx\n\t" \ | |
379 | "movq %%r12,(%%rbx)\n\t" \ | |
380 | "addq $-8,(%%rax)\n\t" \ | |
381 | "movq (%%rax), %%rbx\n\t" \ | |
382 | "movq %%r13,(%%rbx)\n\t" \ | |
383 | "addq $-8,(%%rax)\n\t" \ | |
384 | "movq (%%rax), %%rbx\n\t" \ | |
385 | "movq %%r14,(%%rbx)\n\t" \ | |
386 | "addq $-8,(%%rax)\n\t" \ | |
387 | "movq (%%rax), %%rbx\n\t" \ | |
388 | "movq %%r15,(%%rbx)\n\t" \ | |
636ca5d6 PMF |
389 | /* push cs */ \ |
390 | "addq $-2,(%%rax)\n\t" \ | |
391 | "movq (%%rax), %%rbx\n\t" \ | |
392 | "movw %%cs, (%%rbx)\n\t" \ | |
393 | /* push ss */ \ | |
394 | "addq $-2,(%%rax)\n\t" \ | |
395 | "movq (%%rax), %%rbx\n\t" \ | |
396 | "movw %%ss, (%%rbx)\n\t" \ | |
397 | /* add padding for struct registers */ \ | |
398 | "addq $-4,(%%rax)\n\t" \ | |
399 | /* restore original values of regs that were used internally */ \ | |
400 | "popq %%rdi\n\t" \ | |
401 | "popq %%rbx\n\t" \ | |
402 | "popq %%rax\n\t" \ | |
403 | /* cancel push of rsp */ \ | |
404 | "addq $8,%%rsp\n\t" \ | |
a5850bc4 PMF |
405 | /* cancel push of rflags */ \ |
406 | "addq $8,%%rsp\n\t" \ | |
636ca5d6 PMF |
407 | ::); \ |
408 | memcpy(regsptr, (void *)ust_reg_stack_ptr, sizeof(struct registers)); \ | |
409 | ust_reg_stack_ptr = (void *)(((long)ust_reg_stack_ptr) + sizeof(struct registers)); | |
d98a01c6 | 410 | |
fc1f31ab PMF |
411 | #else /* CONFIG_UST_GDB_INTEGRATION */ |
412 | ||
fc1f31ab PMF |
413 | #define save_registers(a) |
414 | ||
e003d6ee | 415 | #endif /* CONFIG_UST_GDB_INTEGRATION */ |
defa46a7 | 416 | |
9e8f4f52 PMF |
417 | /* Macro to insert the address of a relative jump in an assembly stub, |
418 | * in a relocatable way. On x86-64, this uses a special (%rip) notation. */ | |
419 | #define RELATIVE_ADDRESS(__rel_label__) __rel_label__(%%rip) | |
420 | ||
6fa0d97f | 421 | #define ARCH_COPY_ADDR(dst) "lea 2b(%%rip)," dst "\n\t" |
9692fa18 | 422 | |
9e8f4f52 PMF |
423 | #define _ASM_PTR ".quad " |
424 | ||
6fa0d97f PMF |
425 | #endif /* x86_64 */ |
426 | ||
427 | #ifdef __PPC__ | |
428 | ||
429 | struct registers { | |
430 | }; | |
431 | ||
432 | static __inline__ int fls(unsigned int x) | |
433 | { | |
434 | int lz; | |
435 | ||
436 | asm ("cntlzw %0,%1" : "=r" (lz) : "r" (x)); | |
437 | return 32 - lz; | |
438 | } | |
439 | ||
440 | #define ARCH_COPY_ADDR(dst) \ | |
441 | "lis " dst ",2b@h\n\t" /* load high bytes */ \ | |
442 | "ori " dst "," dst ",2b@l\n\t" /* load low bytes */ | |
443 | ||
444 | #define _ASM_PTR ".long " | |
445 | #define save_registers(a) | |
446 | ||
447 | #endif /* __PPC__ */ | |
d98a01c6 | 448 | |
5af57e62 | 449 | #endif /* UST_PROCESSOR_H */ |