// SPDX-License-Identifier: GPL-2.0-only // Copyright (C) 2015-2021 ARM Limited. // Original author: Dave Martin // // Utility functions for assembly code. #include #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