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