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