+/**\r
+ Process a QEMU_LOADER_WRITE_POINTER command.\r
+\r
+ @param[in] WritePointer The QEMU_LOADER_WRITE_POINTER command to process.\r
+\r
+ @param[in] Tracker The ORDERED_COLLECTION tracking the BLOB user\r
+ structures created thus far.\r
+\r
+ @param[in,out] S3Context The S3_CONTEXT object capturing the fw_cfg actions\r
+ of successfully processed QEMU_LOADER_WRITE_POINTER\r
+ commands, to be replayed at S3 resume. S3Context\r
+ may be NULL if S3 is disabled.\r
+\r
+ @retval EFI_PROTOCOL_ERROR Malformed fw_cfg file name(s) have been found in\r
+ WritePointer. Or, the WritePointer command\r
+ references a file unknown to Tracker or the\r
+ fw_cfg directory. Or, the pointer object to\r
+ rewrite has invalid location, size, or initial\r
+ relative value. Or, the pointer value to store\r
+ does not fit in the given pointer size.\r
+\r
+ @retval EFI_SUCCESS The pointer object inside the writeable fw_cfg\r
+ file has been written. If S3Context is not NULL,\r
+ then WritePointer has been condensed into\r
+ S3Context.\r
+\r
+ @return Error codes propagated from\r
+ SaveCondensedWritePointerToS3Context(). The\r
+ pointer object inside the writeable fw_cfg file\r
+ has not been written.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+ProcessCmdWritePointer (\r
+ IN CONST QEMU_LOADER_WRITE_POINTER *WritePointer,\r
+ IN CONST ORDERED_COLLECTION *Tracker,\r
+ IN OUT S3_CONTEXT *S3Context OPTIONAL\r
+ )\r
+{\r
+ RETURN_STATUS Status;\r
+ FIRMWARE_CONFIG_ITEM PointerItem;\r
+ UINTN PointerItemSize;\r
+ ORDERED_COLLECTION_ENTRY *PointeeEntry;\r
+ BLOB *PointeeBlob;\r
+ UINT64 PointerValue;\r
+\r
+ if (WritePointer->PointerFile[QEMU_LOADER_FNAME_SIZE - 1] != '\0' ||\r
+ WritePointer->PointeeFile[QEMU_LOADER_FNAME_SIZE - 1] != '\0') {\r
+ DEBUG ((DEBUG_ERROR, "%a: malformed file name\n", __FUNCTION__));\r
+ return EFI_PROTOCOL_ERROR;\r
+ }\r
+\r
+ Status = QemuFwCfgFindFile ((CONST CHAR8 *)WritePointer->PointerFile,\r
+ &PointerItem, &PointerItemSize);\r
+ PointeeEntry = OrderedCollectionFind (Tracker, WritePointer->PointeeFile);\r
+ if (RETURN_ERROR (Status) || PointeeEntry == NULL) {\r
+ DEBUG ((DEBUG_ERROR,\r
+ "%a: invalid fw_cfg file or blob reference \"%a\" / \"%a\"\n",\r
+ __FUNCTION__, WritePointer->PointerFile, WritePointer->PointeeFile));\r
+ return EFI_PROTOCOL_ERROR;\r
+ }\r
+\r
+ if ((WritePointer->PointerSize != 1 && WritePointer->PointerSize != 2 &&\r
+ WritePointer->PointerSize != 4 && WritePointer->PointerSize != 8) ||\r
+ (PointerItemSize < WritePointer->PointerSize) ||\r
+ (PointerItemSize - WritePointer->PointerSize <\r
+ WritePointer->PointerOffset)) {\r
+ DEBUG ((DEBUG_ERROR, "%a: invalid pointer location or size in \"%a\"\n",\r
+ __FUNCTION__, WritePointer->PointerFile));\r
+ return EFI_PROTOCOL_ERROR;\r
+ }\r
+\r
+ PointeeBlob = OrderedCollectionUserStruct (PointeeEntry);\r
+ PointerValue = WritePointer->PointeeOffset;\r
+ if (PointerValue >= PointeeBlob->Size) {\r
+ DEBUG ((DEBUG_ERROR, "%a: invalid PointeeOffset\n", __FUNCTION__));\r
+ return EFI_PROTOCOL_ERROR;\r
+ }\r
+\r
+ //\r
+ // The memory allocation system ensures that the address of the byte past the\r
+ // last byte of any allocated object is expressible (no wraparound).\r
+ //\r
+ ASSERT ((UINTN)PointeeBlob->Base <= MAX_ADDRESS - PointeeBlob->Size);\r
+\r
+ PointerValue += (UINT64)(UINTN)PointeeBlob->Base;\r
+ if (WritePointer->PointerSize < 8 &&\r
+ RShiftU64 (PointerValue, WritePointer->PointerSize * 8) != 0) {\r
+ DEBUG ((DEBUG_ERROR, "%a: pointer value unrepresentable in \"%a\"\n",\r
+ __FUNCTION__, WritePointer->PointerFile));\r
+ return EFI_PROTOCOL_ERROR;\r
+ }\r
+\r
+ //\r
+ // If S3 is enabled, we have to capture the below fw_cfg actions in condensed\r
+ // form, to be replayed during S3 resume.\r
+ //\r
+ if (S3Context != NULL) {\r
+ EFI_STATUS SaveStatus;\r
+\r
+ SaveStatus = SaveCondensedWritePointerToS3Context (\r
+ S3Context,\r
+ (UINT16)PointerItem,\r
+ WritePointer->PointerSize,\r
+ WritePointer->PointerOffset,\r
+ PointerValue\r
+ );\r
+ if (EFI_ERROR (SaveStatus)) {\r
+ return SaveStatus;\r
+ }\r
+ }\r
+\r
+ QemuFwCfgSelectItem (PointerItem);\r
+ QemuFwCfgSkipBytes (WritePointer->PointerOffset);\r
+ QemuFwCfgWriteBytes (WritePointer->PointerSize, &PointerValue);\r
+\r
+ //\r
+ // Because QEMU has now learned PointeeBlob->Base, we must mark PointeeBlob\r
+ // as unreleasable, for the case when the whole linker/loader script is\r
+ // handled successfully.\r
+ //\r
+ PointeeBlob->HostsOnlyTableData = FALSE;\r
+\r
+ DEBUG ((DEBUG_VERBOSE, "%a: PointerFile=\"%a\" PointeeFile=\"%a\" "\r
+ "PointerOffset=0x%x PointeeOffset=0x%x PointerSize=%d\n", __FUNCTION__,\r
+ WritePointer->PointerFile, WritePointer->PointeeFile,\r
+ WritePointer->PointerOffset, WritePointer->PointeeOffset,\r
+ WritePointer->PointerSize));\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Undo a QEMU_LOADER_WRITE_POINTER command.\r
+\r
+ This function revokes (zeroes out) a guest memory reference communicated to\r
+ QEMU earlier. The caller is responsible for invoking this function only on\r
+ such QEMU_LOADER_WRITE_POINTER commands that have been successfully processed\r
+ by ProcessCmdWritePointer().\r
+\r
+ @param[in] WritePointer The QEMU_LOADER_WRITE_POINTER command to undo.\r
+**/\r
+STATIC\r
+VOID\r
+UndoCmdWritePointer (\r
+ IN CONST QEMU_LOADER_WRITE_POINTER *WritePointer\r
+ )\r
+{\r
+ RETURN_STATUS Status;\r
+ FIRMWARE_CONFIG_ITEM PointerItem;\r
+ UINTN PointerItemSize;\r
+ UINT64 PointerValue;\r
+\r
+ Status = QemuFwCfgFindFile ((CONST CHAR8 *)WritePointer->PointerFile,\r
+ &PointerItem, &PointerItemSize);\r
+ ASSERT_RETURN_ERROR (Status);\r
+\r
+ PointerValue = 0;\r
+ QemuFwCfgSelectItem (PointerItem);\r
+ QemuFwCfgSkipBytes (WritePointer->PointerOffset);\r
+ QemuFwCfgWriteBytes (WritePointer->PointerSize, &PointerValue);\r
+\r
+ DEBUG ((DEBUG_VERBOSE,\r
+ "%a: PointerFile=\"%a\" PointerOffset=0x%x PointerSize=%d\n", __FUNCTION__,\r
+ WritePointer->PointerFile, WritePointer->PointerOffset,\r
+ WritePointer->PointerSize));\r
+}\r
+\r
+\r