/** @file
  Copyright (C) 2020, vit9696. All rights reserved.

  All rights reserved.

  This program and the accompanying materials
  are licensed and made available under the terms and conditions of the BSD License
  which accompanies this distribution.  The full text of the license may be found at
  http://opensource.org/licenses/bsd-license.php

  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/

#ifndef APPLE_RTC_H
#define APPLE_RTC_H

/**
  Sample RTC memory dump from MBP12,1 running 10.15.4:

  00: 33 02 01 00 12 22 04 16 04 20 26 02 70 80 FF FF
  10: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
  20: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
  30: 01 FE 20 FF FF FF FF FF F8 11 FF FF FF 00 1A 7C
  40: 00 00 00 00 FE 00 00 00 00 00 00 00 00 00 00 00
  50: 00 00 00 00 00 00 00 FF 0B D1 80 00 05 00 00 00
  60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  70: 00 00 00 00 00 00 00 00 FF FF FF FF FF FF FF FF
  80: 44 45 41 44 00 00 00 00 00 00 00 00 00 00 00 00
  90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  A0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  B0: 76 CF 85 13 00 00 00 00 00 00 00 00 00 00 00 00
  C0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  D0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  E0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  F0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
**/

/**
  APPLE_RTC_BG_COLOR_ADDR       - background colour.
  APPLE_RTC_BG_COMPLEMENT_ADDR  - complementary byte to background colour.

  0x00 - Grey background (applies to 10.9 and older).
  0x01 - Black background (applies to 10.10 and newer).

  Valid pair gives APPLE_RTC_BG_COLOR_ADDR ^ APPLE_RTC_BG_COMPLEMENT_ADDR == 0xFF.
  Otherwise background colour should be treated as 0, grey.

  Prior to rebooting to MacEFI firmare upgrade /usr/libexec/efiupdater
  removes DefaultBackgroundColor NVRAM variable and resets background to black.

  When performing hibernate wake OSInfo writes chooses the background colour
  based on reported macOS version (grey for 10.9 and below, black otherwise).
**/
#define APPLE_RTC_BG_COLOR_ADDR       0x30
#define APPLE_RTC_BG_COMPLEMENT_ADDR  0x31

/**
  APPLE_RTC_BG_COLOR_ADDR values.
**/
#define APPLE_RTC_BG_COLOR_GRAY   0x00
#define APPLE_RTC_BG_COLOR_BLACK  0x01

/**
  By default masked out with 0xF8.
  Connected thunderbolt devices can set 3 lower bits.
  BIT3 seems to be set when InstallWindowsUEFI was present at boot.

  See ThunderboltNhi and PchInitDxe.
**/
#define APPLE_RTC_FIRMWARE_STATE_ADDR  0x38

/**
  Used by ApplePlatformInit, 1 byte.
**/
#define APPLE_RTC_FIRMWARE_3D_ADDR  0x3D

/**
  Bitmask of started test indices.
  Little endian 32-bit number.
  Note: memory testing statuses are a bit more complicated,
  but we do not need too much detail atm.
**/
#define APPLE_RTC_MEM_TEST_ACCEPT_ADDR  0x44

/**
  Bitmask of request test indices.
  Little endian 32-bit number.
**/
#define APPLE_RTC_MEM_TEST_REQUEST_ADDR  0x48

/**
  Bitmask of performed test indices.
  Little endian 32-bit number.
**/
#define APPLE_RTC_MEM_TEST_RESULT_ADDR  0x4C

/**
  Another unknown reserved address.
**/
#define APPLE_RTC_FIRMWARE_57_ADDR  0x57

/**
  Firmware boot progress, mostly maintained by AppleBds.

  0x00, 0x01, 0x02 - Set by RomIntegrityPei.
  0x04 - Normal boot started. At this step AppleBds will process hibernation,
         enable video output, check battery state, perform memory test, etc.
  0x05 - Exit Boot Services called. Set in AppleBds event handler.
**/
#define APPLE_RTC_FIRMWARE_PROGRESS_ADDR  0x5C

/**
  Apple RTC reserved memory area for unclear purposes, normally filled with FF.
  Should not be erased during PRAM reset (CMD+OPT+P+R).
**/
#define APPLE_RTC_RESERVED_ADDR  0x78

