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