// Copyright 2016 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#pragma once

#ifndef __ASSEMBLER__
#include <zircon/compiler.h>
#include <stdbool.h>
#include <stdint.h>
#endif

// lsw of sha256("bootdata")
#define BOOTDATA_MAGIC (0x868cf7e6)

// lsw of sha256("bootitem")
#define BOOTITEM_MAGIC (0xb5781729)

// Round n up to the next 8 byte boundary
#define BOOTDATA_ALIGN(n) (((n) + 7) & (~7))

#define BOOTITEM_NO_CRC32 (0x4a87e8d6)

// This flag is required.
#define BOOTDATA_FLAG_V2         (0x00010000)

// Bootdata items with the CRC32 flag must have a valid crc32.
// Otherwise their crc32 field must contain BOOTITEM_NO_CRC32
#define BOOTDATA_FLAG_CRC32      (0x00020000)

// Bootdata types that have least significant byte set to 'm'
// are reserved for driver metadata
#define BOOTDATA_KIND_METADATA   (0x0000006D)
#define BOOTDATA_KIND_MASK       (0x000000FF)

// Containers are used to wrap a set of bootdata items
// written to a file or partition.  The "length" is the
// length of the set of following bootdata items.  The
// "extra" is the value BOOTDATA_MAGIC and "flags" is
// set to 0.
#define BOOTDATA_CONTAINER        (0x544f4f42) // BOOT

// BOOTFS images.  The "extra" field is the decompressed
// size of the image, if compressed, otherwise the same
// as the "length" field.
#define BOOTDATA_BOOTFS_BOOT      (0x42534642) // BFSB
#define BOOTDATA_BOOTFS_SYSTEM    (0x53534642) // BFSS
#define BOOTDATA_BOOTFS_DISCARD   (0x58534642) // BFSX

#define BOOTDATA_BOOTFS_MASK      (0x00FFFFFF)
#define BOOTDATA_BOOTFS_TYPE      (0x00534642) // BFS\0

// Virtual disk images.  The header fields and compression protocol
// are the same as for the BOOTFS types, but the payload before
// compression is a raw disk image rather than BOOTFS format.
#define BOOTDATA_RAMDISK          (0x4b534452) // RDSK

// A Zircon Kernel Image
// Content: bootdata_kernel_t
#define BOOTDATA_KERNEL           (0x4c4e524b) // KRNL

// A Zircon Partition Map
// Content: bootdata_partition_map_t
// The bootdata_t.extra field is used as a board specific index
// to specify which device the partition map applies to.
#define BOOTDATA_PARTITION_MAP    (0x5452506D) // mPRT

// MAC Address for Ethernet, Wifi, Bluetooth, etc.
// Content: uint8_t[] (variable length based on type of MAC address)
// The bootdata_t.extra field is used as a board specific index
// to specify which device the MAC address applies to.
#define BOOTDATA_MAC_ADDRESS      (0x43414D6D) // mMAC

// Flag indicating that the bootfs is compressed.
#define BOOTDATA_BOOTFS_FLAG_COMPRESSED  (1 << 0)


// These items are for passing from bootloader to kernel

// Kernel Command Line String
// Content: uint8_t[]
#define BOOTDATA_CMDLINE          (0x4c444d43) // CMDL

// ACPI Root Table Pointer
// Content: uint64_t phys addr
#define BOOTDATA_ACPI_RSDP        (0x50445352) // RSDP

// SMBIOS entry point pointer
// Content: uint64_t phys addr
#define BOOTDATA_SMBIOS           (0x49424d53) // SMBI

// Framebuffer Parameters
// Content: bootdata_swfb_t
#define BOOTDATA_FRAMEBUFFER      (0x42465753) // SWFB

// Debug Serial Port
// Content: bootdata_uart_t
#define BOOTDATA_DEBUG_UART       (0x54524155) // UART

// Platform ID Information
// Content: bootdata_platform_id_t
#define BOOTDATA_PLATFORM_ID      (0x44494C50) // PLID

// Memory which will persist across warm boots
// Content bootdata_lastlog_nvram_t
#define BOOTDATA_LASTLOG_NVRAM    (0x4c4c564e) // NVLL

// This reflects a typo we need to support for a while
#define BOOTDATA_LASTLOG_NVRAM2   (0x4c4c5643) // CVLL

// E820 Memory Table
// Content: e820entry[]
#define BOOTDATA_E820_TABLE       (0x30323845) // E820

// EFI Memory Map
// Content: a uint64_t entrysz followed by a set of
// efi_memory_descriptor aligned on entrysz
#define BOOTDATA_EFI_MEMORY_MAP   (0x4d494645) // EFIM

// EFI System Table
// Content: a uint64_t physical address of the table
#define BOOTDATA_EFI_SYSTEM_TABLE (0x53494645) // EFIS

// Last crashlog
// Content: ascii/utf8 log data from previous boot
#define BOOTDATA_LAST_CRASHLOG    (0x4d4f4f42) // BOOM

// CPU configuration
// Content: bootdata_cpu_config_t
#define BOOTDATA_CPU_CONFIG       (0x43555043) // CPUC

// Memory configuration
// Content: one or more of bootdata_mem_range_t (count determined by bootdata_t length)
#define BOOTDATA_MEM_CONFIG       (0x434D454D) // MEMC

// Kernel driver configuration
// Content: driver specific struct, with type determined by bootdata "extra" field
#define BOOTDATA_KERNEL_DRIVER    (0x5652444B) // KDRV

#define BOOTDATA_IGNORE           (0x50494b53) // SKIP