/**
  Apple RTC reserved memory size.
**/
#define APPLE_RTC_RESERVED_LENGTH  8

/**
  Hibernation image encryption data, a copy of IOHibernateRTCVariables.
  See AppleRTCHibernateVars type in AppleHibernate.h for the definition.
  - Valid hibernation image encryption data starts with "AAPL" magic.
  - Erased hibernation image encryption data starts with "DEAD" magic.
  Normally handled by AppleBds prior to transfering control to the bootloader.
**/
#define APPLE_RTC_HIBERNATION_KEY_ADDR  0x80

/**
  Effectively equals to sizeof (AppleRTCHibernateVars).
**/
#define APPLE_RTC_HIBERNATION_KEY_LENGTH  0x2C

/**
  Firmware upgrade control and status byte.

  0x00 - Normal boot. AppleBds resets to this value upon BOOT_ON_FLASH_UPDATE
         prior to running BootRomFlash. BootRomFlash may itself reset to this
         value on successful(?) flashing. Mirrored to NOBP SMC key.
  0x01 - Alternative unsuccessful (?) result of firmware flashing written
         by BootRomFlash. Mirrored to NOBP SMC key. Also set in ApplePlatformInit.
  0x02 - Schedule firmware upgrade. Closed-source bless part writes this value
         when intending to upgrade MacEFI firmware.
  0x03 - Peform firmware upgrade. BootRomFlash writes this value prior to
         rebooting into BOOT_ON_FLASH_UPDATE mode. Might be needed due to region
         unlock.
**/
#define APPLE_RTC_FIRMWARE_UPGRADE_ADDR  0xAC

/**
  AppleBds zeroes this byte at the same time it reaches normal booting phase (0x4)
  in APPLE_RTC_FIRMWARE_PROGRESS_ADDR. This may be set to non-zero value by ApplePlatformInit.
**/
#define APPLE_RTC_FIRMWARE_CHECK_ADDR  0xAF

/**
  Data contained in RTC allowing to trace various power management events.
  Called via AppleRTC::rtcRecordTracePoint and also used for EfiBoot wake log.
**/
#define APPLE_RTC_TRACE_POINT_ADDR  0xB0

/**
  Trace point data contains a total of 8 bytes, but they seem to have varying purpose.
**/
#define APPLE_RTC_TRACE_POINT_LENGTH  8

/**
  Trace data is a 32-bit value, which format depends on the phase
  (APPLE_RTC_TRACE_PHASE_ADDR) the platform is currently in.

  For the kernel this may e.g. contain PCI device index currently put
  in sleep or being awoken (kIOPMTracePointSleepPowerPlaneDrivers
  or kIOPMTracePointWakePowerPlaneDrivers).

  For EfiBoot this is named hibernatin wake log. It is also written to
  wake-failure NVRAM variable (and later DeviceTree).
**/
#define APPLE_RTC_TRACE_DATA_ADDR  0xB0

/**
  Trace data length.
**/
#define APPLE_RTC_TRACE_DATA_LENGTH  4

/**
  Mask of events, which happened during booting.
  These events are appended during the boot progress.

  Note, unlike APPLE_RTC_WL_EVENT_ADDR/APPLE_RTC_WL_EVENT_EXTRA_ADDR,
  which only get updated in hibernate wake, this value is always written
  when a non-zero event is supplied.
**/
#define APPLE_RTC_WL_MASK_ADDR  0xB1

/**
  Known event bits.
**/
#define APPLE_RTC_WL_MASK_BOOT_STARTED    BIT0 ///< Called early at boot.efi startup.
#define APPLE_RTC_WL_MASK_BOOT_FAILED     BIT1 ///< gBS->Exit: Boot failed; will sleep for 10 seconds before exiting.
#define APPLE_RTC_WL_MASK_BOOT_KERNEL     BIT2 ///< Called right before jumping to the kernel code.
#define APPLE_RTC_WL_MASK_CS_UNLOCKED     BIT3 ///< Set along with APPLE_RTC_WL_CS_VOLUME_UNLOCKED.
#define APPLE_RTC_WL_MASK_HIB_CLEAR_KEYS  BIT4 ///< Removed boot-image-key, EFI_STATUS in EXTRA.
#define APPLE_RTC_WL_MASK_HIB_CLEAR_IMG   BIT5 ///< Removed boot-image, will reboot now.
#define APPLE_RTC_WL_MASK_BOOT_RESET      BIT6 ///< gBS->Reset was called.

