/** @file
  Copyright (C) 2019, Goldfish64. 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_MKEXT_H
#define APPLE_MKEXT_H

#include <IndustryStandard/AppleMachoImage.h>

//
// Based upon XNU libkern/libkern/mkext.h.
//

//
// Magic value "MKXT" used to identify an MKEXT file.
//
#define MKEXT_MAGIC  0x4D4B5854
//
// Magic value "MKXT" used to identify an MKEXT file.
//
#define MKEXT_INVERT_MAGIC  0x54584B4D
//
// Signature "MOSX" used to identify an MKEXT file.
//
#define MKEXT_SIGNATURE  0x4D4F5358
//
// Signature "MOSX" used to identify an MKEXT file.
//
#define MKEXT_INVERT_SIGNATURE  0x58534F4D
//
// Version 1 format.
//
#define MKEXT_VERSION_V1  0x01008000
//
// Version 2 format.
//
#define MKEXT_VERSION_V2  0x02002001

//
// Common MKEXT header.
//
typedef struct {
  //
  // MKEXT magic value "MKXT".
  //
  UINT32              Magic;
  //
  // MKEXT signature "MOSX".
  //
  UINT32              Signature;
  //
  // File length.
  //
  UINT32              Length;
  //
  // Adler32 checksum from Version field to end of file.
  //
  UINT32              Adler32;
  //
  // File version.
  //
  UINT32              Version;
  //
  // Number of kernel extensions in file.
  //
  UINT32              NumKexts;
  //
  // The CPU architecture specifier.
  //
  MACH_CPU_TYPE       CpuType;
  //
  // The CPU sub-architecture specifier.
  //
  MACH_CPU_SUBTYPE    CpuSubtype;
} MKEXT_CORE_HEADER;

//
//
// MKEXT v1 format.
// Version: 0x01008000
//
// Kexts stored within an array as plist/binary pairs, with
// optional lzss compression of each plist and/or binary. V1 allows
// for fat kexts individually within the mkext or the entire mkext
// can be contained within a fat binary.
//
//

//
// MKEXT v1 kext file.
//
typedef struct {
  //
  // Offset into file where data begins.
  //
  UINT32    Offset;
  //
  // Compressed size. Zero indicates no compression.
  //
  UINT32    CompressedSize;
  //
  // Uncompressed size.
  //
  UINT32    FullSize;
  //
  // Last modified time.
  //
  UINT32    ModifiedSeconds;
} MKEXT_V1_KEXT_FILE;

//
// MKEXT v1 kext entry.
//
typedef struct {
  //
  // Info.plist entry.
  //
  MKEXT_V1_KEXT_FILE    Plist;
  //
  // Binary entry; optional.
  //
  MKEXT_V1_KEXT_FILE    Binary;
} MKEXT_V1_KEXT;

//
// MKEXT v1 header.
//
typedef struct {
  //
  // Common header.
  //
  MKEXT_CORE_HEADER    Header;
  //
  // Array of kext entries.
  //
  MKEXT_V1_KEXT        Kexts[];
} MKEXT_V1_HEADER;

//
//
// MKEXT v2 format. Introduced in XNU 10.0.
// Version: 0x02001000
//
// Kext binaries and resources are stored together in sequence
// followed by a combined plist of all kexts at the end. This plist
// further contains offset information to respective binaries and resources.
// Zlib compression can be optionally used, with individual fat kexts
// diallowed, requiring all to be of the same single arch.
//
//

//
// MKEXT v2 file entry.
//
typedef struct {
  //
  // Compressed size. Zero indicates no compression.
  UINT32    CompressedSize;
  //
  // Uncompressed size.
  //
  UINT32    FullSize;
  //
  // Data.
  //
  UINT8     Data[];
} MKEXT_V2_FILE_ENTRY;

//
// MKEXT v2 header.
//
typedef struct {
  //
  // Common header.
  //
  MKEXT_CORE_HEADER    Header;
  //
  // Offset of plist in file.
  //
  UINT32               PlistOffset;
  //
  // Compressed size of plist. Zero indicates no compression.
  //
  UINT32               PlistCompressedSize;
  //
  // Uncompressed size of plist.
  //
  UINT32               PlistFullSize;
} MKEXT_V2_HEADER;

//
// Allow selecting correct header based on version.
//
typedef union {
  MKEXT_CORE_HEADER    Common;
  MKEXT_V1_HEADER      V1;
  MKEXT_V2_HEADER      V2;
} MKEXT_HEADER_ANY;

#endif // APPLE_MKEXT_H
