]>
Commit | Line | Data |
---|---|---|
cf1d4549 JY |
1 | /** @file\r |
2 | \r | |
35897da2 | 3 | Copyright (c) 2014 - 2019, Intel Corporation. All rights reserved.<BR>\r |
9672cd30 | 4 | SPDX-License-Identifier: BSD-2-Clause-Patent\r |
cf1d4549 JY |
5 | \r |
6 | **/\r | |
7 | \r | |
8 | #include <PiPei.h>\r | |
9 | #include <Library/BaseLib.h>\r | |
10 | #include <Library/DebugLib.h>\r | |
11 | #include <Library/PcdLib.h>\r | |
12 | #include <FspGlobalData.h>\r | |
13 | #include <FspEas.h>\r | |
6b5677e1 | 14 | #include <Library/FspSwitchStackLib.h>\r |
cf1d4549 JY |
15 | \r |
16 | #pragma pack(1)\r | |
17 | \r | |
18 | //\r | |
19 | // API Parameter +0x34\r | |
20 | // API return address +0x30\r | |
21 | //\r | |
22 | // push FspInfoHeader +0x2C\r | |
23 | // pushfd +0x28\r | |
24 | // cli\r | |
25 | // pushad +0x24\r | |
26 | // sub esp, 8 +0x00\r | |
27 | // sidt fword ptr [esp]\r | |
28 | //\r | |
29 | typedef struct {\r | |
30 | UINT16 IdtrLimit;\r | |
31 | UINT32 IdtrBase;\r | |
32 | UINT16 Reserved;\r | |
33 | UINT32 Edi;\r | |
34 | UINT32 Esi;\r | |
35 | UINT32 Ebp;\r | |
36 | UINT32 Esp;\r | |
37 | UINT32 Ebx;\r | |
38 | UINT32 Edx;\r | |
39 | UINT32 Ecx;\r | |
40 | UINT32 Eax;\r | |
41 | UINT16 Flags[2];\r | |
42 | UINT32 FspInfoHeader;\r | |
43 | UINT32 ApiRet;\r | |
44 | UINT32 ApiParam[2];\r | |
45 | } CONTEXT_STACK;\r | |
46 | \r | |
47 | #define CONTEXT_STACK_OFFSET(x) (UINT32)&((CONTEXT_STACK *)(UINTN)0)->x\r | |
48 | \r | |
49 | #pragma pack()\r | |
50 | \r | |
51 | /**\r | |
52 | This function sets the FSP global data pointer.\r | |
53 | \r | |
86079a4d | 54 | @param[in] FspData FSP global data pointer.\r |
cf1d4549 JY |
55 | \r |
56 | **/\r | |
57 | VOID\r | |
58 | EFIAPI\r | |
59 | SetFspGlobalDataPointer (\r | |
111f2228 | 60 | IN FSP_GLOBAL_DATA *FspData\r |
cf1d4549 JY |
61 | )\r |
62 | {\r | |
63 | ASSERT (FspData != NULL);\r | |
111f2228 | 64 | *((volatile UINT32 *)(UINTN)PcdGet32 (PcdGlobalDataPointerAddress)) = (UINT32)(UINTN)FspData;\r |
cf1d4549 JY |
65 | }\r |
66 | \r | |
67 | /**\r | |
68 | This function gets the FSP global data pointer.\r | |
69 | \r | |
70 | **/\r | |
71 | FSP_GLOBAL_DATA *\r | |
72 | EFIAPI\r | |
73 | GetFspGlobalDataPointer (\r | |
74 | VOID\r | |
75 | )\r | |
76 | {\r | |
111f2228 | 77 | FSP_GLOBAL_DATA *FspData;\r |
cf1d4549 | 78 | \r |
111f2228 | 79 | FspData = *(FSP_GLOBAL_DATA **)(UINTN)PcdGet32 (PcdGlobalDataPointerAddress);\r |
cf1d4549 JY |
80 | return FspData;\r |
81 | }\r | |
82 | \r | |
83 | /**\r | |
35897da2 | 84 | This function gets back the FSP API first parameter passed by the bootloader.\r |
cf1d4549 | 85 | \r |
35897da2 | 86 | @retval ApiParameter FSP API first parameter passed by the bootloader.\r |
cf1d4549 JY |
87 | **/\r |
88 | UINT32\r | |
89 | EFIAPI\r | |
90 | GetFspApiParameter (\r | |
91 | VOID\r | |
92 | )\r | |
93 | {\r | |
94 | FSP_GLOBAL_DATA *FspData;\r | |
95 | \r | |
111f2228 MK |
96 | FspData = GetFspGlobalDataPointer ();\r |
97 | return *(UINT32 *)(UINTN)(FspData->CoreStack + CONTEXT_STACK_OFFSET (ApiParam[0]));\r | |
cf1d4549 JY |
98 | }\r |
99 | \r | |
100 | /**\r | |
35897da2 | 101 | This function returns the FSP entry stack pointer from address of the first API parameter.\r |
cf1d4549 | 102 | \r |
35897da2 CC |
103 | @retval FSP entry stack pointer.\r |
104 | **/\r | |
111f2228 | 105 | VOID *\r |
35897da2 CC |
106 | EFIAPI\r |
107 | GetFspEntryStack (\r | |
108 | VOID\r | |
109 | )\r | |
110 | {\r | |
111 | FSP_GLOBAL_DATA *FspData;\r | |
112 | \r | |
111f2228 MK |
113 | FspData = GetFspGlobalDataPointer ();\r |
114 | return (VOID *)(FspData->CoreStack + CONTEXT_STACK_OFFSET (ApiParam[0]));\r | |
35897da2 CC |
115 | }\r |
116 | \r | |
117 | /**\r | |
118 | This function gets back the FSP API second parameter passed by the bootloader.\r | |
119 | \r | |
120 | @retval ApiParameter FSP API second parameter passed by the bootloader.\r | |
cf1d4549 JY |
121 | **/\r |
122 | UINT32\r | |
123 | EFIAPI\r | |
124 | GetFspApiParameter2 (\r | |
125 | VOID\r | |
126 | )\r | |
127 | {\r | |
128 | FSP_GLOBAL_DATA *FspData;\r | |
129 | \r | |
111f2228 MK |
130 | FspData = GetFspGlobalDataPointer ();\r |
131 | return *(UINT32 *)(UINTN)(FspData->CoreStack + CONTEXT_STACK_OFFSET (ApiParam[1]));\r | |
cf1d4549 JY |
132 | }\r |
133 | \r | |
134 | /**\r | |
135 | This function sets the FSP API parameter in the stack.\r | |
136 | \r | |
137 | @param[in] Value New parameter value.\r | |
138 | \r | |
139 | **/\r | |
140 | VOID\r | |
141 | EFIAPI\r | |
142 | SetFspApiParameter (\r | |
111f2228 | 143 | IN UINT32 Value\r |
cf1d4549 JY |
144 | )\r |
145 | {\r | |
146 | FSP_GLOBAL_DATA *FspData;\r | |
147 | \r | |
111f2228 MK |
148 | FspData = GetFspGlobalDataPointer ();\r |
149 | *(UINT32 *)(UINTN)(FspData->CoreStack + CONTEXT_STACK_OFFSET (ApiParam)) = Value;\r | |
cf1d4549 JY |
150 | }\r |
151 | \r | |
152 | /**\r | |
153 | This function set the API status code returned to the BootLoader.\r | |
154 | \r | |
155 | @param[in] ReturnStatus Status code to return.\r | |
156 | \r | |
157 | **/\r | |
158 | VOID\r | |
159 | EFIAPI\r | |
160 | SetFspApiReturnStatus (\r | |
161 | IN UINT32 ReturnStatus\r | |
162 | )\r | |
163 | {\r | |
164 | FSP_GLOBAL_DATA *FspData;\r | |
165 | \r | |
111f2228 MK |
166 | FspData = GetFspGlobalDataPointer ();\r |
167 | *(UINT32 *)(UINTN)(FspData->CoreStack + CONTEXT_STACK_OFFSET (Eax)) = ReturnStatus;\r | |
cf1d4549 JY |
168 | }\r |
169 | \r | |
170 | /**\r | |
171 | This function sets the context switching stack to a new stack frame.\r | |
172 | \r | |
173 | @param[in] NewStackTop New core stack to be set.\r | |
174 | \r | |
175 | **/\r | |
176 | VOID\r | |
177 | EFIAPI\r | |
178 | SetFspCoreStackPointer (\r | |
111f2228 | 179 | IN VOID *NewStackTop\r |
cf1d4549 JY |
180 | )\r |
181 | {\r | |
182 | FSP_GLOBAL_DATA *FspData;\r | |
183 | UINT32 *OldStack;\r | |
184 | UINT32 *NewStack;\r | |
185 | UINT32 StackContextLen;\r | |
186 | \r | |
111f2228 MK |
187 | FspData = GetFspGlobalDataPointer ();\r |
188 | StackContextLen = sizeof (CONTEXT_STACK) / sizeof (UINT32);\r | |
cf1d4549 JY |
189 | \r |
190 | //\r | |
191 | // Reserve space for the ContinuationFunc two parameters\r | |
192 | //\r | |
111f2228 MK |
193 | OldStack = (UINT32 *)FspData->CoreStack;\r |
194 | NewStack = (UINT32 *)NewStackTop - StackContextLen - 2;\r | |
cf1d4549 JY |
195 | FspData->CoreStack = (UINT32)NewStack;\r |
196 | while (StackContextLen-- != 0) {\r | |
197 | *NewStack++ = *OldStack++;\r | |
198 | }\r | |
199 | }\r | |
200 | \r | |
201 | /**\r | |
202 | This function sets the platform specific data pointer.\r | |
203 | \r | |
86079a4d | 204 | @param[in] PlatformData FSP platform specific data pointer.\r |
cf1d4549 JY |
205 | \r |
206 | **/\r | |
207 | VOID\r | |
208 | EFIAPI\r | |
209 | SetFspPlatformDataPointer (\r | |
111f2228 | 210 | IN VOID *PlatformData\r |
cf1d4549 JY |
211 | )\r |
212 | {\r | |
213 | FSP_GLOBAL_DATA *FspData;\r | |
214 | \r | |
111f2228 | 215 | FspData = GetFspGlobalDataPointer ();\r |
cf1d4549 JY |
216 | FspData->PlatformData.DataPtr = PlatformData;\r |
217 | }\r | |
218 | \r | |
cf1d4549 JY |
219 | /**\r |
220 | This function gets the platform specific data pointer.\r | |
221 | \r | |
86079a4d | 222 | @param[in] PlatformData FSP platform specific data pointer.\r |
cf1d4549 JY |
223 | \r |
224 | **/\r | |
225 | VOID *\r | |
226 | EFIAPI\r | |
227 | GetFspPlatformDataPointer (\r | |
228 | VOID\r | |
229 | )\r | |
230 | {\r | |
231 | FSP_GLOBAL_DATA *FspData;\r | |
232 | \r | |
111f2228 | 233 | FspData = GetFspGlobalDataPointer ();\r |
cf1d4549 JY |
234 | return FspData->PlatformData.DataPtr;\r |
235 | }\r | |
236 | \r | |
cf1d4549 JY |
237 | /**\r |
238 | This function sets the UPD data pointer.\r | |
239 | \r | |
240 | @param[in] UpdDataPtr UPD data pointer.\r | |
241 | **/\r | |
242 | VOID\r | |
243 | EFIAPI\r | |
244 | SetFspUpdDataPointer (\r | |
111f2228 | 245 | IN VOID *UpdDataPtr\r |
cf1d4549 JY |
246 | )\r |
247 | {\r | |
248 | FSP_GLOBAL_DATA *FspData;\r | |
249 | \r | |
250 | //\r | |
86079a4d | 251 | // Get the FSP Global Data Pointer\r |
cf1d4549 | 252 | //\r |
111f2228 | 253 | FspData = GetFspGlobalDataPointer ();\r |
cf1d4549 JY |
254 | \r |
255 | //\r | |
256 | // Set the UPD pointer.\r | |
257 | //\r | |
258 | FspData->UpdDataPtr = UpdDataPtr;\r | |
259 | }\r | |
260 | \r | |
261 | /**\r | |
262 | This function gets the UPD data pointer.\r | |
263 | \r | |
264 | @return UpdDataPtr UPD data pointer.\r | |
265 | **/\r | |
266 | VOID *\r | |
267 | EFIAPI\r | |
268 | GetFspUpdDataPointer (\r | |
269 | VOID\r | |
270 | )\r | |
271 | {\r | |
272 | FSP_GLOBAL_DATA *FspData;\r | |
273 | \r | |
111f2228 | 274 | FspData = GetFspGlobalDataPointer ();\r |
cf1d4549 JY |
275 | return FspData->UpdDataPtr;\r |
276 | }\r | |
277 | \r | |
cf1d4549 | 278 | /**\r |
86079a4d | 279 | This function sets the FspMemoryInit UPD data pointer.\r |
cf1d4549 | 280 | \r |
86079a4d | 281 | @param[in] MemoryInitUpdPtr FspMemoryInit UPD data pointer.\r |
cf1d4549 JY |
282 | **/\r |
283 | VOID\r | |
284 | EFIAPI\r | |
285 | SetFspMemoryInitUpdDataPointer (\r | |
111f2228 | 286 | IN VOID *MemoryInitUpdPtr\r |
cf1d4549 JY |
287 | )\r |
288 | {\r | |
289 | FSP_GLOBAL_DATA *FspData;\r | |
290 | \r | |
291 | //\r | |
86079a4d | 292 | // Get the FSP Global Data Pointer\r |
cf1d4549 | 293 | //\r |
111f2228 | 294 | FspData = GetFspGlobalDataPointer ();\r |
cf1d4549 JY |
295 | \r |
296 | //\r | |
86079a4d | 297 | // Set the FspMemoryInit UPD pointer.\r |
cf1d4549 JY |
298 | //\r |
299 | FspData->MemoryInitUpdPtr = MemoryInitUpdPtr;\r | |
300 | }\r | |
301 | \r | |
302 | /**\r | |
86079a4d | 303 | This function gets the FspMemoryInit UPD data pointer.\r |
cf1d4549 | 304 | \r |
86079a4d | 305 | @return FspMemoryInit UPD data pointer.\r |
cf1d4549 JY |
306 | **/\r |
307 | VOID *\r | |
308 | EFIAPI\r | |
309 | GetFspMemoryInitUpdDataPointer (\r | |
310 | VOID\r | |
311 | )\r | |
312 | {\r | |
313 | FSP_GLOBAL_DATA *FspData;\r | |
314 | \r | |
111f2228 | 315 | FspData = GetFspGlobalDataPointer ();\r |
cf1d4549 JY |
316 | return FspData->MemoryInitUpdPtr;\r |
317 | }\r | |
318 | \r | |
cf1d4549 | 319 | /**\r |
86079a4d | 320 | This function sets the FspSiliconInit UPD data pointer.\r |
cf1d4549 | 321 | \r |
86079a4d | 322 | @param[in] SiliconInitUpdPtr FspSiliconInit UPD data pointer.\r |
cf1d4549 JY |
323 | **/\r |
324 | VOID\r | |
325 | EFIAPI\r | |
326 | SetFspSiliconInitUpdDataPointer (\r | |
111f2228 | 327 | IN VOID *SiliconInitUpdPtr\r |
cf1d4549 JY |
328 | )\r |
329 | {\r | |
330 | FSP_GLOBAL_DATA *FspData;\r | |
331 | \r | |
332 | //\r | |
86079a4d | 333 | // Get the FSP Global Data Pointer\r |
cf1d4549 | 334 | //\r |
111f2228 | 335 | FspData = GetFspGlobalDataPointer ();\r |
cf1d4549 JY |
336 | \r |
337 | //\r | |
86079a4d | 338 | // Set the FspSiliconInit UPD data pointer.\r |
cf1d4549 JY |
339 | //\r |
340 | FspData->SiliconInitUpdPtr = SiliconInitUpdPtr;\r | |
341 | }\r | |
342 | \r | |
343 | /**\r | |
86079a4d | 344 | This function gets the FspSiliconInit UPD data pointer.\r |
cf1d4549 | 345 | \r |
86079a4d | 346 | @return FspSiliconInit UPD data pointer.\r |
cf1d4549 JY |
347 | **/\r |
348 | VOID *\r | |
349 | EFIAPI\r | |
350 | GetFspSiliconInitUpdDataPointer (\r | |
351 | VOID\r | |
352 | )\r | |
353 | {\r | |
354 | FSP_GLOBAL_DATA *FspData;\r | |
355 | \r | |
111f2228 | 356 | FspData = GetFspGlobalDataPointer ();\r |
cf1d4549 JY |
357 | return FspData->SiliconInitUpdPtr;\r |
358 | }\r | |
359 | \r | |
cf1d4549 JY |
360 | /**\r |
361 | Set FSP measurement point timestamp.\r | |
362 | \r | |
363 | @param[in] Id Measurement point ID.\r | |
364 | \r | |
365 | @return performance timestamp.\r | |
366 | **/\r | |
367 | UINT64\r | |
368 | EFIAPI\r | |
369 | SetFspMeasurePoint (\r | |
370 | IN UINT8 Id\r | |
371 | )\r | |
372 | {\r | |
373 | FSP_GLOBAL_DATA *FspData;\r | |
374 | \r | |
375 | //\r | |
376 | // Bit [55: 0] will be the timestamp\r | |
377 | // Bit [63:56] will be the ID\r | |
378 | //\r | |
111f2228 MK |
379 | FspData = GetFspGlobalDataPointer ();\r |
380 | if (FspData->PerfIdx < sizeof (FspData->PerfData) / sizeof (FspData->PerfData[0])) {\r | |
381 | FspData->PerfData[FspData->PerfIdx] = AsmReadTsc ();\r | |
cf1d4549 JY |
382 | ((UINT8 *)(&FspData->PerfData[FspData->PerfIdx]))[7] = Id;\r |
383 | }\r | |
384 | \r | |
385 | return FspData->PerfData[(FspData->PerfIdx)++];\r | |
386 | }\r | |
387 | \r | |
388 | /**\r | |
389 | This function gets the FSP info header pointer.\r | |
390 | \r | |
391 | @retval FspInfoHeader FSP info header pointer\r | |
392 | **/\r | |
393 | FSP_INFO_HEADER *\r | |
394 | EFIAPI\r | |
395 | GetFspInfoHeader (\r | |
396 | VOID\r | |
397 | )\r | |
398 | {\r | |
111f2228 | 399 | return GetFspGlobalDataPointer ()->FspInfoHeader;\r |
cf1d4549 JY |
400 | }\r |
401 | \r | |
402 | /**\r | |
403 | This function sets the FSP info header pointer.\r | |
404 | \r | |
405 | @param[in] FspInfoHeader FSP info header pointer\r | |
406 | **/\r | |
407 | VOID\r | |
408 | EFIAPI\r | |
409 | SetFspInfoHeader (\r | |
111f2228 | 410 | FSP_INFO_HEADER *FspInfoHeader\r |
cf1d4549 JY |
411 | )\r |
412 | {\r | |
111f2228 | 413 | GetFspGlobalDataPointer ()->FspInfoHeader = FspInfoHeader;\r |
cf1d4549 JY |
414 | }\r |
415 | \r | |
416 | /**\r | |
417 | This function gets the FSP info header pointer using the API stack context.\r | |
418 | \r | |
419 | @retval FspInfoHeader FSP info header pointer using the API stack context\r | |
420 | **/\r | |
421 | FSP_INFO_HEADER *\r | |
422 | EFIAPI\r | |
423 | GetFspInfoHeaderFromApiContext (\r | |
424 | VOID\r | |
425 | )\r | |
426 | {\r | |
427 | FSP_GLOBAL_DATA *FspData;\r | |
428 | \r | |
111f2228 MK |
429 | FspData = GetFspGlobalDataPointer ();\r |
430 | return (FSP_INFO_HEADER *)(*(UINT32 *)(UINTN)(FspData->CoreStack + CONTEXT_STACK_OFFSET (FspInfoHeader)));\r | |
cf1d4549 JY |
431 | }\r |
432 | \r | |
433 | /**\r | |
cc0b456a | 434 | This function gets the CfgRegion data pointer.\r |
cf1d4549 | 435 | \r |
cc0b456a | 436 | @return CfgRegion data pointer.\r |
cf1d4549 JY |
437 | **/\r |
438 | VOID *\r | |
439 | EFIAPI\r | |
cc0b456a | 440 | GetFspCfgRegionDataPointer (\r |
cf1d4549 JY |
441 | VOID\r |
442 | )\r | |
443 | {\r | |
111f2228 | 444 | FSP_INFO_HEADER *FspInfoHeader;\r |
cf1d4549 JY |
445 | \r |
446 | FspInfoHeader = GetFspInfoHeader ();\r | |
447 | return (VOID *)(FspInfoHeader->ImageBase + FspInfoHeader->CfgRegionOffset);\r | |
448 | }\r | |
449 | \r | |
450 | /**\r | |
451 | This function gets FSP API calling index.\r | |
452 | \r | |
453 | @retval API calling index\r | |
454 | **/\r | |
455 | UINT8\r | |
456 | EFIAPI\r | |
457 | GetFspApiCallingIndex (\r | |
458 | VOID\r | |
459 | )\r | |
460 | {\r | |
111f2228 | 461 | return GetFspGlobalDataPointer ()->ApiIdx;\r |
cf1d4549 JY |
462 | }\r |
463 | \r | |
464 | /**\r | |
465 | This function sets FSP API calling mode.\r | |
466 | \r | |
467 | @param[in] Index API calling index\r | |
468 | **/\r | |
469 | VOID\r | |
470 | EFIAPI\r | |
471 | SetFspApiCallingIndex (\r | |
472 | UINT8 Index\r | |
473 | )\r | |
474 | {\r | |
475 | FSP_GLOBAL_DATA *FspData;\r | |
476 | \r | |
111f2228 | 477 | FspData = GetFspGlobalDataPointer ();\r |
cf1d4549 JY |
478 | FspData->ApiIdx = Index;\r |
479 | }\r | |
480 | \r | |
481 | /**\r | |
482 | This function gets FSP Phase StatusCode.\r | |
483 | \r | |
484 | @retval StatusCode\r | |
485 | **/\r | |
486 | UINT32\r | |
487 | EFIAPI\r | |
488 | GetPhaseStatusCode (\r | |
489 | VOID\r | |
490 | )\r | |
491 | {\r | |
111f2228 | 492 | return GetFspGlobalDataPointer ()->StatusCode;\r |
cf1d4549 JY |
493 | }\r |
494 | \r | |
495 | /**\r | |
496 | This function sets FSP Phase StatusCode.\r | |
497 | \r | |
498 | @param[in] Mode Phase StatusCode\r | |
499 | **/\r | |
500 | VOID\r | |
501 | EFIAPI\r | |
502 | SetPhaseStatusCode (\r | |
503 | UINT32 StatusCode\r | |
504 | )\r | |
505 | {\r | |
506 | FSP_GLOBAL_DATA *FspData;\r | |
507 | \r | |
111f2228 | 508 | FspData = GetFspGlobalDataPointer ();\r |
cf1d4549 JY |
509 | FspData->StatusCode = StatusCode;\r |
510 | }\r | |
511 | \r | |
6b5677e1 YS |
512 | /**\r |
513 | This function updates the return status of the FSP API with requested reset type and returns to Boot Loader.\r | |
514 | \r | |
515 | @param[in] FspResetType Reset type that needs to returned as API return status\r | |
516 | \r | |
517 | **/\r | |
518 | VOID\r | |
519 | EFIAPI\r | |
520 | FspApiReturnStatusReset (\r | |
111f2228 | 521 | IN UINT32 FspResetType\r |
6b5677e1 YS |
522 | )\r |
523 | {\r | |
524 | volatile BOOLEAN LoopUntilReset;\r | |
e37bb20c | 525 | \r |
6b5677e1 | 526 | LoopUntilReset = TRUE;\r |
111f2228 | 527 | DEBUG ((DEBUG_INFO, "FSP returning control to Bootloader with reset required return status %x\n", FspResetType));\r |
a2e61f34 CC |
528 | if (GetFspGlobalDataPointer ()->FspMode == FSP_IN_API_MODE) {\r |
529 | ///\r | |
530 | /// Below code is not an infinite loop.The control will go back to API calling function in BootLoader each time BootLoader\r | |
531 | /// calls the FSP API without honoring the reset request by FSP\r | |
532 | ///\r | |
533 | do {\r | |
534 | SetFspApiReturnStatus ((EFI_STATUS)FspResetType);\r | |
535 | Pei2LoaderSwitchStack ();\r | |
536 | DEBUG ((DEBUG_ERROR, "!!!ERROR: FSP has requested BootLoader for reset. But BootLoader has not honored the reset\n"));\r | |
537 | DEBUG ((DEBUG_ERROR, "!!!ERROR: Please add support in BootLoader to honor the reset request from FSP\n"));\r | |
538 | } while (LoopUntilReset);\r | |
539 | }\r | |
6b5677e1 | 540 | }\r |