/**
  Event index that happened last during booting.
  0xB2 is the event type and 0xB3 is its subtype.
**/
#define APPLE_RTC_WL_EVENT_ADDR        0xB2
#define APPLE_RTC_WL_EVENT_EXTRA_ADDR  0xB3

/**
  Known events.
**/
#define APPLE_RTC_WL_EVENT_DEFAULT           0   ///< For everything.
#define APPLE_RTC_WL_INIT_DEVICE_TREE        2   ///< Before first "Start InitDeviceTree".
#define APPLE_RTC_WL_KERNEL_ALLOC_CALL_GATE  3   ///< After "End InitDeviceTree".
#define APPLE_RTC_WL_INIT_MEMORY_CONFIG      4   ///< Before "Start InitMemoryConfig".
#define APPLE_RTC_WL_HIB_CHECK               5   ///< Before "Start CheckHibernate".
#define APPLE_RTC_WL_CS_LOAD_CONFIGURATION   6   ///< Before "Start LoadCoreStorageConfiguration".
#define APPLE_RTC_WL_GET_FDE_KEY             7   ///< Before reading HBKP key.
#define APPLE_RTC_WL_HIB_WAKE_START          8   ///< Before reading FACP table.
#define APPLE_RTC_WL_HIB_GET_MMAP            9   ///< Before GetMemoryMap for hibernation.
#define APPLE_RTC_WL_HIB_HWSIG_VALID         10  ///< After confirming FACP signature validity with the image.
#define APPLE_RTC_WL_HIB_MEM_ALLOC           11  ///< Before restore1CodePhysPage / runtimePages allocation.
#define APPLE_RTC_WL_HIB_SPLASH              12  ///< Before "Start OpenBootGraphics".
#define APPLE_RTC_WL_HIB_READ                13  ///< After "Start hibernate read".
#define APPLE_RTC_WL_HIB_HANDOFF             14  ///< Before adjusting IOHibernateImageHeader and booting kernel.
#define APPLE_RTC_WL_HIB_EXIT_BOOT_SERVICES  15  ///< Done ExitBootServices for hibernate, EFI_STATUS in EXTRA.
#define APPLE_RTC_WL_HIB_KERNEL_START        16  ///< Calling kernel entry point for hibernate.
#define APPLE_RTC_WL_HIB_FINISH_FDE          17  ///< After "Start FinishFDEHibernate".
#define APPLE_RTC_WL_HIB_WIRED_KEY_VALID     18  ///< Before APPLE_RTC_WL_HIBERNATE_WAKE_START with valid FDE key.
#define APPLE_RTC_WL_RECOVERY_OS_FOUND       19  ///< After detecting com.apple.recovery.boot in boot path.
#define APPLE_RTC_WL_CS_VOLUME_UNLOCKED      20  ///< After "End UnlockCoreStorageVolumeKey" with EFI_STATUS in EXTRA.
#define APPLE_RTC_WL_KERNEL_LOAD_CACHE_FAIL  22  ///< Failed to load kernel cache, EFI_STATUS in EXTRA.
#define APPLE_RTC_WL_HIB_BS_MISSING          23  ///< Missing boot-signature, EFI_STATUS in EXTRA.
#define APPLE_RTC_WL_HIB_BIK_MISSING         24  ///< Missing boot-image-key, EFI_STATUS in EXTRA.
#define APPLE_RTC_WL_RECOVERY_OS_REBOOT      25  ///< Before rebooting into recovery with APPLE_RTC_WL_MASK_BOOT_RESET.
#define APPLE_RTC_WL_LOGIN_WINDOW_PWRESET    26  ///< Requested FDE password recovery.
#define APPLE_RTC_WL_LOGIN_WINDOW_GUEST      27  ///< Chose guest in FV2 login window, will gBS->Reset now.
#define APPLE_RTC_WL_LOGIN_WINDOW_RESET      28  ///< Chose reset in FV2 login window, will gBS->Reset now.
#define APPLE_RTC_WL_LOGIN_WINDOW_HIB        29  ///< Will save hibernation data after FV2 login window and shutdown.
#define APPLE_RTC_WL_LOGIN_WINDOW_SHUTDOWN   30  ///< Chose shutdown in FV2 login window, will gBS->Reset now.
#define APPLE_RTC_WL_LOGIN_WINDOW_FAIL       31  ///< After "End LoginWindow Initialize", EFI_STATUS in EXTRA.
#define APPLE_RTC_WL_HIB_ABORT_SAFE_MODE     32  ///< Hibernation aborted due to safe mode, after "Start CheckHibernate".
#define APPLE_RTC_WL_HIB_BI_ALLOC            33  ///< Failed to allocate memory for boot-image, EFI_STATUS in EXTRA.
#define APPLE_RTC_WL_HIB_BI_MISSING          34  ///< Missing boot-image variable or 0 size, EFI_STATUS in EXTRA.
#define APPLE_RTC_WL_HIB_BI_INVALID          35  ///< Did not find valid data in boot-image.
#define APPLE_RTC_WL_HIB_BI_DP_ALLOC         36  ///< Failed to allocate boot-image device path(?).
#define APPLE_RTC_WL_HIB_BI_DP_ZERO          37  ///< boot-image contains empty DP(?).
#define APPLE_RTC_WL_HIB_BI_DP_MISSING       38  ///< Failed to locate boot-image device path, EFI_STATUS in EXTRA.
#define APPLE_RTC_WL_HIB_BI_DP_NO_DISK_IO    39  ///< Failed to find Disk I/O protocol, EFI_STATUS in EXTRA.
#define APPLE_RTC_WL_HIB_BI_DP_NI_BLOCK_IO   40  ///< Failed to find Block I/O protocol, EFI_STATUS in EXTRA.

