VirtualBox

source: vbox/trunk/include/iprt/asm-mem.h

Last change on this file was 103025, checked in by vboxsync, 4 months ago

*: Replaced some ASMMemZero32 uses with RT_BZERO. bugref:10588

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.3 KB
Line 
1/** @file
2 * IPRT - Assembly Memory Functions.
3 */
4
5/*
6 * Copyright (C) 2006-2024 Oracle and/or its affiliates.
7 *
8 * This file is part of VirtualBox base platform packages, as
9 * available from https://www.virtualbox.org.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation, in version 3 of the
14 * License.
15 *
16 * This program is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, see <https://www.gnu.org/licenses>.
23 *
24 * The contents of this file may alternatively be used under the terms
25 * of the Common Development and Distribution License Version 1.0
26 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
27 * in the VirtualBox distribution, in which case the provisions of the
28 * CDDL are applicable instead of those of the GPL.
29 *
30 * You may elect to license modified versions of this file under the
31 * terms and conditions of either the GPL or the CDDL or both.
32 *
33 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
34 */
35
36#ifndef IPRT_INCLUDED_asm_mem_h
37#define IPRT_INCLUDED_asm_mem_h
38#ifndef RT_WITHOUT_PRAGMA_ONCE
39# pragma once
40#endif
41
42#include <iprt/cdefs.h>
43#include <iprt/types.h>
44#include <iprt/assert.h>
45
46#if defined(_MSC_VER) && RT_INLINE_ASM_USES_INTRIN
47/* Emit the intrinsics at all optimization levels. */
48# include <iprt/sanitized/intrin.h>
49# pragma intrinsic(__cpuid)
50# pragma intrinsic(__stosd)
51# pragma intrinsic(__stosw)
52# pragma intrinsic(__stosb)
53# ifdef RT_ARCH_AMD64
54# pragma intrinsic(__stosq)
55# endif
56#endif
57
58
59/*
60 * Undefine all symbols we have Watcom C/C++ #pragma aux'es for.
61 */
62#if defined(__WATCOMC__) && ARCH_BITS == 16 && defined(RT_ARCH_X86)
63# include "asm-mem-watcom-x86-16.h"
64#elif defined(__WATCOMC__) && ARCH_BITS == 32 && defined(RT_ARCH_X86)
65# include "asm-mem-watcom-x86-32.h"
66#endif
67
68
69
70/** @defgroup grp_rt_asm_mem ASM - Memory Assembly Routines
71 * @ingroup grp_rt_asm
72 * @{
73 */
74
75/**
76 * Zeros a memory block with a 32-bit aligned size.
77 *
78 * @param pv Pointer to the memory block.
79 * @param cb Number of bytes in the block. This MUST be aligned on 32-bit!
80 */
81#if (RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN) || (!defined(RT_ARCH_AMD64) && !defined(RT_ARCH_X86))
82RT_ASM_DECL_PRAGMA_WATCOM(void) ASMMemZero32(volatile void RT_FAR *pv, size_t cb) RT_NOTHROW_PROTO;
83#else
84DECLINLINE(void) ASMMemZero32(volatile void RT_FAR *pv, size_t cb) RT_NOTHROW_DEF
85{
86# if RT_INLINE_ASM_USES_INTRIN
87# ifdef RT_ARCH_AMD64
88 if (!(cb & 7))
89 __stosq((unsigned __int64 RT_FAR *)pv, 0, cb / 8);
90 else
91# endif
92 __stosd((unsigned long RT_FAR *)pv, 0, cb / 4);
93
94# elif RT_INLINE_ASM_GNU_STYLE
95 __asm__ __volatile__("rep stosl"
96 : "=D" (pv),
97 "=c" (cb)
98 : "0" (pv),
99 "1" (cb >> 2),
100 "a" (0)
101 : "memory");
102# else
103 __asm
104 {
105 xor eax, eax
106# ifdef RT_ARCH_AMD64
107 mov rcx, [cb]
108 shr rcx, 2
109 mov rdi, [pv]
110# else
111 mov ecx, [cb]
112 shr ecx, 2
113 mov edi, [pv]
114# endif
115 rep stosd
116 }
117# endif
118}
119#endif
120
121
122/**
123 * Fills a memory block with a 32-bit aligned size.
124 *
125 * @param pv Pointer to the memory block.
126 * @param cb Number of bytes in the block. This MUST be aligned on 32-bit!
127 * @param u32 The value to fill with.
128 */
129#if (RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN) || (!defined(RT_ARCH_AMD64) && !defined(RT_ARCH_X86))
130RT_ASM_DECL_PRAGMA_WATCOM(void) ASMMemFill32(volatile void RT_FAR *pv, size_t cb, uint32_t u32) RT_NOTHROW_PROTO;
131#else
132DECLINLINE(void) ASMMemFill32(volatile void RT_FAR *pv, size_t cb, uint32_t u32) RT_NOTHROW_DEF
133{
134 Assert(!(cb & 3));
135 Assert(cb > 0);
136# if RT_INLINE_ASM_USES_INTRIN
137# ifdef RT_ARCH_AMD64
138 if (!(cb & 7))
139 __stosq((unsigned __int64 RT_FAR *)pv, RT_MAKE_U64(u32, u32), cb / 8);
140 else
141# endif
142 __stosd((unsigned long RT_FAR *)pv, u32, cb / 4);
143
144# elif RT_INLINE_ASM_GNU_STYLE
145 __asm__ __volatile__("rep stosl"
146 : "=D" (pv),
147 "=c" (cb)
148 : "0" (pv),
149 "1" (cb >> 2),
150 "a" (u32)
151 : "memory");
152# else
153 __asm
154 {
155# ifdef RT_ARCH_AMD64
156 mov rcx, [cb]
157 shr rcx, 2
158 mov rdi, [pv]
159# else
160 mov ecx, [cb]
161 shr ecx, 2
162 mov edi, [pv]
163# endif
164 mov eax, [u32]
165 rep stosd
166 }
167# endif
168}
169#endif
170
171
172/**
173 * Checks if a memory block is all zeros.
174 *
175 * @returns Pointer to the first non-zero byte.
176 * @returns NULL if all zero.
177 *
178 * @param pv Pointer to the memory block.
179 * @param cb Number of bytes in the block.
180 */
181#if !defined(RDESKTOP) && (!defined(RT_OS_LINUX) || !defined(__KERNEL__))
182DECLASM(void RT_FAR *) ASMMemFirstNonZero(void const RT_FAR *pv, size_t cb) RT_NOTHROW_PROTO;
183#else
184DECLINLINE(void RT_FAR *) ASMMemFirstNonZero(void const RT_FAR *pv, size_t cb) RT_NOTHROW_DEF
185{
186/** @todo replace with ASMMemFirstNonZero-generic.cpp in kernel modules. */
187 uint8_t const *pb = (uint8_t const RT_FAR *)pv;
188 for (; cb; cb--, pb++)
189 if (RT_LIKELY(*pb == 0))
190 { /* likely */ }
191 else
192 return (void RT_FAR *)pb;
193 return NULL;
194}
195#endif
196
197
198/**
199 * Checks if a memory block is all zeros.
200 *
201 * @returns true if zero, false if not.
202 *
203 * @param pv Pointer to the memory block.
204 * @param cb Number of bytes in the block.
205 *
206 * @sa ASMMemFirstNonZero
207 */
208DECLINLINE(bool) ASMMemIsZero(void const RT_FAR *pv, size_t cb) RT_NOTHROW_DEF
209{
210 return ASMMemFirstNonZero(pv, cb) == NULL;
211}
212
213
214/**
215 * Checks if a memory block is filled with the specified byte, returning the
216 * first mismatch.
217 *
218 * This is sort of an inverted memchr.
219 *
220 * @returns Pointer to the byte which doesn't equal u8.
221 * @returns NULL if all equal to u8.
222 *
223 * @param pv Pointer to the memory block.
224 * @param cb Number of bytes in the block.
225 * @param u8 The value it's supposed to be filled with.
226 *
227 * @remarks No alignment requirements.
228 */
229#if (!defined(RT_OS_LINUX) || !defined(__KERNEL__)) \
230 && (!defined(RT_OS_FREEBSD) || !defined(_KERNEL))
231DECLASM(void *) ASMMemFirstMismatchingU8(void const RT_FAR *pv, size_t cb, uint8_t u8) RT_NOTHROW_PROTO;
232#else
233DECLINLINE(void *) ASMMemFirstMismatchingU8(void const RT_FAR *pv, size_t cb, uint8_t u8) RT_NOTHROW_DEF
234{
235/** @todo replace with ASMMemFirstMismatchingU8-generic.cpp in kernel modules. */
236 uint8_t const *pb = (uint8_t const RT_FAR *)pv;
237 for (; cb; cb--, pb++)
238 if (RT_LIKELY(*pb == u8))
239 { /* likely */ }
240 else
241 return (void *)pb;
242 return NULL;
243}
244#endif
245
246
247/**
248 * Checks if a memory block is filled with the specified byte.
249 *
250 * @returns true if all matching, false if not.
251 *
252 * @param pv Pointer to the memory block.
253 * @param cb Number of bytes in the block.
254 * @param u8 The value it's supposed to be filled with.
255 *
256 * @remarks No alignment requirements.
257 */
258DECLINLINE(bool) ASMMemIsAllU8(void const RT_FAR *pv, size_t cb, uint8_t u8) RT_NOTHROW_DEF
259{
260 return ASMMemFirstMismatchingU8(pv, cb, u8) == NULL;
261}
262
263
264/**
265 * Checks if a memory block is filled with the specified 32-bit value.
266 *
267 * This is a sort of inverted memchr.
268 *
269 * @returns Pointer to the first value which doesn't equal u32.
270 * @returns NULL if all equal to u32.
271 *
272 * @param pv Pointer to the memory block.
273 * @param cb Number of bytes in the block. This MUST be aligned on 32-bit!
274 * @param u32 The value it's supposed to be filled with.
275 */
276DECLINLINE(uint32_t RT_FAR *) ASMMemFirstMismatchingU32(void const RT_FAR *pv, size_t cb, uint32_t u32) RT_NOTHROW_DEF
277{
278/** @todo rewrite this in inline assembly? */
279 uint32_t const RT_FAR *pu32 = (uint32_t const RT_FAR *)pv;
280 for (; cb; cb -= 4, pu32++)
281 if (RT_LIKELY(*pu32 == u32))
282 { /* likely */ }
283 else
284 return (uint32_t RT_FAR *)pu32;
285 return NULL;
286}
287
288
289/**
290 * Probes a byte pointer for read access.
291 *
292 * While the function will not fault if the byte is not read accessible,
293 * the idea is to do this in a safe place like before acquiring locks
294 * and such like.
295 *
296 * Also, this functions guarantees that an eager compiler is not going
297 * to optimize the probing away.
298 *
299 * @param pvByte Pointer to the byte.
300 */
301#if RT_INLINE_ASM_EXTERNAL_TMP_ARM
302RT_ASM_DECL_PRAGMA_WATCOM(uint8_t) ASMProbeReadByte(const void RT_FAR *pvByte) RT_NOTHROW_PROTO;
303#else
304DECLINLINE(uint8_t) ASMProbeReadByte(const void RT_FAR *pvByte) RT_NOTHROW_DEF
305{
306# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
307 uint8_t u8;
308# if RT_INLINE_ASM_GNU_STYLE
309 __asm__ __volatile__("movb %1, %0\n\t"
310 : "=q" (u8)
311 : "m" (*(const uint8_t *)pvByte));
312# else
313 __asm
314 {
315# ifdef RT_ARCH_AMD64
316 mov rax, [pvByte]
317 mov al, [rax]
318# else
319 mov eax, [pvByte]
320 mov al, [eax]
321# endif
322 mov [u8], al
323 }
324# endif
325 return u8;
326
327# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32)
328 uint32_t u32;
329 __asm__ __volatile__("Lstart_ASMProbeReadByte_%=:\n\t"
330# if defined(RT_ARCH_ARM64)
331 "ldxrb %w[uDst], %[pMem]\n\t"
332# else
333 "ldrexb %[uDst], %[pMem]\n\t"
334# endif
335 : [uDst] "=&r" (u32)
336 : [pMem] "Q" (*(uint8_t const *)pvByte));
337 return (uint8_t)u32;
338
339# else
340# error "Port me"
341# endif
342}
343#endif
344
345/** @} */
346
347/*
348 * Include #pragma aux definitions for Watcom C/C++.
349 */
350#if defined(__WATCOMC__) && ARCH_BITS == 16 && defined(RT_ARCH_X86)
351# define IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS
352# undef IPRT_INCLUDED_asm_mem_watcom_x86_16_h
353# include "asm-mem-watcom-x86-16.h"
354#elif defined(__WATCOMC__) && ARCH_BITS == 32 && defined(RT_ARCH_X86)
355# define IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS
356# undef IPRT_INCLUDED_asm_mem_watcom_x86_32_h
357# include "asm-mem-watcom-x86-32.h"
358#endif
359
360#endif /* !IPRT_INCLUDED_asm_mem_h */
361
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use