VirtualBox

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

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

iprt/asm-mem.h: Eliminated the unused ASMProbeReadBuffer.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.2 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# if RT_INLINE_ASM_USES_INTRIN
135# ifdef RT_ARCH_AMD64
136 if (!(cb & 7))
137 __stosq((unsigned __int64 RT_FAR *)pv, RT_MAKE_U64(u32, u32), cb / 8);
138 else
139# endif
140 __stosd((unsigned long RT_FAR *)pv, u32, cb / 4);
141
142# elif RT_INLINE_ASM_GNU_STYLE
143 __asm__ __volatile__("rep stosl"
144 : "=D" (pv),
145 "=c" (cb)
146 : "0" (pv),
147 "1" (cb >> 2),
148 "a" (u32)
149 : "memory");
150# else
151 __asm
152 {
153# ifdef RT_ARCH_AMD64
154 mov rcx, [cb]
155 shr rcx, 2
156 mov rdi, [pv]
157# else
158 mov ecx, [cb]
159 shr ecx, 2
160 mov edi, [pv]
161# endif
162 mov eax, [u32]
163 rep stosd
164 }
165# endif
166}
167#endif
168
169
170/**
171 * Checks if a memory block is all zeros.
172 *
173 * @returns Pointer to the first non-zero byte.
174 * @returns NULL if all zero.
175 *
176 * @param pv Pointer to the memory block.
177 * @param cb Number of bytes in the block.
178 */
179#if !defined(RDESKTOP) && (!defined(RT_OS_LINUX) || !defined(__KERNEL__))
180DECLASM(void RT_FAR *) ASMMemFirstNonZero(void const RT_FAR *pv, size_t cb) RT_NOTHROW_PROTO;
181#else
182DECLINLINE(void RT_FAR *) ASMMemFirstNonZero(void const RT_FAR *pv, size_t cb) RT_NOTHROW_DEF
183{
184/** @todo replace with ASMMemFirstNonZero-generic.cpp in kernel modules. */
185 uint8_t const *pb = (uint8_t const RT_FAR *)pv;
186 for (; cb; cb--, pb++)
187 if (RT_LIKELY(*pb == 0))
188 { /* likely */ }
189 else
190 return (void RT_FAR *)pb;
191 return NULL;
192}
193#endif
194
195
196/**
197 * Checks if a memory block is all zeros.
198 *
199 * @returns true if zero, false if not.
200 *
201 * @param pv Pointer to the memory block.
202 * @param cb Number of bytes in the block.
203 *
204 * @sa ASMMemFirstNonZero
205 */
206DECLINLINE(bool) ASMMemIsZero(void const RT_FAR *pv, size_t cb) RT_NOTHROW_DEF
207{
208 return ASMMemFirstNonZero(pv, cb) == NULL;
209}
210
211
212/**
213 * Checks if a memory block is filled with the specified byte, returning the
214 * first mismatch.
215 *
216 * This is sort of an inverted memchr.
217 *
218 * @returns Pointer to the byte which doesn't equal u8.
219 * @returns NULL if all equal to u8.
220 *
221 * @param pv Pointer to the memory block.
222 * @param cb Number of bytes in the block.
223 * @param u8 The value it's supposed to be filled with.
224 *
225 * @remarks No alignment requirements.
226 */
227#if (!defined(RT_OS_LINUX) || !defined(__KERNEL__)) \
228 && (!defined(RT_OS_FREEBSD) || !defined(_KERNEL))
229DECLASM(void *) ASMMemFirstMismatchingU8(void const RT_FAR *pv, size_t cb, uint8_t u8) RT_NOTHROW_PROTO;
230#else
231DECLINLINE(void *) ASMMemFirstMismatchingU8(void const RT_FAR *pv, size_t cb, uint8_t u8) RT_NOTHROW_DEF
232{
233/** @todo replace with ASMMemFirstMismatchingU8-generic.cpp in kernel modules. */
234 uint8_t const *pb = (uint8_t const RT_FAR *)pv;
235 for (; cb; cb--, pb++)
236 if (RT_LIKELY(*pb == u8))
237 { /* likely */ }
238 else
239 return (void *)pb;
240 return NULL;
241}
242#endif
243
244
245/**
246 * Checks if a memory block is filled with the specified byte.
247 *
248 * @returns true if all matching, false if not.
249 *
250 * @param pv Pointer to the memory block.
251 * @param cb Number of bytes in the block.
252 * @param u8 The value it's supposed to be filled with.
253 *
254 * @remarks No alignment requirements.
255 */
256DECLINLINE(bool) ASMMemIsAllU8(void const RT_FAR *pv, size_t cb, uint8_t u8) RT_NOTHROW_DEF
257{
258 return ASMMemFirstMismatchingU8(pv, cb, u8) == NULL;
259}
260
261
262/**
263 * Checks if a memory block is filled with the specified 32-bit value.
264 *
265 * This is a sort of inverted memchr.
266 *
267 * @returns Pointer to the first value which doesn't equal u32.
268 * @returns NULL if all equal to u32.
269 *
270 * @param pv Pointer to the memory block.
271 * @param cb Number of bytes in the block. This MUST be aligned on 32-bit!
272 * @param u32 The value it's supposed to be filled with.
273 */
274DECLINLINE(uint32_t RT_FAR *) ASMMemFirstMismatchingU32(void const RT_FAR *pv, size_t cb, uint32_t u32) RT_NOTHROW_DEF
275{
276/** @todo rewrite this in inline assembly? */
277 uint32_t const RT_FAR *pu32 = (uint32_t const RT_FAR *)pv;
278 for (; cb; cb -= 4, pu32++)
279 if (RT_LIKELY(*pu32 == u32))
280 { /* likely */ }
281 else
282 return (uint32_t RT_FAR *)pu32;
283 return NULL;
284}
285
286
287/**
288 * Probes a byte pointer for read access.
289 *
290 * While the function will not fault if the byte is not read accessible,
291 * the idea is to do this in a safe place like before acquiring locks
292 * and such like.
293 *
294 * Also, this functions guarantees that an eager compiler is not going
295 * to optimize the probing away.
296 *
297 * @param pvByte Pointer to the byte.
298 */
299#if RT_INLINE_ASM_EXTERNAL_TMP_ARM
300RT_ASM_DECL_PRAGMA_WATCOM(uint8_t) ASMProbeReadByte(const void RT_FAR *pvByte) RT_NOTHROW_PROTO;
301#else
302DECLINLINE(uint8_t) ASMProbeReadByte(const void RT_FAR *pvByte) RT_NOTHROW_DEF
303{
304# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
305 uint8_t u8;
306# if RT_INLINE_ASM_GNU_STYLE
307 __asm__ __volatile__("movb %1, %0\n\t"
308 : "=q" (u8)
309 : "m" (*(const uint8_t *)pvByte));
310# else
311 __asm
312 {
313# ifdef RT_ARCH_AMD64
314 mov rax, [pvByte]
315 mov al, [rax]
316# else
317 mov eax, [pvByte]
318 mov al, [eax]
319# endif
320 mov [u8], al
321 }
322# endif
323 return u8;
324
325# elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32)
326 uint32_t u32;
327 __asm__ __volatile__("Lstart_ASMProbeReadByte_%=:\n\t"
328# if defined(RT_ARCH_ARM64)
329 "ldxrb %w[uDst], %[pMem]\n\t"
330# else
331 "ldrexb %[uDst], %[pMem]\n\t"
332# endif
333 : [uDst] "=&r" (u32)
334 : [pMem] "Q" (*(uint8_t const *)pvByte));
335 return (uint8_t)u32;
336
337# else
338# error "Port me"
339# endif
340}
341#endif
342
343/** @} */
344
345/*
346 * Include #pragma aux definitions for Watcom C/C++.
347 */
348#if defined(__WATCOMC__) && ARCH_BITS == 16 && defined(RT_ARCH_X86)
349# define IPRT_ASM_WATCOM_X86_16_WITH_PRAGMAS
350# undef IPRT_INCLUDED_asm_mem_watcom_x86_16_h
351# include "asm-mem-watcom-x86-16.h"
352#elif defined(__WATCOMC__) && ARCH_BITS == 32 && defined(RT_ARCH_X86)
353# define IPRT_ASM_WATCOM_X86_32_WITH_PRAGMAS
354# undef IPRT_INCLUDED_asm_mem_watcom_x86_32_h
355# include "asm-mem-watcom-x86-32.h"
356#endif
357
358#endif /* !IPRT_INCLUDED_asm_mem_h */
359
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use