/**
  Certain components have the ability to log their wake progress
  directly via RTC. See XNU IOPMPrivate.h for more details.

  LoginWindow  - 4 bits
  CoreDisplay  - 8 bits
  CoreGraphics - 8 bits

  Apparently these look mostly unused, at least in release builds.
  CoreDisplay is known to report 0 (very helpful) on screen wake.
  I guess we can abuse them if we want.
**/
#define APPLE_RTC_TRACE_LOGIN_WINDOW_ADDR   0xB4
#define APPLE_RTC_TRACE_CORE_DISPLAY_ADDR   0xB5
#define APPLE_RTC_TRACE_CORE_GRAPHICS_ADDR  0xB6

/**
  Trace point power phase e.g. kIOPMTracePointSystemUp.
  See XNU IOPMPrivate.h for more details.
**/
#define APPLE_RTC_TRACE_PHASE_ADDR  0xB7

/**
  256-bit full disk encryption (FDE) key used for authenticated restart.
  AppleRTC and other kexts name it key stash.

  Written by AppleRTC at the request of IOHibernateSMCVariables I/O registry
  entry submitted either by XNU kernel or AppleFDEKeyStore.kext. The variable
  itself is a pair of 64-bit values: key size and key address in kernel memory.

  This was replaced with HBKP SMC key in modern Macs.

  *** VirtualSMC addendum ***

  Since this value is no longer used due to HBKP present in almost every Mac
  we badly abuse this area when vertualising SMC.

  When HBKP SMC key is written VirtualSMC AES-128 encrypts the submitted value
  with a unique key and writes the result to an NVRAM variable (vsmc-key).
  The AES encryption key goes to RTC at this address instead.
  Afterwards the EFI module implementing SMC protocol performs the decryption.

  TODO: Replace AES with one-time pad, i.e. increase the temporary key size
        to 256 bits and just XOR the value. This will break old VirtualSmc.efi
        module, but we do not care anymore.
**/
#define APPLE_RTC_FDE_KEY_ADDR  0xD0

