xref: /xnu-12377.41.6/iokit/IOKit/IOCircularDataQueueImplementation.h (revision bbb1b6f9e71b8cdde6e5cd6f4841f207dee3d828)
1*bbb1b6f9SApple OSS Distributions /*
2*bbb1b6f9SApple OSS Distributions  * Copyright (c) 2024 Apple Inc. All rights reserved.
3*bbb1b6f9SApple OSS Distributions  *
4*bbb1b6f9SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5*bbb1b6f9SApple OSS Distributions  *
6*bbb1b6f9SApple OSS Distributions  * This file contains Original Code and/or Modifications of Original Code
7*bbb1b6f9SApple OSS Distributions  * as defined in and that are subject to the Apple Public Source License
8*bbb1b6f9SApple OSS Distributions  * Version 2.0 (the 'License'). You may not use this file except in
9*bbb1b6f9SApple OSS Distributions  * compliance with the License. The rights granted to you under the License
10*bbb1b6f9SApple OSS Distributions  * may not be used to create, or enable the creation or redistribution of,
11*bbb1b6f9SApple OSS Distributions  * unlawful or unlicensed copies of an Apple operating system, or to
12*bbb1b6f9SApple OSS Distributions  * circumvent, violate, or enable the circumvention or violation of, any
13*bbb1b6f9SApple OSS Distributions  * terms of an Apple operating system software license agreement.
14*bbb1b6f9SApple OSS Distributions  *
15*bbb1b6f9SApple OSS Distributions  * Please obtain a copy of the License at
16*bbb1b6f9SApple OSS Distributions  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17*bbb1b6f9SApple OSS Distributions  *
18*bbb1b6f9SApple OSS Distributions  * The Original Code and all software distributed under the License are
19*bbb1b6f9SApple OSS Distributions  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20*bbb1b6f9SApple OSS Distributions  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21*bbb1b6f9SApple OSS Distributions  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22*bbb1b6f9SApple OSS Distributions  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23*bbb1b6f9SApple OSS Distributions  * Please see the License for the specific language governing rights and
24*bbb1b6f9SApple OSS Distributions  * limitations under the License.
25*bbb1b6f9SApple OSS Distributions  *
26*bbb1b6f9SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27*bbb1b6f9SApple OSS Distributions  */
28*bbb1b6f9SApple OSS Distributions 
29*bbb1b6f9SApple OSS Distributions #include <IOKit/IOCircularDataQueue.h>
30*bbb1b6f9SApple OSS Distributions 
31*bbb1b6f9SApple OSS Distributions __BEGIN_DECLS
32*bbb1b6f9SApple OSS Distributions 
33*bbb1b6f9SApple OSS Distributions /*!
34*bbb1b6f9SApple OSS Distributions  *  @header IOCircularDataQueueMemory
35*bbb1b6f9SApple OSS Distributions  *
36*bbb1b6f9SApple OSS Distributions  *  This header contains the memory layout for a circular data queue.
37*bbb1b6f9SApple OSS Distributions  *
38*bbb1b6f9SApple OSS Distributions  *  A circular data queue supports a single producer and zero or more consumers.
39*bbb1b6f9SApple OSS Distributions  *
40*bbb1b6f9SApple OSS Distributions  *
41*bbb1b6f9SApple OSS Distributions  *  The producer does not wait for consumers to read the data.  If a
42*bbb1b6f9SApple OSS Distributions  *  consumer falls behind, it will miss data.
43*bbb1b6f9SApple OSS Distributions  *
44*bbb1b6f9SApple OSS Distributions  *  The queue can be configured to support either fixed or variable sized
45*bbb1b6f9SApple OSS Distributions  *  entries.
46*bbb1b6f9SApple OSS Distributions  *  Currently only fixed is supported.
47*bbb1b6f9SApple OSS Distributions  */
48*bbb1b6f9SApple OSS Distributions 
49*bbb1b6f9SApple OSS Distributions /*
50*bbb1b6f9SApple OSS Distributions  *  Fixed sized entry circular queue
51*bbb1b6f9SApple OSS Distributions  *
52*bbb1b6f9SApple OSS Distributions  +------------+
53*bbb1b6f9SApple OSS Distributions  |    Queue   |
54*bbb1b6f9SApple OSS Distributions  |   Header   |
55*bbb1b6f9SApple OSS Distributions  +------------+ <--- First Data Entry
56*bbb1b6f9SApple OSS Distributions  |Entry Header|
57*bbb1b6f9SApple OSS Distributions  +------------+
58*bbb1b6f9SApple OSS Distributions  |            |
59*bbb1b6f9SApple OSS Distributions  |    Entry   |
60*bbb1b6f9SApple OSS Distributions  |    Data    |
61*bbb1b6f9SApple OSS Distributions  |            |
62*bbb1b6f9SApple OSS Distributions  +------------+ <--- Second Data Entry
63*bbb1b6f9SApple OSS Distributions  |Entry Header|
64*bbb1b6f9SApple OSS Distributions  +------------+
65*bbb1b6f9SApple OSS Distributions  |            |
66*bbb1b6f9SApple OSS Distributions  |            |
67*bbb1b6f9SApple OSS Distributions  |     ...    |
68*bbb1b6f9SApple OSS Distributions  |     ...    |
69*bbb1b6f9SApple OSS Distributions  |            |
70*bbb1b6f9SApple OSS Distributions  |            |
71*bbb1b6f9SApple OSS Distributions  |            |
72*bbb1b6f9SApple OSS Distributions  +------------+ <--- Last Data Entry
73*bbb1b6f9SApple OSS Distributions  |Entry Header|
74*bbb1b6f9SApple OSS Distributions  +------------+
75*bbb1b6f9SApple OSS Distributions  |            |
76*bbb1b6f9SApple OSS Distributions  |    Entry   |
77*bbb1b6f9SApple OSS Distributions  |    Data    |
78*bbb1b6f9SApple OSS Distributions  |            |
79*bbb1b6f9SApple OSS Distributions  +------------+
80*bbb1b6f9SApple OSS Distributions  |
81*bbb1b6f9SApple OSS Distributions  */
82*bbb1b6f9SApple OSS Distributions 
83*bbb1b6f9SApple OSS Distributions #if defined(__STDC_VERSION__) && __STDC_VERSION__ < 201112L
84*bbb1b6f9SApple OSS Distributions 	#define _STATIC_ASSERT_OVERLOADED_MACRO(_1, _2, NAME, ...) NAME
85*bbb1b6f9SApple OSS Distributions 	#define static_assert(...) _STATIC_ASSERT_OVERLOADED_MACRO(__VA_ARGS__, _static_assert_2_args, _static_assert_1_arg)(__VA_ARGS__)
86*bbb1b6f9SApple OSS Distributions 
87*bbb1b6f9SApple OSS Distributions 	#define _static_assert_2_args(ex, str) _Static_assert((ex), str)
88*bbb1b6f9SApple OSS Distributions 	#define _static_assert_1_arg(ex) _Static_assert((ex), #ex)
89*bbb1b6f9SApple OSS Distributions #endif
90*bbb1b6f9SApple OSS Distributions 
91*bbb1b6f9SApple OSS Distributions #define HEADER_16BYTE_ALIGNED 1 // do the entry and entry headers need to be 16 byte aligned for perf/correctness ?
92*bbb1b6f9SApple OSS Distributions 
93*bbb1b6f9SApple OSS Distributions /*!
94*bbb1b6f9SApple OSS Distributions  * @typedef IOCircularDataQueueEntryHeaderInfo
95*bbb1b6f9SApple OSS Distributions  * @abstract The state of an entry in the  circular data queue. The state is part of  each entry header in the queue.
96*bbb1b6f9SApple OSS Distributions  * @discussion The entry state has the sequence number, data size, generation and current state of the entry. The state
97*bbb1b6f9SApple OSS Distributions  * is read/updated atomically.
98*bbb1b6f9SApple OSS Distributions  * @field seqNum A unique sequence number for this entry. The sequence number is monotonically increased on each enqueue
99*bbb1b6f9SApple OSS Distributions  * to the queue. Each entry in the queue has a unique sequence number.
100*bbb1b6f9SApple OSS Distributions  * @field dataSize The size of the data at this entry.
101*bbb1b6f9SApple OSS Distributions  * @field generation The queue generation which is copied from the queue header memory into the entry state on an
102*bbb1b6f9SApple OSS Distributions  * enqueue.
103*bbb1b6f9SApple OSS Distributions  * @field `_reserved` Unused
104*bbb1b6f9SApple OSS Distributions  * @field wrStatus Represents if the queue entry is currently being written to or not.
105*bbb1b6f9SApple OSS Distributions  */
106*bbb1b6f9SApple OSS Distributions 
107*bbb1b6f9SApple OSS Distributions #define IOCIRCULARDATAQUEUE_ENTRY_STATE_WRITE_SIZE 1
108*bbb1b6f9SApple OSS Distributions #define IOCIRCULARDATAQUEUE_ENTRY_STATE_GENERATION_SIZE 30
109*bbb1b6f9SApple OSS Distributions #define IOCIRCULARDATAQUEUE_ENTRY_STATE_DATATSIZE_SIZE 32
110*bbb1b6f9SApple OSS Distributions #define IOCIRCULARDATAQUEUE_ENTRY_STATE_SEQNUM_SIZE 64
111*bbb1b6f9SApple OSS Distributions // #define IOCIRCULARDATAQUEUE_ENTRY_STATE_RESERVED_SIZE   1
112*bbb1b6f9SApple OSS Distributions #define IOCIRCULARDATAQUEUE_ENTRY_STATE_RESERVED_SIZE                                                                  \
113*bbb1b6f9SApple OSS Distributions     ((8 * sizeof(__uint128_t)) - IOCIRCULARDATAQUEUE_ENTRY_STATE_WRITE_SIZE                                            \
114*bbb1b6f9SApple OSS Distributions      - IOCIRCULARDATAQUEUE_ENTRY_STATE_GENERATION_SIZE - IOCIRCULARDATAQUEUE_ENTRY_STATE_DATATSIZE_SIZE                \
115*bbb1b6f9SApple OSS Distributions      - IOCIRCULARDATAQUEUE_ENTRY_STATE_SEQNUM_SIZE)
116*bbb1b6f9SApple OSS Distributions 
117*bbb1b6f9SApple OSS Distributions typedef union {
118*bbb1b6f9SApple OSS Distributions 	__uint128_t val;
119*bbb1b6f9SApple OSS Distributions 	struct {
120*bbb1b6f9SApple OSS Distributions 		__uint128_t seqNum : IOCIRCULARDATAQUEUE_ENTRY_STATE_SEQNUM_SIZE; // Sequence Number
121*bbb1b6f9SApple OSS Distributions 		__uint128_t dataSize : IOCIRCULARDATAQUEUE_ENTRY_STATE_DATATSIZE_SIZE; // datasize
122*bbb1b6f9SApple OSS Distributions 		__uint128_t generation : IOCIRCULARDATAQUEUE_ENTRY_STATE_GENERATION_SIZE; // generation
123*bbb1b6f9SApple OSS Distributions 		__uint128_t _reserved : IOCIRCULARDATAQUEUE_ENTRY_STATE_RESERVED_SIZE; // reserved, currently not used
124*bbb1b6f9SApple OSS Distributions 		__uint128_t wrStatus : IOCIRCULARDATAQUEUE_ENTRY_STATE_WRITE_SIZE; // queue writing status
125*bbb1b6f9SApple OSS Distributions 	} fields;
126*bbb1b6f9SApple OSS Distributions } IOCircularDataQueueEntryHeaderInfo;
127*bbb1b6f9SApple OSS Distributions 
128*bbb1b6f9SApple OSS Distributions #define IOCIRCULARDATAQUEUE_ENTRY_STATE_WRITE_INPROGRESS (1)
129*bbb1b6f9SApple OSS Distributions #define IOCIRCULARDATAQUEUE_ENTRY_STATE_WRITE_COMPLETE (0)
130*bbb1b6f9SApple OSS Distributions 
131*bbb1b6f9SApple OSS Distributions static_assert(IOCIRCULARDATAQUEUE_ENTRY_STATE_RESERVED_SIZE > 0, "unexpected reserved field size");
132*bbb1b6f9SApple OSS Distributions 
133*bbb1b6f9SApple OSS Distributions /*!
134*bbb1b6f9SApple OSS Distributions  * @typedef IOCircularDataQueueEntryHeader
135*bbb1b6f9SApple OSS Distributions  * @abstract An entry in the  circular data queue. The entry header is written at the beginning of each entry in the
136*bbb1b6f9SApple OSS Distributions  * queue.
137*bbb1b6f9SApple OSS Distributions  * @discussion The entry has the current state, sentinel, followed by the data at the enty.
138*bbb1b6f9SApple OSS Distributions  * @field info The info of the queue entry. This  includes the size, sequence number, generation and write status of the
139*bbb1b6f9SApple OSS Distributions  * data at this entry.
140*bbb1b6f9SApple OSS Distributions  * @field sentinel unique value written to the queue entry. This is copied from the sentinel in the queue header memory
141*bbb1b6f9SApple OSS Distributions  * when an entry is written.
142*bbb1b6f9SApple OSS Distributions  * @field data Represents the beginning of the data region.  The address of the data field is a pointer to the start of
143*bbb1b6f9SApple OSS Distributions  * the data region.
144*bbb1b6f9SApple OSS Distributions  */
145*bbb1b6f9SApple OSS Distributions typedef struct {
146*bbb1b6f9SApple OSS Distributions 	union {
147*bbb1b6f9SApple OSS Distributions 		volatile _Atomic __uint128_t headerInfoVal;
148*bbb1b6f9SApple OSS Distributions 		IOCircularDataQueueEntryHeaderInfo __headerInfo;         // for clarity, unused
149*bbb1b6f9SApple OSS Distributions 	};
150*bbb1b6f9SApple OSS Distributions 	volatile uint64_t sentinel;
151*bbb1b6f9SApple OSS Distributions 	uint64_t _pad; // pad for 16 byte aligment of data that follows
152*bbb1b6f9SApple OSS Distributions #if HEADER_16BYTE_ALIGNED
153*bbb1b6f9SApple OSS Distributions 	uint8_t data[16]; // Entry data begins.  Aligned to 16 bytes.
154*bbb1b6f9SApple OSS Distributions #else
155*bbb1b6f9SApple OSS Distributions 	uint8_t data[8]; // Entry data begins.  Aligned to 8 bytes.
156*bbb1b6f9SApple OSS Distributions #endif
157*bbb1b6f9SApple OSS Distributions } IOCircularDataQueueEntryHeader;
158*bbb1b6f9SApple OSS Distributions 
159*bbb1b6f9SApple OSS Distributions #if HEADER_16BYTE_ALIGNED
160*bbb1b6f9SApple OSS Distributions #define CIRCULAR_DATA_QUEUE_ENTRY_HEADER_SIZE (sizeof(IOCircularDataQueueEntryHeader) - 16)
161*bbb1b6f9SApple OSS Distributions #else
162*bbb1b6f9SApple OSS Distributions #define CIRCULAR_DATA_QUEUE_ENTRY_HEADER_SIZE (sizeof(IOCircularDataQueueEntryHeader) - 8)
163*bbb1b6f9SApple OSS Distributions #endif
164*bbb1b6f9SApple OSS Distributions 
165*bbb1b6f9SApple OSS Distributions /*!
166*bbb1b6f9SApple OSS Distributions  * @typedef IOCircularDataQueueState
167*bbb1b6f9SApple OSS Distributions  * @abstract The current state of the circular data queue.
168*bbb1b6f9SApple OSS Distributions  * @discussion The queue state is part of the queue memory header. It has the current sequence number, next writing
169*bbb1b6f9SApple OSS Distributions  * index, generation and current reset and writing state off the queue. The queue state is read/updated atomically.
170*bbb1b6f9SApple OSS Distributions  * @field seqNum A monotonically increasing sequence number which is incremented for each enqueue.
171*bbb1b6f9SApple OSS Distributions  * @field wrIndex The next write position into the queue.
172*bbb1b6f9SApple OSS Distributions  * @field generation The generation of the queue. It is a monotonically increasing number, which is incremented on each
173*bbb1b6f9SApple OSS Distributions  * queue reset.
174*bbb1b6f9SApple OSS Distributions  * @field rstStatus The queue reset state. The bit is set if the queue is currently being reset.
175*bbb1b6f9SApple OSS Distributions  * @field wrStatus The queue writing state. The bit is set if an enqueue is in progress.
176*bbb1b6f9SApple OSS Distributions  */
177*bbb1b6f9SApple OSS Distributions // Fahad : I dont think we need a reset bit, since we are doing everything in one atomic op.
178*bbb1b6f9SApple OSS Distributions 
179*bbb1b6f9SApple OSS Distributions #define IOCIRCULARDATAQUEUE_STATE_WRITE_SIZE 1
180*bbb1b6f9SApple OSS Distributions #define IOCIRCULARDATAQUEUE_STATE_RESET_SIZE 1
181*bbb1b6f9SApple OSS Distributions #define IOCIRCULARDATAQUEUE_STATE_GENERATION_SIZE 30
182*bbb1b6f9SApple OSS Distributions #define IOCIRCULARDATAQUEUE_STATE_WRITEINDEX_SIZE 32
183*bbb1b6f9SApple OSS Distributions #define IOCIRCULARDATAQUEUE_STATE_SEQNUM_SIZE 64
184*bbb1b6f9SApple OSS Distributions //#define IOCIRCULARDATAQUEUE_STATE_RESERVED_SIZE                                                                  \
185*bbb1b6f9SApple OSS Distributions //    ((8 * sizeof(__uint128_t)) - IOCIRCULARDATAQUEUE_STATE_WRITE_SIZE                                            \
186*bbb1b6f9SApple OSS Distributions //     - IOCIRCULARDATAQUEUE_STATE_GENERATION_SIZE - IOCIRCULARDATAQUEUE_STATE_WRITEINDEX_SIZE                \
187*bbb1b6f9SApple OSS Distributions //     - IOCIRCULARDATAQUEUE_STATE_SEQNUM_SIZE)
188*bbb1b6f9SApple OSS Distributions 
189*bbb1b6f9SApple OSS Distributions typedef union {
190*bbb1b6f9SApple OSS Distributions 	__uint128_t val;
191*bbb1b6f9SApple OSS Distributions 	struct {
192*bbb1b6f9SApple OSS Distributions 		__uint128_t seqNum : IOCIRCULARDATAQUEUE_STATE_SEQNUM_SIZE; // Sequence Number
193*bbb1b6f9SApple OSS Distributions 		__uint128_t wrIndex : IOCIRCULARDATAQUEUE_STATE_WRITEINDEX_SIZE; // write index
194*bbb1b6f9SApple OSS Distributions 		__uint128_t generation : IOCIRCULARDATAQUEUE_STATE_GENERATION_SIZE; // generation
195*bbb1b6f9SApple OSS Distributions 		// Fahad: We may not need reset.
196*bbb1b6f9SApple OSS Distributions 		__uint128_t rstStatus : IOCIRCULARDATAQUEUE_STATE_RESET_SIZE; // queue reset status
197*bbb1b6f9SApple OSS Distributions 		//        __uint128_t _rsvd : IOCIRCULARDATAQUEUE_STATE_RESERVED_SIZE; // reserved
198*bbb1b6f9SApple OSS Distributions 		__uint128_t wrStatus : IOCIRCULARDATAQUEUE_STATE_WRITE_SIZE; // queue writing status
199*bbb1b6f9SApple OSS Distributions 	} fields;
200*bbb1b6f9SApple OSS Distributions } IOCircularDataQueueState;
201*bbb1b6f9SApple OSS Distributions 
202*bbb1b6f9SApple OSS Distributions #define IOCIRCULARDATAQUEUE_STATE_WRITE_INPROGRESS (1)
203*bbb1b6f9SApple OSS Distributions #define IOCIRCULARDATAQUEUE_STATE_WRITE_COMPLETE (0)
204*bbb1b6f9SApple OSS Distributions #define IOCIRCULARDATAQUEUE_STATE_RESET_INPROGRESS (1)
205*bbb1b6f9SApple OSS Distributions #define IOCIRCULARDATAQUEUE_STATE_RESET_COMPLETE (0)
206*bbb1b6f9SApple OSS Distributions 
207*bbb1b6f9SApple OSS Distributions // #define IOCircularDataQueueStateGeneration              (((uint32_t)1 << 30) - 1)
208*bbb1b6f9SApple OSS Distributions #define IOCIRCULARDATAQUEUE_STATE_GENERATION_MAX (((uint32_t)1 << 30))
209*bbb1b6f9SApple OSS Distributions 
210*bbb1b6f9SApple OSS Distributions // static_assert(IOCIRCULARDATAQUEUE_STATE_RESERVED_SIZE > 0,
211*bbb1b6f9SApple OSS Distributions //               "unexpected reserved field size");
212*bbb1b6f9SApple OSS Distributions 
213*bbb1b6f9SApple OSS Distributions static_assert(IOCIRCULARDATAQUEUE_STATE_GENERATION_SIZE == IOCIRCULARDATAQUEUE_ENTRY_STATE_GENERATION_SIZE,
214*bbb1b6f9SApple OSS Distributions     "mismatched generation sizes");
215*bbb1b6f9SApple OSS Distributions static_assert(IOCIRCULARDATAQUEUE_STATE_SEQNUM_SIZE == IOCIRCULARDATAQUEUE_ENTRY_STATE_SEQNUM_SIZE,
216*bbb1b6f9SApple OSS Distributions     "mismatched sequenece number sizes");
217*bbb1b6f9SApple OSS Distributions 
218*bbb1b6f9SApple OSS Distributions /*!
219*bbb1b6f9SApple OSS Distributions  * @typedef IOCircularDataQueueMemory
220*bbb1b6f9SApple OSS Distributions  * @abstract The queue memory header present at the start of  queue shared memory region.
221*bbb1b6f9SApple OSS Distributions  * @discussion The queue memory header contains the queue info and state and is followed by the data region of the
222*bbb1b6f9SApple OSS Distributions  * queue.
223*bbb1b6f9SApple OSS Distributions  * @field sentinel unique value when the queue was created.
224*bbb1b6f9SApple OSS Distributions  * @field allocMemSize the allocated memory size of the queue including the queue header and the entries
225*bbb1b6f9SApple OSS Distributions  * @field memorySize  the memory size of the queue excluding the queue header
226*bbb1b6f9SApple OSS Distributions  * @field entryDataSize size of each entry in the queue including the entry header. The size is a multiple of 8 bytes
227*bbb1b6f9SApple OSS Distributions  * @field dataSize size of each entry in the queue excluding the entry header.
228*bbb1b6f9SApple OSS Distributions  * @field numEntries the number of fixed entries in the queue
229*bbb1b6f9SApple OSS Distributions  * @field `_padding` memory padding for alingment.
230*bbb1b6f9SApple OSS Distributions  * @field state the current state of the queue.
231*bbb1b6f9SApple OSS Distributions  * @field entries Represents the beginning of the data region.  The address of the data field is a pointer to the start
232*bbb1b6f9SApple OSS Distributions  * of the queue data region.
233*bbb1b6f9SApple OSS Distributions  */
234*bbb1b6f9SApple OSS Distributions 
235*bbb1b6f9SApple OSS Distributions typedef struct IOCircularDataQueueMemory {
236*bbb1b6f9SApple OSS Distributions 	uint64_t sentinel;
237*bbb1b6f9SApple OSS Distributions 	uint64_t _padding; // since we want it to be 16 bytes aligned below this
238*bbb1b6f9SApple OSS Distributions 	union {
239*bbb1b6f9SApple OSS Distributions 		volatile _Atomic __uint128_t queueStateVal;           // needs to be 16 bytes aligned.
240*bbb1b6f9SApple OSS Distributions 		IOCircularDataQueueState  __queueState;               // for clarity, unused
241*bbb1b6f9SApple OSS Distributions 	};
242*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueEntryHeader entries[1]; // Entries begin.  Aligned to 16 bytes.
243*bbb1b6f9SApple OSS Distributions } IOCircularDataQueueMemory;
244*bbb1b6f9SApple OSS Distributions 
245*bbb1b6f9SApple OSS Distributions #define CIRCULAR_DATA_QUEUE_MEMORY_HEADER_SIZE                                                                         \
246*bbb1b6f9SApple OSS Distributions     (sizeof(IOCircularDataQueueMemory) - sizeof(IOCircularDataQueueEntryHeader))
247*bbb1b6f9SApple OSS Distributions 
248*bbb1b6f9SApple OSS Distributions /*!
249*bbb1b6f9SApple OSS Distributions  * @typedef IOCircularDataQueueMemoryCursor
250*bbb1b6f9SApple OSS Distributions  * @abstract The circular data queue cursor struct.
251*bbb1b6f9SApple OSS Distributions  * @discussion This struct represents a readers reference to a position in the queue. Each client holds an instance of
252*bbb1b6f9SApple OSS Distributions  * this in its process indicating its current reading position in the queue. The cursor holds uniqely identifying
253*bbb1b6f9SApple OSS Distributions  * information for the queue entry.
254*bbb1b6f9SApple OSS Distributions  * @field generation  the generation for the entry data at the position in the queue. This generation is only changed
255*bbb1b6f9SApple OSS Distributions  * when the queue is reset.
256*bbb1b6f9SApple OSS Distributions  * @field position the position in the queue  the cursor is at
257*bbb1b6f9SApple OSS Distributions  * @field sequenceNum  The unique number for the data at the  cursor position. The sequence number is unique for each
258*bbb1b6f9SApple OSS Distributions  * entry in the queue.
259*bbb1b6f9SApple OSS Distributions  *
260*bbb1b6f9SApple OSS Distributions  */
261*bbb1b6f9SApple OSS Distributions typedef struct IOCircularDataQueueMemoryCursor {
262*bbb1b6f9SApple OSS Distributions 	uint32_t generation; // uint32_t seems a little excessive right now, since we dont expect these many resets. but
263*bbb1b6f9SApple OSS Distributions 	                     // lets leave it for now.
264*bbb1b6f9SApple OSS Distributions 	uint32_t position;
265*bbb1b6f9SApple OSS Distributions 	uint64_t sequenceNum;
266*bbb1b6f9SApple OSS Distributions } IOCircularDataQueueMemoryCursor;
267*bbb1b6f9SApple OSS Distributions 
268*bbb1b6f9SApple OSS Distributions 
269*bbb1b6f9SApple OSS Distributions /*!
270*bbb1b6f9SApple OSS Distributions  * @typedef IOCircularDataQueueDescription
271*bbb1b6f9SApple OSS Distributions  * @abstract The circular data queue header shadow struct.
272*bbb1b6f9SApple OSS Distributions  * @discussion This struct represents the queue header shadow. Each client has a copy of this struct in its process .
273*bbb1b6f9SApple OSS Distributions  * This is used to detect any memory corruption of the shared memory queue header. This struct needs to be shared from
274*bbb1b6f9SApple OSS Distributions  * the creator of the queue to the clients via an out of band mechanism.
275*bbb1b6f9SApple OSS Distributions  * @field sentinel unique value written to the queue header memory and each queue entry.
276*bbb1b6f9SApple OSS Distributions  * @field allocMemSize the allocated memory size of the queue including the queue header
277*bbb1b6f9SApple OSS Distributions  * @field entryDataSize size of each entry in the queue including the entry header. The size is a multiple of 8 bytes
278*bbb1b6f9SApple OSS Distributions  * @field memorySize  the memory size of the queue excluding the queue header
279*bbb1b6f9SApple OSS Distributions  * @field numEntries the number of fixed entries in the queue
280*bbb1b6f9SApple OSS Distributions  * IOCircularDataQueueDescription
281*bbb1b6f9SApple OSS Distributions  */
282*bbb1b6f9SApple OSS Distributions typedef struct IOCircularDataQueueDescription {
283*bbb1b6f9SApple OSS Distributions 	uint64_t sentinel;
284*bbb1b6f9SApple OSS Distributions 	uint32_t allocMemSize; // total allocated size of the queue including the queue header.
285*bbb1b6f9SApple OSS Distributions 	uint32_t entryDataSize; // size of each queue entry including the per entry header.
286*bbb1b6f9SApple OSS Distributions 	uint32_t memorySize; // memory size of the queue (excluding the queue header)
287*bbb1b6f9SApple OSS Distributions 	uint32_t numEntries;
288*bbb1b6f9SApple OSS Distributions 	uint32_t dataSize; // the client provided data size excluding the per entry header.
289*bbb1b6f9SApple OSS Distributions 	uint32_t padding;
290*bbb1b6f9SApple OSS Distributions } IOCircularDataQueueDescription;
291*bbb1b6f9SApple OSS Distributions 
292*bbb1b6f9SApple OSS Distributions #define kIOCircularQueueDescriptionKey  "IOCircularQueueDescription"
293*bbb1b6f9SApple OSS Distributions 
294*bbb1b6f9SApple OSS Distributions 
295*bbb1b6f9SApple OSS Distributions #if !KERNEL
296*bbb1b6f9SApple OSS Distributions /*
297*bbb1b6f9SApple OSS Distributions  * IORound and IOTrunc convenience functions, in the spirit
298*bbb1b6f9SApple OSS Distributions  * of vm's round_page() and trunc_page().
299*bbb1b6f9SApple OSS Distributions  */
300*bbb1b6f9SApple OSS Distributions #define IORound(value, multiple) ((((value) + (multiple)-1) / (multiple)) * (multiple))
301*bbb1b6f9SApple OSS Distributions 
302*bbb1b6f9SApple OSS Distributions #define IONew(type, count) (type *)calloc(count, sizeof(type))
303*bbb1b6f9SApple OSS Distributions #define IODelete(p, type, count) free(p)
304*bbb1b6f9SApple OSS Distributions 
305*bbb1b6f9SApple OSS Distributions // libkern/os/base.h
306*bbb1b6f9SApple OSS Distributions #if __has_feature(ptrauth_calls)
307*bbb1b6f9SApple OSS Distributions #include <ptrauth.h>
308*bbb1b6f9SApple OSS Distributions #define OS_PTRAUTH_SIGNED_PTR(type) __ptrauth(ptrauth_key_process_independent_data, 1, ptrauth_string_discriminator(type))
309*bbb1b6f9SApple OSS Distributions #define OS_PTRAUTH_SIGNED_PTR_AUTH_NULL(type) __ptrauth(ptrauth_key_process_independent_data, 1, ptrauth_string_discriminator(type), "authenticates-null-values")
310*bbb1b6f9SApple OSS Distributions #define OS_PTRAUTH_DISCRIMINATOR(str) ptrauth_string_discriminator(str)
311*bbb1b6f9SApple OSS Distributions #define __ptrauth_only
312*bbb1b6f9SApple OSS Distributions #else //  __has_feature(ptrauth_calls)
313*bbb1b6f9SApple OSS Distributions #define OS_PTRAUTH_SIGNED_PTR(type)
314*bbb1b6f9SApple OSS Distributions #define OS_PTRAUTH_SIGNED_PTR_AUTH_NULL(type)
315*bbb1b6f9SApple OSS Distributions #define OS_PTRAUTH_DISCRIMINATOR(str) 0
316*bbb1b6f9SApple OSS Distributions #define __ptrauth_only __unused
317*bbb1b6f9SApple OSS Distributions #endif // __has_feature(ptrauth_calls)
318*bbb1b6f9SApple OSS Distributions #endif /* !KERNEL */
319*bbb1b6f9SApple OSS Distributions 
320*bbb1b6f9SApple OSS Distributions #pragma mark - Debugging
321*bbb1b6f9SApple OSS Distributions 
322*bbb1b6f9SApple OSS Distributions #define QUEUE_FORMAT "Queue(%" PRIu64 " gen:%" PRIu64 " pos:%" PRIu64 " next:%" PRIu64 ")"
323*bbb1b6f9SApple OSS Distributions #define QUEUE_ARGS(q) q->guard, q->generation, q->fixed.latestIndex, q->fixed.writingIndex
324*bbb1b6f9SApple OSS Distributions 
325*bbb1b6f9SApple OSS Distributions #define CURSOR_FORMAT "Cursor(%p gen:%" PRIu64 " pos:%" PRIu64 ")"
326*bbb1b6f9SApple OSS Distributions #define CURSOR_ARGS(c) c, c->generation, c->position
327*bbb1b6f9SApple OSS Distributions 
328*bbb1b6f9SApple OSS Distributions #define ENTRY_FORMAT "Entry(%" PRIu64 " gen:%" PRIu64 " pos:%" PRIu64 ")"
329*bbb1b6f9SApple OSS Distributions #define ENTRY_ARGS(e) e->guard, e->generation, e->position
330*bbb1b6f9SApple OSS Distributions 
331*bbb1b6f9SApple OSS Distributions #if 1
332*bbb1b6f9SApple OSS Distributions #define queue_debug_error(fmt, ...)
333*bbb1b6f9SApple OSS Distributions #define queue_debug_note(fmt, ...)
334*bbb1b6f9SApple OSS Distributions #define queue_debug_trace(fmt, ...)
335*bbb1b6f9SApple OSS Distributions #else
336*bbb1b6f9SApple OSS Distributions #define queue_debug_error(fmt, ...)                                                                                    \
337*bbb1b6f9SApple OSS Distributions     {                                                                                                                  \
338*bbb1b6f9SApple OSS Distributions 	os_log_debug(LOG_QUEUE, "#ERROR %s:%d %s " fmt, __FILE__, __LINE__, __func__, ##__VA_ARGS__);                  \
339*bbb1b6f9SApple OSS Distributions     }
340*bbb1b6f9SApple OSS Distributions #define queue_debug_note(fmt, ...)                                                                                     \
341*bbb1b6f9SApple OSS Distributions     {                                                                                                                  \
342*bbb1b6f9SApple OSS Distributions 	os_log_debug(LOG_QUEUE, "#NOTE %s:%d %s " fmt, __FILE__, __LINE__, __func__, ##__VA_ARGS__);                   \
343*bbb1b6f9SApple OSS Distributions     }
344*bbb1b6f9SApple OSS Distributions #define queue_debug_trace(fmt, ...)                                                                                    \
345*bbb1b6f9SApple OSS Distributions     {                                                                                                                  \
346*bbb1b6f9SApple OSS Distributions 	os_log_debug(LOG_QUEUE, "#TRACE %s:%d %s " fmt, __FILE__, __LINE__, __func__, ##__VA_ARGS__);                  \
347*bbb1b6f9SApple OSS Distributions     }
348*bbb1b6f9SApple OSS Distributions #endif
349*bbb1b6f9SApple OSS Distributions 
350*bbb1b6f9SApple OSS Distributions #if HEADER_16BYTE_ALIGNED
351*bbb1b6f9SApple OSS Distributions static_assert(offsetof(IOCircularDataQueueEntryHeader, data) % sizeof(__uint128_t) == 0,
352*bbb1b6f9SApple OSS Distributions     "IOCircularDataQueueEntryHeader.data is not 16-byte aligned!");
353*bbb1b6f9SApple OSS Distributions #else
354*bbb1b6f9SApple OSS Distributions static_assert(offsetof(IOCircularDataQueueEntryHeader, data) % sizeof(uint64_t) == 0,
355*bbb1b6f9SApple OSS Distributions     "IOCircularDataQueueEntryHeader.data is not 8-byte aligned!");
356*bbb1b6f9SApple OSS Distributions #endif
357*bbb1b6f9SApple OSS Distributions 
358*bbb1b6f9SApple OSS Distributions static_assert(sizeof(IOCircularDataQueueState) == sizeof(__uint128_t), "Unexpected padding");
359*bbb1b6f9SApple OSS Distributions static_assert(offsetof(IOCircularDataQueueMemory, queueStateVal) % sizeof(__uint128_t) == 0,
360*bbb1b6f9SApple OSS Distributions     "IOCircularDataQueueMemory.entries is not 16-byte aligned!");
361*bbb1b6f9SApple OSS Distributions 
362*bbb1b6f9SApple OSS Distributions #if HEADER_16BYTE_ALIGNED
363*bbb1b6f9SApple OSS Distributions static_assert(offsetof(IOCircularDataQueueMemory, entries) % sizeof(__uint128_t) == 0,
364*bbb1b6f9SApple OSS Distributions     "IOCircularDataQueueMemory.entries is not 16-byte aligned!");
365*bbb1b6f9SApple OSS Distributions #else
366*bbb1b6f9SApple OSS Distributions static_assert(offsetof(IOCircularDataQueueMemory, entries) % sizeof(uint64_t) == 0,
367*bbb1b6f9SApple OSS Distributions     "IOCircularDataQueueMemory.entries is not 8-byte aligned!");
368*bbb1b6f9SApple OSS Distributions #endif
369*bbb1b6f9SApple OSS Distributions 
370*bbb1b6f9SApple OSS Distributions /*!
371*bbb1b6f9SApple OSS Distributions  * @typedef IOCircularDataQueue
372*bbb1b6f9SApple OSS Distributions  * @abstract A fixed entry size circular queue that supports multiple concurrent readers and a single writer.
373*bbb1b6f9SApple OSS Distributions  * @discussion The queue currently supports fixed size entries. The queue memory size is configured at init when the
374*bbb1b6f9SApple OSS Distributions  * number of entries and size of each entry is specifiied and cannot be resized later. Since the queue is a circular
375*bbb1b6f9SApple OSS Distributions  * buffer, the writer can potentially overwrite an entry while a reader is still reading it. The queue provides facility
376*bbb1b6f9SApple OSS Distributions  * to check for data integrity after reading the entry is complete. There is no support for sending notifications to
377*bbb1b6f9SApple OSS Distributions  * readers when data is enqueued into an empty queue by the writer. The queue supports a "pull model" for reading data
378*bbb1b6f9SApple OSS Distributions  * from the queue. The queue can be used for passing data from user space to kernel and vice-versa.
379*bbb1b6f9SApple OSS Distributions  * @field queueHeaderShadow    The queue header shadow
380*bbb1b6f9SApple OSS Distributions  * @field queueCursor    The queue cursor
381*bbb1b6f9SApple OSS Distributions  * @field isQueueMemoryAllocated    Represents if the queue memory is allocated or if the queue uses a previously
382*bbb1b6f9SApple OSS Distributions  * created queue memory region.
383*bbb1b6f9SApple OSS Distributions  * @field queueMemory    Pointer to the queue shared memory region
384*bbb1b6f9SApple OSS Distributions  */
385*bbb1b6f9SApple OSS Distributions typedef struct IOCircularDataQueue {
386*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueMemoryCursor queueCursor;
387*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueMemory * OS_PTRAUTH_SIGNED_PTR("IOCircularDataQueue.queueMemory") queueMemory;
388*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueDescription queueHeaderShadow;
389*bbb1b6f9SApple OSS Distributions #if KERNEL
390*bbb1b6f9SApple OSS Distributions 	IOBufferMemoryDescriptor * OS_PTRAUTH_SIGNED_PTR("IOCircularDataQueue.iomd") iomd;
391*bbb1b6f9SApple OSS Distributions #else /* KERNEL */
392*bbb1b6f9SApple OSS Distributions 	io_connect_t connect;
393*bbb1b6f9SApple OSS Distributions 	uint32_t memoryType;
394*bbb1b6f9SApple OSS Distributions #endif /* !KERNEL */
395*bbb1b6f9SApple OSS Distributions } IOCircularDataQueue;
396*bbb1b6f9SApple OSS Distributions 
397*bbb1b6f9SApple OSS Distributions 
398*bbb1b6f9SApple OSS Distributions #if defined(__arm64__) && !KERNEL
399*bbb1b6f9SApple OSS Distributions #define ATTR_LSE2 __attribute__((target("lse2")))
400*bbb1b6f9SApple OSS Distributions #else
401*bbb1b6f9SApple OSS Distributions #define ATTR_LSE2
402*bbb1b6f9SApple OSS Distributions #endif /* defined(__arm64__) && !KERNEL */
403*bbb1b6f9SApple OSS Distributions 
404*bbb1b6f9SApple OSS Distributions #pragma mark - Queue
405*bbb1b6f9SApple OSS Distributions 
406*bbb1b6f9SApple OSS Distributions static bool ATTR_LSE2
_isQueueMemoryCorrupted(IOCircularDataQueue * queue)407*bbb1b6f9SApple OSS Distributions _isQueueMemoryCorrupted(IOCircularDataQueue *queue)
408*bbb1b6f9SApple OSS Distributions {
409*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueMemory *queueMemory = queue->queueMemory;
410*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueDescription *queueHeaderShadow = &queue->queueHeaderShadow;
411*bbb1b6f9SApple OSS Distributions 
412*bbb1b6f9SApple OSS Distributions 	const size_t queueSentinel = queueMemory->sentinel;
413*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(queueSentinel != queueHeaderShadow->sentinel)) {
414*bbb1b6f9SApple OSS Distributions 		return true;
415*bbb1b6f9SApple OSS Distributions 	}
416*bbb1b6f9SApple OSS Distributions 	return false;
417*bbb1b6f9SApple OSS Distributions }
418*bbb1b6f9SApple OSS Distributions 
419*bbb1b6f9SApple OSS Distributions inline static bool ATTR_LSE2
_isCursorPositionInvalid(IOCircularDataQueue * queue)420*bbb1b6f9SApple OSS Distributions _isCursorPositionInvalid(IOCircularDataQueue *queue)
421*bbb1b6f9SApple OSS Distributions {
422*bbb1b6f9SApple OSS Distributions //	IOCircularDataQueueMemory *queueMemory = queue->queueMemory;
423*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueDescription *queueHeaderShadow = &queue->queueHeaderShadow;
424*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueMemoryCursor const *cursor = &queue->queueCursor;
425*bbb1b6f9SApple OSS Distributions 
426*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(cursor->position >= queueHeaderShadow->numEntries)) {
427*bbb1b6f9SApple OSS Distributions 		return true;
428*bbb1b6f9SApple OSS Distributions 	}
429*bbb1b6f9SApple OSS Distributions 
430*bbb1b6f9SApple OSS Distributions 	return false;
431*bbb1b6f9SApple OSS Distributions }
432*bbb1b6f9SApple OSS Distributions 
433*bbb1b6f9SApple OSS Distributions inline __unused static bool ATTR_LSE2
_isEntryOutOfBounds(IOCircularDataQueue * queue,IOCircularDataQueueEntryHeader * entry)434*bbb1b6f9SApple OSS Distributions _isEntryOutOfBounds(IOCircularDataQueue *queue, IOCircularDataQueueEntryHeader *entry)
435*bbb1b6f9SApple OSS Distributions {
436*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueMemory *queueMemory = queue->queueMemory;
437*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueDescription *queueHeaderShadow = &queue->queueHeaderShadow;
438*bbb1b6f9SApple OSS Distributions //	IOCircularDataQueueMemoryCursor const *cursor = &queue->queueCursor;
439*bbb1b6f9SApple OSS Distributions 
440*bbb1b6f9SApple OSS Distributions 	bool ret = false;
441*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueEntryHeader *firstEntry = (IOCircularDataQueueEntryHeader *)(&queueMemory->entries[0]);
442*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueEntryHeader *lastEntry
443*bbb1b6f9SApple OSS Distributions 	        = (IOCircularDataQueueEntryHeader *)(uintptr_t)((uint8_t *)&queueMemory->entries[0]
444*bbb1b6f9SApple OSS Distributions 	    + ((queueHeaderShadow->numEntries - 1) * queueHeaderShadow->entryDataSize));
445*bbb1b6f9SApple OSS Distributions 
446*bbb1b6f9SApple OSS Distributions 	// SANITY CHECK - Final check to ensure the 'entry' pointer is
447*bbb1b6f9SApple OSS Distributions 	// within the queueMemory allocation before we begin writing.
448*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(entry < firstEntry || entry > lastEntry)) {
449*bbb1b6f9SApple OSS Distributions 		ret = true;
450*bbb1b6f9SApple OSS Distributions 	}
451*bbb1b6f9SApple OSS Distributions 
452*bbb1b6f9SApple OSS Distributions 	return ret;
453*bbb1b6f9SApple OSS Distributions }
454*bbb1b6f9SApple OSS Distributions 
455*bbb1b6f9SApple OSS Distributions 
456*bbb1b6f9SApple OSS Distributions #if !KERNEL
457*bbb1b6f9SApple OSS Distributions /*!
458*bbb1b6f9SApple OSS Distributions  * @function isQueueMemoryValid
459*bbb1b6f9SApple OSS Distributions  * Verify if the queue header shadow matches the queue header in shared memory.
460*bbb1b6f9SApple OSS Distributions  * @param queue Handle to the queue.
461*bbb1b6f9SApple OSS Distributions  * @return `true` if the queue header shadow matches the queue header in shared memory, else `false`.
462*bbb1b6f9SApple OSS Distributions  *
463*bbb1b6f9SApple OSS Distributions  */
464*bbb1b6f9SApple OSS Distributions 
465*bbb1b6f9SApple OSS Distributions static bool ATTR_LSE2
isQueueMemoryValid(IOCircularDataQueue * queue)466*bbb1b6f9SApple OSS Distributions isQueueMemoryValid(IOCircularDataQueue *queue)
467*bbb1b6f9SApple OSS Distributions {
468*bbb1b6f9SApple OSS Distributions 	return _isQueueMemoryCorrupted(queue) == false;
469*bbb1b6f9SApple OSS Distributions }
470*bbb1b6f9SApple OSS Distributions #endif /* KERNEL */
471*bbb1b6f9SApple OSS Distributions 
472*bbb1b6f9SApple OSS Distributions /*!
473*bbb1b6f9SApple OSS Distributions  * @function destroyQueueMem
474*bbb1b6f9SApple OSS Distributions  * @abstract Function that destroys a previously created IOCircularDataQueueMemory instance.
475*bbb1b6f9SApple OSS Distributions  * @param queue Handle to the queue.
476*bbb1b6f9SApple OSS Distributions  *  @return
477*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnSuccess` if the queue was succesfully destroyed.
478*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnBadArgument` if an invalid queue was provided.
479*bbb1b6f9SApple OSS Distributions  */
480*bbb1b6f9SApple OSS Distributions 
481*bbb1b6f9SApple OSS Distributions static IOReturn ATTR_LSE2
destroyQueueMem(IOCircularDataQueue * queue)482*bbb1b6f9SApple OSS Distributions destroyQueueMem(IOCircularDataQueue *queue)
483*bbb1b6f9SApple OSS Distributions {
484*bbb1b6f9SApple OSS Distributions 	IOReturn ret = kIOReturnBadArgument;
485*bbb1b6f9SApple OSS Distributions 	if (queue != NULL) {
486*bbb1b6f9SApple OSS Distributions #if KERNEL
487*bbb1b6f9SApple OSS Distributions 		OSSafeReleaseNULL(queue->iomd);
488*bbb1b6f9SApple OSS Distributions #else /* !KERNEL */
489*bbb1b6f9SApple OSS Distributions 		IOCircularDataQueueMemory *queueMemory = queue->queueMemory;
490*bbb1b6f9SApple OSS Distributions 		IOCircularDataQueueDescription *queueHeaderShadow = &queue->queueHeaderShadow;
491*bbb1b6f9SApple OSS Distributions 		if (queueMemory) {
492*bbb1b6f9SApple OSS Distributions 			ret = IOConnectUnmapMemory(queue->connect, queue->memoryType,
493*bbb1b6f9SApple OSS Distributions 			    mach_task_self(), (mach_vm_address_t) queueMemory);
494*bbb1b6f9SApple OSS Distributions //			assert(KERN_SUCCESS == ret);
495*bbb1b6f9SApple OSS Distributions 			queue->queueMemory = NULL;
496*bbb1b6f9SApple OSS Distributions 		}
497*bbb1b6f9SApple OSS Distributions #endif
498*bbb1b6f9SApple OSS Distributions 		ret = kIOReturnSuccess;
499*bbb1b6f9SApple OSS Distributions 	}
500*bbb1b6f9SApple OSS Distributions 
501*bbb1b6f9SApple OSS Distributions 	return ret;
502*bbb1b6f9SApple OSS Distributions }
503*bbb1b6f9SApple OSS Distributions 
504*bbb1b6f9SApple OSS Distributions static IOReturn ATTR_LSE2
_reset(IOCircularDataQueue * queue)505*bbb1b6f9SApple OSS Distributions _reset(IOCircularDataQueue *queue)
506*bbb1b6f9SApple OSS Distributions {
507*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueMemory *queueMemory = queue->queueMemory;
508*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueDescription *queueHeaderShadow = &queue->queueHeaderShadow;
509*bbb1b6f9SApple OSS Distributions 
510*bbb1b6f9SApple OSS Distributions 	if (queueMemory == NULL || queueHeaderShadow == NULL) {
511*bbb1b6f9SApple OSS Distributions 		return kIOReturnBadArgument;
512*bbb1b6f9SApple OSS Distributions 	}
513*bbb1b6f9SApple OSS Distributions 
514*bbb1b6f9SApple OSS Distributions 	const size_t queueEntryDataSize = queueHeaderShadow->entryDataSize;
515*bbb1b6f9SApple OSS Distributions 	if (!queueEntryDataSize) {
516*bbb1b6f9SApple OSS Distributions 		return kIOReturnUnsupported;
517*bbb1b6f9SApple OSS Distributions 	}
518*bbb1b6f9SApple OSS Distributions 
519*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueState currState;
520*bbb1b6f9SApple OSS Distributions 	currState.val = atomic_load_explicit(&queueMemory->queueStateVal, memory_order_acquire);
521*bbb1b6f9SApple OSS Distributions 
522*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(currState.fields.wrStatus & IOCIRCULARDATAQUEUE_STATE_WRITE_INPROGRESS)) {
523*bbb1b6f9SApple OSS Distributions 		// Another thread is modifying the queue
524*bbb1b6f9SApple OSS Distributions 		return kIOReturnBusy;
525*bbb1b6f9SApple OSS Distributions 	}
526*bbb1b6f9SApple OSS Distributions 
527*bbb1b6f9SApple OSS Distributions 	uint32_t currGeneration = currState.fields.generation;
528*bbb1b6f9SApple OSS Distributions 	uint32_t newGen = (currGeneration + 1) % IOCIRCULARDATAQUEUE_STATE_GENERATION_MAX;
529*bbb1b6f9SApple OSS Distributions 
530*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueState newState;
531*bbb1b6f9SApple OSS Distributions 	newState.fields.generation = newGen;
532*bbb1b6f9SApple OSS Distributions 	newState.fields.wrIndex = 0;
533*bbb1b6f9SApple OSS Distributions 	newState.fields.seqNum = UINT64_MAX; // since we first increment the seq num on an enqueue.
534*bbb1b6f9SApple OSS Distributions 
535*bbb1b6f9SApple OSS Distributions 	if (!atomic_compare_exchange_strong(&queueMemory->queueStateVal, &currState.val, newState.val)) {
536*bbb1b6f9SApple OSS Distributions 		return kIOReturnBusy;
537*bbb1b6f9SApple OSS Distributions 	}
538*bbb1b6f9SApple OSS Distributions 
539*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(_isQueueMemoryCorrupted(queue))) {
540*bbb1b6f9SApple OSS Distributions 		return kIOReturnBadMedia;
541*bbb1b6f9SApple OSS Distributions 	}
542*bbb1b6f9SApple OSS Distributions 
543*bbb1b6f9SApple OSS Distributions 	queue_debug_trace("Reset " QUEUE_FORMAT, QUEUE_ARGS(queueMemory));
544*bbb1b6f9SApple OSS Distributions 	return kIOReturnSuccess;
545*bbb1b6f9SApple OSS Distributions }
546*bbb1b6f9SApple OSS Distributions 
547*bbb1b6f9SApple OSS Distributions /*!
548*bbb1b6f9SApple OSS Distributions  * @function _enqueueInternal
549*bbb1b6f9SApple OSS Distributions  * @abstract Internal function for enqueuing a new entry on the queue.
550*bbb1b6f9SApple OSS Distributions  * @discussion This method adds a new data entry of dataSize to the queue.  It sets the size parameter of the entry
551*bbb1b6f9SApple OSS Distributions  * pointed to by the tail value and copies the memory pointed to by the data parameter in place in the queue.  Once that
552*bbb1b6f9SApple OSS Distributions  * is done, it moves the tail to the next available location.  When attempting to add a new entry towards the end of the
553*bbb1b6f9SApple OSS Distributions  * queue and there isn't enough space at the end, it wraps back to the beginning.<br>
554*bbb1b6f9SApple OSS Distributions  * @param queue Handle to the queue.
555*bbb1b6f9SApple OSS Distributions  * @param data Pointer to the data to be added to the queue.
556*bbb1b6f9SApple OSS Distributions  * @param dataSize Size of the data pointed to by data.
557*bbb1b6f9SApple OSS Distributions  * @param earlyExitForTesting ealy exit flag used for testing only.
558*bbb1b6f9SApple OSS Distributions  *  @return
559*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnSuccess` on success.
560*bbb1b6f9SApple OSS Distributions  *  - Other values indicate an error.
561*bbb1b6f9SApple OSS Distributions  */
562*bbb1b6f9SApple OSS Distributions 
563*bbb1b6f9SApple OSS Distributions static IOReturn ATTR_LSE2
_enqueueInternal(IOCircularDataQueue * queue,const void * data,size_t dataSize,int earlyExitForTesting)564*bbb1b6f9SApple OSS Distributions _enqueueInternal(IOCircularDataQueue *queue,
565*bbb1b6f9SApple OSS Distributions     const void *data,
566*bbb1b6f9SApple OSS Distributions     size_t dataSize,
567*bbb1b6f9SApple OSS Distributions     int earlyExitForTesting)
568*bbb1b6f9SApple OSS Distributions {
569*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueMemory *queueMemory = queue->queueMemory;
570*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueDescription *queueHeaderShadow = &queue->queueHeaderShadow;
571*bbb1b6f9SApple OSS Distributions //	IOCircularDataQueueMemoryCursor const *cursor = &queue->queueCursor;
572*bbb1b6f9SApple OSS Distributions 
573*bbb1b6f9SApple OSS Distributions 	if (queueMemory == NULL || data == NULL || dataSize == 0 || queueHeaderShadow == NULL) {
574*bbb1b6f9SApple OSS Distributions 		return kIOReturnBadArgument;
575*bbb1b6f9SApple OSS Distributions 	}
576*bbb1b6f9SApple OSS Distributions 
577*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(_isQueueMemoryCorrupted(queue))) {
578*bbb1b6f9SApple OSS Distributions 		return kIOReturnBadMedia;
579*bbb1b6f9SApple OSS Distributions 	}
580*bbb1b6f9SApple OSS Distributions 
581*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(dataSize > queueHeaderShadow->dataSize)) {
582*bbb1b6f9SApple OSS Distributions 		return kIOReturnBadArgument;
583*bbb1b6f9SApple OSS Distributions 	}
584*bbb1b6f9SApple OSS Distributions 
585*bbb1b6f9SApple OSS Distributions 	const size_t queueEntryDataSize = queueHeaderShadow->entryDataSize;
586*bbb1b6f9SApple OSS Distributions 
587*bbb1b6f9SApple OSS Distributions 	if (!queueEntryDataSize) {
588*bbb1b6f9SApple OSS Distributions 		return kIOReturnUnsupported;
589*bbb1b6f9SApple OSS Distributions 	}
590*bbb1b6f9SApple OSS Distributions 
591*bbb1b6f9SApple OSS Distributions 	const size_t queueAllocMemSize = queueHeaderShadow->allocMemSize;
592*bbb1b6f9SApple OSS Distributions 	const uint32_t queueNumEntries = queueHeaderShadow->numEntries;
593*bbb1b6f9SApple OSS Distributions 
594*bbb1b6f9SApple OSS Distributions 	// Do not allow instruction re-ordering prior to the header check.
595*bbb1b6f9SApple OSS Distributions 	os_compiler_barrier();
596*bbb1b6f9SApple OSS Distributions 
597*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueState currState;
598*bbb1b6f9SApple OSS Distributions 	currState.val = atomic_load_explicit(&queueMemory->queueStateVal, memory_order_acquire);
599*bbb1b6f9SApple OSS Distributions 
600*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(currState.fields.wrStatus & IOCIRCULARDATAQUEUE_STATE_WRITE_INPROGRESS)) {
601*bbb1b6f9SApple OSS Distributions 		// Another thread is modifying the queue
602*bbb1b6f9SApple OSS Distributions 		return kIOReturnBusy;
603*bbb1b6f9SApple OSS Distributions 	}
604*bbb1b6f9SApple OSS Distributions 
605*bbb1b6f9SApple OSS Distributions 	//            size_t queueEntriesBufferSize = queueMemory->allocMemSize - CIRCULAR_DATA_QUEUE_MEMORY_HEADER_SIZE;
606*bbb1b6f9SApple OSS Distributions 	uint32_t writeIndex = currState.fields.wrIndex;
607*bbb1b6f9SApple OSS Distributions 	uint64_t nextWriteIndex = (writeIndex + 1) % queueNumEntries;
608*bbb1b6f9SApple OSS Distributions 	uint64_t nextSeqNum = currState.fields.seqNum + 1;
609*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(nextSeqNum == UINT64_MAX)) {
610*bbb1b6f9SApple OSS Distributions 		// End of the world. How many enqueues are you trying to do !!!
611*bbb1b6f9SApple OSS Distributions //        abort();
612*bbb1b6f9SApple OSS Distributions 		return kIOReturnOverrun;
613*bbb1b6f9SApple OSS Distributions 	}
614*bbb1b6f9SApple OSS Distributions 
615*bbb1b6f9SApple OSS Distributions 	__auto_type entry
616*bbb1b6f9SApple OSS Distributions 	        = (IOCircularDataQueueEntryHeader *)(uintptr_t)((uint8_t *)&queueMemory->entries[0] + (writeIndex * queueEntryDataSize));
617*bbb1b6f9SApple OSS Distributions 	//                printf("entry=%p\n", (void *)entry);
618*bbb1b6f9SApple OSS Distributions 
619*bbb1b6f9SApple OSS Distributions 	// SANITY CHECK - Final check to ensure the 'entry' pointer is
620*bbb1b6f9SApple OSS Distributions 	// within the queueMemory allocation before we begin writing.
621*bbb1b6f9SApple OSS Distributions 	if (os_unlikely((uint8_t *)entry < (uint8_t *)(&queueMemory->entries[0])
622*bbb1b6f9SApple OSS Distributions 	    || (uint8_t *)entry >= (uint8_t *)queueMemory + queueAllocMemSize)) {
623*bbb1b6f9SApple OSS Distributions 		return kIOReturnBadArgument;
624*bbb1b6f9SApple OSS Distributions 	}
625*bbb1b6f9SApple OSS Distributions 
626*bbb1b6f9SApple OSS Distributions 	//            if (os_unlikely(_isEntryOutOfBounds(queueHeaderShadow, queueMemory, entry) )) {
627*bbb1b6f9SApple OSS Distributions 	//                ret = kIOReturnBadArgument;
628*bbb1b6f9SApple OSS Distributions 	//                break;
629*bbb1b6f9SApple OSS Distributions 	//            }
630*bbb1b6f9SApple OSS Distributions 
631*bbb1b6f9SApple OSS Distributions 	os_compiler_barrier();
632*bbb1b6f9SApple OSS Distributions 
633*bbb1b6f9SApple OSS Distributions 	// All checks passed. Set the write bit.
634*bbb1b6f9SApple OSS Distributions 
635*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueState newState = currState;
636*bbb1b6f9SApple OSS Distributions 	newState.fields.wrStatus = IOCIRCULARDATAQUEUE_STATE_WRITE_INPROGRESS;
637*bbb1b6f9SApple OSS Distributions 	// lets not change the writeIndex and seq num here.
638*bbb1b6f9SApple OSS Distributions 	//            newState.fields.wrIndex = nextWriteIndex;
639*bbb1b6f9SApple OSS Distributions 	//    newState.fields.seqNum = currState.fields.seqNum + 1; // its ok even if we ever rollover UINT64_MAX!!
640*bbb1b6f9SApple OSS Distributions 
641*bbb1b6f9SApple OSS Distributions 	if (!atomic_compare_exchange_strong(&queueMemory->queueStateVal, &currState.val, newState.val)) {
642*bbb1b6f9SApple OSS Distributions 		// someone else is modifying the queue
643*bbb1b6f9SApple OSS Distributions 		return kIOReturnBusy;
644*bbb1b6f9SApple OSS Distributions 	}
645*bbb1b6f9SApple OSS Distributions 
646*bbb1b6f9SApple OSS Distributions 	// Update the entry header info
647*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueEntryHeaderInfo enHeaderInfo;
648*bbb1b6f9SApple OSS Distributions 	enHeaderInfo.val = 0;
649*bbb1b6f9SApple OSS Distributions 	enHeaderInfo.fields.wrStatus = IOCIRCULARDATAQUEUE_ENTRY_STATE_WRITE_INPROGRESS;
650*bbb1b6f9SApple OSS Distributions 	enHeaderInfo.fields.generation = currState.fields.generation;
651*bbb1b6f9SApple OSS Distributions 	//    enHeaderInfo.fields.seqNum = newState.fields.seqNum;
652*bbb1b6f9SApple OSS Distributions 	enHeaderInfo.fields.seqNum = nextSeqNum;
653*bbb1b6f9SApple OSS Distributions 	enHeaderInfo.fields.dataSize = dataSize;
654*bbb1b6f9SApple OSS Distributions 	atomic_store_explicit(&entry->headerInfoVal, enHeaderInfo.val, memory_order_release);
655*bbb1b6f9SApple OSS Distributions 
656*bbb1b6f9SApple OSS Distributions 	entry->sentinel = queueHeaderShadow->sentinel;
657*bbb1b6f9SApple OSS Distributions 	memcpy(entry->data, data, dataSize);
658*bbb1b6f9SApple OSS Distributions 	enHeaderInfo.fields.wrStatus = IOCIRCULARDATAQUEUE_ENTRY_STATE_WRITE_COMPLETE;
659*bbb1b6f9SApple OSS Distributions 	atomic_store_explicit(&entry->headerInfoVal, enHeaderInfo.val, memory_order_release);
660*bbb1b6f9SApple OSS Distributions 
661*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueState finalState = newState;
662*bbb1b6f9SApple OSS Distributions 	finalState.fields.wrStatus = IOCIRCULARDATAQUEUE_STATE_WRITE_COMPLETE;
663*bbb1b6f9SApple OSS Distributions 	// Lets actually update the write index and seq num
664*bbb1b6f9SApple OSS Distributions 	finalState.fields.wrIndex = nextWriteIndex;
665*bbb1b6f9SApple OSS Distributions 	finalState.fields.seqNum = nextSeqNum;
666*bbb1b6f9SApple OSS Distributions 	atomic_store_explicit(&queueMemory->queueStateVal, finalState.val, memory_order_release);
667*bbb1b6f9SApple OSS Distributions 
668*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(_isQueueMemoryCorrupted(queue))) {
669*bbb1b6f9SApple OSS Distributions 		return kIOReturnBadMedia;
670*bbb1b6f9SApple OSS Distributions 	}
671*bbb1b6f9SApple OSS Distributions 
672*bbb1b6f9SApple OSS Distributions 	return kIOReturnSuccess;
673*bbb1b6f9SApple OSS Distributions }
674*bbb1b6f9SApple OSS Distributions 
675*bbb1b6f9SApple OSS Distributions /*!
676*bbb1b6f9SApple OSS Distributions  * @function enqueueQueueMem
677*bbb1b6f9SApple OSS Distributions  * @abstract Enqueues a new entry on the queue.
678*bbb1b6f9SApple OSS Distributions  * @discussion This method adds a new data entry of dataSize to the queue.  It sets the size parameter of the entry
679*bbb1b6f9SApple OSS Distributions  * pointed to by the write index  and copies the memory pointed to by the data parameter in place in the queue.  Once
680*bbb1b6f9SApple OSS Distributions  * that is done, it moves the write index to the next index.
681*bbb1b6f9SApple OSS Distributions  * @param queue Handle to the queue.
682*bbb1b6f9SApple OSS Distributions  * @param data Pointer to the data to be added to the queue.
683*bbb1b6f9SApple OSS Distributions  * @param dataSize Size of the data pointed to by data.
684*bbb1b6f9SApple OSS Distributions  *  @return
685*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnSuccess` on success.
686*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnBadMedia` if the queue shared memory has been compromised.
687*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnBadArgument` if an invalid queue was provided.
688*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnBusy` if another thread is enqueing concurrently
689*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnUnsupported` if the queue has not been configured to support fixed size entries. Variable size is
690*bbb1b6f9SApple OSS Distributions  * currently not supported
691*bbb1b6f9SApple OSS Distributions  *  - Other values indicate an error.
692*bbb1b6f9SApple OSS Distributions  */
693*bbb1b6f9SApple OSS Distributions 
694*bbb1b6f9SApple OSS Distributions static IOReturn ATTR_LSE2
enqueueQueueMem(IOCircularDataQueue * queue,const void * data,size_t dataSize)695*bbb1b6f9SApple OSS Distributions enqueueQueueMem(IOCircularDataQueue *queue,
696*bbb1b6f9SApple OSS Distributions     const void *data,
697*bbb1b6f9SApple OSS Distributions     size_t dataSize)
698*bbb1b6f9SApple OSS Distributions {
699*bbb1b6f9SApple OSS Distributions 	return _enqueueInternal(queue, data, dataSize, 0);
700*bbb1b6f9SApple OSS Distributions }
701*bbb1b6f9SApple OSS Distributions 
702*bbb1b6f9SApple OSS Distributions /*!
703*bbb1b6f9SApple OSS Distributions  * @function isDataEntryValidInQueueMem
704*bbb1b6f9SApple OSS Distributions  * Verify if the data at the cursor position is still valid. Call this function after having read the data from the
705*bbb1b6f9SApple OSS Distributions  * queue, since the buffer could potentially have been overwritten while being read. <br>
706*bbb1b6f9SApple OSS Distributions  * @param queue Handle to the queue.
707*bbb1b6f9SApple OSS Distributions  *  @return
708*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnSuccess` if the data at the cursor position was valid.
709*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnOverrun` if the entry at the cursor position is no longer valid and is
710*bbb1b6f9SApple OSS Distributions  *     potentially overwritten. Call getLatestInQueueMem to get the latest data and cursor position.
711*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnAborted` if the cursor has become invalid, possibly due to a reset of the queue.
712*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnBadArgument` if an invalid param was passed.
713*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnBadMedia` if the queueMemory is corrupted.
714*bbb1b6f9SApple OSS Distributions  *
715*bbb1b6f9SApple OSS Distributions  */
716*bbb1b6f9SApple OSS Distributions 
717*bbb1b6f9SApple OSS Distributions static IOReturn ATTR_LSE2
isDataEntryValidInQueueMem(IOCircularDataQueue * queue)718*bbb1b6f9SApple OSS Distributions isDataEntryValidInQueueMem(IOCircularDataQueue *queue)
719*bbb1b6f9SApple OSS Distributions {
720*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueMemory *queueMemory = queue->queueMemory;
721*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueDescription *queueHeaderShadow = &queue->queueHeaderShadow;
722*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueMemoryCursor const *cursor = &queue->queueCursor;
723*bbb1b6f9SApple OSS Distributions 
724*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(queueMemory == NULL || queueHeaderShadow == NULL)) {
725*bbb1b6f9SApple OSS Distributions 		return kIOReturnBadArgument;
726*bbb1b6f9SApple OSS Distributions 	}
727*bbb1b6f9SApple OSS Distributions 
728*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(_isQueueMemoryCorrupted(queue))) {
729*bbb1b6f9SApple OSS Distributions 		return kIOReturnBadMedia;
730*bbb1b6f9SApple OSS Distributions 	}
731*bbb1b6f9SApple OSS Distributions 
732*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(_isCursorPositionInvalid(queue))) {
733*bbb1b6f9SApple OSS Distributions 		return kIOReturnBadArgument;
734*bbb1b6f9SApple OSS Distributions 	}
735*bbb1b6f9SApple OSS Distributions 
736*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueState currState;
737*bbb1b6f9SApple OSS Distributions 	currState.val = atomic_load_explicit(&queueMemory->queueStateVal, memory_order_acquire);
738*bbb1b6f9SApple OSS Distributions 
739*bbb1b6f9SApple OSS Distributions 	// Fahad: We may remove this filed since we don't actually use it. Instead just use generation check below.
740*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(currState.fields.rstStatus & IOCIRCULARDATAQUEUE_STATE_RESET_INPROGRESS)) {
741*bbb1b6f9SApple OSS Distributions 		// Another thread is resetting the queue
742*bbb1b6f9SApple OSS Distributions 		return kIOReturnBusy;
743*bbb1b6f9SApple OSS Distributions 	}
744*bbb1b6f9SApple OSS Distributions 
745*bbb1b6f9SApple OSS Distributions 	uint32_t queueGeneration = currState.fields.generation;
746*bbb1b6f9SApple OSS Distributions 	if (queueGeneration != cursor->generation) {
747*bbb1b6f9SApple OSS Distributions 		//        return kIOReturnOverrun;
748*bbb1b6f9SApple OSS Distributions 		return kIOReturnAborted;
749*bbb1b6f9SApple OSS Distributions 	}
750*bbb1b6f9SApple OSS Distributions 
751*bbb1b6f9SApple OSS Distributions 	const size_t queueAllocMemSize = queueHeaderShadow->allocMemSize;
752*bbb1b6f9SApple OSS Distributions 	const size_t queueEntryDataSize = queueHeaderShadow->entryDataSize;
753*bbb1b6f9SApple OSS Distributions 	__auto_type entry = (IOCircularDataQueueEntryHeader *)(uintptr_t)((uint8_t *)&queueMemory->entries[0]
754*bbb1b6f9SApple OSS Distributions 	    + (cursor->position * queueEntryDataSize));
755*bbb1b6f9SApple OSS Distributions 
756*bbb1b6f9SApple OSS Distributions 	// SANITY CHECK - Final check to ensure the 'entry' pointer is
757*bbb1b6f9SApple OSS Distributions 	// within the queueMemory entries buffer before we begin writing.
758*bbb1b6f9SApple OSS Distributions 	if (os_unlikely((uint8_t *)entry < (uint8_t *)(&queueMemory->entries[0])
759*bbb1b6f9SApple OSS Distributions 	    || (uint8_t *)entry >= (uint8_t *)queueMemory + queueAllocMemSize)) {
760*bbb1b6f9SApple OSS Distributions 		queue_debug_error("Out of Bounds! " QUEUE_FORMAT " " CURSOR_FORMAT " " ENTRY_FORMAT, QUEUE_ARGS(queueMemory),
761*bbb1b6f9SApple OSS Distributions 		    CURSOR_ARGS(cursor), ENTRY_ARGS(entry));
762*bbb1b6f9SApple OSS Distributions 		return kIOReturnBadArgument;
763*bbb1b6f9SApple OSS Distributions 	}
764*bbb1b6f9SApple OSS Distributions 
765*bbb1b6f9SApple OSS Distributions 	os_compiler_barrier();
766*bbb1b6f9SApple OSS Distributions 
767*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(entry->sentinel != queueHeaderShadow->sentinel)) {
768*bbb1b6f9SApple OSS Distributions 		queue_debug_error("entry->sentinel != queueMemory->sentinel " QUEUE_FORMAT " " CURSOR_FORMAT " " ENTRY_FORMAT,
769*bbb1b6f9SApple OSS Distributions 		    QUEUE_ARGS(queueMemory), CURSOR_ARGS(cursor), ENTRY_ARGS(entry));
770*bbb1b6f9SApple OSS Distributions 		return kIOReturnBadMedia;
771*bbb1b6f9SApple OSS Distributions 	}
772*bbb1b6f9SApple OSS Distributions 
773*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueEntryHeaderInfo enHeaderInfo;
774*bbb1b6f9SApple OSS Distributions 	enHeaderInfo.val = atomic_load_explicit(&entry->headerInfoVal, memory_order_acquire);
775*bbb1b6f9SApple OSS Distributions 	uint32_t entryGeneration = enHeaderInfo.fields.generation;
776*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(entryGeneration != queueGeneration)) {
777*bbb1b6f9SApple OSS Distributions 		queue_debug_note("entryGeneration != queueGeneration " QUEUE_FORMAT " " CURSOR_FORMAT " " ENTRY_FORMAT,
778*bbb1b6f9SApple OSS Distributions 		    QUEUE_ARGS(queueMemory), CURSOR_ARGS(cursor), ENTRY_ARGS(entry));
779*bbb1b6f9SApple OSS Distributions 		return kIOReturnOverrun;
780*bbb1b6f9SApple OSS Distributions 	}
781*bbb1b6f9SApple OSS Distributions 
782*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(enHeaderInfo.fields.wrStatus == IOCIRCULARDATAQUEUE_ENTRY_STATE_WRITE_INPROGRESS
783*bbb1b6f9SApple OSS Distributions 	    || enHeaderInfo.fields.seqNum != cursor->sequenceNum)) {
784*bbb1b6f9SApple OSS Distributions 		return kIOReturnOverrun;
785*bbb1b6f9SApple OSS Distributions 	}
786*bbb1b6f9SApple OSS Distributions 
787*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(_isQueueMemoryCorrupted(queue))) {
788*bbb1b6f9SApple OSS Distributions 		return kIOReturnBadMedia;
789*bbb1b6f9SApple OSS Distributions 	}
790*bbb1b6f9SApple OSS Distributions 
791*bbb1b6f9SApple OSS Distributions 	return kIOReturnSuccess;
792*bbb1b6f9SApple OSS Distributions }
793*bbb1b6f9SApple OSS Distributions 
794*bbb1b6f9SApple OSS Distributions /*!
795*bbb1b6f9SApple OSS Distributions  * @function setCursorLatestInQueueMem
796*bbb1b6f9SApple OSS Distributions  * Set the current cursor position to the latest entry in the queue. This only updates the cursor and does not read the
797*bbb1b6f9SApple OSS Distributions  * data from the queue. If nothing has been enqueued into the queue yet, this returns an error.
798*bbb1b6f9SApple OSS Distributions  * @param queue Handle to the queue.
799*bbb1b6f9SApple OSS Distributions  *  @return
800*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnSuccess` if the cursor position was updated to the latest.
801*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnUnderrun` if nothing has ever been enqueued into the queue since there is no latest entry.
802*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnAborted` if the queue is in an irrecoverable state.
803*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnBadArgument` if an invalid argument is passsed.
804*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnBadMedia` if the queue shared memory has been compromised.
805*bbb1b6f9SApple OSS Distributions  *  - Other values indicate an error.
806*bbb1b6f9SApple OSS Distributions  *
807*bbb1b6f9SApple OSS Distributions  */
808*bbb1b6f9SApple OSS Distributions 
809*bbb1b6f9SApple OSS Distributions static IOReturn ATTR_LSE2
setCursorLatestInQueueMem(IOCircularDataQueue * queue)810*bbb1b6f9SApple OSS Distributions setCursorLatestInQueueMem(IOCircularDataQueue *queue)
811*bbb1b6f9SApple OSS Distributions {
812*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueMemory *queueMemory = queue->queueMemory;
813*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueDescription *queueHeaderShadow = &queue->queueHeaderShadow;
814*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueMemoryCursor *cursor = &queue->queueCursor;
815*bbb1b6f9SApple OSS Distributions 
816*bbb1b6f9SApple OSS Distributions 	if (queueMemory == NULL || queueHeaderShadow == NULL) {
817*bbb1b6f9SApple OSS Distributions 		return kIOReturnBadArgument;
818*bbb1b6f9SApple OSS Distributions 	}
819*bbb1b6f9SApple OSS Distributions 
820*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(_isQueueMemoryCorrupted(queue))) {
821*bbb1b6f9SApple OSS Distributions 		return kIOReturnBadMedia;
822*bbb1b6f9SApple OSS Distributions 	}
823*bbb1b6f9SApple OSS Distributions 
824*bbb1b6f9SApple OSS Distributions 	const size_t queueAllocMemSize = queueHeaderShadow->allocMemSize;
825*bbb1b6f9SApple OSS Distributions 	const size_t queueEntryDataSize = queueHeaderShadow->entryDataSize;
826*bbb1b6f9SApple OSS Distributions 
827*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueState currState;
828*bbb1b6f9SApple OSS Distributions 	currState.val = atomic_load_explicit(&queueMemory->queueStateVal, memory_order_acquire);
829*bbb1b6f9SApple OSS Distributions 
830*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(currState.fields.rstStatus & IOCIRCULARDATAQUEUE_STATE_RESET_INPROGRESS)) {
831*bbb1b6f9SApple OSS Distributions 		// Another thread is resetting the queue
832*bbb1b6f9SApple OSS Distributions 		return kIOReturnBusy;
833*bbb1b6f9SApple OSS Distributions 	}
834*bbb1b6f9SApple OSS Distributions 
835*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(currState.fields.seqNum == UINT64_MAX)) {
836*bbb1b6f9SApple OSS Distributions 		// Nothing has ever been written to the queue yet.
837*bbb1b6f9SApple OSS Distributions 		return kIOReturnUnderrun;
838*bbb1b6f9SApple OSS Distributions 	}
839*bbb1b6f9SApple OSS Distributions 
840*bbb1b6f9SApple OSS Distributions 	uint32_t queueGeneration = currState.fields.generation;
841*bbb1b6f9SApple OSS Distributions 	uint32_t readIndex
842*bbb1b6f9SApple OSS Distributions 	        = (currState.fields.wrIndex > 0) ? (currState.fields.wrIndex - 1) : (queueHeaderShadow->numEntries - 1);
843*bbb1b6f9SApple OSS Distributions 
844*bbb1b6f9SApple OSS Distributions 	__auto_type entry
845*bbb1b6f9SApple OSS Distributions 	        = (IOCircularDataQueueEntryHeader *)(uintptr_t)((uint8_t *)&queueMemory->entries[0] + (readIndex * queueEntryDataSize));
846*bbb1b6f9SApple OSS Distributions 
847*bbb1b6f9SApple OSS Distributions 	// SANITY CHECK - Final check to ensure the 'entry' pointer is
848*bbb1b6f9SApple OSS Distributions 	// within the queueMemory entries buffer before we begin writing.
849*bbb1b6f9SApple OSS Distributions 	if (os_unlikely((uint8_t *)entry < (uint8_t *)(&queueMemory->entries[0])
850*bbb1b6f9SApple OSS Distributions 	    || (uint8_t *)entry >= (uint8_t *)queueMemory + queueAllocMemSize)) {
851*bbb1b6f9SApple OSS Distributions 		queue_debug_error("Out of Bounds! " QUEUE_FORMAT " " CURSOR_FORMAT " " ENTRY_FORMAT, QUEUE_ARGS(queueMemory),
852*bbb1b6f9SApple OSS Distributions 		    CURSOR_ARGS(cursor), ENTRY_ARGS(entry));
853*bbb1b6f9SApple OSS Distributions 		return kIOReturnAborted;
854*bbb1b6f9SApple OSS Distributions 	}
855*bbb1b6f9SApple OSS Distributions 
856*bbb1b6f9SApple OSS Distributions 	os_compiler_barrier();
857*bbb1b6f9SApple OSS Distributions 
858*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(entry->sentinel != queueHeaderShadow->sentinel)) {
859*bbb1b6f9SApple OSS Distributions 		queue_debug_error("entry->sentinel != queueMemory->sentinel " QUEUE_FORMAT " " CURSOR_FORMAT " " ENTRY_FORMAT,
860*bbb1b6f9SApple OSS Distributions 		    QUEUE_ARGS(queueMemory), CURSOR_ARGS(cursor), ENTRY_ARGS(entry));
861*bbb1b6f9SApple OSS Distributions 		return kIOReturnBadMedia;
862*bbb1b6f9SApple OSS Distributions 	}
863*bbb1b6f9SApple OSS Distributions 
864*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueEntryHeaderInfo enHeaderInfo;
865*bbb1b6f9SApple OSS Distributions 	enHeaderInfo.val = atomic_load_explicit(&entry->headerInfoVal, memory_order_acquire);
866*bbb1b6f9SApple OSS Distributions 	uint32_t entryGeneration = enHeaderInfo.fields.generation;
867*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(entryGeneration != queueGeneration)) {
868*bbb1b6f9SApple OSS Distributions 		queue_debug_note("entryGeneration != queueGeneration " QUEUE_FORMAT " " CURSOR_FORMAT " " ENTRY_FORMAT,
869*bbb1b6f9SApple OSS Distributions 		    QUEUE_ARGS(queueMemory), CURSOR_ARGS(cursor), ENTRY_ARGS(entry));
870*bbb1b6f9SApple OSS Distributions 		return kIOReturnAborted;
871*bbb1b6f9SApple OSS Distributions 	}
872*bbb1b6f9SApple OSS Distributions 
873*bbb1b6f9SApple OSS Distributions 	cursor->position = readIndex;
874*bbb1b6f9SApple OSS Distributions 	cursor->generation = entryGeneration;
875*bbb1b6f9SApple OSS Distributions 	cursor->sequenceNum = enHeaderInfo.fields.seqNum;
876*bbb1b6f9SApple OSS Distributions 
877*bbb1b6f9SApple OSS Distributions 	return kIOReturnSuccess;
878*bbb1b6f9SApple OSS Distributions }
879*bbb1b6f9SApple OSS Distributions 
880*bbb1b6f9SApple OSS Distributions static IOReturn ATTR_LSE2
_getLatestInQueueMemInternal(IOCircularDataQueue * queue,void ** data,size_t * size,bool copyMem)881*bbb1b6f9SApple OSS Distributions _getLatestInQueueMemInternal(IOCircularDataQueue *queue,
882*bbb1b6f9SApple OSS Distributions     void **data,
883*bbb1b6f9SApple OSS Distributions     size_t *size,
884*bbb1b6f9SApple OSS Distributions     bool copyMem)
885*bbb1b6f9SApple OSS Distributions {
886*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueMemory *queueMemory = queue->queueMemory;
887*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueDescription *queueHeaderShadow = &queue->queueHeaderShadow;
888*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueMemoryCursor *cursor = &queue->queueCursor;
889*bbb1b6f9SApple OSS Distributions 
890*bbb1b6f9SApple OSS Distributions 	IOReturn ret = kIOReturnTimeout;
891*bbb1b6f9SApple OSS Distributions 	if (queueMemory == NULL || data == NULL || size == NULL || queueHeaderShadow == NULL) {
892*bbb1b6f9SApple OSS Distributions 		return kIOReturnBadArgument;
893*bbb1b6f9SApple OSS Distributions 	}
894*bbb1b6f9SApple OSS Distributions 
895*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(_isQueueMemoryCorrupted(queue))) {
896*bbb1b6f9SApple OSS Distributions 		return kIOReturnBadMedia;
897*bbb1b6f9SApple OSS Distributions 	}
898*bbb1b6f9SApple OSS Distributions 
899*bbb1b6f9SApple OSS Distributions 	const size_t kNumRetries = 5; // Number of retries if the latest index data gets overwritten by a writer.
900*bbb1b6f9SApple OSS Distributions 	size_t retry = kNumRetries;
901*bbb1b6f9SApple OSS Distributions 	const size_t queueAllocMemSize = queueHeaderShadow->allocMemSize;
902*bbb1b6f9SApple OSS Distributions 	const size_t queueEntryDataSize = queueHeaderShadow->entryDataSize;
903*bbb1b6f9SApple OSS Distributions 	size_t inSize;
904*bbb1b6f9SApple OSS Distributions 
905*bbb1b6f9SApple OSS Distributions 	inSize = *size;
906*bbb1b6f9SApple OSS Distributions 	do {
907*bbb1b6f9SApple OSS Distributions 		*size = 0;
908*bbb1b6f9SApple OSS Distributions 		retry--;
909*bbb1b6f9SApple OSS Distributions 		IOCircularDataQueueState currState;
910*bbb1b6f9SApple OSS Distributions 		currState.val = atomic_load_explicit(&queueMemory->queueStateVal, memory_order_consume);
911*bbb1b6f9SApple OSS Distributions 
912*bbb1b6f9SApple OSS Distributions 		if (os_unlikely(currState.fields.rstStatus & IOCIRCULARDATAQUEUE_STATE_RESET_INPROGRESS)) {
913*bbb1b6f9SApple OSS Distributions 			// Another thread is resetting the queue
914*bbb1b6f9SApple OSS Distributions 			return kIOReturnBusy;
915*bbb1b6f9SApple OSS Distributions 		}
916*bbb1b6f9SApple OSS Distributions 
917*bbb1b6f9SApple OSS Distributions 		if (os_unlikely(currState.fields.seqNum == UINT64_MAX)) {
918*bbb1b6f9SApple OSS Distributions 			// Nothing has ever been written to the queue yet.
919*bbb1b6f9SApple OSS Distributions 			return kIOReturnUnderrun;
920*bbb1b6f9SApple OSS Distributions 		}
921*bbb1b6f9SApple OSS Distributions 
922*bbb1b6f9SApple OSS Distributions 		uint32_t queueGeneration = currState.fields.generation;
923*bbb1b6f9SApple OSS Distributions 		uint32_t readIndex
924*bbb1b6f9SApple OSS Distributions 		        = (currState.fields.wrIndex > 0) ? (currState.fields.wrIndex - 1) : (queueHeaderShadow->numEntries - 1);
925*bbb1b6f9SApple OSS Distributions 
926*bbb1b6f9SApple OSS Distributions 		__auto_type entry = (IOCircularDataQueueEntryHeader *)(uintptr_t)((uint8_t *)&queueMemory->entries[0]
927*bbb1b6f9SApple OSS Distributions 		    + (readIndex * queueEntryDataSize));
928*bbb1b6f9SApple OSS Distributions 
929*bbb1b6f9SApple OSS Distributions 		// SANITY CHECK - Final check to ensure the 'entry' pointer is
930*bbb1b6f9SApple OSS Distributions 		// within the queueMemory entries buffer before we begin writing.
931*bbb1b6f9SApple OSS Distributions 		if (os_unlikely((uint8_t *)entry < (uint8_t *)(&queueMemory->entries[0])
932*bbb1b6f9SApple OSS Distributions 		    || (uint8_t *)entry >= (uint8_t *)queueMemory + queueAllocMemSize)) {
933*bbb1b6f9SApple OSS Distributions 			queue_debug_error("Out of Bounds! " QUEUE_FORMAT " " CURSOR_FORMAT " " ENTRY_FORMAT,
934*bbb1b6f9SApple OSS Distributions 			    QUEUE_ARGS(queueMemory), CURSOR_ARGS(cursor), ENTRY_ARGS(entry));
935*bbb1b6f9SApple OSS Distributions 			return kIOReturnBadArgument;
936*bbb1b6f9SApple OSS Distributions 		}
937*bbb1b6f9SApple OSS Distributions 
938*bbb1b6f9SApple OSS Distributions 		os_compiler_barrier();
939*bbb1b6f9SApple OSS Distributions 
940*bbb1b6f9SApple OSS Distributions 		if (os_unlikely(entry->sentinel != queueHeaderShadow->sentinel)) {
941*bbb1b6f9SApple OSS Distributions 			queue_debug_error("entry->sentinel != queueMemory->sentinel " QUEUE_FORMAT " " CURSOR_FORMAT
942*bbb1b6f9SApple OSS Distributions 			    " " ENTRY_FORMAT,
943*bbb1b6f9SApple OSS Distributions 			    QUEUE_ARGS(queueMemory), CURSOR_ARGS(cursor), ENTRY_ARGS(entry));
944*bbb1b6f9SApple OSS Distributions 			return kIOReturnBadMedia;
945*bbb1b6f9SApple OSS Distributions 		}
946*bbb1b6f9SApple OSS Distributions 
947*bbb1b6f9SApple OSS Distributions 		IOCircularDataQueueEntryHeaderInfo enHeaderInfo;
948*bbb1b6f9SApple OSS Distributions 		enHeaderInfo.val = atomic_load_explicit(&entry->headerInfoVal, memory_order_acquire);
949*bbb1b6f9SApple OSS Distributions 		uint32_t entryGeneration = enHeaderInfo.fields.generation;
950*bbb1b6f9SApple OSS Distributions 		/* Since the time we read the queue header, was the queue
951*bbb1b6f9SApple OSS Distributions 		 *   - reset
952*bbb1b6f9SApple OSS Distributions 		 *   - the entry is being overwritten
953*bbb1b6f9SApple OSS Distributions 		 *   - the entry was overwritten and hence the seq numbers don't match anymore.
954*bbb1b6f9SApple OSS Distributions 		 *
955*bbb1b6f9SApple OSS Distributions 		 *  Lets retry in such a case
956*bbb1b6f9SApple OSS Distributions 		 */
957*bbb1b6f9SApple OSS Distributions 		if (os_unlikely(entryGeneration != queueGeneration
958*bbb1b6f9SApple OSS Distributions 		    || enHeaderInfo.fields.wrStatus == IOCIRCULARDATAQUEUE_ENTRY_STATE_WRITE_INPROGRESS
959*bbb1b6f9SApple OSS Distributions 		    || currState.fields.seqNum != enHeaderInfo.fields.seqNum)) {
960*bbb1b6f9SApple OSS Distributions 			continue;
961*bbb1b6f9SApple OSS Distributions 		}
962*bbb1b6f9SApple OSS Distributions 
963*bbb1b6f9SApple OSS Distributions 		cursor->position = readIndex;
964*bbb1b6f9SApple OSS Distributions 		cursor->generation = entryGeneration;
965*bbb1b6f9SApple OSS Distributions 		cursor->sequenceNum = enHeaderInfo.fields.seqNum;
966*bbb1b6f9SApple OSS Distributions 
967*bbb1b6f9SApple OSS Distributions 		if (os_unlikely(enHeaderInfo.fields.dataSize > queueHeaderShadow->entryDataSize)) {
968*bbb1b6f9SApple OSS Distributions 			ret = kIOReturnOverrun;
969*bbb1b6f9SApple OSS Distributions 			break;
970*bbb1b6f9SApple OSS Distributions 		}
971*bbb1b6f9SApple OSS Distributions 		*size = enHeaderInfo.fields.dataSize;
972*bbb1b6f9SApple OSS Distributions 
973*bbb1b6f9SApple OSS Distributions 		if (!copyMem) {
974*bbb1b6f9SApple OSS Distributions 			*data = entry->data;
975*bbb1b6f9SApple OSS Distributions 			ret = kIOReturnSuccess;
976*bbb1b6f9SApple OSS Distributions 			break; // break out, we're done
977*bbb1b6f9SApple OSS Distributions 		} else {
978*bbb1b6f9SApple OSS Distributions 			if (os_unlikely(enHeaderInfo.fields.dataSize > inSize)) {
979*bbb1b6f9SApple OSS Distributions 				return kIOReturnOverrun;
980*bbb1b6f9SApple OSS Distributions 			}
981*bbb1b6f9SApple OSS Distributions 			memcpy(*data, entry->data, enHeaderInfo.fields.dataSize);
982*bbb1b6f9SApple OSS Distributions 			// Lets re-verify after the memcpy if the buffer is/has been overwritten.
983*bbb1b6f9SApple OSS Distributions 
984*bbb1b6f9SApple OSS Distributions 			IOCircularDataQueueEntryHeaderInfo enHeaderInfoAfter;
985*bbb1b6f9SApple OSS Distributions 			enHeaderInfoAfter.val = atomic_load_explicit(&entry->headerInfoVal, memory_order_acquire);
986*bbb1b6f9SApple OSS Distributions 			// Did something change ?
987*bbb1b6f9SApple OSS Distributions 			if (enHeaderInfo.val == enHeaderInfoAfter.val) {
988*bbb1b6f9SApple OSS Distributions 				ret = kIOReturnSuccess;
989*bbb1b6f9SApple OSS Distributions 				break;
990*bbb1b6f9SApple OSS Distributions 			} else {
991*bbb1b6f9SApple OSS Distributions 				// we failed so we'll retry.
992*bbb1b6f9SApple OSS Distributions 				*size = 0;
993*bbb1b6f9SApple OSS Distributions 			}
994*bbb1b6f9SApple OSS Distributions 		}
995*bbb1b6f9SApple OSS Distributions 	} while (retry);
996*bbb1b6f9SApple OSS Distributions 
997*bbb1b6f9SApple OSS Distributions 	if ((kIOReturnSuccess == ret) && os_unlikely(_isQueueMemoryCorrupted(queue))) {
998*bbb1b6f9SApple OSS Distributions 		return kIOReturnBadMedia;
999*bbb1b6f9SApple OSS Distributions 	}
1000*bbb1b6f9SApple OSS Distributions 
1001*bbb1b6f9SApple OSS Distributions 	return ret;
1002*bbb1b6f9SApple OSS Distributions }
1003*bbb1b6f9SApple OSS Distributions 
1004*bbb1b6f9SApple OSS Distributions /*!
1005*bbb1b6f9SApple OSS Distributions  * @function getLatestInQueueMem
1006*bbb1b6f9SApple OSS Distributions  * Access the latest entry data, also update the cursor position to the latest. No copy is made of the data. <br> Caller
1007*bbb1b6f9SApple OSS Distributions  * is supposed to call isDataEntryValidInQueueMem() to check data integrity after reading the data is complete.
1008*bbb1b6f9SApple OSS Distributions  * @param queue Handle to the queue.
1009*bbb1b6f9SApple OSS Distributions  * @param data A pointer to the data memory region for the latest entry data in the queue.
1010*bbb1b6f9SApple OSS Distributions  * @param size A pointer to the size of the data parameter.  On return, this contains the actual size of the data
1011*bbb1b6f9SApple OSS Distributions  * pointed to by data param.
1012*bbb1b6f9SApple OSS Distributions  *  @return
1013*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnSuccess` if the cursor position was updated.
1014*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnUnderrun` if nothing has ever been enqueued into the queue
1015*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnBadMedia` if the queue shared memory has been compromised.
1016*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnBadArgument` if an invalid queue was provided.
1017*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnTimeout` if the reader timed out when trying to read. This is possible if the writer overwrites the
1018*bbb1b6f9SApple OSS Distributions  * latest index a reader is about to read. The function times out if the read is unsuccessful after multiple retries.
1019*bbb1b6f9SApple OSS Distributions  *  - Other values indicate an error.
1020*bbb1b6f9SApple OSS Distributions  *
1021*bbb1b6f9SApple OSS Distributions  */
1022*bbb1b6f9SApple OSS Distributions 
1023*bbb1b6f9SApple OSS Distributions static IOReturn ATTR_LSE2
getLatestInQueueMem(IOCircularDataQueue * queue,void ** data,size_t * size)1024*bbb1b6f9SApple OSS Distributions getLatestInQueueMem(IOCircularDataQueue *queue,
1025*bbb1b6f9SApple OSS Distributions     void **data,
1026*bbb1b6f9SApple OSS Distributions     size_t *size)
1027*bbb1b6f9SApple OSS Distributions {
1028*bbb1b6f9SApple OSS Distributions 	return _getLatestInQueueMemInternal(queue, data, size, false);
1029*bbb1b6f9SApple OSS Distributions }
1030*bbb1b6f9SApple OSS Distributions 
1031*bbb1b6f9SApple OSS Distributions /*!
1032*bbb1b6f9SApple OSS Distributions  * @function copyLatestInQueueMem
1033*bbb1b6f9SApple OSS Distributions  *  Access the latest entry data and copy into the provided buffer. Also update the cursor position to the latest.
1034*bbb1b6f9SApple OSS Distributions  * Function gaurantees that the new data returned is always valid hence no need to call isDataEntryValidInQueueMem().
1035*bbb1b6f9SApple OSS Distributions  * @param queue Handle to the queue.
1036*bbb1b6f9SApple OSS Distributions  * @param data Pointer to memory into which the latest data from the queue is copied. Lifetime of this memory is
1037*bbb1b6f9SApple OSS Distributions  * controlled by the caller.
1038*bbb1b6f9SApple OSS Distributions  * @param size Size of the data buffer provided for copying. On return, this contains the actual size of the data
1039*bbb1b6f9SApple OSS Distributions  * pointed to by data param.
1040*bbb1b6f9SApple OSS Distributions  *  @return
1041*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnSuccess` if the cursor position was updated.
1042*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnUnderrun` if nothing has ever been enqueued into the queue
1043*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnBadArgument` if the buffer provided to copy the data is NULL or  if an invalid queue was provided..
1044*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnBadMedia` if the queue shared memory has been compromised.
1045*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnTimeout` if the reader timed out when trying to copy the latest data. This is possible if the writer
1046*bbb1b6f9SApple OSS Distributions  * overwrites the latest index a reader is about to copy. The function times out if the copy is unsuccessful after
1047*bbb1b6f9SApple OSS Distributions  * multiple retries.
1048*bbb1b6f9SApple OSS Distributions  *  - Other values indicate an error.
1049*bbb1b6f9SApple OSS Distributions  *
1050*bbb1b6f9SApple OSS Distributions  */
1051*bbb1b6f9SApple OSS Distributions 
1052*bbb1b6f9SApple OSS Distributions static IOReturn ATTR_LSE2
copyLatestInQueueMem(IOCircularDataQueue * queue,void * data,size_t * size)1053*bbb1b6f9SApple OSS Distributions copyLatestInQueueMem(IOCircularDataQueue *queue,
1054*bbb1b6f9SApple OSS Distributions     void *data,
1055*bbb1b6f9SApple OSS Distributions     size_t *size)
1056*bbb1b6f9SApple OSS Distributions {
1057*bbb1b6f9SApple OSS Distributions 	return _getLatestInQueueMemInternal(queue, &data, size, true);
1058*bbb1b6f9SApple OSS Distributions }
1059*bbb1b6f9SApple OSS Distributions 
1060*bbb1b6f9SApple OSS Distributions static IOReturn ATTR_LSE2
_getNextInQueueMemInternal(IOCircularDataQueue * queue,void ** data,size_t * size,bool copyMem)1061*bbb1b6f9SApple OSS Distributions _getNextInQueueMemInternal(IOCircularDataQueue *queue,
1062*bbb1b6f9SApple OSS Distributions     void **data,
1063*bbb1b6f9SApple OSS Distributions     size_t *size,
1064*bbb1b6f9SApple OSS Distributions     bool copyMem)
1065*bbb1b6f9SApple OSS Distributions {
1066*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueMemory *queueMemory = queue->queueMemory;
1067*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueDescription *queueHeaderShadow = &queue->queueHeaderShadow;
1068*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueMemoryCursor *cursor = &queue->queueCursor;
1069*bbb1b6f9SApple OSS Distributions 
1070*bbb1b6f9SApple OSS Distributions 	IOReturn ret = kIOReturnError;
1071*bbb1b6f9SApple OSS Distributions 	size_t inSize;
1072*bbb1b6f9SApple OSS Distributions 
1073*bbb1b6f9SApple OSS Distributions 	if (queueMemory == NULL || data == NULL || size == NULL || queueHeaderShadow == NULL) {
1074*bbb1b6f9SApple OSS Distributions 		return kIOReturnBadArgument;
1075*bbb1b6f9SApple OSS Distributions 	}
1076*bbb1b6f9SApple OSS Distributions 
1077*bbb1b6f9SApple OSS Distributions 	inSize = *size;
1078*bbb1b6f9SApple OSS Distributions 	*size = 0;
1079*bbb1b6f9SApple OSS Distributions 
1080*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(_isQueueMemoryCorrupted(queue))) {
1081*bbb1b6f9SApple OSS Distributions 		return kIOReturnBadMedia;
1082*bbb1b6f9SApple OSS Distributions 	}
1083*bbb1b6f9SApple OSS Distributions 
1084*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(_isCursorPositionInvalid(queue))) {
1085*bbb1b6f9SApple OSS Distributions 		return kIOReturnAborted;
1086*bbb1b6f9SApple OSS Distributions 	}
1087*bbb1b6f9SApple OSS Distributions 
1088*bbb1b6f9SApple OSS Distributions 	const size_t queueAllocMemSize = queueHeaderShadow->allocMemSize;
1089*bbb1b6f9SApple OSS Distributions 	const size_t queueEntryDataSize = queueHeaderShadow->entryDataSize;
1090*bbb1b6f9SApple OSS Distributions 
1091*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueState currState;
1092*bbb1b6f9SApple OSS Distributions 	currState.val = atomic_load_explicit(&queueMemory->queueStateVal, memory_order_acquire);
1093*bbb1b6f9SApple OSS Distributions 
1094*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(currState.fields.rstStatus & IOCIRCULARDATAQUEUE_STATE_RESET_INPROGRESS)) {
1095*bbb1b6f9SApple OSS Distributions 		// Another thread is resetting the queue
1096*bbb1b6f9SApple OSS Distributions 		return kIOReturnBusy;
1097*bbb1b6f9SApple OSS Distributions 	}
1098*bbb1b6f9SApple OSS Distributions 
1099*bbb1b6f9SApple OSS Distributions 	uint32_t queueGeneration = currState.fields.generation;
1100*bbb1b6f9SApple OSS Distributions 
1101*bbb1b6f9SApple OSS Distributions 	// was the queue reset ?
1102*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(cursor->generation != queueGeneration || cursor->sequenceNum > currState.fields.seqNum)) {
1103*bbb1b6f9SApple OSS Distributions 		return kIOReturnAborted;
1104*bbb1b6f9SApple OSS Distributions 	}
1105*bbb1b6f9SApple OSS Distributions 
1106*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(currState.fields.seqNum == UINT64_MAX)) {
1107*bbb1b6f9SApple OSS Distributions 		// Nothing has ever been written to the queue yet.
1108*bbb1b6f9SApple OSS Distributions 		return kIOReturnUnderrun;
1109*bbb1b6f9SApple OSS Distributions 	}
1110*bbb1b6f9SApple OSS Distributions 
1111*bbb1b6f9SApple OSS Distributions 	// nothing new written or an active write is in progress for the next entry.
1112*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(cursor->sequenceNum == currState.fields.seqNum
1113*bbb1b6f9SApple OSS Distributions 	    || ((cursor->sequenceNum + 1) == currState.fields.seqNum
1114*bbb1b6f9SApple OSS Distributions 	    && currState.fields.wrStatus == IOCIRCULARDATAQUEUE_STATE_WRITE_INPROGRESS))) {
1115*bbb1b6f9SApple OSS Distributions 		return kIOReturnUnderrun;
1116*bbb1b6f9SApple OSS Distributions 	}
1117*bbb1b6f9SApple OSS Distributions 
1118*bbb1b6f9SApple OSS Distributions 	uint32_t nextIndex = (cursor->position + 1) % queueHeaderShadow->numEntries;
1119*bbb1b6f9SApple OSS Distributions 	__auto_type entry
1120*bbb1b6f9SApple OSS Distributions 	        = (IOCircularDataQueueEntryHeader *)(uintptr_t)((uint8_t *)&queueMemory->entries[0] + (nextIndex * queueEntryDataSize));
1121*bbb1b6f9SApple OSS Distributions 
1122*bbb1b6f9SApple OSS Distributions 	// SANITY CHECK - Final check to ensure the 'entry' pointer is
1123*bbb1b6f9SApple OSS Distributions 	// within the queueMemory entries buffer before we begin writing.
1124*bbb1b6f9SApple OSS Distributions 	if (os_unlikely((uint8_t *)entry < (uint8_t *)(&queueMemory->entries[0])
1125*bbb1b6f9SApple OSS Distributions 	    || (uint8_t *)entry >= (uint8_t *)queueMemory + queueAllocMemSize)) {
1126*bbb1b6f9SApple OSS Distributions 		queue_debug_error("Out of Bounds! " QUEUE_FORMAT " " CURSOR_FORMAT " " ENTRY_FORMAT, QUEUE_ARGS(queueMemory),
1127*bbb1b6f9SApple OSS Distributions 		    CURSOR_ARGS(cursor), ENTRY_ARGS(entry));
1128*bbb1b6f9SApple OSS Distributions 		return kIOReturnBadArgument;
1129*bbb1b6f9SApple OSS Distributions 	}
1130*bbb1b6f9SApple OSS Distributions 
1131*bbb1b6f9SApple OSS Distributions 	os_compiler_barrier();
1132*bbb1b6f9SApple OSS Distributions 
1133*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(entry->sentinel != queueHeaderShadow->sentinel)) {
1134*bbb1b6f9SApple OSS Distributions 		queue_debug_error("entry->sentinel != queueMemory->sentinel " QUEUE_FORMAT " " CURSOR_FORMAT " " ENTRY_FORMAT,
1135*bbb1b6f9SApple OSS Distributions 		    QUEUE_ARGS(queueMemory), CURSOR_ARGS(cursor), ENTRY_ARGS(entry));
1136*bbb1b6f9SApple OSS Distributions 		return kIOReturnBadMedia;
1137*bbb1b6f9SApple OSS Distributions 	}
1138*bbb1b6f9SApple OSS Distributions 
1139*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueEntryHeaderInfo enHeaderInfo;
1140*bbb1b6f9SApple OSS Distributions 	enHeaderInfo.val = atomic_load_explicit(&entry->headerInfoVal, memory_order_acquire);
1141*bbb1b6f9SApple OSS Distributions 	uint32_t entryGeneration = enHeaderInfo.fields.generation;
1142*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(entryGeneration != queueGeneration)) {
1143*bbb1b6f9SApple OSS Distributions 		queue_debug_note("entryGeneration != queueGeneration " QUEUE_FORMAT " " CURSOR_FORMAT " " ENTRY_FORMAT,
1144*bbb1b6f9SApple OSS Distributions 		    QUEUE_ARGS(queueMemory), CURSOR_ARGS(cursor), ENTRY_ARGS(entry));
1145*bbb1b6f9SApple OSS Distributions 		return kIOReturnAborted;
1146*bbb1b6f9SApple OSS Distributions 	}
1147*bbb1b6f9SApple OSS Distributions 
1148*bbb1b6f9SApple OSS Distributions 	// is the entry currently being written to or has the cursor fallen too far behind and the cursor is no longer
1149*bbb1b6f9SApple OSS Distributions 	// valid.
1150*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(enHeaderInfo.fields.wrStatus == IOCIRCULARDATAQUEUE_ENTRY_STATE_WRITE_INPROGRESS
1151*bbb1b6f9SApple OSS Distributions 	    || enHeaderInfo.fields.seqNum != cursor->sequenceNum + 1)) {
1152*bbb1b6f9SApple OSS Distributions 		return kIOReturnOverrun;
1153*bbb1b6f9SApple OSS Distributions 	}
1154*bbb1b6f9SApple OSS Distributions 
1155*bbb1b6f9SApple OSS Distributions 	cursor->position = nextIndex;
1156*bbb1b6f9SApple OSS Distributions 	cursor->generation = entryGeneration;
1157*bbb1b6f9SApple OSS Distributions 	cursor->sequenceNum = enHeaderInfo.fields.seqNum;
1158*bbb1b6f9SApple OSS Distributions 
1159*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(enHeaderInfo.fields.dataSize > queueHeaderShadow->entryDataSize)) {
1160*bbb1b6f9SApple OSS Distributions 		return kIOReturnOverrun;
1161*bbb1b6f9SApple OSS Distributions 	}
1162*bbb1b6f9SApple OSS Distributions 	*size = enHeaderInfo.fields.dataSize;
1163*bbb1b6f9SApple OSS Distributions 
1164*bbb1b6f9SApple OSS Distributions 	if (!copyMem) {
1165*bbb1b6f9SApple OSS Distributions 		*data = entry->data;
1166*bbb1b6f9SApple OSS Distributions 		ret = kIOReturnSuccess;
1167*bbb1b6f9SApple OSS Distributions 	} else {
1168*bbb1b6f9SApple OSS Distributions 		if (os_unlikely(enHeaderInfo.fields.dataSize > inSize)) {
1169*bbb1b6f9SApple OSS Distributions 			return kIOReturnOverrun;
1170*bbb1b6f9SApple OSS Distributions 		}
1171*bbb1b6f9SApple OSS Distributions 		memcpy(*data, entry->data, enHeaderInfo.fields.dataSize);
1172*bbb1b6f9SApple OSS Distributions 		// Lets re-verify after the memcpy if the buffer is/has been overwritten.
1173*bbb1b6f9SApple OSS Distributions 
1174*bbb1b6f9SApple OSS Distributions 		IOCircularDataQueueEntryHeaderInfo enHeaderInfoAfter;
1175*bbb1b6f9SApple OSS Distributions 		enHeaderInfoAfter.val = atomic_load_explicit(&entry->headerInfoVal, memory_order_acquire);
1176*bbb1b6f9SApple OSS Distributions 		// Did something change, while we were memcopying ?
1177*bbb1b6f9SApple OSS Distributions 		if (enHeaderInfo.val == enHeaderInfoAfter.val) {
1178*bbb1b6f9SApple OSS Distributions 			ret = kIOReturnSuccess;
1179*bbb1b6f9SApple OSS Distributions 		} else {
1180*bbb1b6f9SApple OSS Distributions 			// while we were memcopying, the writer wrapped around and is writing into our index. or the queue got reset
1181*bbb1b6f9SApple OSS Distributions 			*size = 0;
1182*bbb1b6f9SApple OSS Distributions 			ret = kIOReturnOverrun;
1183*bbb1b6f9SApple OSS Distributions 		}
1184*bbb1b6f9SApple OSS Distributions 	}
1185*bbb1b6f9SApple OSS Distributions 
1186*bbb1b6f9SApple OSS Distributions 	if ((kIOReturnSuccess == ret) && os_unlikely(_isQueueMemoryCorrupted(queue))) {
1187*bbb1b6f9SApple OSS Distributions 		return kIOReturnBadMedia;
1188*bbb1b6f9SApple OSS Distributions 	}
1189*bbb1b6f9SApple OSS Distributions 
1190*bbb1b6f9SApple OSS Distributions 	return ret;
1191*bbb1b6f9SApple OSS Distributions }
1192*bbb1b6f9SApple OSS Distributions 
1193*bbb1b6f9SApple OSS Distributions /*!
1194*bbb1b6f9SApple OSS Distributions  * @function getNextInQueueMem
1195*bbb1b6f9SApple OSS Distributions  * Access the data at the next cursor position and updates the cursor position to the next. No copy is made of the data.
1196*bbb1b6f9SApple OSS Distributions  * <br> Caller is supposed to call isDataEntryValidInQueueMem() to check data integrity after reading the data is
1197*bbb1b6f9SApple OSS Distributions  * complete.
1198*bbb1b6f9SApple OSS Distributions  * @param queue Handle to the queue.
1199*bbb1b6f9SApple OSS Distributions  * @param data A pointer to the data memory region for the next entry data in the queue.
1200*bbb1b6f9SApple OSS Distributions  * @param size A pointer to the size of the data parameter.  On return, this contains the actual size of the data
1201*bbb1b6f9SApple OSS Distributions  * pointed to by data param.
1202*bbb1b6f9SApple OSS Distributions  *  @return
1203*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnSuccess` if the cursor position was updated.
1204*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnAborted` if the cursor has become invalid, possibly due to a reset of the queue.
1205*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnUnderrun` if the cursor has reached the latest available data.
1206*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnOverrun` if the entry at the cursor position is no longer in
1207*bbb1b6f9SApple OSS Distributions  *     the queue's buffer. Call getLatestInQueueMem to get the latest data and cursor position.
1208*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnBadArgument` if an invalid argument is passsed.
1209*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnBadMedia` if the queue shared memory has been compromised.
1210*bbb1b6f9SApple OSS Distributions  *  - Other values indicate an error.
1211*bbb1b6f9SApple OSS Distributions  *
1212*bbb1b6f9SApple OSS Distributions  */
1213*bbb1b6f9SApple OSS Distributions 
1214*bbb1b6f9SApple OSS Distributions static IOReturn ATTR_LSE2
getNextInQueueMem(IOCircularDataQueue * queue,void ** data,size_t * size)1215*bbb1b6f9SApple OSS Distributions getNextInQueueMem(IOCircularDataQueue *queue,
1216*bbb1b6f9SApple OSS Distributions     void **data,
1217*bbb1b6f9SApple OSS Distributions     size_t *size)
1218*bbb1b6f9SApple OSS Distributions {
1219*bbb1b6f9SApple OSS Distributions 	return _getNextInQueueMemInternal(queue, data, size, false);
1220*bbb1b6f9SApple OSS Distributions }
1221*bbb1b6f9SApple OSS Distributions 
1222*bbb1b6f9SApple OSS Distributions /*!
1223*bbb1b6f9SApple OSS Distributions  * @function copyNextInQueueMem
1224*bbb1b6f9SApple OSS Distributions  * Access the data at the next cursor position and copy into the provided buffer. Also update the cursor position to the
1225*bbb1b6f9SApple OSS Distributions  * next. If successful, function gaurantees that the data returned is always valid hence no need to call
1226*bbb1b6f9SApple OSS Distributions  * isDataEntryValidInQueueMem().
1227*bbb1b6f9SApple OSS Distributions  * @param queue Handle to the queue.
1228*bbb1b6f9SApple OSS Distributions  * @param data Pointer to memory into which the next data from the queue is copied. Lifetime of this memory is
1229*bbb1b6f9SApple OSS Distributions  * controlled by the caller.
1230*bbb1b6f9SApple OSS Distributions  * @param size Size of the data buffer provided for copying. On return, this contains the actual size of the data
1231*bbb1b6f9SApple OSS Distributions  * pointed to by data param.
1232*bbb1b6f9SApple OSS Distributions  *  @return
1233*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnSuccess` if the cursor position was updated.
1234*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnAborted` if the cursor has become invalid, possibly due to a reset of the queue.
1235*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnUnderrun` if the cursor has reached the latest available data.
1236*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnOverrun` if the entry at the cursor position is no longer in
1237*bbb1b6f9SApple OSS Distributions  *     the queue's buffer. Call getLatestInQueueMem to get the latest data and cursor position.
1238*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnBadArgument` if an invalid argument is passsed.
1239*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnBadMedia` if the queue shared memory has been compromised.
1240*bbb1b6f9SApple OSS Distributions  *  - Other values indicate an error.
1241*bbb1b6f9SApple OSS Distributions  *
1242*bbb1b6f9SApple OSS Distributions  */
1243*bbb1b6f9SApple OSS Distributions 
1244*bbb1b6f9SApple OSS Distributions static IOReturn ATTR_LSE2
copyNextInQueueMem(IOCircularDataQueue * queue,void * data,size_t * size)1245*bbb1b6f9SApple OSS Distributions copyNextInQueueMem(IOCircularDataQueue *queue,
1246*bbb1b6f9SApple OSS Distributions     void *data,
1247*bbb1b6f9SApple OSS Distributions     size_t *size)
1248*bbb1b6f9SApple OSS Distributions {
1249*bbb1b6f9SApple OSS Distributions 	return _getNextInQueueMemInternal(queue, &data, size, true);
1250*bbb1b6f9SApple OSS Distributions }
1251*bbb1b6f9SApple OSS Distributions 
1252*bbb1b6f9SApple OSS Distributions /*!
1253*bbb1b6f9SApple OSS Distributions  * @function getPrevInQueueMem
1254*bbb1b6f9SApple OSS Distributions  * Access the data at the previous cursor position and updates the cursor position to the previous. No copy is made of
1255*bbb1b6f9SApple OSS Distributions  * the data. <br> Caller is supposed to call isDataEntryValidInQueueMem() to check data integrity after reading the data
1256*bbb1b6f9SApple OSS Distributions  * is complete.
1257*bbb1b6f9SApple OSS Distributions  * @param queue Handle to the queue.
1258*bbb1b6f9SApple OSS Distributions  * @param data A pointer to the data memory region for the previous entry data in the queue.
1259*bbb1b6f9SApple OSS Distributions  * @param size A pointer to the size of the data parameter.  On return, this contains the actual size of the data
1260*bbb1b6f9SApple OSS Distributions  * pointed to by data param.
1261*bbb1b6f9SApple OSS Distributions  *  @return
1262*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnSuccess` if the cursor position was updated to the previous.
1263*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnAborted` if the cursor has become invalid, possibly due to a reset of the queue.
1264*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnOverrun` if the entry at the cursor position is no longer in
1265*bbb1b6f9SApple OSS Distributions  *     the queue's buffer. Call getLatestInQueueMem to get the latest data and cursor position.
1266*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnBadArgument` if an invalid argument is passsed.
1267*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnBadMedia` if the queue shared memory has been compromised.
1268*bbb1b6f9SApple OSS Distributions  *  - Other values indicate an error.
1269*bbb1b6f9SApple OSS Distributions  *
1270*bbb1b6f9SApple OSS Distributions  */
1271*bbb1b6f9SApple OSS Distributions 
1272*bbb1b6f9SApple OSS Distributions static IOReturn ATTR_LSE2
_getPrevInQueueMemInternal(IOCircularDataQueue * queue,void ** data,size_t * size,bool copyMem)1273*bbb1b6f9SApple OSS Distributions _getPrevInQueueMemInternal(IOCircularDataQueue *queue,
1274*bbb1b6f9SApple OSS Distributions     void **data,
1275*bbb1b6f9SApple OSS Distributions     size_t *size,
1276*bbb1b6f9SApple OSS Distributions     bool copyMem)
1277*bbb1b6f9SApple OSS Distributions {
1278*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueMemory *queueMemory = queue->queueMemory;
1279*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueDescription *queueHeaderShadow = &queue->queueHeaderShadow;
1280*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueMemoryCursor *cursor = &queue->queueCursor;
1281*bbb1b6f9SApple OSS Distributions 	size_t inSize;
1282*bbb1b6f9SApple OSS Distributions 
1283*bbb1b6f9SApple OSS Distributions 	IOReturn ret = kIOReturnError;
1284*bbb1b6f9SApple OSS Distributions 	if (queueMemory == NULL || data == NULL || size == NULL || queueHeaderShadow == NULL) {
1285*bbb1b6f9SApple OSS Distributions 		return kIOReturnBadArgument;
1286*bbb1b6f9SApple OSS Distributions 	}
1287*bbb1b6f9SApple OSS Distributions 
1288*bbb1b6f9SApple OSS Distributions 	inSize = *size;
1289*bbb1b6f9SApple OSS Distributions 	*size = 0;
1290*bbb1b6f9SApple OSS Distributions 
1291*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(_isQueueMemoryCorrupted(queue))) {
1292*bbb1b6f9SApple OSS Distributions 		return kIOReturnBadMedia;
1293*bbb1b6f9SApple OSS Distributions 	}
1294*bbb1b6f9SApple OSS Distributions 
1295*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(_isCursorPositionInvalid(queue))) {
1296*bbb1b6f9SApple OSS Distributions 		return kIOReturnAborted;
1297*bbb1b6f9SApple OSS Distributions 	}
1298*bbb1b6f9SApple OSS Distributions 
1299*bbb1b6f9SApple OSS Distributions 	const size_t queueAllocMemSize = queueHeaderShadow->allocMemSize;
1300*bbb1b6f9SApple OSS Distributions 	const size_t queueEntryDataSize = queueHeaderShadow->entryDataSize;
1301*bbb1b6f9SApple OSS Distributions 
1302*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueState currState;
1303*bbb1b6f9SApple OSS Distributions 	currState.val = atomic_load_explicit(&queueMemory->queueStateVal, memory_order_acquire);
1304*bbb1b6f9SApple OSS Distributions 
1305*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(currState.fields.rstStatus & IOCIRCULARDATAQUEUE_STATE_RESET_INPROGRESS)) {
1306*bbb1b6f9SApple OSS Distributions 		// Another thread is resetting the queue
1307*bbb1b6f9SApple OSS Distributions 		return kIOReturnBusy;
1308*bbb1b6f9SApple OSS Distributions 	}
1309*bbb1b6f9SApple OSS Distributions 
1310*bbb1b6f9SApple OSS Distributions 	uint32_t queueGeneration = currState.fields.generation;
1311*bbb1b6f9SApple OSS Distributions 
1312*bbb1b6f9SApple OSS Distributions 	// was the queue reset ?
1313*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(cursor->generation != queueGeneration || cursor->sequenceNum > currState.fields.seqNum)) {
1314*bbb1b6f9SApple OSS Distributions 		return kIOReturnAborted;
1315*bbb1b6f9SApple OSS Distributions 	}
1316*bbb1b6f9SApple OSS Distributions 
1317*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(currState.fields.seqNum == UINT64_MAX)) {
1318*bbb1b6f9SApple OSS Distributions 		// Nothing has ever been written to the queue yet.
1319*bbb1b6f9SApple OSS Distributions 		return kIOReturnUnderrun;
1320*bbb1b6f9SApple OSS Distributions 	}
1321*bbb1b6f9SApple OSS Distributions 
1322*bbb1b6f9SApple OSS Distributions 	uint32_t prevIndex = (cursor->position == 0) ? (queueHeaderShadow->numEntries - 1) : (cursor->position - 1);
1323*bbb1b6f9SApple OSS Distributions 	__auto_type entry
1324*bbb1b6f9SApple OSS Distributions 	        = (IOCircularDataQueueEntryHeader *)(uintptr_t)((uint8_t *)&queueMemory->entries[0] + (prevIndex * queueEntryDataSize));
1325*bbb1b6f9SApple OSS Distributions 
1326*bbb1b6f9SApple OSS Distributions 	// SANITY CHECK - Final check to ensure the 'entry' pointer is
1327*bbb1b6f9SApple OSS Distributions 	// within the queueMemory entries buffer before we begin writing.
1328*bbb1b6f9SApple OSS Distributions 	if (os_unlikely((uint8_t *)entry < (uint8_t *)(&queueMemory->entries[0])
1329*bbb1b6f9SApple OSS Distributions 	    || (uint8_t *)entry >= (uint8_t *)queueMemory + queueAllocMemSize)) {
1330*bbb1b6f9SApple OSS Distributions 		queue_debug_error("Out of Bounds! " QUEUE_FORMAT " " CURSOR_FORMAT " " ENTRY_FORMAT, QUEUE_ARGS(queueMemory),
1331*bbb1b6f9SApple OSS Distributions 		    CURSOR_ARGS(cursor), ENTRY_ARGS(entry));
1332*bbb1b6f9SApple OSS Distributions 		return kIOReturnBadArgument;
1333*bbb1b6f9SApple OSS Distributions 	}
1334*bbb1b6f9SApple OSS Distributions 
1335*bbb1b6f9SApple OSS Distributions 	os_compiler_barrier();
1336*bbb1b6f9SApple OSS Distributions 
1337*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueEntryHeaderInfo enHeaderInfo;
1338*bbb1b6f9SApple OSS Distributions 	enHeaderInfo.val = atomic_load_explicit(&entry->headerInfoVal, memory_order_acquire);
1339*bbb1b6f9SApple OSS Distributions 	// is the entry currently being written to or this is the newest entry that was just written.
1340*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(enHeaderInfo.fields.wrStatus == IOCIRCULARDATAQUEUE_ENTRY_STATE_WRITE_INPROGRESS
1341*bbb1b6f9SApple OSS Distributions 	    || enHeaderInfo.fields.seqNum > cursor->sequenceNum)) {
1342*bbb1b6f9SApple OSS Distributions 		return kIOReturnOverrun;
1343*bbb1b6f9SApple OSS Distributions 	}
1344*bbb1b6f9SApple OSS Distributions 
1345*bbb1b6f9SApple OSS Distributions 	uint32_t entryGeneration = enHeaderInfo.fields.generation;
1346*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(entryGeneration != queueGeneration)) {
1347*bbb1b6f9SApple OSS Distributions 		queue_debug_note("entryGeneration != queueGeneration " QUEUE_FORMAT " " CURSOR_FORMAT " " ENTRY_FORMAT,
1348*bbb1b6f9SApple OSS Distributions 		    QUEUE_ARGS(queueMemory), CURSOR_ARGS(cursor), ENTRY_ARGS(entry));
1349*bbb1b6f9SApple OSS Distributions 		return kIOReturnOverrun;
1350*bbb1b6f9SApple OSS Distributions 	}
1351*bbb1b6f9SApple OSS Distributions 
1352*bbb1b6f9SApple OSS Distributions 	// the sentinel has been corrupted.
1353*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(entry->sentinel != queueHeaderShadow->sentinel)) {
1354*bbb1b6f9SApple OSS Distributions 		queue_debug_error("entry->sentinel != queueMemory->sentinel " QUEUE_FORMAT " " CURSOR_FORMAT " " ENTRY_FORMAT,
1355*bbb1b6f9SApple OSS Distributions 		    QUEUE_ARGS(queueMemory), CURSOR_ARGS(cursor), ENTRY_ARGS(entry));
1356*bbb1b6f9SApple OSS Distributions 		return kIOReturnBadMedia;
1357*bbb1b6f9SApple OSS Distributions 	}
1358*bbb1b6f9SApple OSS Distributions 
1359*bbb1b6f9SApple OSS Distributions 	cursor->position = prevIndex;
1360*bbb1b6f9SApple OSS Distributions 	cursor->generation = entryGeneration;
1361*bbb1b6f9SApple OSS Distributions 	cursor->sequenceNum = enHeaderInfo.fields.seqNum;
1362*bbb1b6f9SApple OSS Distributions 
1363*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(enHeaderInfo.fields.dataSize > queueHeaderShadow->entryDataSize)) {
1364*bbb1b6f9SApple OSS Distributions 		return kIOReturnOverrun;
1365*bbb1b6f9SApple OSS Distributions 	}
1366*bbb1b6f9SApple OSS Distributions 	*size = enHeaderInfo.fields.dataSize;
1367*bbb1b6f9SApple OSS Distributions 	ret = kIOReturnSuccess;
1368*bbb1b6f9SApple OSS Distributions 
1369*bbb1b6f9SApple OSS Distributions 	if (!copyMem) {
1370*bbb1b6f9SApple OSS Distributions 		*data = entry->data;
1371*bbb1b6f9SApple OSS Distributions 	} else {
1372*bbb1b6f9SApple OSS Distributions 		if (os_unlikely(enHeaderInfo.fields.dataSize > inSize)) {
1373*bbb1b6f9SApple OSS Distributions 			return kIOReturnOverrun;
1374*bbb1b6f9SApple OSS Distributions 		}
1375*bbb1b6f9SApple OSS Distributions 		memcpy(*data, entry->data, enHeaderInfo.fields.dataSize);
1376*bbb1b6f9SApple OSS Distributions 		// Lets re-verify after the memcpy if the buffer is/has been overwritten.
1377*bbb1b6f9SApple OSS Distributions 
1378*bbb1b6f9SApple OSS Distributions 		IOCircularDataQueueEntryHeaderInfo enHeaderInfoAfter;
1379*bbb1b6f9SApple OSS Distributions 		enHeaderInfoAfter.val = atomic_load_explicit(&entry->headerInfoVal, memory_order_acquire);
1380*bbb1b6f9SApple OSS Distributions 		// Did something change, while we were memcopying ?
1381*bbb1b6f9SApple OSS Distributions 		if (enHeaderInfo.val != enHeaderInfoAfter.val) {
1382*bbb1b6f9SApple OSS Distributions 			// while we were memcopying, the writer wrapped around and is writing into our index. or the queue got reset
1383*bbb1b6f9SApple OSS Distributions 			*size = 0;
1384*bbb1b6f9SApple OSS Distributions 			ret = kIOReturnOverrun;
1385*bbb1b6f9SApple OSS Distributions 		}
1386*bbb1b6f9SApple OSS Distributions 	}
1387*bbb1b6f9SApple OSS Distributions 
1388*bbb1b6f9SApple OSS Distributions 	if ((kIOReturnSuccess == ret) && os_unlikely(_isQueueMemoryCorrupted(queue))) {
1389*bbb1b6f9SApple OSS Distributions 		return kIOReturnBadMedia;
1390*bbb1b6f9SApple OSS Distributions 	}
1391*bbb1b6f9SApple OSS Distributions 
1392*bbb1b6f9SApple OSS Distributions 	return ret;
1393*bbb1b6f9SApple OSS Distributions }
1394*bbb1b6f9SApple OSS Distributions 
1395*bbb1b6f9SApple OSS Distributions static IOReturn ATTR_LSE2
getPrevInQueueMem(IOCircularDataQueue * queue,void ** data,size_t * size)1396*bbb1b6f9SApple OSS Distributions getPrevInQueueMem(IOCircularDataQueue *queue,
1397*bbb1b6f9SApple OSS Distributions     void **data,
1398*bbb1b6f9SApple OSS Distributions     size_t *size)
1399*bbb1b6f9SApple OSS Distributions {
1400*bbb1b6f9SApple OSS Distributions 	return _getPrevInQueueMemInternal(queue, data, size, false);
1401*bbb1b6f9SApple OSS Distributions }
1402*bbb1b6f9SApple OSS Distributions 
1403*bbb1b6f9SApple OSS Distributions /*!
1404*bbb1b6f9SApple OSS Distributions  * @function copyPrevInQueueMem
1405*bbb1b6f9SApple OSS Distributions  * Access the data at the previous cursor position and copy into the provided buffer. Also update the cursor position to
1406*bbb1b6f9SApple OSS Distributions  * the previous. If successful, function gaurantees that the data returned is always valid, hence no need to call
1407*bbb1b6f9SApple OSS Distributions  * isDataEntryValidInQueueMem().
1408*bbb1b6f9SApple OSS Distributions  * @param queue Handle to the queue.
1409*bbb1b6f9SApple OSS Distributions  * @param data Pointer to memory into which the previous data is copied. Lifetime of this memory is controlled by the
1410*bbb1b6f9SApple OSS Distributions  * caller.
1411*bbb1b6f9SApple OSS Distributions  * @param size Size of the data buffer provided for copying. On return, this contains the actual size of the data
1412*bbb1b6f9SApple OSS Distributions  * pointed to by data param.
1413*bbb1b6f9SApple OSS Distributions  *  @return
1414*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnSuccess` if the cursor position was updated.
1415*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnAborted` if the cursor has become invalid, possibly due to a reset of the queue.
1416*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnOverrun` if the entry at the cursor position is no longer in
1417*bbb1b6f9SApple OSS Distributions  *     the queue's buffer. Call getLatestInQueueMem to get the latest data and cursor position.
1418*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnBadArgument` if an invalid argument is passsed.
1419*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnBadMedia` if the queue shared memory has been compromised.
1420*bbb1b6f9SApple OSS Distributions  *  - Other values indicate an error.
1421*bbb1b6f9SApple OSS Distributions  *
1422*bbb1b6f9SApple OSS Distributions  */
1423*bbb1b6f9SApple OSS Distributions 
1424*bbb1b6f9SApple OSS Distributions static IOReturn ATTR_LSE2
copyPrevInQueueMem(IOCircularDataQueue * queue,void * data,size_t * size)1425*bbb1b6f9SApple OSS Distributions copyPrevInQueueMem(IOCircularDataQueue *queue,
1426*bbb1b6f9SApple OSS Distributions     void *data,
1427*bbb1b6f9SApple OSS Distributions     size_t *size)
1428*bbb1b6f9SApple OSS Distributions {
1429*bbb1b6f9SApple OSS Distributions 	return _getPrevInQueueMemInternal(queue, &data, size, true);
1430*bbb1b6f9SApple OSS Distributions }
1431*bbb1b6f9SApple OSS Distributions 
1432*bbb1b6f9SApple OSS Distributions static IOReturn ATTR_LSE2
_getCurrentInQueueMemInternal(IOCircularDataQueue * queue,void ** data,size_t * size,bool copyMem)1433*bbb1b6f9SApple OSS Distributions _getCurrentInQueueMemInternal(IOCircularDataQueue *queue,
1434*bbb1b6f9SApple OSS Distributions     void **data,
1435*bbb1b6f9SApple OSS Distributions     size_t *size,
1436*bbb1b6f9SApple OSS Distributions     bool copyMem)
1437*bbb1b6f9SApple OSS Distributions {
1438*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueMemory *queueMemory = queue->queueMemory;
1439*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueDescription *queueHeaderShadow = &queue->queueHeaderShadow;
1440*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueMemoryCursor const *cursor = &queue->queueCursor;
1441*bbb1b6f9SApple OSS Distributions 
1442*bbb1b6f9SApple OSS Distributions 	size_t inSize;
1443*bbb1b6f9SApple OSS Distributions 
1444*bbb1b6f9SApple OSS Distributions 	if (queueMemory == NULL || data == NULL || size == NULL || queueHeaderShadow == NULL) {
1445*bbb1b6f9SApple OSS Distributions 		return kIOReturnBadArgument;
1446*bbb1b6f9SApple OSS Distributions 	}
1447*bbb1b6f9SApple OSS Distributions 
1448*bbb1b6f9SApple OSS Distributions 	inSize = *size;
1449*bbb1b6f9SApple OSS Distributions 	*size = 0;
1450*bbb1b6f9SApple OSS Distributions 
1451*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(_isQueueMemoryCorrupted(queue))) {
1452*bbb1b6f9SApple OSS Distributions 		return kIOReturnBadMedia;
1453*bbb1b6f9SApple OSS Distributions 	}
1454*bbb1b6f9SApple OSS Distributions 
1455*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(_isCursorPositionInvalid(queue))) {
1456*bbb1b6f9SApple OSS Distributions 		return kIOReturnAborted;
1457*bbb1b6f9SApple OSS Distributions 	}
1458*bbb1b6f9SApple OSS Distributions 
1459*bbb1b6f9SApple OSS Distributions 	const size_t queueAllocMemSize = queueHeaderShadow->allocMemSize;
1460*bbb1b6f9SApple OSS Distributions 	const size_t queueEntryDataSize = queueHeaderShadow->entryDataSize;
1461*bbb1b6f9SApple OSS Distributions 
1462*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueState currState;
1463*bbb1b6f9SApple OSS Distributions 	currState.val = atomic_load_explicit(&queueMemory->queueStateVal, memory_order_acquire);
1464*bbb1b6f9SApple OSS Distributions 
1465*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(currState.fields.rstStatus & IOCIRCULARDATAQUEUE_STATE_RESET_INPROGRESS)) {
1466*bbb1b6f9SApple OSS Distributions 		// Another thread is resetting the queue
1467*bbb1b6f9SApple OSS Distributions 		return kIOReturnBusy;
1468*bbb1b6f9SApple OSS Distributions 	}
1469*bbb1b6f9SApple OSS Distributions 
1470*bbb1b6f9SApple OSS Distributions 	uint32_t queueGeneration = currState.fields.generation;
1471*bbb1b6f9SApple OSS Distributions 
1472*bbb1b6f9SApple OSS Distributions 	// was the queue reset ?
1473*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(cursor->generation != queueGeneration || cursor->sequenceNum > currState.fields.seqNum)) {
1474*bbb1b6f9SApple OSS Distributions 		return kIOReturnAborted;
1475*bbb1b6f9SApple OSS Distributions 	}
1476*bbb1b6f9SApple OSS Distributions 
1477*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(currState.fields.seqNum == UINT64_MAX)) {
1478*bbb1b6f9SApple OSS Distributions 		// Nothing has ever been written to the queue yet.
1479*bbb1b6f9SApple OSS Distributions 		return kIOReturnUnderrun;
1480*bbb1b6f9SApple OSS Distributions 	}
1481*bbb1b6f9SApple OSS Distributions 
1482*bbb1b6f9SApple OSS Distributions 	__auto_type entry = (IOCircularDataQueueEntryHeader *)(uintptr_t)((uint8_t *)&queueMemory->entries[0]
1483*bbb1b6f9SApple OSS Distributions 	    + (cursor->position * queueEntryDataSize));
1484*bbb1b6f9SApple OSS Distributions 
1485*bbb1b6f9SApple OSS Distributions 	// SANITY CHECK - Final check to ensure the 'entry' pointer is
1486*bbb1b6f9SApple OSS Distributions 	// within the queueMemory entries buffer before we begin writing.
1487*bbb1b6f9SApple OSS Distributions 	if (os_unlikely((uint8_t *)entry < (uint8_t *)(&queueMemory->entries[0])
1488*bbb1b6f9SApple OSS Distributions 	    || (uint8_t *)entry >= (uint8_t *)queueMemory + queueAllocMemSize)) {
1489*bbb1b6f9SApple OSS Distributions 		queue_debug_error("Out of Bounds! " QUEUE_FORMAT " " CURSOR_FORMAT " " ENTRY_FORMAT, QUEUE_ARGS(queueMemory),
1490*bbb1b6f9SApple OSS Distributions 		    CURSOR_ARGS(cursor), ENTRY_ARGS(entry));
1491*bbb1b6f9SApple OSS Distributions 		return kIOReturnBadArgument;
1492*bbb1b6f9SApple OSS Distributions 	}
1493*bbb1b6f9SApple OSS Distributions 
1494*bbb1b6f9SApple OSS Distributions 	os_compiler_barrier();
1495*bbb1b6f9SApple OSS Distributions 
1496*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(entry->sentinel != queueHeaderShadow->sentinel)) {
1497*bbb1b6f9SApple OSS Distributions 		queue_debug_error("entry->sentinel != queueMemory->sentinel " QUEUE_FORMAT " " CURSOR_FORMAT " " ENTRY_FORMAT,
1498*bbb1b6f9SApple OSS Distributions 		    QUEUE_ARGS(queueMemory), CURSOR_ARGS(cursor), ENTRY_ARGS(entry));
1499*bbb1b6f9SApple OSS Distributions 		return kIOReturnBadMedia;
1500*bbb1b6f9SApple OSS Distributions 	}
1501*bbb1b6f9SApple OSS Distributions 
1502*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueEntryHeaderInfo enHeaderInfo;
1503*bbb1b6f9SApple OSS Distributions 	enHeaderInfo.val = atomic_load_explicit(&entry->headerInfoVal, memory_order_acquire);
1504*bbb1b6f9SApple OSS Distributions 	uint32_t entryGeneration = enHeaderInfo.fields.generation;
1505*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(entryGeneration != queueGeneration)) {
1506*bbb1b6f9SApple OSS Distributions 		queue_debug_note("entryGeneration != queueGeneration " QUEUE_FORMAT " " CURSOR_FORMAT " " ENTRY_FORMAT,
1507*bbb1b6f9SApple OSS Distributions 		    QUEUE_ARGS(queueMemory), CURSOR_ARGS(cursor), ENTRY_ARGS(entry));
1508*bbb1b6f9SApple OSS Distributions 		return kIOReturnAborted;
1509*bbb1b6f9SApple OSS Distributions 	}
1510*bbb1b6f9SApple OSS Distributions 
1511*bbb1b6f9SApple OSS Distributions 	// is the entry currently being written to or has the cursor fallen too far behind and the cursor is no longer
1512*bbb1b6f9SApple OSS Distributions 	// valid.
1513*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(enHeaderInfo.fields.wrStatus == IOCIRCULARDATAQUEUE_ENTRY_STATE_WRITE_INPROGRESS
1514*bbb1b6f9SApple OSS Distributions 	    || enHeaderInfo.fields.seqNum != cursor->sequenceNum)) {
1515*bbb1b6f9SApple OSS Distributions 		return kIOReturnOverrun;
1516*bbb1b6f9SApple OSS Distributions 	}
1517*bbb1b6f9SApple OSS Distributions 
1518*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(enHeaderInfo.fields.dataSize > queueHeaderShadow->entryDataSize)) {
1519*bbb1b6f9SApple OSS Distributions 		return kIOReturnOverrun;
1520*bbb1b6f9SApple OSS Distributions 	}
1521*bbb1b6f9SApple OSS Distributions 	*size = enHeaderInfo.fields.dataSize;
1522*bbb1b6f9SApple OSS Distributions 
1523*bbb1b6f9SApple OSS Distributions 	if (!copyMem) {
1524*bbb1b6f9SApple OSS Distributions 		*data = entry->data;
1525*bbb1b6f9SApple OSS Distributions 	} else {
1526*bbb1b6f9SApple OSS Distributions 		if (os_unlikely(enHeaderInfo.fields.dataSize > inSize)) {
1527*bbb1b6f9SApple OSS Distributions 			return kIOReturnOverrun;
1528*bbb1b6f9SApple OSS Distributions 		}
1529*bbb1b6f9SApple OSS Distributions 		memcpy(*data, entry->data, enHeaderInfo.fields.dataSize);
1530*bbb1b6f9SApple OSS Distributions 		// Lets re-verify after the memcpy if the buffer is/has been overwritten.
1531*bbb1b6f9SApple OSS Distributions 
1532*bbb1b6f9SApple OSS Distributions 		IOCircularDataQueueEntryHeaderInfo enHeaderInfoAfter;
1533*bbb1b6f9SApple OSS Distributions 		enHeaderInfoAfter.val = atomic_load_explicit(&entry->headerInfoVal, memory_order_acquire);
1534*bbb1b6f9SApple OSS Distributions 		// Did something change, while we were memcopying ?
1535*bbb1b6f9SApple OSS Distributions 		if (enHeaderInfo.val != enHeaderInfoAfter.val) {
1536*bbb1b6f9SApple OSS Distributions 			// while we were memcopying, the writer wrapped around and is writing into our index. or the queue got reset
1537*bbb1b6f9SApple OSS Distributions 			*size = 0;
1538*bbb1b6f9SApple OSS Distributions 			return kIOReturnBusy;
1539*bbb1b6f9SApple OSS Distributions 		}
1540*bbb1b6f9SApple OSS Distributions 	}
1541*bbb1b6f9SApple OSS Distributions 
1542*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(_isQueueMemoryCorrupted(queue))) {
1543*bbb1b6f9SApple OSS Distributions 		return kIOReturnBadMedia;
1544*bbb1b6f9SApple OSS Distributions 	}
1545*bbb1b6f9SApple OSS Distributions 
1546*bbb1b6f9SApple OSS Distributions 	return kIOReturnSuccess;
1547*bbb1b6f9SApple OSS Distributions }
1548*bbb1b6f9SApple OSS Distributions 
1549*bbb1b6f9SApple OSS Distributions /*!
1550*bbb1b6f9SApple OSS Distributions  * @function getCurrentInQueueMem
1551*bbb1b6f9SApple OSS Distributions  * Access the data at the current cursor position. The cursor position is unchanged. No copy is made of the data. <br>
1552*bbb1b6f9SApple OSS Distributions  * Caller is supposed to call isDataEntryValidInQueueMem() to check data integrity after reading the data is complete.
1553*bbb1b6f9SApple OSS Distributions  * @param queue Handle to the queue.
1554*bbb1b6f9SApple OSS Distributions  * @param data A pointer to the data memory region for the previous entry data in the queue.
1555*bbb1b6f9SApple OSS Distributions  * @param size A pointer to the size of the data parameter.  On return, this contains the actual size of the data
1556*bbb1b6f9SApple OSS Distributions  * pointed to by data param.
1557*bbb1b6f9SApple OSS Distributions  *  @return
1558*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnSuccess` if the cursor position was updated to the previous.
1559*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnAborted` if the cursor has become invalid, possibly due to a reset of the queue.
1560*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnOverrun` if the entry at the cursor position is no longer in
1561*bbb1b6f9SApple OSS Distributions  *     the queue's buffer. Call getLatestInQueueMem to get the latest data and cursor position.
1562*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnBadArgument` if an invalid argument is passsed.
1563*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnBadMedia` if the queue shared memory has been compromised.
1564*bbb1b6f9SApple OSS Distributions  *  - Other values indicate an error.
1565*bbb1b6f9SApple OSS Distributions  *
1566*bbb1b6f9SApple OSS Distributions  */
1567*bbb1b6f9SApple OSS Distributions 
1568*bbb1b6f9SApple OSS Distributions static IOReturn ATTR_LSE2
getCurrentInQueueMem(IOCircularDataQueue * queue,void ** data,size_t * size)1569*bbb1b6f9SApple OSS Distributions getCurrentInQueueMem(IOCircularDataQueue *queue,
1570*bbb1b6f9SApple OSS Distributions     void **data,
1571*bbb1b6f9SApple OSS Distributions     size_t *size)
1572*bbb1b6f9SApple OSS Distributions {
1573*bbb1b6f9SApple OSS Distributions 	return _getCurrentInQueueMemInternal(queue, data, size, false);
1574*bbb1b6f9SApple OSS Distributions }
1575*bbb1b6f9SApple OSS Distributions 
1576*bbb1b6f9SApple OSS Distributions /*!
1577*bbb1b6f9SApple OSS Distributions  * @function copyCurrentInQueueMem
1578*bbb1b6f9SApple OSS Distributions  * Access the data at the current cursor position and copy into the provided buffer. The cursor position is unchanged.
1579*bbb1b6f9SApple OSS Distributions  * If successful, function gaurantees that the data returned is always valid, hence no need to call
1580*bbb1b6f9SApple OSS Distributions  * isDataEntryValidInQueueMem().
1581*bbb1b6f9SApple OSS Distributions  * @param queue Handle to the queue.
1582*bbb1b6f9SApple OSS Distributions  * @param data Pointer to memory into which the previous data is copied. Lifetime of this memory is controlled by the
1583*bbb1b6f9SApple OSS Distributions  * caller.
1584*bbb1b6f9SApple OSS Distributions  * @param size Size of the data buffer provided for copying. On return, this contains the actual size of the data
1585*bbb1b6f9SApple OSS Distributions  * pointed to by data param.
1586*bbb1b6f9SApple OSS Distributions  *  @return
1587*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnSuccess` if the cursor position was updated.
1588*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnAborted` if the cursor has become invalid.
1589*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnOverrun` if the entry at the cursor position is no longer in
1590*bbb1b6f9SApple OSS Distributions  *     the queue's buffer. Call getLatestInQueueMem to get the latest data and cursor position.
1591*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnBadArgument` if an invalid argument is passsed.
1592*bbb1b6f9SApple OSS Distributions  *  - `kIOReturnBadMedia` if the queue shared memory has been compromised.
1593*bbb1b6f9SApple OSS Distributions  *  - Other values indicate an error.
1594*bbb1b6f9SApple OSS Distributions  *
1595*bbb1b6f9SApple OSS Distributions  */
1596*bbb1b6f9SApple OSS Distributions 
1597*bbb1b6f9SApple OSS Distributions static IOReturn ATTR_LSE2
copyCurrentInQueueMem(IOCircularDataQueue * queue,void * data,size_t * size)1598*bbb1b6f9SApple OSS Distributions copyCurrentInQueueMem(IOCircularDataQueue *queue,
1599*bbb1b6f9SApple OSS Distributions     void *data,
1600*bbb1b6f9SApple OSS Distributions     size_t *size)
1601*bbb1b6f9SApple OSS Distributions {
1602*bbb1b6f9SApple OSS Distributions 	return _getCurrentInQueueMemInternal(queue, &data, size, true);
1603*bbb1b6f9SApple OSS Distributions }
1604*bbb1b6f9SApple OSS Distributions 
1605*bbb1b6f9SApple OSS Distributions 
1606*bbb1b6f9SApple OSS Distributions /* API */
1607*bbb1b6f9SApple OSS Distributions 
1608*bbb1b6f9SApple OSS Distributions static void ATTR_LSE2
_initCursor(IOCircularDataQueue * queue)1609*bbb1b6f9SApple OSS Distributions _initCursor(IOCircularDataQueue *queue)
1610*bbb1b6f9SApple OSS Distributions {
1611*bbb1b6f9SApple OSS Distributions 	// Invalidate the cursor
1612*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueMemoryCursor *cursor = &queue->queueCursor;
1613*bbb1b6f9SApple OSS Distributions 	cursor->generation = UINT32_MAX;
1614*bbb1b6f9SApple OSS Distributions 	cursor->position = UINT32_MAX;
1615*bbb1b6f9SApple OSS Distributions 	cursor->sequenceNum = UINT64_MAX;
1616*bbb1b6f9SApple OSS Distributions }
1617*bbb1b6f9SApple OSS Distributions 
1618*bbb1b6f9SApple OSS Distributions #if KERNEL
1619*bbb1b6f9SApple OSS Distributions 
1620*bbb1b6f9SApple OSS Distributions IOReturn ATTR_LSE2
IOCircularDataQueueCreateWithEntries(IOCircularDataQueueCreateOptions options,uint32_t numEntries,uint32_t entrySize,IOCircularDataQueue ** pQueue)1621*bbb1b6f9SApple OSS Distributions IOCircularDataQueueCreateWithEntries(IOCircularDataQueueCreateOptions options, uint32_t numEntries, uint32_t entrySize, IOCircularDataQueue **pQueue)
1622*bbb1b6f9SApple OSS Distributions {
1623*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueMemory *queueMemory;
1624*bbb1b6f9SApple OSS Distributions 	IOReturn ret;
1625*bbb1b6f9SApple OSS Distributions 
1626*bbb1b6f9SApple OSS Distributions 	if (!pQueue) {
1627*bbb1b6f9SApple OSS Distributions 		return kIOReturnBadArgument;
1628*bbb1b6f9SApple OSS Distributions 	}
1629*bbb1b6f9SApple OSS Distributions 	*pQueue = NULL;
1630*bbb1b6f9SApple OSS Distributions 	if (!numEntries || !entrySize) {
1631*bbb1b6f9SApple OSS Distributions 		return kIOReturnBadArgument;
1632*bbb1b6f9SApple OSS Distributions 	}
1633*bbb1b6f9SApple OSS Distributions 
1634*bbb1b6f9SApple OSS Distributions 	uint64_t sentinel = 0xA5A5A5A5A5A5A5A5;
1635*bbb1b6f9SApple OSS Distributions 
1636*bbb1b6f9SApple OSS Distributions #if HEADER_16BYTE_ALIGNED
1637*bbb1b6f9SApple OSS Distributions 	size_t entryRoundedDataSize = IORound(entrySize, sizeof(__uint128_t));
1638*bbb1b6f9SApple OSS Distributions #else
1639*bbb1b6f9SApple OSS Distributions 	size_t entryRoundedDataSize = IORound(entrySize, sizeof(UInt64));
1640*bbb1b6f9SApple OSS Distributions #endif
1641*bbb1b6f9SApple OSS Distributions 	size_t entryDataSize = entryRoundedDataSize + CIRCULAR_DATA_QUEUE_ENTRY_HEADER_SIZE;
1642*bbb1b6f9SApple OSS Distributions 	size_t entriesSize = numEntries * (entryDataSize);
1643*bbb1b6f9SApple OSS Distributions 	size_t totalSize = entriesSize + CIRCULAR_DATA_QUEUE_MEMORY_HEADER_SIZE;
1644*bbb1b6f9SApple OSS Distributions 
1645*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(numEntries > UINT32_MAX - 1
1646*bbb1b6f9SApple OSS Distributions 	    || entryRoundedDataSize > (UINT32_MAX - sizeof(IOCircularDataQueueEntryHeader))
1647*bbb1b6f9SApple OSS Distributions 	    || entryDataSize > UINT32_MAX || totalSize > UINT32_MAX)) {
1648*bbb1b6f9SApple OSS Distributions 		return kIOReturnBadArgument;
1649*bbb1b6f9SApple OSS Distributions 	}
1650*bbb1b6f9SApple OSS Distributions 
1651*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueue *queue = IONew(IOCircularDataQueue, 1);
1652*bbb1b6f9SApple OSS Distributions 	if (!queue) {
1653*bbb1b6f9SApple OSS Distributions 		return kIOReturnNoMemory;
1654*bbb1b6f9SApple OSS Distributions 	}
1655*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueDescription *queueHeaderShadow = &queue->queueHeaderShadow;
1656*bbb1b6f9SApple OSS Distributions 
1657*bbb1b6f9SApple OSS Distributions 	OSData * desc;
1658*bbb1b6f9SApple OSS Distributions 	queue->iomd = IOBufferMemoryDescriptor::inTaskWithOptions(
1659*bbb1b6f9SApple OSS Distributions 		kernel_task, kIOMemoryDirectionOutIn | kIOMemoryKernelUserShared, totalSize, page_size);
1660*bbb1b6f9SApple OSS Distributions 	if (os_unlikely(queue->iomd == NULL)) {
1661*bbb1b6f9SApple OSS Distributions 		ret = kIOReturnNoMemory;
1662*bbb1b6f9SApple OSS Distributions 		goto error;
1663*bbb1b6f9SApple OSS Distributions 	}
1664*bbb1b6f9SApple OSS Distributions 	queueMemory = (IOCircularDataQueueMemory *)queue->iomd->getBytesNoCopy();
1665*bbb1b6f9SApple OSS Distributions 	queue->queueMemory = queueMemory;
1666*bbb1b6f9SApple OSS Distributions 	queueMemory->sentinel = queueHeaderShadow->sentinel = sentinel;
1667*bbb1b6f9SApple OSS Distributions 
1668*bbb1b6f9SApple OSS Distributions 	queueHeaderShadow->allocMemSize = (uint32_t)totalSize;
1669*bbb1b6f9SApple OSS Distributions 	queueHeaderShadow->entryDataSize
1670*bbb1b6f9SApple OSS Distributions 	        = (uint32_t)entryDataSize; // totalSize check above gaurantess this will not overflow UINT32_MAX.
1671*bbb1b6f9SApple OSS Distributions 	queueHeaderShadow->numEntries = numEntries;
1672*bbb1b6f9SApple OSS Distributions 	queueHeaderShadow->dataSize = entrySize; // the client requested fixed entry size.
1673*bbb1b6f9SApple OSS Distributions 	queueHeaderShadow->memorySize = (uint32_t)entriesSize;
1674*bbb1b6f9SApple OSS Distributions 
1675*bbb1b6f9SApple OSS Distributions 	desc = OSData::withBytes(queueHeaderShadow, sizeof(*queueHeaderShadow));
1676*bbb1b6f9SApple OSS Distributions 	queue->iomd->setSharingContext(kIOCircularQueueDescriptionKey, desc);
1677*bbb1b6f9SApple OSS Distributions 
1678*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueState newState;
1679*bbb1b6f9SApple OSS Distributions 	newState.val = 0;
1680*bbb1b6f9SApple OSS Distributions 	newState.fields.seqNum = UINT64_MAX;
1681*bbb1b6f9SApple OSS Distributions 	atomic_store_explicit(&queueMemory->queueStateVal, newState.val, memory_order_release);
1682*bbb1b6f9SApple OSS Distributions 
1683*bbb1b6f9SApple OSS Distributions 	ret = _reset(queue);
1684*bbb1b6f9SApple OSS Distributions 	if (ret != kIOReturnSuccess) {
1685*bbb1b6f9SApple OSS Distributions 		goto error;
1686*bbb1b6f9SApple OSS Distributions 	}
1687*bbb1b6f9SApple OSS Distributions 
1688*bbb1b6f9SApple OSS Distributions 	_initCursor(queue);
1689*bbb1b6f9SApple OSS Distributions 	*pQueue = queue;
1690*bbb1b6f9SApple OSS Distributions 	return kIOReturnSuccess;
1691*bbb1b6f9SApple OSS Distributions 
1692*bbb1b6f9SApple OSS Distributions 
1693*bbb1b6f9SApple OSS Distributions error:
1694*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueDestroy(&queue);
1695*bbb1b6f9SApple OSS Distributions 	return ret;
1696*bbb1b6f9SApple OSS Distributions }
1697*bbb1b6f9SApple OSS Distributions 
1698*bbb1b6f9SApple OSS Distributions IOMemoryDescriptor * ATTR_LSE2
IOCircularDataQueueCopyMemoryDescriptor(IOCircularDataQueue * queue)1699*bbb1b6f9SApple OSS Distributions IOCircularDataQueueCopyMemoryDescriptor(IOCircularDataQueue  *queue)
1700*bbb1b6f9SApple OSS Distributions {
1701*bbb1b6f9SApple OSS Distributions 	IOMemoryDescriptor * md;
1702*bbb1b6f9SApple OSS Distributions 	md = queue->iomd;
1703*bbb1b6f9SApple OSS Distributions 	if (md) {
1704*bbb1b6f9SApple OSS Distributions 		md->retain();
1705*bbb1b6f9SApple OSS Distributions 	}
1706*bbb1b6f9SApple OSS Distributions 	return md;
1707*bbb1b6f9SApple OSS Distributions }
1708*bbb1b6f9SApple OSS Distributions 
1709*bbb1b6f9SApple OSS Distributions #else /* KERNEL */
1710*bbb1b6f9SApple OSS Distributions 
1711*bbb1b6f9SApple OSS Distributions #if defined(__arm64__) && defined(__LP64__)
1712*bbb1b6f9SApple OSS Distributions #include <System/arm/cpu_capabilities.h>
1713*bbb1b6f9SApple OSS Distributions #endif /* defined(__arm64__) */
1714*bbb1b6f9SApple OSS Distributions 
1715*bbb1b6f9SApple OSS Distributions IOReturn ATTR_LSE2
IOCircularDataQueueCreateWithConnection(IOCircularDataQueueCreateOptions options,io_connect_t connect,uint32_t memoryType,IOCircularDataQueue ** pQueue)1716*bbb1b6f9SApple OSS Distributions IOCircularDataQueueCreateWithConnection(IOCircularDataQueueCreateOptions options, io_connect_t connect, uint32_t memoryType, IOCircularDataQueue **pQueue)
1717*bbb1b6f9SApple OSS Distributions {
1718*bbb1b6f9SApple OSS Distributions 	if (!pQueue) {
1719*bbb1b6f9SApple OSS Distributions 		return kIOReturnBadArgument;
1720*bbb1b6f9SApple OSS Distributions 	}
1721*bbb1b6f9SApple OSS Distributions 	*pQueue = NULL;
1722*bbb1b6f9SApple OSS Distributions 
1723*bbb1b6f9SApple OSS Distributions #if defined(__arm64__) && defined(__LP64__)
1724*bbb1b6f9SApple OSS Distributions 	if (0 == (kHasFeatLSE2 & _get_cpu_capabilities())) {
1725*bbb1b6f9SApple OSS Distributions 		return kIOReturnUnsupported;
1726*bbb1b6f9SApple OSS Distributions 	}
1727*bbb1b6f9SApple OSS Distributions #else
1728*bbb1b6f9SApple OSS Distributions 	return kIOReturnUnsupported;
1729*bbb1b6f9SApple OSS Distributions #endif /* defined(__arm64__) */
1730*bbb1b6f9SApple OSS Distributions 
1731*bbb1b6f9SApple OSS Distributions 	uint64_t sentinel = 0xA5A5A5A5A5A5A5A5;
1732*bbb1b6f9SApple OSS Distributions 
1733*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueue *queue = IONew(IOCircularDataQueue, 1);
1734*bbb1b6f9SApple OSS Distributions 	if (!queue) {
1735*bbb1b6f9SApple OSS Distributions 		return kIOReturnNoMemory;
1736*bbb1b6f9SApple OSS Distributions 	}
1737*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueueDescription *queueHeaderShadow = &queue->queueHeaderShadow;
1738*bbb1b6f9SApple OSS Distributions 
1739*bbb1b6f9SApple OSS Distributions 	queue->connect = connect;
1740*bbb1b6f9SApple OSS Distributions 	queue->memoryType = memoryType;
1741*bbb1b6f9SApple OSS Distributions 
1742*bbb1b6f9SApple OSS Distributions 	io_struct_inband_t inband_output;
1743*bbb1b6f9SApple OSS Distributions 	mach_msg_type_number_t inband_outputCnt;
1744*bbb1b6f9SApple OSS Distributions 	mach_vm_address_t map_address;
1745*bbb1b6f9SApple OSS Distributions 	mach_vm_size_t map_size;
1746*bbb1b6f9SApple OSS Distributions 	IOReturn ret;
1747*bbb1b6f9SApple OSS Distributions 
1748*bbb1b6f9SApple OSS Distributions 	inband_outputCnt = sizeof(inband_output);
1749*bbb1b6f9SApple OSS Distributions 
1750*bbb1b6f9SApple OSS Distributions 	ret = io_connect_map_shared_memory(connect, memoryType, mach_task_self(),
1751*bbb1b6f9SApple OSS Distributions 	    &map_address, &map_size,
1752*bbb1b6f9SApple OSS Distributions 	    /* flags */ 0,
1753*bbb1b6f9SApple OSS Distributions 	    (char *) kIOCircularQueueDescriptionKey,
1754*bbb1b6f9SApple OSS Distributions 	    inband_output,
1755*bbb1b6f9SApple OSS Distributions 	    &inband_outputCnt);
1756*bbb1b6f9SApple OSS Distributions 
1757*bbb1b6f9SApple OSS Distributions 	printf("%x, %lx, 0x%llx, 0x%llx\n", inband_outputCnt, sizeof(IOCircularDataQueueDescription), map_address, map_size);
1758*bbb1b6f9SApple OSS Distributions 
1759*bbb1b6f9SApple OSS Distributions 	assert(sizeof(IOCircularDataQueueDescription) == inband_outputCnt);
1760*bbb1b6f9SApple OSS Distributions 	memcpy(queueHeaderShadow, inband_output, sizeof(IOCircularDataQueueDescription));
1761*bbb1b6f9SApple OSS Distributions 	printf("sentinel %qx\n", queueHeaderShadow->sentinel);
1762*bbb1b6f9SApple OSS Distributions 	assert(queueHeaderShadow->allocMemSize == map_size);
1763*bbb1b6f9SApple OSS Distributions 	queue->queueMemory = (IOCircularDataQueueMemory *) map_address;
1764*bbb1b6f9SApple OSS Distributions 
1765*bbb1b6f9SApple OSS Distributions 	if (!isQueueMemoryValid(queue)) {
1766*bbb1b6f9SApple OSS Distributions 		IOCircularDataQueueDestroy(&queue);
1767*bbb1b6f9SApple OSS Distributions 		return kIOReturnBadArgument;
1768*bbb1b6f9SApple OSS Distributions 	}
1769*bbb1b6f9SApple OSS Distributions 
1770*bbb1b6f9SApple OSS Distributions 	_initCursor(queue);
1771*bbb1b6f9SApple OSS Distributions 	*pQueue = queue;
1772*bbb1b6f9SApple OSS Distributions 
1773*bbb1b6f9SApple OSS Distributions 	return ret;
1774*bbb1b6f9SApple OSS Distributions }
1775*bbb1b6f9SApple OSS Distributions 
1776*bbb1b6f9SApple OSS Distributions #endif /* !KERNEL */
1777*bbb1b6f9SApple OSS Distributions 
1778*bbb1b6f9SApple OSS Distributions IOReturn ATTR_LSE2
IOCircularDataQueueDestroy(IOCircularDataQueue ** pQueue)1779*bbb1b6f9SApple OSS Distributions IOCircularDataQueueDestroy(IOCircularDataQueue **pQueue)
1780*bbb1b6f9SApple OSS Distributions {
1781*bbb1b6f9SApple OSS Distributions 	IOCircularDataQueue * queue;
1782*bbb1b6f9SApple OSS Distributions 	IOReturn ret = kIOReturnSuccess;
1783*bbb1b6f9SApple OSS Distributions 
1784*bbb1b6f9SApple OSS Distributions 	if (!pQueue) {
1785*bbb1b6f9SApple OSS Distributions 		return kIOReturnBadArgument;
1786*bbb1b6f9SApple OSS Distributions 	}
1787*bbb1b6f9SApple OSS Distributions 	queue = *pQueue;
1788*bbb1b6f9SApple OSS Distributions 	if (queue) {
1789*bbb1b6f9SApple OSS Distributions 		ret = destroyQueueMem(queue);
1790*bbb1b6f9SApple OSS Distributions 		IODelete(queue, IOCircularDataQueue, 1);
1791*bbb1b6f9SApple OSS Distributions 		*pQueue = NULL;
1792*bbb1b6f9SApple OSS Distributions 	}
1793*bbb1b6f9SApple OSS Distributions 	return ret;
1794*bbb1b6f9SApple OSS Distributions }
1795*bbb1b6f9SApple OSS Distributions 
1796*bbb1b6f9SApple OSS Distributions IOReturn ATTR_LSE2
IOCircularDataQueueEnqueue(IOCircularDataQueue * queue,const void * data,size_t dataSize)1797*bbb1b6f9SApple OSS Distributions IOCircularDataQueueEnqueue(IOCircularDataQueue *queue, const void *data, size_t dataSize)
1798*bbb1b6f9SApple OSS Distributions {
1799*bbb1b6f9SApple OSS Distributions 	if (!queue) {
1800*bbb1b6f9SApple OSS Distributions 		return kIOReturnBadArgument;
1801*bbb1b6f9SApple OSS Distributions 	}
1802*bbb1b6f9SApple OSS Distributions 
1803*bbb1b6f9SApple OSS Distributions 	return enqueueQueueMem(queue, data, dataSize);
1804*bbb1b6f9SApple OSS Distributions }
1805*bbb1b6f9SApple OSS Distributions 
1806*bbb1b6f9SApple OSS Distributions IOReturn ATTR_LSE2
IOCircularDataQueueGetLatest(IOCircularDataQueue * queue,void ** data,size_t * size)1807*bbb1b6f9SApple OSS Distributions IOCircularDataQueueGetLatest(IOCircularDataQueue *queue, void **data, size_t *size)
1808*bbb1b6f9SApple OSS Distributions {
1809*bbb1b6f9SApple OSS Distributions 	if (!queue) {
1810*bbb1b6f9SApple OSS Distributions 		return kIOReturnBadArgument;
1811*bbb1b6f9SApple OSS Distributions 	}
1812*bbb1b6f9SApple OSS Distributions 
1813*bbb1b6f9SApple OSS Distributions 	return getLatestInQueueMem(queue, data, size);
1814*bbb1b6f9SApple OSS Distributions }
1815*bbb1b6f9SApple OSS Distributions 
1816*bbb1b6f9SApple OSS Distributions IOReturn ATTR_LSE2
IOCircularDataQueueCopyLatest(IOCircularDataQueue * queue,void * data,size_t * size)1817*bbb1b6f9SApple OSS Distributions IOCircularDataQueueCopyLatest(IOCircularDataQueue *queue, void *data, size_t *size)
1818*bbb1b6f9SApple OSS Distributions {
1819*bbb1b6f9SApple OSS Distributions 	if (!queue) {
1820*bbb1b6f9SApple OSS Distributions 		return kIOReturnBadArgument;
1821*bbb1b6f9SApple OSS Distributions 	}
1822*bbb1b6f9SApple OSS Distributions 
1823*bbb1b6f9SApple OSS Distributions 	return copyLatestInQueueMem(queue, data, size);
1824*bbb1b6f9SApple OSS Distributions }
1825*bbb1b6f9SApple OSS Distributions 
1826*bbb1b6f9SApple OSS Distributions IOReturn ATTR_LSE2
IOCircularDataQueueGetNext(IOCircularDataQueue * queue,void ** data,size_t * size)1827*bbb1b6f9SApple OSS Distributions IOCircularDataQueueGetNext(IOCircularDataQueue *queue, void **data, size_t *size)
1828*bbb1b6f9SApple OSS Distributions {
1829*bbb1b6f9SApple OSS Distributions 	if (!queue) {
1830*bbb1b6f9SApple OSS Distributions 		return kIOReturnBadArgument;
1831*bbb1b6f9SApple OSS Distributions 	}
1832*bbb1b6f9SApple OSS Distributions 
1833*bbb1b6f9SApple OSS Distributions 	return getNextInQueueMem(queue, data, size);
1834*bbb1b6f9SApple OSS Distributions }
1835*bbb1b6f9SApple OSS Distributions 
1836*bbb1b6f9SApple OSS Distributions IOReturn ATTR_LSE2
IOCircularDataQueueCopyNext(IOCircularDataQueue * queue,void * data,size_t * size)1837*bbb1b6f9SApple OSS Distributions IOCircularDataQueueCopyNext(IOCircularDataQueue *queue, void *data, size_t *size)
1838*bbb1b6f9SApple OSS Distributions {
1839*bbb1b6f9SApple OSS Distributions 	if (!queue) {
1840*bbb1b6f9SApple OSS Distributions 		return kIOReturnBadArgument;
1841*bbb1b6f9SApple OSS Distributions 	}
1842*bbb1b6f9SApple OSS Distributions 
1843*bbb1b6f9SApple OSS Distributions 	return copyNextInQueueMem(queue, data, size);
1844*bbb1b6f9SApple OSS Distributions }
1845*bbb1b6f9SApple OSS Distributions 
1846*bbb1b6f9SApple OSS Distributions IOReturn ATTR_LSE2
IOCircularDataQueueGetPrevious(IOCircularDataQueue * queue,void ** data,size_t * size)1847*bbb1b6f9SApple OSS Distributions IOCircularDataQueueGetPrevious(IOCircularDataQueue *queue, void **data, size_t *size)
1848*bbb1b6f9SApple OSS Distributions {
1849*bbb1b6f9SApple OSS Distributions 	if (!queue) {
1850*bbb1b6f9SApple OSS Distributions 		return kIOReturnBadArgument;
1851*bbb1b6f9SApple OSS Distributions 	}
1852*bbb1b6f9SApple OSS Distributions 
1853*bbb1b6f9SApple OSS Distributions 	return getPrevInQueueMem(queue, data, size);
1854*bbb1b6f9SApple OSS Distributions }
1855*bbb1b6f9SApple OSS Distributions 
1856*bbb1b6f9SApple OSS Distributions IOReturn ATTR_LSE2
IOCircularDataQueueCopyPrevious(IOCircularDataQueue * queue,void * data,size_t * size)1857*bbb1b6f9SApple OSS Distributions IOCircularDataQueueCopyPrevious(IOCircularDataQueue *queue, void *data, size_t *size)
1858*bbb1b6f9SApple OSS Distributions {
1859*bbb1b6f9SApple OSS Distributions 	if (!queue) {
1860*bbb1b6f9SApple OSS Distributions 		return kIOReturnBadArgument;
1861*bbb1b6f9SApple OSS Distributions 	}
1862*bbb1b6f9SApple OSS Distributions 
1863*bbb1b6f9SApple OSS Distributions 	return copyPrevInQueueMem(queue, data, size);
1864*bbb1b6f9SApple OSS Distributions }
1865*bbb1b6f9SApple OSS Distributions 
1866*bbb1b6f9SApple OSS Distributions // IOReturn
1867*bbb1b6f9SApple OSS Distributions //IOCircularDataQueueGetLatestWithBlock(IOCircularDataQueue *queue, void (^handler)(void * data, size_t size))
1868*bbb1b6f9SApple OSS Distributions //{
1869*bbb1b6f9SApple OSS Distributions //     if (!queue) {
1870*bbb1b6f9SApple OSS Distributions //         return kIOReturnBadArgument;
1871*bbb1b6f9SApple OSS Distributions //     }
1872*bbb1b6f9SApple OSS Distributions //
1873*bbb1b6f9SApple OSS Distributions ////    return getPrevInQueueMem(queue->queueMemory, (IOCircularDataQueueDescription *)
1874*bbb1b6f9SApple OSS Distributions ///&queue->queueHeaderShadow, (IOCircularDataQueueMemoryCursor *) &queue->queueCursor, data, size);
1875*bbb1b6f9SApple OSS Distributions //}
1876*bbb1b6f9SApple OSS Distributions //
1877*bbb1b6f9SApple OSS Distributions 
1878*bbb1b6f9SApple OSS Distributions IOReturn ATTR_LSE2
IOCircularDataQueueIsCurrentDataValid(IOCircularDataQueue * queue)1879*bbb1b6f9SApple OSS Distributions IOCircularDataQueueIsCurrentDataValid(IOCircularDataQueue *queue)
1880*bbb1b6f9SApple OSS Distributions {
1881*bbb1b6f9SApple OSS Distributions 	if (!queue) {
1882*bbb1b6f9SApple OSS Distributions 		return kIOReturnBadArgument;
1883*bbb1b6f9SApple OSS Distributions 	}
1884*bbb1b6f9SApple OSS Distributions 
1885*bbb1b6f9SApple OSS Distributions 	return isDataEntryValidInQueueMem(queue);
1886*bbb1b6f9SApple OSS Distributions }
1887*bbb1b6f9SApple OSS Distributions 
1888*bbb1b6f9SApple OSS Distributions IOReturn ATTR_LSE2
IOCircularDataQueueSetCursorLatest(IOCircularDataQueue * queue)1889*bbb1b6f9SApple OSS Distributions IOCircularDataQueueSetCursorLatest(IOCircularDataQueue *queue)
1890*bbb1b6f9SApple OSS Distributions {
1891*bbb1b6f9SApple OSS Distributions 	if (!queue) {
1892*bbb1b6f9SApple OSS Distributions 		return kIOReturnBadArgument;
1893*bbb1b6f9SApple OSS Distributions 	}
1894*bbb1b6f9SApple OSS Distributions 
1895*bbb1b6f9SApple OSS Distributions 	return setCursorLatestInQueueMem(queue);
1896*bbb1b6f9SApple OSS Distributions }
1897*bbb1b6f9SApple OSS Distributions 
1898*bbb1b6f9SApple OSS Distributions IOReturn ATTR_LSE2
IOCircularDataQueueGetCurrent(IOCircularDataQueue * queue,void ** data,size_t * size)1899*bbb1b6f9SApple OSS Distributions IOCircularDataQueueGetCurrent(IOCircularDataQueue *queue, void **data, size_t *size)
1900*bbb1b6f9SApple OSS Distributions {
1901*bbb1b6f9SApple OSS Distributions 	if (!queue) {
1902*bbb1b6f9SApple OSS Distributions 		return kIOReturnBadArgument;
1903*bbb1b6f9SApple OSS Distributions 	}
1904*bbb1b6f9SApple OSS Distributions 
1905*bbb1b6f9SApple OSS Distributions 	return getCurrentInQueueMem(queue, data, size);
1906*bbb1b6f9SApple OSS Distributions }
1907*bbb1b6f9SApple OSS Distributions 
1908*bbb1b6f9SApple OSS Distributions IOReturn ATTR_LSE2
IOCircularDataQueueCopyCurrent(IOCircularDataQueue * queue,void * data,size_t * size)1909*bbb1b6f9SApple OSS Distributions IOCircularDataQueueCopyCurrent(IOCircularDataQueue *queue, void *data, size_t *size)
1910*bbb1b6f9SApple OSS Distributions {
1911*bbb1b6f9SApple OSS Distributions 	if (!queue) {
1912*bbb1b6f9SApple OSS Distributions 		return kIOReturnBadArgument;
1913*bbb1b6f9SApple OSS Distributions 	}
1914*bbb1b6f9SApple OSS Distributions 
1915*bbb1b6f9SApple OSS Distributions 	return copyCurrentInQueueMem(queue, data, size);
1916*bbb1b6f9SApple OSS Distributions }
1917*bbb1b6f9SApple OSS Distributions 
1918*bbb1b6f9SApple OSS Distributions __END_DECLS
1919