xref: /qemu/pc-bios/s390-ccw/bootmap.h (revision 5340eb07)
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