+NTSTATUS
+acpi_create_registry_table(HANDLE ParentKeyHandle, ACPI_TABLE_HEADER *OutTable, PCWSTR KeyName)
+{
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ UNICODE_STRING HardwareKeyName, ValueName;
+ ANSI_STRING HardwareKeyNameA;
+ HANDLE KeyHandle = NULL, SubKeyHandle = NULL;
+ NTSTATUS Status;
+ char OemId[7] = { 0 }; /* exactly one byte more than ACPI_TABLE_HEADER->OemId */
+ char OemTableId[9] = { 0 }; /* exactly one byte more than ACPI_TABLE_HEADER->OemTableId */
+ WCHAR OemRevision[9] = { 0 }; /* enough to accept hex DWORD */
+
+ C_ASSERT(sizeof(OemId) == RTL_FIELD_SIZE(ACPI_TABLE_HEADER, OemId) + 1);
+ C_ASSERT(sizeof(OemTableId) == RTL_FIELD_SIZE(ACPI_TABLE_HEADER, OemTableId) + 1);
+ /* Copy OEM data from the table */
+ RtlCopyMemory(OemId, OutTable->OemId, sizeof(OutTable->OemId));
+ RtlCopyMemory(OemTableId, OutTable->OemTableId, sizeof(OutTable->OemTableId));
+ /* Create table subkey */
+ RtlInitUnicodeString(&HardwareKeyName, KeyName);
+ InitializeObjectAttributes(&ObjectAttributes,
+ &HardwareKeyName,
+ OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
+ ParentKeyHandle,
+ NULL);
+ Status = ZwCreateKey(&KeyHandle,
+ KEY_WRITE,
+ &ObjectAttributes,
+ 0,
+ NULL,
+ REG_OPTION_VOLATILE,
+ NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("ZwCreateKey() for %ws failed (Status 0x%08lx)\n", KeyName, Status);
+ return Status;
+ }
+
+ if (OutTable->OemRevision != 0)
+ {
+ /* We have OEM info in table, so create other OEM subkeys */
+ RtlInitAnsiString(&HardwareKeyNameA, OemId);
+ Status = RtlAnsiStringToUnicodeString(&HardwareKeyName, &HardwareKeyNameA, TRUE);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("RtlAnsiStringToUnicodeString() for %s failed (Status 0x%08lx)\n", HardwareKeyNameA, Status);
+ return Status;
+ }
+
+ InitializeObjectAttributes(&ObjectAttributes,
+ &HardwareKeyName,
+ OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
+ KeyHandle,
+ NULL);
+ Status = ZwCreateKey(&SubKeyHandle,
+ KEY_WRITE,
+ &ObjectAttributes,
+ 0,
+ NULL,
+ REG_OPTION_VOLATILE,
+ NULL);
+ RtlFreeUnicodeString(&HardwareKeyName);
+ ZwClose(KeyHandle);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("ZwCreateKey() for %s failed (Status 0x%08lx)\n", HardwareKeyNameA, Status);
+ return Status;
+ }
+ KeyHandle = SubKeyHandle;
+
+ RtlInitAnsiString(&HardwareKeyNameA, OemTableId);
+ Status = RtlAnsiStringToUnicodeString(&HardwareKeyName, &HardwareKeyNameA, TRUE);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("RtlAnsiStringToUnicodeString() for %s failed (Status 0x%08lx)\n", HardwareKeyNameA, Status);
+ return Status;
+ }
+
+ InitializeObjectAttributes(&ObjectAttributes,
+ &HardwareKeyName,
+ OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
+ KeyHandle,
+ NULL);
+ Status = ZwCreateKey(&SubKeyHandle,
+ KEY_WRITE,
+ &ObjectAttributes,
+ 0,
+ NULL,
+ REG_OPTION_VOLATILE,
+ NULL);
+ RtlFreeUnicodeString(&HardwareKeyName);
+ ZwClose(KeyHandle);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("ZwCreateKey() for %s failed (Status 0x%08lx)\n", HardwareKeyNameA, Status);
+ return Status;
+ }
+ KeyHandle = SubKeyHandle;
+
+ Status = RtlStringCbPrintfW(OemRevision,
+ sizeof(OemRevision),
+ L"%08X",
+ OutTable->OemRevision);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("RtlStringCbPrintfW() for 0x%08lx failed (Status 0x%08lx)\n", OutTable->OemRevision, Status);
+ return Status;
+ }
+ RtlInitUnicodeString(&HardwareKeyName, OemRevision);
+
+ InitializeObjectAttributes(&ObjectAttributes,
+ &HardwareKeyName,
+ OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
+ KeyHandle,
+ NULL);
+ Status = ZwCreateKey(&SubKeyHandle,
+ KEY_WRITE,
+ &ObjectAttributes,
+ 0,
+ NULL,
+ REG_OPTION_VOLATILE,
+ NULL);
+ ZwClose(KeyHandle);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("ZwCreateKey() for %ws failed (Status 0x%08lx)\n", KeyName, Status);
+ return Status;
+ }
+ KeyHandle = SubKeyHandle;
+ }
+ /* Table reg value name is always '00000000' */
+ RtlInitUnicodeString(&ValueName,
+ L"00000000");
+ Status = ZwSetValueKey(KeyHandle,
+ &ValueName,
+ 0,
+ REG_BINARY,
+ OutTable,
+ OutTable->Length);
+ ZwClose(KeyHandle);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("ZwSetValueKey() failed (Status 0x%08lx)\n", Status);
+ return Status;
+ }
+
+ return STATUS_SUCCESS;
+}