/**
  FDE key maximum and default, as AES-256-XTS has 256-bit key.
  For smaller keys remaining bytes are zeroed.
**/
#define APPLE_RTC_FDE_KEY_LENGTH  0x20

/**
  FDE key state. Normally written by ApplePlatformInit.

  0x00 - The key is either present or not.
  0x41 - The key is not present, and should be copied to RTC from HBKP
         SMC key prior to transfering control to the bootloader. After the
         copying succeeds this value is overwritten with 0x00. Normally
         this is done by AppleBds.
**/
#define APPLE_RTC_FDE_STATE_ADDR  0xF0

/**
  Known values for APPLE_RTC_FDE_STATE_ADDR.
**/
#define APPLE_RTC_FDE_STATE_DEFAULT   0x00
#define APPLE_RTC_FDE_STATE_NEED_KEY  0x41

/**
  Checksum is calculated starting from this address.
**/
#define APPLE_RTC_CHECKSUM_START  0x0E

/**
  First 64 bytes are RTC core and are hashed separately.
**/
#define APPLE_RTC_CORE_SIZE  0x40

/**
  All Apple hardware cares about 256 bytes of RTC memory.
**/
#define APPLE_RTC_TOTAL_SIZE  0x100

/**
  Apple checksum custom CRC polynomial.
  Apple checksum is a modified version of ANSI CRC16 in REFIN mode (0xA001 poly).
  See http://zlib.net/crc_v3.txt for more details.

  Effective poly is 0x2001 due to a bitwise OR with BIT15.
  The change turns CRC16 into CRC14, making BIT14 and BIT15 always zero.
  This modification is commonly found in legacy Phoenix firmware,
  where it was used for password hashing as found by dogbert:
  http://sites.google.com/site/dogber1/blag/pwgen-5dec.py
**/
#define APPLE_RTC_CHECKSUM_POLYNOMIAL  0x2001

/**
  Apple checksum rounds.

  Only 7 shifts per byte are performed instead of the usual 8.
  This might improve checksum quality against specific data, but the exact
  reasons are unknown. The algorithm did not change since its introduction
  in 10.4.x, and since Apple Developer Transition Kit was based on Phoenix
  firmware, this could just be a quick change to get a different checksum.
**/
#define APPLE_RTC_CHECKSUM_ROUNDS  7

/**
  Checksum for Apple RTC with core part of the memory hashed:
  [APPLE_RTC_CHECKSUM_SART, APPLE_RTC_CORE_SIZE).
**/
#define APPLE_RTC_CORE_CHECKSUM_ADDR1  0x3E
#define APPLE_RTC_CORE_CHECKSUM_ADDR2  0x3F

/**
  Apple RTC core checksum to byte convertion macros.
  BYTE1 BIT0~BIT7 = CHECKSUM BIT0~BIT7
  BYTE2 BIT1~BIT7 = CHECKSUM BIT8~BIT14
**/
#define APPLE_RTC_CORE_CHECKSUM_BYTE1(Checksum)  ((UINT8) ((UINT32) (Checksum) & 0xFFU))
#define APPLE_RTC_CORE_CHECKSUM_BYTE2(Checksum)  ((UINT8) (((UINT32) (Checksum) >> 7U) & 0xFEU))

/**
  Checksum for Apple RTC with all the memory hashed:
  [APPLE_RTC_CHECKSUM_SART, APPLE_RTC_TOTAL_SIZE).
**/
#define APPLE_RTC_MAIN_CHECKSUM_ADDR1  0x58
#define APPLE_RTC_MAIN_CHECKSUM_ADDR2  0x59

/**
  Apple RTC main checksum to byte convertion macros.
  BYTE1 BIT0~BIT7 = CHECKSUM BIT0~BIT7
  BYTE2 BIT0~BIT7 = CHECKSUM BIT8~BIT15
**/
#define APPLE_RTC_MAIN_CHECKSUM_BYTE1(Checksum)  ((UINT8) (((UINT32) (Checksum) >> 8U) & 0xFFU))
#define APPLE_RTC_MAIN_CHECKSUM_BYTE2(Checksum)  ((UINT8) ((UINT32) (Checksum) & 0xFFU))

#endif // APPLE_RTC_H
