Patrick Georgi | 11f0079 | 2020-03-04 15:10:45 +0100 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ |
Stefan Reinauer | 1afe51a | 2011-10-26 22:11:52 +0000 | [diff] [blame] | 2 | |
| 3 | /* From glibc-2.14, sysdeps/i386/memset.c */ |
| 4 | |
| 5 | #include <string.h> |
| 6 | #include <stdint.h> |
Harshit Sharma | 51593dd | 2020-08-08 17:51:59 -0700 | [diff] [blame] | 7 | #include <stdbool.h> |
| 8 | #include <asan.h> |
Stefan Reinauer | 1afe51a | 2011-10-26 22:11:52 +0000 | [diff] [blame] | 9 | |
| 10 | typedef uint32_t op_t; |
| 11 | |
| 12 | void *memset(void *dstpp, int c, size_t len) |
| 13 | { |
| 14 | int d0; |
Elyes Haouas | 2ba796e | 2022-11-18 15:21:37 +0100 | [diff] [blame] | 15 | unsigned long int dstp = (unsigned long int)dstpp; |
Stefan Reinauer | 1afe51a | 2011-10-26 22:11:52 +0000 | [diff] [blame] | 16 | |
Arthur Heymans | a2bc254 | 2021-05-29 08:10:49 +0200 | [diff] [blame] | 17 | #if (ENV_SEPARATE_ROMSTAGE && CONFIG(ASAN_IN_ROMSTAGE)) || \ |
Harshit Sharma | 51593dd | 2020-08-08 17:51:59 -0700 | [diff] [blame] | 18 | (ENV_RAMSTAGE && CONFIG(ASAN_IN_RAMSTAGE)) |
| 19 | check_memory_region((unsigned long)dstpp, len, true, _RET_IP_); |
| 20 | #endif |
| 21 | |
Stefan Reinauer | 1afe51a | 2011-10-26 22:11:52 +0000 | [diff] [blame] | 22 | /* This explicit register allocation improves code very much indeed. */ |
| 23 | register op_t x asm("ax"); |
| 24 | |
Elyes Haouas | 2ba796e | 2022-11-18 15:21:37 +0100 | [diff] [blame] | 25 | x = (unsigned char)c; |
Stefan Reinauer | 1afe51a | 2011-10-26 22:11:52 +0000 | [diff] [blame] | 26 | |
| 27 | /* Clear the direction flag, so filling will move forward. */ |
| 28 | asm volatile("cld"); |
| 29 | |
| 30 | /* This threshold value is optimal. */ |
| 31 | if (len >= 12) { |
| 32 | /* Fill X with four copies of the char we want to fill with. */ |
| 33 | x |= (x << 8); |
| 34 | x |= (x << 16); |
| 35 | |
| 36 | /* Adjust LEN for the bytes handled in the first loop. */ |
| 37 | len -= (-dstp) % sizeof(op_t); |
| 38 | |
| 39 | /* |
| 40 | * There are at least some bytes to set. No need to test for |
| 41 | * LEN == 0 in this alignment loop. |
| 42 | */ |
| 43 | |
| 44 | /* Fill bytes until DSTP is aligned on a longword boundary. */ |
| 45 | asm volatile( |
| 46 | "rep\n" |
| 47 | "stosb" /* %0, %2, %3 */ : |
| 48 | "=D" (dstp), "=c" (d0) : |
| 49 | "0" (dstp), "1" ((-dstp) % sizeof(op_t)), "a" (x) : |
| 50 | "memory"); |
| 51 | |
| 52 | /* Fill longwords. */ |
| 53 | asm volatile( |
| 54 | "rep\n" |
| 55 | "stosl" /* %0, %2, %3 */ : |
| 56 | "=D" (dstp), "=c" (d0) : |
| 57 | "0" (dstp), "1" (len / sizeof(op_t)), "a" (x) : |
| 58 | "memory"); |
| 59 | len %= sizeof(op_t); |
| 60 | } |
| 61 | |
| 62 | /* Write the last few bytes. */ |
| 63 | asm volatile( |
| 64 | "rep\n" |
| 65 | "stosb" /* %0, %2, %3 */ : |
| 66 | "=D" (dstp), "=c" (d0) : |
| 67 | "0" (dstp), "1" (len), "a" (x) : |
| 68 | "memory"); |
| 69 | |
| 70 | return dstpp; |
| 71 | } |