]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/Library/VirtioLib/VirtioLib.c
OvmfPkg: Apply uncrustify changes
[mirror_edk2.git] / OvmfPkg / Library / VirtioLib / VirtioLib.c
CommitLineData
263559b8 1/** @file\r
2\r
3 Utility functions used by virtio device drivers.\r
4\r
8bc951a2 5 Copyright (C) 2012-2016, Red Hat, Inc.\r
56f65ed8 6 Portion of Copyright (C) 2013, ARM Ltd.\r
0a78d754 7 Copyright (C) 2017, AMD Inc, All rights reserved.<BR>\r
263559b8 8\r
b26f0cf9 9 SPDX-License-Identifier: BSD-2-Clause-Patent\r
263559b8 10\r
11**/\r
12\r
e371e7e5 13#include <Library/BaseLib.h>\r
263559b8 14#include <Library/BaseMemoryLib.h>\r
15#include <Library/DebugLib.h>\r
e371e7e5 16#include <Library/UefiBootServicesTableLib.h>\r
263559b8 17\r
18#include <Library/VirtioLib.h>\r
19\r
263559b8 20/**\r
21\r
22 Configure a virtio ring.\r
23\r
24 This function sets up internal storage (the guest-host communication area)\r
25 and lays out several "navigation" (ie. no-ownership) pointers to parts of\r
26 that storage.\r
27\r
28 Relevant sections from the virtio-0.9.5 spec:\r
29 - 1.1 Virtqueues,\r
30 - 2.3 Virtqueue Configuration.\r
31\r
fc2c1543
BS
32 @param[in] VirtIo The virtio device which will use the ring.\r
33\r
263559b8 34 @param[in] The number of descriptors to allocate for the\r
35 virtio ring, as requested by the host.\r
36\r
37 @param[out] Ring The virtio ring to set up.\r
38\r
b0338c53
BS
39 @return Status codes propagated from\r
40 VirtIo->AllocateSharedPages().\r
263559b8 41\r
42 @retval EFI_SUCCESS Allocation and setup successful. Ring->Base\r
43 (and nothing else) is responsible for\r
44 deallocation.\r
45\r
46**/\r
47EFI_STATUS\r
48EFIAPI\r
49VirtioRingInit (\r
ac0a286f
MK
50 IN VIRTIO_DEVICE_PROTOCOL *VirtIo,\r
51 IN UINT16 QueueSize,\r
52 OUT VRING *Ring\r
263559b8 53 )\r
54{\r
ac0a286f
MK
55 EFI_STATUS Status;\r
56 UINTN RingSize;\r
57 volatile UINT8 *RingPagesPtr;\r
263559b8 58\r
59 RingSize = ALIGN_VALUE (\r
60 sizeof *Ring->Desc * QueueSize +\r
61 sizeof *Ring->Avail.Flags +\r
62 sizeof *Ring->Avail.Idx +\r
63 sizeof *Ring->Avail.Ring * QueueSize +\r
64 sizeof *Ring->Avail.UsedEvent,\r
ac0a286f
MK
65 EFI_PAGE_SIZE\r
66 );\r
263559b8 67\r
68 RingSize += ALIGN_VALUE (\r
69 sizeof *Ring->Used.Flags +\r
70 sizeof *Ring->Used.Idx +\r
71 sizeof *Ring->Used.UsedElem * QueueSize +\r
72 sizeof *Ring->Used.AvailEvent,\r
ac0a286f
MK
73 EFI_PAGE_SIZE\r
74 );\r
263559b8 75\r
b0338c53
BS
76 //\r
77 // Allocate a shared ring buffer\r
78 //\r
263559b8 79 Ring->NumPages = EFI_SIZE_TO_PAGES (RingSize);\r
ac0a286f
MK
80 Status = VirtIo->AllocateSharedPages (\r
81 VirtIo,\r
82 Ring->NumPages,\r
83 &Ring->Base\r
84 );\r
b0338c53
BS
85 if (EFI_ERROR (Status)) {\r
86 return Status;\r
263559b8 87 }\r
ac0a286f 88\r
263559b8 89 SetMem (Ring->Base, RingSize, 0x00);\r
90 RingPagesPtr = Ring->Base;\r
91\r
ac0a286f 92 Ring->Desc = (volatile VOID *)RingPagesPtr;\r
263559b8 93 RingPagesPtr += sizeof *Ring->Desc * QueueSize;\r
94\r
ac0a286f
MK
95 Ring->Avail.Flags = (volatile VOID *)RingPagesPtr;\r
96 RingPagesPtr += sizeof *Ring->Avail.Flags;\r
263559b8 97\r
ac0a286f
MK
98 Ring->Avail.Idx = (volatile VOID *)RingPagesPtr;\r
99 RingPagesPtr += sizeof *Ring->Avail.Idx;\r
263559b8 100\r
ac0a286f
MK
101 Ring->Avail.Ring = (volatile VOID *)RingPagesPtr;\r
102 RingPagesPtr += sizeof *Ring->Avail.Ring * QueueSize;\r
263559b8 103\r
ac0a286f
MK
104 Ring->Avail.UsedEvent = (volatile VOID *)RingPagesPtr;\r
105 RingPagesPtr += sizeof *Ring->Avail.UsedEvent;\r
263559b8 106\r
ac0a286f
MK
107 RingPagesPtr = (volatile UINT8 *)Ring->Base +\r
108 ALIGN_VALUE (\r
109 RingPagesPtr - (volatile UINT8 *)Ring->Base,\r
110 EFI_PAGE_SIZE\r
111 );\r
263559b8 112\r
ac0a286f
MK
113 Ring->Used.Flags = (volatile VOID *)RingPagesPtr;\r
114 RingPagesPtr += sizeof *Ring->Used.Flags;\r
263559b8 115\r
ac0a286f
MK
116 Ring->Used.Idx = (volatile VOID *)RingPagesPtr;\r
117 RingPagesPtr += sizeof *Ring->Used.Idx;\r
263559b8 118\r
ac0a286f
MK
119 Ring->Used.UsedElem = (volatile VOID *)RingPagesPtr;\r
120 RingPagesPtr += sizeof *Ring->Used.UsedElem * QueueSize;\r
263559b8 121\r
ac0a286f
MK
122 Ring->Used.AvailEvent = (volatile VOID *)RingPagesPtr;\r
123 RingPagesPtr += sizeof *Ring->Used.AvailEvent;\r
263559b8 124\r
125 Ring->QueueSize = QueueSize;\r
126 return EFI_SUCCESS;\r
127}\r
128\r
263559b8 129/**\r
130\r
131 Tear down the internal resources of a configured virtio ring.\r
132\r
133 The caller is responsible to stop the host from using this ring before\r
134 invoking this function: the VSTAT_DRIVER_OK bit must be clear in\r
135 VhdrDeviceStatus.\r
136\r
fc2c1543
BS
137 @param[in] VirtIo The virtio device which was using the ring.\r
138\r
139 @param[out] Ring The virtio ring to clean up.\r
263559b8 140\r
141**/\r
142VOID\r
143EFIAPI\r
144VirtioRingUninit (\r
ac0a286f
MK
145 IN VIRTIO_DEVICE_PROTOCOL *VirtIo,\r
146 IN OUT VRING *Ring\r
263559b8 147 )\r
148{\r
b0338c53 149 VirtIo->FreeSharedPages (VirtIo, Ring->NumPages, Ring->Base);\r
263559b8 150 SetMem (Ring, sizeof *Ring, 0x00);\r
151}\r
152\r
e371e7e5 153/**\r
154\r
155 Turn off interrupt notifications from the host, and prepare for appending\r
156 multiple descriptors to the virtio ring.\r
157\r
158 The calling driver must be in VSTAT_DRIVER_OK state.\r
159\r
f2965f4e 160 @param[in,out] Ring The virtio ring we intend to append descriptors to.\r
e371e7e5 161\r
162 @param[out] Indices The DESC_INDICES structure to initialize.\r
163\r
164**/\r
165VOID\r
166EFIAPI\r
167VirtioPrepare (\r
ac0a286f
MK
168 IN OUT VRING *Ring,\r
169 OUT DESC_INDICES *Indices\r
e371e7e5 170 )\r
171{\r
172 //\r
173 // Prepare for virtio-0.9.5, 2.4.2 Receiving Used Buffers From the Device.\r
174 // We're going to poll the answer, the host should not send an interrupt.\r
175 //\r
ac0a286f 176 *Ring->Avail.Flags = (UINT16)VRING_AVAIL_F_NO_INTERRUPT;\r
e371e7e5 177\r
178 //\r
179 // Prepare for virtio-0.9.5, 2.4.1 Supplying Buffers to the Device.\r
180 //\r
635a3ca2 181 // Since we support only one in-flight descriptor chain, we can always build\r
182 // that chain starting at entry #0 of the descriptor table.\r
183 //\r
184 Indices->HeadDescIdx = 0;\r
185 Indices->NextDescIdx = Indices->HeadDescIdx;\r
e371e7e5 186}\r
187\r
263559b8 188/**\r
189\r
190 Append a contiguous buffer for transmission / reception via the virtio ring.\r
191\r
635a3ca2 192 This function implements the following section from virtio-0.9.5:\r
263559b8 193 - 2.4.1.1 Placing Buffers into the Descriptor Table\r
263559b8 194\r
195 Free space is taken as granted, since the individual drivers support only\r
196 synchronous requests and host side status is processed in lock-step with\r
197 request submission. It is the calling driver's responsibility to verify the\r
198 ring size in advance.\r
199\r
e371e7e5 200 The caller is responsible for initializing *Indices with VirtioPrepare()\r
201 first.\r
202\r
4b725858
BS
203 @param[in,out] Ring The virtio ring to append the buffer to,\r
204 as a descriptor.\r
11a5fdf4 205\r
4b725858
BS
206 @param[in] BufferDeviceAddress (Bus master device) start address of the\r
207 transmit / receive buffer.\r
11a5fdf4 208\r
4b725858 209 @param[in] BufferSize Number of bytes to transmit or receive.\r
11a5fdf4 210\r
4b725858
BS
211 @param[in] Flags A bitmask of VRING_DESC_F_* flags. The\r
212 caller computes this mask dependent on\r
213 further buffers to append and transfer\r
214 direction. VRING_DESC_F_INDIRECT is\r
215 unsupported. The VRING_DESC.Next field is\r
216 always set, but the host only interprets\r
217 it dependent on VRING_DESC_F_NEXT.\r
11a5fdf4 218\r
4b725858
BS
219 @param[in,out] Indices Indices->HeadDescIdx is not accessed.\r
220 On input, Indices->NextDescIdx identifies\r
221 the next descriptor to carry the buffer.\r
222 On output, Indices->NextDescIdx is\r
223 incremented by one, modulo 2^16.\r
263559b8 224\r
225**/\r
226VOID\r
227EFIAPI\r
7fcacd6c 228VirtioAppendDesc (\r
ac0a286f
MK
229 IN OUT VRING *Ring,\r
230 IN UINT64 BufferDeviceAddress,\r
231 IN UINT32 BufferSize,\r
232 IN UINT16 Flags,\r
233 IN OUT DESC_INDICES *Indices\r
263559b8 234 )\r
235{\r
ac0a286f 236 volatile VRING_DESC *Desc;\r
263559b8 237\r
635a3ca2 238 Desc = &Ring->Desc[Indices->NextDescIdx++ % Ring->QueueSize];\r
4b725858 239 Desc->Addr = BufferDeviceAddress;\r
263559b8 240 Desc->Len = BufferSize;\r
241 Desc->Flags = Flags;\r
635a3ca2 242 Desc->Next = Indices->NextDescIdx % Ring->QueueSize;\r
e371e7e5 243}\r
244\r
e371e7e5 245/**\r
246\r
635a3ca2 247 Notify the host about the descriptor chain just built, and wait until the\r
248 host processes it.\r
e371e7e5 249\r
56f65ed8 250 @param[in] VirtIo The target virtio device to notify.\r
e371e7e5 251\r
252 @param[in] VirtQueueId Identifies the queue for the target device.\r
253\r
a7615fa8 254 @param[in,out] Ring The virtio ring with descriptors to submit.\r
e371e7e5 255\r
a7615fa8 256 @param[in] Indices Indices->NextDescIdx is not accessed.\r
257 Indices->HeadDescIdx identifies the head descriptor\r
258 of the descriptor chain.\r
e371e7e5 259\r
8bc951a2
LE
260 @param[out] UsedLen On success, the total number of bytes, consecutively\r
261 across the buffers linked by the descriptor chain,\r
262 that the host wrote. May be NULL if the caller\r
263 doesn't care, or can compute the same information\r
264 from device-specific request structures linked by the\r
265 descriptor chain.\r
e371e7e5 266\r
56f65ed8 267 @return Error code from VirtIo->SetQueueNotify() if it fails.\r
e371e7e5 268\r
269 @retval EFI_SUCCESS Otherwise, the host processed all descriptors.\r
270\r
271**/\r
272EFI_STATUS\r
273EFIAPI\r
274VirtioFlush (\r
ac0a286f
MK
275 IN VIRTIO_DEVICE_PROTOCOL *VirtIo,\r
276 IN UINT16 VirtQueueId,\r
277 IN OUT VRING *Ring,\r
278 IN DESC_INDICES *Indices,\r
279 OUT UINT32 *UsedLen OPTIONAL\r
e371e7e5 280 )\r
281{\r
ac0a286f
MK
282 UINT16 NextAvailIdx;\r
283 UINT16 LastUsedIdx;\r
284 EFI_STATUS Status;\r
285 UINTN PollPeriodUsecs;\r
e371e7e5 286\r
635a3ca2 287 //\r
288 // virtio-0.9.5, 2.4.1.2 Updating the Available Ring\r
289 //\r
290 // It is not exactly clear from the wording of the virtio-0.9.5\r
291 // specification, but each entry in the Available Ring references only the\r
292 // head descriptor of any given descriptor chain.\r
293 //\r
294 NextAvailIdx = *Ring->Avail.Idx;\r
8bc951a2
LE
295 //\r
296 // (Due to our lock-step progress, this is where the host will produce the\r
297 // used element with the head descriptor's index in it.)\r
298 //\r
ac0a286f 299 LastUsedIdx = NextAvailIdx;\r
635a3ca2 300 Ring->Avail.Ring[NextAvailIdx++ % Ring->QueueSize] =\r
301 Indices->HeadDescIdx % Ring->QueueSize;\r
302\r
e371e7e5 303 //\r
304 // virtio-0.9.5, 2.4.1.3 Updating the Index Field\r
305 //\r
ac0a286f 306 MemoryFence ();\r
635a3ca2 307 *Ring->Avail.Idx = NextAvailIdx;\r
e371e7e5 308\r
309 //\r
310 // virtio-0.9.5, 2.4.1.4 Notifying the Device -- gratuitous notifications are\r
311 // OK.\r
312 //\r
ac0a286f 313 MemoryFence ();\r
56f65ed8 314 Status = VirtIo->SetQueueNotify (VirtIo, VirtQueueId);\r
e371e7e5 315 if (EFI_ERROR (Status)) {\r
316 return Status;\r
317 }\r
318\r
319 //\r
320 // virtio-0.9.5, 2.4.2 Receiving Used Buffers From the Device\r
321 // Wait until the host processes and acknowledges our descriptor chain. The\r
322 // condition we use for polling is greatly simplified and relies on the\r
323 // synchronous, lock-step progress.\r
324 //\r
325 // Keep slowing down until we reach a poll period of slightly above 1 ms.\r
326 //\r
327 PollPeriodUsecs = 1;\r
ac0a286f 328 MemoryFence ();\r
635a3ca2 329 while (*Ring->Used.Idx != NextAvailIdx) {\r
e371e7e5 330 gBS->Stall (PollPeriodUsecs); // calls AcpiTimerLib::MicroSecondDelay\r
331\r
332 if (PollPeriodUsecs < 1024) {\r
333 PollPeriodUsecs *= 2;\r
334 }\r
ac0a286f
MK
335\r
336 MemoryFence ();\r
e371e7e5 337 }\r
338\r
ac0a286f 339 MemoryFence ();\r
8bc951a2
LE
340\r
341 if (UsedLen != NULL) {\r
ac0a286f 342 volatile CONST VRING_USED_ELEM *UsedElem;\r
8bc951a2
LE
343\r
344 UsedElem = &Ring->Used.UsedElem[LastUsedIdx % Ring->QueueSize];\r
345 ASSERT (UsedElem->Id == Indices->HeadDescIdx);\r
346 *UsedLen = UsedElem->Len;\r
347 }\r
348\r
e371e7e5 349 return EFI_SUCCESS;\r
263559b8 350}\r
d0ece0d8 351\r
d0ece0d8
LE
352/**\r
353\r
354 Report the feature bits to the VirtIo 1.0 device that the VirtIo 1.0 driver\r
355 understands.\r
356\r
357 In VirtIo 1.0, a device can reject a self-inconsistent feature bitmap through\r
358 the new VSTAT_FEATURES_OK status bit. (For example if the driver requests a\r
359 higher level feature but clears a prerequisite feature.) This function is a\r
360 small wrapper around VIRTIO_DEVICE_PROTOCOL.SetGuestFeatures() that also\r
361 verifies if the VirtIo 1.0 device accepts the feature bitmap.\r
362\r
363 @param[in] VirtIo Report feature bits to this device.\r
364\r
365 @param[in] Features The set of feature bits that the driver wishes\r
366 to report. The caller is responsible to perform\r
367 any masking before calling this function; the\r
368 value is directly written with\r
369 VIRTIO_DEVICE_PROTOCOL.SetGuestFeatures().\r
370\r
371 @param[in,out] DeviceStatus On input, the status byte most recently written\r
372 to the device's status register. On output (even\r
373 on error), DeviceStatus will be updated so that\r
374 it is suitable for further status bit\r
375 manipulation and writing to the device's status\r
376 register.\r
377\r
378 @retval EFI_SUCCESS The device accepted the configuration in Features.\r
379\r
380 @return EFI_UNSUPPORTED The device rejected the configuration in Features.\r
381\r
382 @retval EFI_UNSUPPORTED VirtIo->Revision is smaller than 1.0.0.\r
383\r
384 @return Error codes from the SetGuestFeatures(),\r
385 SetDeviceStatus(), GetDeviceStatus() member\r
386 functions.\r
387\r
388**/\r
389EFI_STATUS\r
390EFIAPI\r
391Virtio10WriteFeatures (\r
ac0a286f
MK
392 IN VIRTIO_DEVICE_PROTOCOL *VirtIo,\r
393 IN UINT64 Features,\r
394 IN OUT UINT8 *DeviceStatus\r
d0ece0d8
LE
395 )\r
396{\r
ac0a286f 397 EFI_STATUS Status;\r
d0ece0d8
LE
398\r
399 if (VirtIo->Revision < VIRTIO_SPEC_REVISION (1, 0, 0)) {\r
400 return EFI_UNSUPPORTED;\r
401 }\r
402\r
403 Status = VirtIo->SetGuestFeatures (VirtIo, Features);\r
404 if (EFI_ERROR (Status)) {\r
405 return Status;\r
406 }\r
407\r
408 *DeviceStatus |= VSTAT_FEATURES_OK;\r
ac0a286f 409 Status = VirtIo->SetDeviceStatus (VirtIo, *DeviceStatus);\r
d0ece0d8
LE
410 if (EFI_ERROR (Status)) {\r
411 return Status;\r
412 }\r
413\r
414 Status = VirtIo->GetDeviceStatus (VirtIo, DeviceStatus);\r
415 if (EFI_ERROR (Status)) {\r
416 return Status;\r
417 }\r
418\r
419 if ((*DeviceStatus & VSTAT_FEATURES_OK) == 0) {\r
420 Status = EFI_UNSUPPORTED;\r
421 }\r
422\r
423 return Status;\r
424}\r
0a78d754
BS
425\r
426/**\r
427 Provides the virtio device address required to access system memory from a\r
428 DMA bus master.\r
429\r
430 The interface follows the same usage pattern as defined in UEFI spec 2.6\r
431 (Section 13.2 PCI Root Bridge I/O Protocol)\r
432\r
433 The VirtioMapAllBytesInSharedBuffer() is similar to VIRTIO_MAP_SHARED\r
434 with exception that NumberOfBytes is IN-only parameter. The function\r
435 maps all the bytes specified in NumberOfBytes param in one consecutive\r
436 range.\r
437\r
438 @param[in] VirtIo The virtio device for which the mapping is\r
439 requested.\r
440\r
441 @param[in] Operation Indicates if the bus master is going to\r
442 read or write to system memory.\r
443\r
444 @param[in] HostAddress The system memory address to map to shared\r
445 buffer address.\r
446\r
447 @param[in] NumberOfBytes Number of bytes to map.\r
448\r
449 @param[out] DeviceAddress The resulting shared map address for the\r
450 bus master to access the hosts HostAddress.\r
451\r
452 @param[out] Mapping A resulting token to pass to\r
453 VIRTIO_UNMAP_SHARED.\r
454\r
455\r
9854561c 456 @retval EFI_SUCCESS The NumberOfBytes is successfully mapped.\r
0a78d754
BS
457 @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a\r
458 common buffer.\r
459 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
460 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to\r
461 a lack of resources. This includes the case\r
462 when NumberOfBytes bytes cannot be mapped\r
463 in one consecutive range.\r
464 @retval EFI_DEVICE_ERROR The system hardware could not map the\r
465 requested address.\r
466**/\r
467EFI_STATUS\r
468EFIAPI\r
469VirtioMapAllBytesInSharedBuffer (\r
470 IN VIRTIO_DEVICE_PROTOCOL *VirtIo,\r
471 IN VIRTIO_MAP_OPERATION Operation,\r
472 IN VOID *HostAddress,\r
473 IN UINTN NumberOfBytes,\r
474 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,\r
475 OUT VOID **Mapping\r
476 )\r
477{\r
478 EFI_STATUS Status;\r
479 VOID *MapInfo;\r
480 UINTN Size;\r
481 EFI_PHYSICAL_ADDRESS PhysicalAddress;\r
482\r
ac0a286f 483 Size = NumberOfBytes;\r
0a78d754
BS
484 Status = VirtIo->MapSharedBuffer (\r
485 VirtIo,\r
486 Operation,\r
487 HostAddress,\r
488 &Size,\r
489 &PhysicalAddress,\r
490 &MapInfo\r
491 );\r
492 if (EFI_ERROR (Status)) {\r
493 return Status;\r
494 }\r
495\r
496 if (Size < NumberOfBytes) {\r
497 goto Failed;\r
498 }\r
499\r
ac0a286f 500 *Mapping = MapInfo;\r
0a78d754
BS
501 *DeviceAddress = PhysicalAddress;\r
502\r
503 return EFI_SUCCESS;\r
504\r
505Failed:\r
506 VirtIo->UnmapSharedBuffer (VirtIo, MapInfo);\r
507 return EFI_OUT_OF_RESOURCES;\r
508}\r
fef6becb
BS
509\r
510/**\r
511\r
512 Map the ring buffer so that it can be accessed equally by both guest\r
513 and hypervisor.\r
514\r
515 @param[in] VirtIo The virtio device instance.\r
516\r
517 @param[in] Ring The virtio ring to map.\r
518\r
519 @param[out] RingBaseShift A resulting translation offset, to be\r
520 passed to VirtIo->SetQueueAddress().\r
521\r
522 @param[out] Mapping A resulting token to pass to\r
523 VirtIo->UnmapSharedBuffer().\r
524\r
525 @return Status code from VirtIo->MapSharedBuffer()\r
526**/\r
527EFI_STATUS\r
528EFIAPI\r
529VirtioRingMap (\r
ac0a286f
MK
530 IN VIRTIO_DEVICE_PROTOCOL *VirtIo,\r
531 IN VRING *Ring,\r
532 OUT UINT64 *RingBaseShift,\r
533 OUT VOID **Mapping\r
fef6becb
BS
534 )\r
535{\r
536 EFI_STATUS Status;\r
537 EFI_PHYSICAL_ADDRESS DeviceAddress;\r
538\r
539 Status = VirtioMapAllBytesInSharedBuffer (\r
540 VirtIo,\r
541 VirtioOperationBusMasterCommonBuffer,\r
542 Ring->Base,\r
543 EFI_PAGES_TO_SIZE (Ring->NumPages),\r
544 &DeviceAddress,\r
545 Mapping\r
546 );\r
547 if (EFI_ERROR (Status)) {\r
548 return Status;\r
549 }\r
550\r
551 *RingBaseShift = DeviceAddress - (UINT64)(UINTN)Ring->Base;\r
552 return EFI_SUCCESS;\r
553}\r