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