xref: /openbmc/qemu/pc-bios/s390-ccw/bootmap.h (revision 869648e87eeb998cc0ede230f3b7aabfdf0eb2dd)
126f2bbd6SEugene (jno) Dvurechenski /*
226f2bbd6SEugene (jno) Dvurechenski  * QEMU S390 bootmap interpreter -- declarations
326f2bbd6SEugene (jno) Dvurechenski  *
426f2bbd6SEugene (jno) Dvurechenski  * Copyright 2014 IBM Corp.
526f2bbd6SEugene (jno) Dvurechenski  * Author(s): Eugene (jno) Dvurechenski <jno@linux.vnet.ibm.com>
626f2bbd6SEugene (jno) Dvurechenski  *
726f2bbd6SEugene (jno) Dvurechenski  * This work is licensed under the terms of the GNU GPL, version 2 or (at
826f2bbd6SEugene (jno) Dvurechenski  * your option) any later version. See the COPYING file in the top-level
926f2bbd6SEugene (jno) Dvurechenski  * directory.
1026f2bbd6SEugene (jno) Dvurechenski  */
1126f2bbd6SEugene (jno) Dvurechenski #ifndef _PC_BIOS_S390_CCW_BOOTMAP_H
1226f2bbd6SEugene (jno) Dvurechenski #define _PC_BIOS_S390_CCW_BOOTMAP_H
1326f2bbd6SEugene (jno) Dvurechenski 
1426f2bbd6SEugene (jno) Dvurechenski #include "s390-ccw.h"
15a94b485eSEugene (jno) Dvurechenski #include "virtio.h"
16a94b485eSEugene (jno) Dvurechenski 
17a94b485eSEugene (jno) Dvurechenski typedef uint64_t block_number_t;
18f17a8430SChristian Borntraeger #define NULL_BLOCK_NR 0xffffffffffffffffULL
1926f2bbd6SEugene (jno) Dvurechenski 
2026f2bbd6SEugene (jno) Dvurechenski #define FREE_SPACE_FILLER '\xAA'
2126f2bbd6SEugene (jno) Dvurechenski 
2226f2bbd6SEugene (jno) Dvurechenski typedef struct ScsiBlockPtr {
2326f2bbd6SEugene (jno) Dvurechenski     uint64_t blockno;
2426f2bbd6SEugene (jno) Dvurechenski     uint16_t size;
2526f2bbd6SEugene (jno) Dvurechenski     uint16_t blockct;
2626f2bbd6SEugene (jno) Dvurechenski     uint8_t reserved[4];
2726f2bbd6SEugene (jno) Dvurechenski } __attribute__ ((packed)) ScsiBlockPtr;
2826f2bbd6SEugene (jno) Dvurechenski 
2926f2bbd6SEugene (jno) Dvurechenski typedef struct FbaBlockPtr {
3026f2bbd6SEugene (jno) Dvurechenski     uint32_t blockno;
3126f2bbd6SEugene (jno) Dvurechenski     uint16_t size;
3226f2bbd6SEugene (jno) Dvurechenski     uint16_t blockct;
3326f2bbd6SEugene (jno) Dvurechenski } __attribute__ ((packed)) FbaBlockPtr;
3426f2bbd6SEugene (jno) Dvurechenski 
3526f2bbd6SEugene (jno) Dvurechenski typedef struct EckdBlockPtr {
3626f2bbd6SEugene (jno) Dvurechenski     uint16_t cylinder; /* cylinder/head/sector is an address of the block */
3726f2bbd6SEugene (jno) Dvurechenski     uint16_t head;
3826f2bbd6SEugene (jno) Dvurechenski     uint8_t sector;
3926f2bbd6SEugene (jno) Dvurechenski     uint16_t size;
4026f2bbd6SEugene (jno) Dvurechenski     uint8_t count; /* (size_in_blocks-1);
4126f2bbd6SEugene (jno) Dvurechenski                     * it's 0 for TablePtr, ScriptPtr, and SectionPtr */
4226f2bbd6SEugene (jno) Dvurechenski } __attribute__ ((packed)) EckdBlockPtr;
4326f2bbd6SEugene (jno) Dvurechenski 
4426f2bbd6SEugene (jno) Dvurechenski typedef struct ExtEckdBlockPtr {
4526f2bbd6SEugene (jno) Dvurechenski     EckdBlockPtr bptr;
4626f2bbd6SEugene (jno) Dvurechenski     uint8_t reserved[8];
4726f2bbd6SEugene (jno) Dvurechenski } __attribute__ ((packed)) ExtEckdBlockPtr;
4826f2bbd6SEugene (jno) Dvurechenski 
4926f2bbd6SEugene (jno) Dvurechenski typedef union BootMapPointer {
5026f2bbd6SEugene (jno) Dvurechenski     ScsiBlockPtr scsi;
5126f2bbd6SEugene (jno) Dvurechenski     FbaBlockPtr fba;
5226f2bbd6SEugene (jno) Dvurechenski     EckdBlockPtr eckd;
5326f2bbd6SEugene (jno) Dvurechenski     ExtEckdBlockPtr xeckd;
5426f2bbd6SEugene (jno) Dvurechenski } __attribute__ ((packed)) BootMapPointer;
5526f2bbd6SEugene (jno) Dvurechenski 
5626f2bbd6SEugene (jno) Dvurechenski typedef struct ComponentEntry {
5726f2bbd6SEugene (jno) Dvurechenski     ScsiBlockPtr data;
5826f2bbd6SEugene (jno) Dvurechenski     uint8_t pad[7];
5926f2bbd6SEugene (jno) Dvurechenski     uint8_t component_type;
6026f2bbd6SEugene (jno) Dvurechenski     uint64_t load_address;
6126f2bbd6SEugene (jno) Dvurechenski } __attribute((packed)) ComponentEntry;
6226f2bbd6SEugene (jno) Dvurechenski 
6326f2bbd6SEugene (jno) Dvurechenski typedef struct ComponentHeader {
6426f2bbd6SEugene (jno) Dvurechenski     uint8_t magic[4];   /* == "zIPL"                    */
6526f2bbd6SEugene (jno) Dvurechenski     uint8_t type;       /* == ZIPL_COMP_HEADER_*        */
6626f2bbd6SEugene (jno) Dvurechenski     uint8_t reserved[27];
6726f2bbd6SEugene (jno) Dvurechenski } __attribute((packed)) ComponentHeader;
6826f2bbd6SEugene (jno) Dvurechenski 
6926f2bbd6SEugene (jno) Dvurechenski typedef struct ScsiMbr {
7026f2bbd6SEugene (jno) Dvurechenski     uint8_t magic[4];
7126f2bbd6SEugene (jno) Dvurechenski     uint32_t version_id;
7226f2bbd6SEugene (jno) Dvurechenski     uint8_t reserved[8];
7326f2bbd6SEugene (jno) Dvurechenski     ScsiBlockPtr blockptr;
7426f2bbd6SEugene (jno) Dvurechenski } __attribute__ ((packed)) ScsiMbr;
7526f2bbd6SEugene (jno) Dvurechenski 
7626f2bbd6SEugene (jno) Dvurechenski #define ZIPL_MAGIC              "zIPL"
7726f2bbd6SEugene (jno) Dvurechenski #define IPL1_MAGIC "\xc9\xd7\xd3\xf1" /* == "IPL1" in EBCDIC */
7826f2bbd6SEugene (jno) Dvurechenski #define IPL2_MAGIC "\xc9\xd7\xd3\xf2" /* == "IPL2" in EBCDIC */
7926f2bbd6SEugene (jno) Dvurechenski #define VOL1_MAGIC "\xe5\xd6\xd3\xf1" /* == "VOL1" in EBCDIC */
8026f2bbd6SEugene (jno) Dvurechenski #define LNX1_MAGIC "\xd3\xd5\xe7\xf1" /* == "LNX1" in EBCDIC */
8126f2bbd6SEugene (jno) Dvurechenski #define CMS1_MAGIC "\xc3\xd4\xe2\xf1" /* == "CMS1" in EBCDIC */
8226f2bbd6SEugene (jno) Dvurechenski 
8326f2bbd6SEugene (jno) Dvurechenski #define LDL1_VERSION '\x40' /* == ' ' in EBCDIC */
8426f2bbd6SEugene (jno) Dvurechenski #define LDL2_VERSION '\xf2' /* == '2' in EBCDIC */
8526f2bbd6SEugene (jno) Dvurechenski 
8626f2bbd6SEugene (jno) Dvurechenski #define ZIPL_COMP_HEADER_IPL    0x00
8726f2bbd6SEugene (jno) Dvurechenski #define ZIPL_COMP_HEADER_DUMP   0x01
8826f2bbd6SEugene (jno) Dvurechenski 
8926f2bbd6SEugene (jno) Dvurechenski #define ZIPL_COMP_ENTRY_LOAD    0x02
9026f2bbd6SEugene (jno) Dvurechenski #define ZIPL_COMP_ENTRY_EXEC    0x01
9126f2bbd6SEugene (jno) Dvurechenski 
9226f2bbd6SEugene (jno) Dvurechenski typedef struct XEckdMbr {
9326f2bbd6SEugene (jno) Dvurechenski     uint8_t magic[4];   /* == "xIPL"        */
9426f2bbd6SEugene (jno) Dvurechenski     uint8_t version;
9526f2bbd6SEugene (jno) Dvurechenski     uint8_t bp_type;
9626f2bbd6SEugene (jno) Dvurechenski     uint8_t dev_type;   /* == DEV_TYPE_*    */
9726f2bbd6SEugene (jno) Dvurechenski #define DEV_TYPE_ECKD 0x00
9826f2bbd6SEugene (jno) Dvurechenski #define DEV_TYPE_FBA  0x01
9926f2bbd6SEugene (jno) Dvurechenski     uint8_t flags;
10026f2bbd6SEugene (jno) Dvurechenski     BootMapPointer blockptr;
10126f2bbd6SEugene (jno) Dvurechenski     uint8_t reserved[8];
10226f2bbd6SEugene (jno) Dvurechenski } __attribute__ ((packed)) XEckdMbr; /* see also BootInfo */
10326f2bbd6SEugene (jno) Dvurechenski 
10426f2bbd6SEugene (jno) Dvurechenski typedef struct BootMapScriptEntry {
10526f2bbd6SEugene (jno) Dvurechenski     BootMapPointer blkptr;
10626f2bbd6SEugene (jno) Dvurechenski     uint8_t pad[7];
10726f2bbd6SEugene (jno) Dvurechenski     uint8_t type;   /* == BOOT_SCRIPT_* */
10826f2bbd6SEugene (jno) Dvurechenski #define BOOT_SCRIPT_EXEC 0x01
10926f2bbd6SEugene (jno) Dvurechenski #define BOOT_SCRIPT_LOAD 0x02
11026f2bbd6SEugene (jno) Dvurechenski     union {
11126f2bbd6SEugene (jno) Dvurechenski         uint64_t load_address;
11226f2bbd6SEugene (jno) Dvurechenski         uint64_t load_psw;
11326f2bbd6SEugene (jno) Dvurechenski     } address;
11426f2bbd6SEugene (jno) Dvurechenski } __attribute__ ((packed)) BootMapScriptEntry;
11526f2bbd6SEugene (jno) Dvurechenski 
11626f2bbd6SEugene (jno) Dvurechenski typedef struct BootMapScriptHeader {
11726f2bbd6SEugene (jno) Dvurechenski     uint32_t magic;
11826f2bbd6SEugene (jno) Dvurechenski     uint8_t type;
11926f2bbd6SEugene (jno) Dvurechenski #define BOOT_SCRIPT_HDR_IPL 0x00
12026f2bbd6SEugene (jno) Dvurechenski     uint8_t reserved[27];
12126f2bbd6SEugene (jno) Dvurechenski } __attribute__ ((packed)) BootMapScriptHeader;
12226f2bbd6SEugene (jno) Dvurechenski 
12326f2bbd6SEugene (jno) Dvurechenski typedef struct BootMapScript {
12426f2bbd6SEugene (jno) Dvurechenski     BootMapScriptHeader header;
12526f2bbd6SEugene (jno) Dvurechenski     BootMapScriptEntry  entry[0];
12626f2bbd6SEugene (jno) Dvurechenski } __attribute__ ((packed)) BootMapScript;
12726f2bbd6SEugene (jno) Dvurechenski 
12826f2bbd6SEugene (jno) Dvurechenski /*
12926f2bbd6SEugene (jno) Dvurechenski  * These aren't real VTOCs, but referred to this way in some docs.
13026f2bbd6SEugene (jno) Dvurechenski  * They are "volume labels" actually.
13126f2bbd6SEugene (jno) Dvurechenski  *
13226f2bbd6SEugene (jno) Dvurechenski  * Some structures looks similar to described above, but left
13326f2bbd6SEugene (jno) Dvurechenski  * separate as there is no indication that they are the same.
13426f2bbd6SEugene (jno) Dvurechenski  * So, the value definitions are left separate too.
13526f2bbd6SEugene (jno) Dvurechenski  */
13626f2bbd6SEugene (jno) Dvurechenski typedef struct LDL_VTOC {       /* @ rec.3 cyl.0 trk.0 for ECKD */
13726f2bbd6SEugene (jno) Dvurechenski     char magic[4];              /* "LNX1", EBCDIC               */
13826f2bbd6SEugene (jno) Dvurechenski     char volser[6];             /* volser, EBCDIC               */
13926f2bbd6SEugene (jno) Dvurechenski     uint8_t reserved[69];       /* reserved, 0x40               */
14026f2bbd6SEugene (jno) Dvurechenski     uint8_t LDL_version;        /* 0x40 or 0xF2                 */
14126f2bbd6SEugene (jno) Dvurechenski     uint64_t formatted_blocks;  /* if LDL_version >= 0xF2       */
14226f2bbd6SEugene (jno) Dvurechenski } __attribute__ ((packed)) LDL_VTOC;
14326f2bbd6SEugene (jno) Dvurechenski 
14426f2bbd6SEugene (jno) Dvurechenski typedef struct format_date {
14526f2bbd6SEugene (jno) Dvurechenski     uint8_t YY;
14626f2bbd6SEugene (jno) Dvurechenski     uint8_t MM;
14726f2bbd6SEugene (jno) Dvurechenski     uint8_t DD;
14826f2bbd6SEugene (jno) Dvurechenski     uint8_t hh;
14926f2bbd6SEugene (jno) Dvurechenski     uint8_t mm;
15026f2bbd6SEugene (jno) Dvurechenski     uint8_t ss;
15126f2bbd6SEugene (jno) Dvurechenski } __attribute__ ((packed)) format_date_t;
15226f2bbd6SEugene (jno) Dvurechenski 
15326f2bbd6SEugene (jno) Dvurechenski typedef struct CMS_VTOC {       /* @ rec.3 cyl.0 trk.0 for ECKD */
15426f2bbd6SEugene (jno) Dvurechenski                                 /* @ blk.1 (zero based) for FBA */
15526f2bbd6SEugene (jno) Dvurechenski     char magic[4];              /* 'CMS1', EBCDIC               */
15626f2bbd6SEugene (jno) Dvurechenski     char volser[6];             /* volser, EBCDIC               */
15726f2bbd6SEugene (jno) Dvurechenski     uint16_t version;           /* = 0                          */
15826f2bbd6SEugene (jno) Dvurechenski     uint32_t block_size;        /* = 512, 1024, 2048, or 4096   */
15926f2bbd6SEugene (jno) Dvurechenski     uint32_t disk_origin;       /* = 4 or 5                     */
16026f2bbd6SEugene (jno) Dvurechenski     uint32_t blocks;            /* Number of usable cyls/blocks */
16126f2bbd6SEugene (jno) Dvurechenski     uint32_t formatted;         /* Max number of fmtd cyls/blks */
16226f2bbd6SEugene (jno) Dvurechenski     uint32_t CMS_blocks;        /* disk size in CMS blocks      */
16326f2bbd6SEugene (jno) Dvurechenski     uint32_t CMS_used;          /* Number of CMS blocks in use  */
16426f2bbd6SEugene (jno) Dvurechenski     uint32_t FST_size;          /* = 64, bytes                  */
16526f2bbd6SEugene (jno) Dvurechenski     uint32_t FST_per_CMS_blk;   /*                              */
16626f2bbd6SEugene (jno) Dvurechenski     format_date_t format_date;  /* YYMMDDhhmmss as 6 bytes      */
16726f2bbd6SEugene (jno) Dvurechenski     uint8_t reserved1[2];       /* = 0                          */
16826f2bbd6SEugene (jno) Dvurechenski     uint32_t offset;            /* disk offset when reserved    */
16926f2bbd6SEugene (jno) Dvurechenski     uint32_t next_hole;         /* block nr                     */
17026f2bbd6SEugene (jno) Dvurechenski     uint32_t HBLK_hole_offset;  /* >> HBLK data of next hole    */
17126f2bbd6SEugene (jno) Dvurechenski     uint32_t alloc_map_usr_off; /* >> user part of Alloc map    */
17226f2bbd6SEugene (jno) Dvurechenski     uint8_t reserved2[4];       /* = 0                          */
17326f2bbd6SEugene (jno) Dvurechenski     char shared_seg_name[8];    /*                              */
17426f2bbd6SEugene (jno) Dvurechenski } __attribute__ ((packed)) CMS_VTOC;
17526f2bbd6SEugene (jno) Dvurechenski 
17626f2bbd6SEugene (jno) Dvurechenski /* from zipl/include/boot.h */
17726f2bbd6SEugene (jno) Dvurechenski typedef struct BootInfoBpIpl {
17826f2bbd6SEugene (jno) Dvurechenski     union {
17926f2bbd6SEugene (jno) Dvurechenski         ExtEckdBlockPtr eckd;
18026f2bbd6SEugene (jno) Dvurechenski         ScsiBlockPtr linr;
18126f2bbd6SEugene (jno) Dvurechenski     } bm_ptr;
18226f2bbd6SEugene (jno) Dvurechenski     uint8_t unused[16];
18326f2bbd6SEugene (jno) Dvurechenski } __attribute__ ((packed)) BootInfoBpIpl;
18426f2bbd6SEugene (jno) Dvurechenski 
18526f2bbd6SEugene (jno) Dvurechenski typedef struct EckdDumpParam {
18626f2bbd6SEugene (jno) Dvurechenski     uint32_t        start_blk;
18726f2bbd6SEugene (jno) Dvurechenski     uint32_t        end_blk;
18826f2bbd6SEugene (jno) Dvurechenski     uint16_t        blocksize;
18926f2bbd6SEugene (jno) Dvurechenski     uint8_t         num_heads;
19026f2bbd6SEugene (jno) Dvurechenski     uint8_t         bpt;
19126f2bbd6SEugene (jno) Dvurechenski     char            reserved[4];
19226f2bbd6SEugene (jno) Dvurechenski } __attribute((packed, may_alias)) EckdDumpParam;
19326f2bbd6SEugene (jno) Dvurechenski 
19426f2bbd6SEugene (jno) Dvurechenski typedef struct FbaDumpParam {
19526f2bbd6SEugene (jno) Dvurechenski     uint64_t        start_blk;
19626f2bbd6SEugene (jno) Dvurechenski     uint64_t        blockct;
19726f2bbd6SEugene (jno) Dvurechenski } __attribute((packed)) FbaDumpParam;
19826f2bbd6SEugene (jno) Dvurechenski 
19926f2bbd6SEugene (jno) Dvurechenski typedef struct BootInfoBpDump {
20026f2bbd6SEugene (jno) Dvurechenski     union {
20126f2bbd6SEugene (jno) Dvurechenski         EckdDumpParam eckd;
20226f2bbd6SEugene (jno) Dvurechenski         FbaDumpParam fba;
20326f2bbd6SEugene (jno) Dvurechenski     } param;
20426f2bbd6SEugene (jno) Dvurechenski     uint8_t         unused[16];
20526f2bbd6SEugene (jno) Dvurechenski } __attribute__ ((packed)) BootInfoBpDump;
20626f2bbd6SEugene (jno) Dvurechenski 
20726f2bbd6SEugene (jno) Dvurechenski typedef struct BootInfo {          /* @ 0x70, record #0    */
20826f2bbd6SEugene (jno) Dvurechenski     unsigned char magic[4]; /* = 'zIPL', ASCII      */
20926f2bbd6SEugene (jno) Dvurechenski     uint8_t version;        /* = 1                  */
21026f2bbd6SEugene (jno) Dvurechenski #define BOOT_INFO_VERSION               1
21126f2bbd6SEugene (jno) Dvurechenski     uint8_t bp_type;        /* = 0                  */
21226f2bbd6SEugene (jno) Dvurechenski #define BOOT_INFO_BP_TYPE_IPL           0x00
21326f2bbd6SEugene (jno) Dvurechenski #define BOOT_INFO_BP_TYPE_DUMP          0x01
21426f2bbd6SEugene (jno) Dvurechenski     uint8_t dev_type;       /* = 0                  */
21526f2bbd6SEugene (jno) Dvurechenski #define BOOT_INFO_DEV_TYPE_ECKD         0x00
21626f2bbd6SEugene (jno) Dvurechenski #define BOOT_INFO_DEV_TYPE_FBA          0x01
21726f2bbd6SEugene (jno) Dvurechenski     uint8_t flags;          /* = 1                  */
21826f2bbd6SEugene (jno) Dvurechenski #ifdef __s390x__
21926f2bbd6SEugene (jno) Dvurechenski #define BOOT_INFO_FLAGS_ARCH            0x01
22026f2bbd6SEugene (jno) Dvurechenski #else
22126f2bbd6SEugene (jno) Dvurechenski #define BOOT_INFO_FLAGS_ARCH            0x00
22226f2bbd6SEugene (jno) Dvurechenski #endif
22326f2bbd6SEugene (jno) Dvurechenski     union {
22426f2bbd6SEugene (jno) Dvurechenski         BootInfoBpDump dump;
22526f2bbd6SEugene (jno) Dvurechenski         BootInfoBpIpl ipl;
22626f2bbd6SEugene (jno) Dvurechenski     } bp;
22726f2bbd6SEugene (jno) Dvurechenski } __attribute__ ((packed)) BootInfo; /* see also XEckdMbr   */
22826f2bbd6SEugene (jno) Dvurechenski 
22926f2bbd6SEugene (jno) Dvurechenski typedef struct Ipl1 {
23026f2bbd6SEugene (jno) Dvurechenski     unsigned char key[4]; /* == "IPL1" */
23126f2bbd6SEugene (jno) Dvurechenski     unsigned char data[24];
23226f2bbd6SEugene (jno) Dvurechenski } __attribute__((packed)) Ipl1;
23326f2bbd6SEugene (jno) Dvurechenski 
23426f2bbd6SEugene (jno) Dvurechenski typedef struct Ipl2 {
23526f2bbd6SEugene (jno) Dvurechenski     unsigned char key[4]; /* == "IPL2" */
23626f2bbd6SEugene (jno) Dvurechenski     union {
23726f2bbd6SEugene (jno) Dvurechenski         unsigned char data[144];
23826f2bbd6SEugene (jno) Dvurechenski         struct {
23926f2bbd6SEugene (jno) Dvurechenski             unsigned char reserved1[92-4];
24026f2bbd6SEugene (jno) Dvurechenski             XEckdMbr mbr;
24126f2bbd6SEugene (jno) Dvurechenski             unsigned char reserved2[144-(92-4)-sizeof(XEckdMbr)];
24226f2bbd6SEugene (jno) Dvurechenski         } x;
24326f2bbd6SEugene (jno) Dvurechenski     } u;
24426f2bbd6SEugene (jno) Dvurechenski } __attribute__((packed)) Ipl2;
24526f2bbd6SEugene (jno) Dvurechenski 
24626f2bbd6SEugene (jno) Dvurechenski typedef struct IplVolumeLabel {
24726f2bbd6SEugene (jno) Dvurechenski     unsigned char key[4]; /* == "VOL1" */
24826f2bbd6SEugene (jno) Dvurechenski     union {
24926f2bbd6SEugene (jno) Dvurechenski         unsigned char data[80];
25026f2bbd6SEugene (jno) Dvurechenski         struct {
25126f2bbd6SEugene (jno) Dvurechenski             unsigned char key[4]; /* == "VOL1" */
25226f2bbd6SEugene (jno) Dvurechenski             unsigned char volser[6];
25326f2bbd6SEugene (jno) Dvurechenski             unsigned char reserved[6];
25426f2bbd6SEugene (jno) Dvurechenski         } f;
25526f2bbd6SEugene (jno) Dvurechenski     };
25626f2bbd6SEugene (jno) Dvurechenski } __attribute__((packed)) IplVolumeLabel;
25726f2bbd6SEugene (jno) Dvurechenski 
258564e52b9SEugene (jno) Dvurechenski typedef enum {
259564e52b9SEugene (jno) Dvurechenski     ECKD_NO_IPL,
260564e52b9SEugene (jno) Dvurechenski     ECKD_CMS,
261564e52b9SEugene (jno) Dvurechenski     ECKD_LDL,
26214f56a2eSEugene (jno) Dvurechenski     ECKD_LDL_UNLABELED,
263564e52b9SEugene (jno) Dvurechenski } ECKD_IPL_mode_t;
264564e52b9SEugene (jno) Dvurechenski 
265a94b485eSEugene (jno) Dvurechenski /* utility code below */
266a94b485eSEugene (jno) Dvurechenski 
267a94b485eSEugene (jno) Dvurechenski static inline void IPL_assert(bool term, const char *message)
268a94b485eSEugene (jno) Dvurechenski {
269a94b485eSEugene (jno) Dvurechenski     if (!term) {
270a94b485eSEugene (jno) Dvurechenski         sclp_print("\n! ");
271a94b485eSEugene (jno) Dvurechenski         sclp_print(message);
272a94b485eSEugene (jno) Dvurechenski         virtio_panic(" !\n"); /* no return */
273a94b485eSEugene (jno) Dvurechenski     }
274a94b485eSEugene (jno) Dvurechenski }
275a94b485eSEugene (jno) Dvurechenski 
276a94b485eSEugene (jno) Dvurechenski static const unsigned char ebc2asc[256] =
277a94b485eSEugene (jno) Dvurechenski       /* 0123456789abcdef0123456789abcdef */
278a94b485eSEugene (jno) Dvurechenski         "................................" /* 1F */
279a94b485eSEugene (jno) Dvurechenski         "................................" /* 3F */
280a94b485eSEugene (jno) Dvurechenski         " ...........<(+|&.........!$*);." /* 5F first.chr.here.is.real.space */
281a94b485eSEugene (jno) Dvurechenski         "-/.........,%_>?.........`:#@'=\""/* 7F */
282a94b485eSEugene (jno) Dvurechenski         ".abcdefghi.......jklmnopqr......" /* 9F */
283a94b485eSEugene (jno) Dvurechenski         "..stuvwxyz......................" /* BF */
284a94b485eSEugene (jno) Dvurechenski         ".ABCDEFGHI.......JKLMNOPQR......" /* DF */
285a94b485eSEugene (jno) Dvurechenski         "..STUVWXYZ......0123456789......";/* FF */
286a94b485eSEugene (jno) Dvurechenski 
287a94b485eSEugene (jno) Dvurechenski static inline void ebcdic_to_ascii(const char *src,
288a94b485eSEugene (jno) Dvurechenski                                    char *dst,
289a94b485eSEugene (jno) Dvurechenski                                    unsigned int size)
290a94b485eSEugene (jno) Dvurechenski {
291a94b485eSEugene (jno) Dvurechenski     unsigned int i;
292a94b485eSEugene (jno) Dvurechenski     for (i = 0; i < size; i++) {
293a94b485eSEugene (jno) Dvurechenski         unsigned c = src[i];
294a94b485eSEugene (jno) Dvurechenski         dst[i] = ebc2asc[c];
295a94b485eSEugene (jno) Dvurechenski     }
296a94b485eSEugene (jno) Dvurechenski }
297a94b485eSEugene (jno) Dvurechenski 
298a94b485eSEugene (jno) Dvurechenski static inline void print_volser(const void *volser)
299a94b485eSEugene (jno) Dvurechenski {
300a94b485eSEugene (jno) Dvurechenski     char ascii[8];
301a94b485eSEugene (jno) Dvurechenski 
302a94b485eSEugene (jno) Dvurechenski     ebcdic_to_ascii((char *)volser, ascii, 6);
303a94b485eSEugene (jno) Dvurechenski     ascii[6] = '\0';
304a94b485eSEugene (jno) Dvurechenski     sclp_print("VOLSER=[");
305a94b485eSEugene (jno) Dvurechenski     sclp_print(ascii);
306a94b485eSEugene (jno) Dvurechenski     sclp_print("]\n");
307a94b485eSEugene (jno) Dvurechenski }
308a94b485eSEugene (jno) Dvurechenski 
309a94b485eSEugene (jno) Dvurechenski static inline bool unused_space(const void *p, size_t size)
310a94b485eSEugene (jno) Dvurechenski {
311a94b485eSEugene (jno) Dvurechenski     size_t i;
312a94b485eSEugene (jno) Dvurechenski     const unsigned char *m = p;
313a94b485eSEugene (jno) Dvurechenski 
314a94b485eSEugene (jno) Dvurechenski     for (i = 0; i < size; i++) {
315a94b485eSEugene (jno) Dvurechenski         if (m[i] != FREE_SPACE_FILLER) {
316a94b485eSEugene (jno) Dvurechenski             return false;
317a94b485eSEugene (jno) Dvurechenski         }
318a94b485eSEugene (jno) Dvurechenski     }
319a94b485eSEugene (jno) Dvurechenski     return true;
320a94b485eSEugene (jno) Dvurechenski }
321a94b485eSEugene (jno) Dvurechenski 
322a94b485eSEugene (jno) Dvurechenski static inline bool is_null_block_number(block_number_t x)
323a94b485eSEugene (jno) Dvurechenski {
324a94b485eSEugene (jno) Dvurechenski     return x == NULL_BLOCK_NR;
325a94b485eSEugene (jno) Dvurechenski }
326a94b485eSEugene (jno) Dvurechenski 
327a94b485eSEugene (jno) Dvurechenski static inline void read_block(block_number_t blockno,
328a94b485eSEugene (jno) Dvurechenski                               void *buffer,
329a94b485eSEugene (jno) Dvurechenski                               const char *errmsg)
330a94b485eSEugene (jno) Dvurechenski {
331a94b485eSEugene (jno) Dvurechenski     IPL_assert(virtio_read(blockno, buffer) == 0, errmsg);
332a94b485eSEugene (jno) Dvurechenski }
333a94b485eSEugene (jno) Dvurechenski 
334a94b485eSEugene (jno) Dvurechenski static inline bool block_size_ok(uint32_t block_size)
335a94b485eSEugene (jno) Dvurechenski {
336a94b485eSEugene (jno) Dvurechenski     return block_size == virtio_get_block_size();
337a94b485eSEugene (jno) Dvurechenski }
338a94b485eSEugene (jno) Dvurechenski 
339a94b485eSEugene (jno) Dvurechenski static inline bool magic_match(const void *data, const void *magic)
340a94b485eSEugene (jno) Dvurechenski {
341a94b485eSEugene (jno) Dvurechenski     return *((uint32_t *)data) == *((uint32_t *)magic);
342a94b485eSEugene (jno) Dvurechenski }
343a94b485eSEugene (jno) Dvurechenski 
344866cac91SMaxim Samoylov static inline int _memcmp(const void *s1, const void *s2, size_t n)
345866cac91SMaxim Samoylov {
346866cac91SMaxim Samoylov     int i;
347866cac91SMaxim Samoylov     const uint8_t *p1 = s1, *p2 = s2;
348866cac91SMaxim Samoylov 
349866cac91SMaxim Samoylov     for (i = 0; i < n; i++) {
350866cac91SMaxim Samoylov         if (p1[i] != p2[i]) {
351866cac91SMaxim Samoylov             return p1[i] > p2[i] ? 1 : -1;
352866cac91SMaxim Samoylov         }
353866cac91SMaxim Samoylov     }
354866cac91SMaxim Samoylov 
355866cac91SMaxim Samoylov     return 0;
356866cac91SMaxim Samoylov }
357866cac91SMaxim Samoylov 
358866cac91SMaxim Samoylov /* from include/qemu/bswap.h */
359866cac91SMaxim Samoylov 
360866cac91SMaxim Samoylov /* El Torito is always little-endian */
361866cac91SMaxim Samoylov static inline uint16_t bswap16(uint16_t x)
362866cac91SMaxim Samoylov {
363866cac91SMaxim Samoylov     return ((x & 0x00ff) << 8) | ((x & 0xff00) >> 8);
364866cac91SMaxim Samoylov }
365866cac91SMaxim Samoylov 
366866cac91SMaxim Samoylov static inline uint32_t bswap32(uint32_t x)
367866cac91SMaxim Samoylov {
368866cac91SMaxim Samoylov     return ((x & 0x000000ffU) << 24) | ((x & 0x0000ff00U) <<  8) |
369866cac91SMaxim Samoylov            ((x & 0x00ff0000U) >>  8) | ((x & 0xff000000U) >> 24);
370866cac91SMaxim Samoylov }
371866cac91SMaxim Samoylov 
372866cac91SMaxim Samoylov static inline uint64_t bswap64(uint64_t x)
373866cac91SMaxim Samoylov {
374866cac91SMaxim Samoylov     return ((x & 0x00000000000000ffULL) << 56) |
375866cac91SMaxim Samoylov            ((x & 0x000000000000ff00ULL) << 40) |
376866cac91SMaxim Samoylov            ((x & 0x0000000000ff0000ULL) << 24) |
377866cac91SMaxim Samoylov            ((x & 0x00000000ff000000ULL) <<  8) |
378866cac91SMaxim Samoylov            ((x & 0x000000ff00000000ULL) >>  8) |
379866cac91SMaxim Samoylov            ((x & 0x0000ff0000000000ULL) >> 24) |
380866cac91SMaxim Samoylov            ((x & 0x00ff000000000000ULL) >> 40) |
381866cac91SMaxim Samoylov            ((x & 0xff00000000000000ULL) >> 56);
382866cac91SMaxim Samoylov }
383866cac91SMaxim Samoylov 
384*869648e8SMaxim Samoylov static inline uint32_t iso_733_to_u32(uint64_t x)
385*869648e8SMaxim Samoylov {
386*869648e8SMaxim Samoylov     return (uint32_t)x;
387*869648e8SMaxim Samoylov }
388*869648e8SMaxim Samoylov 
389866cac91SMaxim Samoylov #define ISO_SECTOR_SIZE 2048
390866cac91SMaxim Samoylov /* El Torito specifies boot image size in 512 byte blocks */
391866cac91SMaxim Samoylov #define ET_SECTOR_SHIFT 2
392866cac91SMaxim Samoylov #define KERN_IMAGE_START 0x010000UL
393866cac91SMaxim Samoylov #define PSW_MASK_64 0x0000000100000000ULL
394866cac91SMaxim Samoylov #define PSW_MASK_32 0x0000000080000000ULL
395866cac91SMaxim Samoylov #define IPL_PSW_MASK (PSW_MASK_32 | PSW_MASK_64)
396866cac91SMaxim Samoylov 
397866cac91SMaxim Samoylov #define ISO_PRIMARY_VD_SECTOR 16
398866cac91SMaxim Samoylov 
399866cac91SMaxim Samoylov static inline void read_iso_sector(uint32_t block_offset, void *buf,
400866cac91SMaxim Samoylov                                    const char *errmsg)
401866cac91SMaxim Samoylov {
402866cac91SMaxim Samoylov     IPL_assert(virtio_read_many(block_offset, buf, 1) == 0, errmsg);
403866cac91SMaxim Samoylov }
404866cac91SMaxim Samoylov 
405866cac91SMaxim Samoylov static inline void read_iso_boot_image(uint32_t block_offset, void *load_addr,
406866cac91SMaxim Samoylov                                        uint32_t blks_to_load)
407866cac91SMaxim Samoylov {
408866cac91SMaxim Samoylov     IPL_assert(virtio_read_many(block_offset, load_addr, blks_to_load) == 0,
409866cac91SMaxim Samoylov                "Failed to read boot image!");
410866cac91SMaxim Samoylov }
411866cac91SMaxim Samoylov 
412866cac91SMaxim Samoylov const uint8_t el_torito_magic[] = "EL TORITO SPECIFICATION"
413866cac91SMaxim Samoylov                                   "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
414866cac91SMaxim Samoylov 
415*869648e8SMaxim Samoylov #define ISO9660_MAX_DIR_DEPTH 8
416*869648e8SMaxim Samoylov 
417866cac91SMaxim Samoylov typedef struct IsoDirHdr {
418866cac91SMaxim Samoylov     uint8_t dr_len;
419866cac91SMaxim Samoylov     uint8_t ear_len;
420866cac91SMaxim Samoylov     uint64_t ext_loc;
421866cac91SMaxim Samoylov     uint64_t data_len;
422866cac91SMaxim Samoylov     uint8_t recording_datetime[7];
423866cac91SMaxim Samoylov     uint8_t file_flags;
424866cac91SMaxim Samoylov     uint8_t file_unit_size;
425866cac91SMaxim Samoylov     uint8_t gap_size;
426866cac91SMaxim Samoylov     uint32_t vol_seqnum;
427866cac91SMaxim Samoylov     uint8_t fileid_len;
428866cac91SMaxim Samoylov } __attribute__((packed)) IsoDirHdr;
429866cac91SMaxim Samoylov 
430866cac91SMaxim Samoylov typedef struct IsoVdElTorito {
431866cac91SMaxim Samoylov     uint8_t el_torito[32]; /* must contain el_torito_magic value */
432866cac91SMaxim Samoylov     uint8_t unused0[32];
433866cac91SMaxim Samoylov     uint32_t bc_offset;
434866cac91SMaxim Samoylov     uint8_t unused1[1974];
435866cac91SMaxim Samoylov } __attribute__((packed)) IsoVdElTorito;
436866cac91SMaxim Samoylov 
437866cac91SMaxim Samoylov typedef struct IsoVdPrimary {
438866cac91SMaxim Samoylov     uint8_t unused1;
439866cac91SMaxim Samoylov     uint8_t sys_id[32];
440866cac91SMaxim Samoylov     uint8_t vol_id[32];
441866cac91SMaxim Samoylov     uint8_t unused2[8];
442866cac91SMaxim Samoylov     uint64_t vol_space_size;
443866cac91SMaxim Samoylov     uint8_t unused3[32];
444866cac91SMaxim Samoylov     uint32_t vol_set_size;
445866cac91SMaxim Samoylov     uint32_t vol_seqnum;
446866cac91SMaxim Samoylov     uint32_t log_block_size;
447866cac91SMaxim Samoylov     uint64_t path_table_size;
448866cac91SMaxim Samoylov     uint32_t l_path_table;
449866cac91SMaxim Samoylov     uint32_t opt_l_path_table;
450866cac91SMaxim Samoylov     uint32_t m_path_table;
451866cac91SMaxim Samoylov     uint32_t opt_m_path_table;
452866cac91SMaxim Samoylov     IsoDirHdr rootdir;
453866cac91SMaxim Samoylov     uint8_t root_null;
454866cac91SMaxim Samoylov     uint8_t reserved2[1858];
455866cac91SMaxim Samoylov } __attribute__((packed)) IsoVdPrimary;
456866cac91SMaxim Samoylov 
457866cac91SMaxim Samoylov typedef struct IsoVolDesc {
458866cac91SMaxim Samoylov     uint8_t type;
459866cac91SMaxim Samoylov     uint8_t ident[5];
460866cac91SMaxim Samoylov     uint8_t version;
461866cac91SMaxim Samoylov     union {
462866cac91SMaxim Samoylov         IsoVdElTorito boot;
463866cac91SMaxim Samoylov         IsoVdPrimary primary;
464866cac91SMaxim Samoylov     } vd;
465866cac91SMaxim Samoylov } __attribute__((packed)) IsoVolDesc;
466866cac91SMaxim Samoylov 
467866cac91SMaxim Samoylov const uint8_t vol_desc_magic[] = "CD001";
468866cac91SMaxim Samoylov #define VOL_DESC_TYPE_BOOT 0
469866cac91SMaxim Samoylov #define VOL_DESC_TYPE_PRIMARY 1
470866cac91SMaxim Samoylov #define VOL_DESC_TYPE_SUPPLEMENT 2
471866cac91SMaxim Samoylov #define VOL_DESC_TYPE_PARTITION 3
472866cac91SMaxim Samoylov #define VOL_DESC_TERMINATOR 255
473866cac91SMaxim Samoylov 
474866cac91SMaxim Samoylov static inline bool is_iso_vd_valid(IsoVolDesc *vd)
475866cac91SMaxim Samoylov {
476866cac91SMaxim Samoylov     return !_memcmp(&vd->ident[0], vol_desc_magic, 5) &&
477866cac91SMaxim Samoylov            vd->version == 0x1 &&
478866cac91SMaxim Samoylov            vd->type <= VOL_DESC_TYPE_PARTITION;
479866cac91SMaxim Samoylov }
480866cac91SMaxim Samoylov 
481866cac91SMaxim Samoylov typedef struct IsoBcValid {
482866cac91SMaxim Samoylov     uint8_t platform_id;
483866cac91SMaxim Samoylov     uint16_t reserved;
484866cac91SMaxim Samoylov     uint8_t id[24];
485866cac91SMaxim Samoylov     uint16_t checksum;
486866cac91SMaxim Samoylov     uint8_t key[2];
487866cac91SMaxim Samoylov } __attribute__((packed)) IsoBcValid;
488866cac91SMaxim Samoylov 
489866cac91SMaxim Samoylov typedef struct IsoBcSection {
490866cac91SMaxim Samoylov     uint8_t boot_type;
491866cac91SMaxim Samoylov     uint16_t load_segment;
492866cac91SMaxim Samoylov     uint8_t sys_type;
493866cac91SMaxim Samoylov     uint8_t unused;
494866cac91SMaxim Samoylov     uint16_t sector_count;
495866cac91SMaxim Samoylov     uint32_t load_rba;
496866cac91SMaxim Samoylov     uint8_t selection[20];
497866cac91SMaxim Samoylov } __attribute__((packed)) IsoBcSection;
498866cac91SMaxim Samoylov 
499866cac91SMaxim Samoylov typedef struct IsoBcHdr {
500866cac91SMaxim Samoylov     uint8_t platform_id;
501866cac91SMaxim Samoylov     uint16_t sect_num;
502866cac91SMaxim Samoylov     uint8_t id[28];
503866cac91SMaxim Samoylov } __attribute__((packed)) IsoBcHdr;
504866cac91SMaxim Samoylov 
505ba21f0ccSMaxim Samoylov /*
506ba21f0ccSMaxim Samoylov  * Match two CCWs located after PSW and eight filler bytes.
507ba21f0ccSMaxim Samoylov  * From libmagic and arch/s390/kernel/head.S.
508ba21f0ccSMaxim Samoylov  */
509ba21f0ccSMaxim Samoylov const uint8_t linux_s390_magic[] = "\x02\x00\x00\x18\x60\x00\x00\x50\x02\x00"
510ba21f0ccSMaxim Samoylov                                    "\x00\x68\x60\x00\x00\x50\x40\x40\x40\x40"
511ba21f0ccSMaxim Samoylov                                    "\x40\x40\x40\x40";
512ba21f0ccSMaxim Samoylov 
513866cac91SMaxim Samoylov typedef struct IsoBcEntry {
514866cac91SMaxim Samoylov     uint8_t id;
515866cac91SMaxim Samoylov     union {
516866cac91SMaxim Samoylov         IsoBcValid valid; /* id == 0x01 */
517866cac91SMaxim Samoylov         IsoBcSection sect; /* id == 0x88 || id == 0x0 */
518866cac91SMaxim Samoylov         IsoBcHdr hdr; /* id == 0x90 || id == 0x91 */
519866cac91SMaxim Samoylov     } body;
520866cac91SMaxim Samoylov } __attribute__((packed)) IsoBcEntry;
521866cac91SMaxim Samoylov 
522866cac91SMaxim Samoylov #define ISO_BC_ENTRY_PER_SECTOR (ISO_SECTOR_SIZE / sizeof(IsoBcEntry))
523866cac91SMaxim Samoylov #define ISO_BC_HDR_VALIDATION 0x01
524866cac91SMaxim Samoylov #define ISO_BC_BOOTABLE_SECTION 0x88
525866cac91SMaxim Samoylov #define ISO_BC_MAGIC_55 0x55
526866cac91SMaxim Samoylov #define ISO_BC_MAGIC_AA 0xaa
527866cac91SMaxim Samoylov #define ISO_BC_PLATFORM_X86 0x0
528866cac91SMaxim Samoylov #define ISO_BC_PLATFORM_PPC 0x1
529866cac91SMaxim Samoylov #define ISO_BC_PLATFORM_MAC 0x2
530866cac91SMaxim Samoylov 
531866cac91SMaxim Samoylov static inline bool is_iso_bc_valid(IsoBcEntry *e)
532866cac91SMaxim Samoylov {
533866cac91SMaxim Samoylov     IsoBcValid *v = &e->body.valid;
534866cac91SMaxim Samoylov 
535866cac91SMaxim Samoylov     if (e->id != ISO_BC_HDR_VALIDATION) {
536866cac91SMaxim Samoylov         return false;
537866cac91SMaxim Samoylov     }
538866cac91SMaxim Samoylov 
539866cac91SMaxim Samoylov     if (v->platform_id != ISO_BC_PLATFORM_X86 &&
540866cac91SMaxim Samoylov         v->platform_id != ISO_BC_PLATFORM_PPC &&
541866cac91SMaxim Samoylov         v->platform_id != ISO_BC_PLATFORM_MAC) {
542866cac91SMaxim Samoylov         return false;
543866cac91SMaxim Samoylov     }
544866cac91SMaxim Samoylov 
545866cac91SMaxim Samoylov     return v->key[0] == ISO_BC_MAGIC_55 &&
546866cac91SMaxim Samoylov            v->key[1] == ISO_BC_MAGIC_AA &&
547866cac91SMaxim Samoylov            v->reserved == 0x0;
548866cac91SMaxim Samoylov }
549866cac91SMaxim Samoylov 
55026f2bbd6SEugene (jno) Dvurechenski #endif /* _PC_BIOS_S390_CCW_BOOTMAP_H */
551