| // SPDX-License-Identifier: GPL-2.0-only | |
| // Copyright (C) 2015-2021 ARM Limited. | |
| // Original author: Dave Martin <Dave.Martin@arm.com> | |
| // | |
| // Utility functions for assembly code. | |
| #include <asm/unistd.h> | |
| #include "assembler.h" | |
| // Print a single character x0 to stdout | |
| // Clobbers x0-x2,x8 | |
| function putc | |
| str x0, [sp, #-16]! | |
| mov x0, #1 // STDOUT_FILENO | |
| mov x1, sp | |
| mov x2, #1 | |
| mov x8, #__NR_write | |
| svc #0 | |
| add sp, sp, #16 | |
| ret | |
| endfunction | |
| .globl putc | |
| // Print a NUL-terminated string starting at address x0 to stdout | |
| // Clobbers x0-x3,x8 | |
| function puts | |
| mov x1, x0 | |
| mov x2, #0 | |
| 0: ldrb w3, [x0], #1 | |
| cbz w3, 1f | |
| add x2, x2, #1 | |
| b 0b | |
| 1: mov w0, #1 // STDOUT_FILENO | |
| mov x8, #__NR_write | |
| svc #0 | |
| ret | |
| endfunction | |
| .globl puts | |
| // Print an unsigned decimal number x0 to stdout | |
| // Clobbers x0-x4,x8 | |
| function putdec | |
| mov x1, sp | |
| str x30, [sp, #-32]! // Result can't be > 20 digits | |
| mov x2, #0 | |
| strb w2, [x1, #-1]! // Write the NUL terminator | |
| mov x2, #10 | |
| 0: udiv x3, x0, x2 // div-mod loop to generate the digits | |
| msub x0, x3, x2, x0 | |
| add w0, w0, #'0' | |
| strb w0, [x1, #-1]! | |
| mov x0, x3 | |
| cbnz x3, 0b | |
| ldrb w0, [x1] | |
| cbnz w0, 1f | |
| mov w0, #'0' // Print "0" for 0, not "" | |
| strb w0, [x1, #-1]! | |
| 1: mov x0, x1 | |
| bl puts | |
| ldr x30, [sp], #32 | |
| ret | |
| endfunction | |
| .globl putdec | |
| // Print an unsigned decimal number x0 to stdout, followed by a newline | |
| // Clobbers x0-x5,x8 | |
| function putdecn | |
| mov x5, x30 | |
| bl putdec | |
| mov x0, #'\n' | |
| bl putc | |
| ret x5 | |
| endfunction | |
| .globl putdecn | |
| // Clobbers x0-x3,x8 | |
| function puthexb | |
| str x30, [sp, #-0x10]! | |
| mov w3, w0 | |
| lsr w0, w0, #4 | |
| bl puthexnibble | |
| mov w0, w3 | |
| ldr x30, [sp], #0x10 | |
| // fall through to puthexnibble | |
| endfunction | |
| .globl puthexb | |
| // Clobbers x0-x2,x8 | |
| function puthexnibble | |
| and w0, w0, #0xf | |
| cmp w0, #10 | |
| blo 1f | |
| add w0, w0, #'a' - ('9' + 1) | |
| 1: add w0, w0, #'0' | |
| b putc | |
| endfunction | |
| .globl puthexnibble | |
| // x0=data in, x1=size in, clobbers x0-x5,x8 | |
| function dumphex | |
| str x30, [sp, #-0x10]! | |
| mov x4, x0 | |
| mov x5, x1 | |
| 0: subs x5, x5, #1 | |
| b.lo 1f | |
| ldrb w0, [x4], #1 | |
| bl puthexb | |
| b 0b | |
| 1: ldr x30, [sp], #0x10 | |
| ret | |
| endfunction | |
| .globl dumphex | |
| // Trivial memory copy: copy x2 bytes, starting at address x1, to address x0. | |
| // Clobbers x0-x3 | |
| function memcpy | |
| cmp x2, #0 | |
| b.eq 1f | |
| 0: ldrb w3, [x1], #1 | |
| strb w3, [x0], #1 | |
| subs x2, x2, #1 | |
| b.ne 0b | |
| 1: ret | |
| endfunction | |
| .globl memcpy | |
| // Fill x1 bytes starting at x0 with 0xae (for canary purposes) | |
| // Clobbers x1, x2. | |
| function memfill_ae | |
| mov w2, #0xae | |
| b memfill | |
| endfunction | |
| .globl memfill_ae | |
| // Fill x1 bytes starting at x0 with 0. | |
| // Clobbers x1, x2. | |
| function memclr | |
| mov w2, #0 | |
| endfunction | |
| .globl memclr | |
| // fall through to memfill | |
| // Trivial memory fill: fill x1 bytes starting at address x0 with byte w2 | |
| // Clobbers x1 | |
| function memfill | |
| cmp x1, #0 | |
| b.eq 1f | |
| 0: strb w2, [x0], #1 | |
| subs x1, x1, #1 | |
| b.ne 0b | |
| 1: ret | |
| endfunction | |
| .globl memfill |