qemu/pc-bios/s390-ccw/bootmap.h
<<
>>
Prefs
   1/*
   2 * QEMU S390 bootmap interpreter -- declarations
   3 *
   4 * Copyright 2014 IBM Corp.
   5 * Author(s): Eugene (jno) Dvurechenski <jno@linux.vnet.ibm.com>
   6 *
   7 * This work is licensed under the terms of the GNU GPL, version 2 or (at
   8 * your option) any later version. See the COPYING file in the top-level
   9 * directory.
  10 */
  11#ifndef _PC_BIOS_S390_CCW_BOOTMAP_H
  12#define _PC_BIOS_S390_CCW_BOOTMAP_H
  13
  14#include "s390-ccw.h"
  15#include "virtio.h"
  16
  17typedef uint64_t block_number_t;
  18#define NULL_BLOCK_NR 0xffffffffffffffffULL
  19
  20#define FREE_SPACE_FILLER '\xAA'
  21
  22typedef struct ScsiBlockPtr {
  23    uint64_t blockno;
  24    uint16_t size;
  25    uint16_t blockct;
  26    uint8_t reserved[4];
  27} __attribute__ ((packed)) ScsiBlockPtr;
  28
  29typedef struct FbaBlockPtr {
  30    uint32_t blockno;
  31    uint16_t size;
  32    uint16_t blockct;
  33} __attribute__ ((packed)) FbaBlockPtr;
  34
  35typedef struct EckdCHS {
  36    uint16_t cylinder;
  37    uint16_t head;
  38    uint8_t sector;
  39} __attribute__ ((packed)) EckdCHS;
  40
  41typedef struct EckdBlockPtr {
  42    EckdCHS chs; /* cylinder/head/sector is an address of the block */
  43    uint16_t size;
  44    uint8_t count; /* (size_in_blocks-1);
  45                    * it's 0 for TablePtr, ScriptPtr, and SectionPtr */
  46} __attribute__ ((packed)) EckdBlockPtr;
  47
  48typedef struct ExtEckdBlockPtr {
  49    EckdBlockPtr bptr;
  50    uint8_t reserved[8];
  51} __attribute__ ((packed)) ExtEckdBlockPtr;
  52
  53typedef union BootMapPointer {
  54    ScsiBlockPtr scsi;
  55    FbaBlockPtr fba;
  56    EckdBlockPtr eckd;
  57    ExtEckdBlockPtr xeckd;
  58} __attribute__ ((packed)) BootMapPointer;
  59
  60/* aka Program Table */
  61typedef struct BootMapTable {
  62    uint8_t magic[4];
  63    uint8_t reserved[12];
  64    BootMapPointer entry[];
  65} __attribute__ ((packed)) BootMapTable;
  66
  67typedef struct ComponentEntry {
  68    ScsiBlockPtr data;
  69    uint8_t pad[7];
  70    uint8_t component_type;
  71    uint64_t load_address;
  72} __attribute((packed)) ComponentEntry;
  73
  74typedef struct ComponentHeader {
  75    uint8_t magic[4];   /* == "zIPL"                    */
  76    uint8_t type;       /* == ZIPL_COMP_HEADER_*        */
  77    uint8_t reserved[27];
  78} __attribute((packed)) ComponentHeader;
  79
  80typedef struct ScsiMbr {
  81    uint8_t magic[4];
  82    uint32_t version_id;
  83    uint8_t reserved[8];
  84    ScsiBlockPtr pt;   /* block pointer to program table */
  85} __attribute__ ((packed)) ScsiMbr;
  86
  87#define ZIPL_MAGIC              "zIPL"
  88#define ZIPL_MAGIC_EBCDIC       "\xa9\xc9\xd7\xd3"
  89#define IPL1_MAGIC "\xc9\xd7\xd3\xf1" /* == "IPL1" in EBCDIC */
  90#define IPL2_MAGIC "\xc9\xd7\xd3\xf2" /* == "IPL2" in EBCDIC */
  91#define VOL1_MAGIC "\xe5\xd6\xd3\xf1" /* == "VOL1" in EBCDIC */
  92#define LNX1_MAGIC "\xd3\xd5\xe7\xf1" /* == "LNX1" in EBCDIC */
  93#define CMS1_MAGIC "\xc3\xd4\xe2\xf1" /* == "CMS1" in EBCDIC */
  94
  95#define LDL1_VERSION '\x40' /* == ' ' in EBCDIC */
  96#define LDL2_VERSION '\xf2' /* == '2' in EBCDIC */
  97
  98#define ZIPL_COMP_HEADER_IPL    0x00
  99#define ZIPL_COMP_HEADER_DUMP   0x01
 100
 101#define ZIPL_COMP_ENTRY_EXEC      0x01
 102#define ZIPL_COMP_ENTRY_LOAD      0x02
 103#define ZIPL_COMP_ENTRY_SIGNATURE 0x03
 104
 105typedef struct XEckdMbr {
 106    uint8_t magic[4];   /* == "xIPL"        */
 107    uint8_t version;
 108    uint8_t bp_type;
 109    uint8_t dev_type;   /* == DEV_TYPE_*    */
 110#define DEV_TYPE_ECKD 0x00
 111#define DEV_TYPE_FBA  0x01
 112    uint8_t flags;
 113    BootMapPointer blockptr;
 114    uint8_t reserved[8];
 115} __attribute__ ((packed)) XEckdMbr; /* see also BootInfo */
 116
 117typedef struct BootMapScriptEntry {
 118    BootMapPointer blkptr;
 119    uint8_t pad[7];
 120    uint8_t type;   /* == BOOT_SCRIPT_* */
 121#define BOOT_SCRIPT_EXEC      0x01
 122#define BOOT_SCRIPT_LOAD      0x02
 123#define BOOT_SCRIPT_SIGNATURE 0x03
 124    union {
 125        uint64_t load_address;
 126        uint64_t load_psw;
 127    } address;
 128} __attribute__ ((packed)) BootMapScriptEntry;
 129
 130typedef struct BootMapScriptHeader {
 131    uint32_t magic;
 132    uint8_t type;
 133#define BOOT_SCRIPT_HDR_IPL 0x00
 134    uint8_t reserved[27];
 135} __attribute__ ((packed)) BootMapScriptHeader;
 136
 137typedef struct BootMapScript {
 138    BootMapScriptHeader header;
 139    BootMapScriptEntry  entry[0];
 140} __attribute__ ((packed)) BootMapScript;
 141
 142/*
 143 * These aren't real VTOCs, but referred to this way in some docs.
 144 * They are "volume labels" actually.
 145 *
 146 * Some structures looks similar to described above, but left
 147 * separate as there is no indication that they are the same.
 148 * So, the value definitions are left separate too.
 149 */
 150typedef struct LDL_VTOC {       /* @ rec.3 cyl.0 trk.0 for ECKD */
 151    char magic[4];              /* "LNX1", EBCDIC               */
 152    char volser[6];             /* volser, EBCDIC               */
 153    uint8_t reserved[69];       /* reserved, 0x40               */
 154    uint8_t LDL_version;        /* 0x40 or 0xF2                 */
 155    uint64_t formatted_blocks;  /* if LDL_version >= 0xF2       */
 156} __attribute__ ((packed)) LDL_VTOC;
 157
 158typedef struct format_date {
 159    uint8_t YY;
 160    uint8_t MM;
 161    uint8_t DD;
 162    uint8_t hh;
 163    uint8_t mm;
 164    uint8_t ss;
 165} __attribute__ ((packed)) format_date_t;
 166
 167typedef struct CMS_VTOC {       /* @ rec.3 cyl.0 trk.0 for ECKD */
 168                                /* @ blk.1 (zero based) for FBA */
 169    char magic[4];              /* 'CMS1', EBCDIC               */
 170    char volser[6];             /* volser, EBCDIC               */
 171    uint16_t version;           /* = 0                          */
 172    uint32_t block_size;        /* = 512, 1024, 2048, or 4096   */
 173    uint32_t disk_origin;       /* = 4 or 5                     */
 174    uint32_t blocks;            /* Number of usable cyls/blocks */
 175    uint32_t formatted;         /* Max number of fmtd cyls/blks */
 176    uint32_t CMS_blocks;        /* disk size in CMS blocks      */
 177    uint32_t CMS_used;          /* Number of CMS blocks in use  */
 178    uint32_t FST_size;          /* = 64, bytes                  */
 179    uint32_t FST_per_CMS_blk;   /*                              */
 180    format_date_t format_date;  /* YYMMDDhhmmss as 6 bytes      */
 181    uint8_t reserved1[2];       /* = 0                          */
 182    uint32_t offset;            /* disk offset when reserved    */
 183    uint32_t next_hole;         /* block nr                     */
 184    uint32_t HBLK_hole_offset;  /* >> HBLK data of next hole    */
 185    uint32_t alloc_map_usr_off; /* >> user part of Alloc map    */
 186    uint8_t reserved2[4];       /* = 0                          */
 187    char shared_seg_name[8];    /*                              */
 188} __attribute__ ((packed)) CMS_VTOC;
 189
 190/* from zipl/include/boot.h */
 191typedef struct BootInfoBpIpl {
 192    union {
 193        ExtEckdBlockPtr eckd;
 194        ScsiBlockPtr linr;
 195    } bm_ptr;
 196    uint8_t unused[16];
 197} __attribute__ ((packed)) BootInfoBpIpl;
 198
 199typedef struct EckdDumpParam {
 200    uint32_t        start_blk;
 201    uint32_t        end_blk;
 202    uint16_t        blocksize;
 203    uint8_t         num_heads;
 204    uint8_t         bpt;
 205    char            reserved[4];
 206} __attribute((packed, may_alias)) EckdDumpParam;
 207
 208typedef struct FbaDumpParam {
 209    uint64_t        start_blk;
 210    uint64_t        blockct;
 211} __attribute((packed)) FbaDumpParam;
 212
 213typedef struct BootInfoBpDump {
 214    union {
 215        EckdDumpParam eckd;
 216        FbaDumpParam fba;
 217    } param;
 218    uint8_t         unused[16];
 219} __attribute__ ((packed)) BootInfoBpDump;
 220
 221typedef struct BootInfo {          /* @ 0x70, record #0    */
 222    unsigned char magic[4]; /* = 'zIPL', ASCII      */
 223    uint8_t version;        /* = 1                  */
 224#define BOOT_INFO_VERSION               1
 225    uint8_t bp_type;        /* = 0                  */
 226#define BOOT_INFO_BP_TYPE_IPL           0x00
 227#define BOOT_INFO_BP_TYPE_DUMP          0x01
 228    uint8_t dev_type;       /* = 0                  */
 229#define BOOT_INFO_DEV_TYPE_ECKD         0x00
 230#define BOOT_INFO_DEV_TYPE_FBA          0x01
 231    uint8_t flags;          /* = 1                  */
 232#ifdef __s390x__
 233#define BOOT_INFO_FLAGS_ARCH            0x01
 234#else
 235#define BOOT_INFO_FLAGS_ARCH            0x00
 236#endif
 237    union {
 238        BootInfoBpDump dump;
 239        BootInfoBpIpl ipl;
 240    } bp;
 241} __attribute__ ((packed)) BootInfo; /* see also XEckdMbr   */
 242
 243/*
 244 * Structs for IPL
 245 */
 246#define STAGE2_BLK_CNT_MAX  24 /* Stage 1b can load up to 24 blocks */
 247
 248typedef struct EckdCdlIpl1 {
 249    uint8_t key[4]; /* == "IPL1" */
 250    uint8_t data[24];
 251} __attribute__((packed)) EckdCdlIpl1;
 252
 253typedef struct EckdSeekArg {
 254    uint16_t pad;
 255    EckdCHS chs;
 256    uint8_t pad2;
 257} __attribute__ ((packed)) EckdSeekArg;
 258
 259typedef struct EckdStage1b {
 260    uint8_t reserved[32 * STAGE2_BLK_CNT_MAX];
 261    struct EckdSeekArg seek[STAGE2_BLK_CNT_MAX];
 262    uint8_t unused[64];
 263} __attribute__ ((packed)) EckdStage1b;
 264
 265typedef struct EckdStage1 {
 266    uint8_t reserved[72];
 267    struct EckdSeekArg seek[2];
 268} __attribute__ ((packed)) EckdStage1;
 269
 270typedef struct EckdCdlIpl2 {
 271    uint8_t key[4]; /* == "IPL2" */
 272    struct EckdStage1 stage1;
 273    XEckdMbr mbr;
 274    uint8_t reserved[24];
 275} __attribute__((packed)) EckdCdlIpl2;
 276
 277typedef struct EckdLdlIpl1 {
 278    uint8_t reserved[24];
 279    struct EckdStage1 stage1;
 280    BootInfo bip; /* BootInfo is MBR for LDL */
 281} __attribute__((packed)) EckdLdlIpl1;
 282
 283typedef struct IplVolumeLabel {
 284    unsigned char key[4]; /* == "VOL1" */
 285    union {
 286        unsigned char data[80];
 287        struct {
 288            unsigned char key[4]; /* == "VOL1" */
 289            unsigned char volser[6];
 290            unsigned char reserved[6];
 291        } f;
 292    };
 293} __attribute__((packed)) IplVolumeLabel;
 294
 295typedef enum {
 296    ECKD_NO_IPL,
 297    ECKD_CMS,
 298    ECKD_LDL,
 299    ECKD_LDL_UNLABELED,
 300} ECKD_IPL_mode_t;
 301
 302/* utility code below */
 303
 304static inline void print_volser(const void *volser)
 305{
 306    char ascii[8];
 307
 308    ebcdic_to_ascii((char *)volser, ascii, 6);
 309    ascii[6] = '\0';
 310    sclp_print("VOLSER=[");
 311    sclp_print(ascii);
 312    sclp_print("]\n");
 313}
 314
 315static inline bool unused_space(const void *p, size_t size)
 316{
 317    size_t i;
 318    const unsigned char *m = p;
 319
 320    for (i = 0; i < size; i++) {
 321        if (m[i] != FREE_SPACE_FILLER) {
 322            return false;
 323        }
 324    }
 325    return true;
 326}
 327
 328static inline bool is_null_block_number(block_number_t x)
 329{
 330    return x == NULL_BLOCK_NR;
 331}
 332
 333static inline void read_block(block_number_t blockno,
 334                              void *buffer,
 335                              const char *errmsg)
 336{
 337    IPL_assert(virtio_read(blockno, buffer) == 0, errmsg);
 338}
 339
 340static inline bool block_size_ok(uint32_t block_size)
 341{
 342    return block_size == virtio_get_block_size();
 343}
 344
 345static inline bool magic_match(const void *data, const void *magic)
 346{
 347    return *((uint32_t *)data) == *((uint32_t *)magic);
 348}
 349
 350static inline uint32_t iso_733_to_u32(uint64_t x)
 351{
 352    return (uint32_t)x;
 353}
 354
 355#define ISO_SECTOR_SIZE 2048
 356/* El Torito specifies boot image size in 512 byte blocks */
 357#define ET_SECTOR_SHIFT 2
 358
 359#define ISO_PRIMARY_VD_SECTOR 16
 360
 361static inline void read_iso_sector(uint32_t block_offset, void *buf,
 362                                   const char *errmsg)
 363{
 364    IPL_assert(virtio_read_many(block_offset, buf, 1) == 0, errmsg);
 365}
 366
 367static inline void read_iso_boot_image(uint32_t block_offset, void *load_addr,
 368                                       uint32_t blks_to_load)
 369{
 370    IPL_assert(virtio_read_many(block_offset, load_addr, blks_to_load) == 0,
 371               "Failed to read boot image!");
 372}
 373
 374#define ISO9660_MAX_DIR_DEPTH 8
 375
 376typedef struct IsoDirHdr {
 377    uint8_t dr_len;
 378    uint8_t ear_len;
 379    uint64_t ext_loc;
 380    uint64_t data_len;
 381    uint8_t recording_datetime[7];
 382    uint8_t file_flags;
 383    uint8_t file_unit_size;
 384    uint8_t gap_size;
 385    uint32_t vol_seqnum;
 386    uint8_t fileid_len;
 387} __attribute__((packed)) IsoDirHdr;
 388
 389typedef struct IsoVdElTorito {
 390    uint8_t el_torito[32]; /* must contain el_torito_magic value */
 391    uint8_t unused0[32];
 392    uint32_t bc_offset;
 393    uint8_t unused1[1974];
 394} __attribute__((packed)) IsoVdElTorito;
 395
 396typedef struct IsoVdPrimary {
 397    uint8_t unused1;
 398    uint8_t sys_id[32];
 399    uint8_t vol_id[32];
 400    uint8_t unused2[8];
 401    uint64_t vol_space_size;
 402    uint8_t unused3[32];
 403    uint32_t vol_set_size;
 404    uint32_t vol_seqnum;
 405    uint32_t log_block_size;
 406    uint64_t path_table_size;
 407    uint32_t l_path_table;
 408    uint32_t opt_l_path_table;
 409    uint32_t m_path_table;
 410    uint32_t opt_m_path_table;
 411    IsoDirHdr rootdir;
 412    uint8_t root_null;
 413    uint8_t reserved2[1858];
 414} __attribute__((packed)) IsoVdPrimary;
 415
 416typedef struct IsoVolDesc {
 417    uint8_t type;
 418    uint8_t ident[5];
 419    uint8_t version;
 420    union {
 421        IsoVdElTorito boot;
 422        IsoVdPrimary primary;
 423    } vd;
 424} __attribute__((packed)) IsoVolDesc;
 425
 426#define VOL_DESC_TYPE_BOOT 0
 427#define VOL_DESC_TYPE_PRIMARY 1
 428#define VOL_DESC_TYPE_SUPPLEMENT 2
 429#define VOL_DESC_TYPE_PARTITION 3
 430#define VOL_DESC_TERMINATOR 255
 431
 432typedef struct IsoBcValid {
 433    uint8_t platform_id;
 434    uint16_t reserved;
 435    uint8_t id[24];
 436    uint16_t checksum;
 437    uint8_t key[2];
 438} __attribute__((packed)) IsoBcValid;
 439
 440typedef struct IsoBcSection {
 441    uint8_t boot_type;
 442    uint16_t load_segment;
 443    uint8_t sys_type;
 444    uint8_t unused;
 445    uint16_t sector_count;
 446    uint32_t load_rba;
 447    uint8_t selection[20];
 448} __attribute__((packed)) IsoBcSection;
 449
 450typedef struct IsoBcHdr {
 451    uint8_t platform_id;
 452    uint16_t sect_num;
 453    uint8_t id[28];
 454} __attribute__((packed)) IsoBcHdr;
 455
 456typedef struct IsoBcEntry {
 457    uint8_t id;
 458    union {
 459        IsoBcValid valid; /* id == 0x01 */
 460        IsoBcSection sect; /* id == 0x88 || id == 0x0 */
 461        IsoBcHdr hdr; /* id == 0x90 || id == 0x91 */
 462    } body;
 463} __attribute__((packed)) IsoBcEntry;
 464
 465#define ISO_BC_ENTRY_PER_SECTOR (ISO_SECTOR_SIZE / sizeof(IsoBcEntry))
 466#define ISO_BC_HDR_VALIDATION 0x01
 467#define ISO_BC_BOOTABLE_SECTION 0x88
 468#define ISO_BC_MAGIC_55 0x55
 469#define ISO_BC_MAGIC_AA 0xaa
 470#define ISO_BC_PLATFORM_X86 0x0
 471#define ISO_BC_PLATFORM_PPC 0x1
 472#define ISO_BC_PLATFORM_MAC 0x2
 473
 474static inline bool is_iso_bc_valid(IsoBcEntry *e)
 475{
 476    IsoBcValid *v = &e->body.valid;
 477
 478    if (e->id != ISO_BC_HDR_VALIDATION) {
 479        return false;
 480    }
 481
 482    if (v->platform_id != ISO_BC_PLATFORM_X86 &&
 483        v->platform_id != ISO_BC_PLATFORM_PPC &&
 484        v->platform_id != ISO_BC_PLATFORM_MAC) {
 485        return false;
 486    }
 487
 488    return v->key[0] == ISO_BC_MAGIC_55 &&
 489           v->key[1] == ISO_BC_MAGIC_AA &&
 490           v->reserved == 0x0;
 491}
 492
 493#endif /* _PC_BIOS_S390_CCW_BOOTMAP_H */
 494