#ifndef __ASSEMBLER__
__BEGIN_CDECLS;

// BootData header, describing the type and size of data
// used to initialize the system. All fields are little-endian.
//
// BootData headers in a stream must be 8-byte-aligned.
//
// The length field specifies the actual payload length
// and does not include the size of padding.
typedef struct {
    // Boot data type
    uint32_t type;

    // Size of the payload following this header
    uint32_t length;

    // type-specific extra data
    // For CONTAINER this is MAGIC.
    // For BOOTFS this is the decompressed size.
    uint32_t extra;

    // Flags for the boot data. See flag descriptions for each type.
    uint32_t flags;

    // For future expansion.  Set to 0.
    uint32_t reserved0;
    uint32_t reserved1;

    // Must be BOOTITEM_MAGIC
    uint32_t magic;

    // Must be the CRC32 of payload if FLAG_CRC32 is set,
    // otherwise must be BOOTITEM_NO_CRC32
    uint32_t crc32;
} bootdata_t;

typedef struct {
    uint64_t base; // physical base addr
    uint32_t width;
    uint32_t height;
    uint32_t stride;
    uint32_t format;
} bootdata_swfb_t;

typedef struct {
    uint64_t entry64;
    uint64_t reserved;
} bootdata_kernel_t;

#define BOOTDATA_PART_NAME_LEN 32
#define BOOTDATA_PART_GUID_LEN 16

typedef struct {
    uint8_t type_guid[BOOTDATA_PART_GUID_LEN];
    uint8_t uniq_guid[BOOTDATA_PART_GUID_LEN];
    uint64_t first_block;
    uint64_t last_block;
    uint64_t flags;
    char name[BOOTDATA_PART_NAME_LEN];
} bootdata_partition_t;

typedef struct {
    uint64_t block_count;
    uint64_t block_size;
    uint32_t partition_count;
    uint32_t reserved;
    char guid[BOOTDATA_PART_GUID_LEN];
    bootdata_partition_t partitions[];
} bootdata_partition_map_t;

typedef struct {
    uint64_t base;
    uint64_t length;
} bootdata_nvram_t;

#define BOOTDATA_UART_NONE 0
#define BOOTDATA_UART_PC_PORT 1
#define BOOTDATA_UART_PC_MMIO 2
typedef struct {
    uint64_t base;
    uint32_t type;
    uint32_t irq;
} bootdata_uart_t;

typedef struct {
    uint32_t vid;
    uint32_t pid;
    char board_name[32];
} bootdata_platform_id_t;

typedef struct {
    uint32_t cpu_count;     // number of CPU cores in the cluster
    uint32_t type;          // for future use
    uint32_t flags;         // for future use
    uint32_t reserved;
} bootdata_cpu_cluster_t;

typedef struct {
    uint32_t cluster_count;
    uint32_t reserved[3];
    bootdata_cpu_cluster_t clusters[];
} bootdata_cpu_config_t;

#define BOOTDATA_MEM_RANGE_RAM          1
#define BOOTDATA_MEM_RANGE_PERIPHERAL   2
#define BOOTDATA_MEM_RANGE_RESERVED     3
typedef struct {
    uint64_t    paddr;
    uint64_t    length;
    uint32_t    type;
    uint32_t    reserved;
} bootdata_mem_range_t;

/* EFI Variable for Crash Log */
#define ZIRCON_VENDOR_GUID \
    {0x82305eb2, 0xd39e, 0x4575, {0xa0, 0xc8, 0x6c, 0x20, 0x72, 0xd0, 0x84, 0x4c}}
#define ZIRCON_CRASHLOG_EFIVAR \
    { 'c', 'r', 'a', 's', 'h', 'l', 'o', 'g', 0 };
#define ZIRCON_CRASHLOG_EFIATTR \
    (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS)

__END_CDECLS;


// BOOTFS is a trivial "filesystem" format
//
// It consists of a bootfs_header_t
//
// Followed by a series of bootfs_entry_t's of:
//   name length (32bit le)
//   data size   (32bit le)
//   data offset (32bit le)
//   namedata   (namelength bytes, includes \0)
//
// - data offsets must be page aligned (multiple of 4096)
// - entries start on uint32 boundaries

//lsw of sha256("bootfs")
#define BOOTFS_MAGIC (0xa56d3ff9)

#define BOOTFS_PAGE_SIZE (4096)
#define BOOTFS_PAGE_ALIGN(size) \
    (((size) + BOOTFS_PAGE_SIZE - 1) & -BOOTFS_PAGE_SIZE)

#define BOOTFS_MAX_NAME_LEN 256

typedef struct bootfs_header {
    // magic value BOOTFS_MAGIC
    uint32_t magic;

    // total size of all bootfs_entry_t's
    // does not include the size of the bootfs_header_t
    uint32_t dirsize;

    // 0, 0
    uint32_t reserved0;
    uint32_t reserved1;
} bootfs_header_t;

typedef struct bootfs_entry {
    uint32_t name_len;
    uint32_t data_len;
    uint32_t data_off;
    char name[];
} bootfs_entry_t;

#define BOOTFS_ALIGN(nlen) (((nlen) + 3) & (~3))
#define BOOTFS_RECSIZE(entry) \
    (sizeof(bootfs_entry_t) + BOOTFS_ALIGN(entry->name_len))

static inline bool bootdata_is_metadata(uint32_t type) {
    return ((type & BOOTDATA_KIND_MASK) == BOOTDATA_KIND_METADATA);
}

#endif