xref: /openbmc/qemu/pc-bios/s390-ccw/bootmap.c (revision 2c9b15ca)
1 /*
2  * QEMU S390 bootmap interpreter
3  *
4  * Copyright (c) 2009 Alexander Graf <agraf@suse.de>
5  *
6  * This work is licensed under the terms of the GNU GPL, version 2 or (at
7  * your option) any later version. See the COPYING file in the top-level
8  * directory.
9  */
10 
11 #include "s390-ccw.h"
12 
13 // #define DEBUG_FALLBACK
14 
15 #ifdef DEBUG_FALLBACK
16 #define dputs(txt) \
17     do { sclp_print("zipl: " txt); } while (0)
18 #else
19 #define dputs(fmt, ...) \
20     do { } while (0)
21 #endif
22 
23 struct scsi_blockptr {
24     uint64_t blockno;
25     uint16_t size;
26     uint16_t blockct;
27     uint8_t reserved[4];
28 } __attribute__ ((packed));
29 
30 struct component_entry {
31     struct scsi_blockptr data;
32     uint8_t pad[7];
33     uint8_t component_type;
34     uint64_t load_address;
35 } __attribute((packed));
36 
37 struct component_header {
38     uint8_t magic[4];
39     uint8_t type;
40     uint8_t reserved[27];
41 } __attribute((packed));
42 
43 struct mbr {
44     uint8_t magic[4];
45     uint32_t version_id;
46     uint8_t reserved[8];
47     struct scsi_blockptr blockptr;
48 } __attribute__ ((packed));
49 
50 #define ZIPL_MAGIC			"zIPL"
51 
52 #define ZIPL_COMP_HEADER_IPL		0x00
53 #define ZIPL_COMP_HEADER_DUMP		0x01
54 
55 #define ZIPL_COMP_ENTRY_LOAD		0x02
56 #define ZIPL_COMP_ENTRY_EXEC		0x01
57 
58 /* Scratch space */
59 static uint8_t sec[SECTOR_SIZE] __attribute__((__aligned__(SECTOR_SIZE)));
60 
61 /* Check for ZIPL magic. Returns 0 if not matched. */
62 static int zipl_magic(uint8_t *ptr)
63 {
64     uint32_t *p = (void*)ptr;
65     uint32_t *z = (void*)ZIPL_MAGIC;
66 
67     if (*p != *z) {
68         debug_print_int("invalid magic", *p);
69         virtio_panic("invalid magic");
70     }
71 
72     return 1;
73 }
74 
75 static int zipl_load_segment(struct component_entry *entry)
76 {
77     const int max_entries = (SECTOR_SIZE / sizeof(struct scsi_blockptr));
78     struct scsi_blockptr *bprs = (void*)sec;
79     uint64_t blockno;
80     long address;
81     int i;
82 
83     blockno = entry->data.blockno;
84     address = entry->load_address;
85 
86     debug_print_int("loading segment at block", blockno);
87     debug_print_int("addr", address);
88 
89     do {
90         if (virtio_read(blockno, (uint8_t *)bprs)) {
91             debug_print_int("failed reading bprs at", blockno);
92             goto fail;
93         }
94 
95         for (i = 0;; i++) {
96             u64 *cur_desc = (void*)&bprs[i];
97 
98             blockno = bprs[i].blockno;
99             if (!blockno)
100                 break;
101 
102             /* we need the updated blockno for the next indirect entry in the
103                chain, but don't want to advance address */
104             if (i == (max_entries - 1))
105                 break;
106 
107             address = virtio_load_direct(cur_desc[0], cur_desc[1], 0,
108                                          (void*)address);
109             if (address == -1)
110                 goto fail;
111         }
112     } while (blockno);
113 
114     return 0;
115 
116 fail:
117     sclp_print("failed loading segment\n");
118     return -1;
119 }
120 
121 /* Run a zipl program */
122 static int zipl_run(struct scsi_blockptr *pte)
123 {
124     struct component_header *header;
125     struct component_entry *entry;
126     void (*ipl)(void);
127     uint8_t tmp_sec[SECTOR_SIZE];
128 
129     virtio_read(pte->blockno, tmp_sec);
130     header = (struct component_header *)tmp_sec;
131 
132     if (!zipl_magic(tmp_sec)) {
133         goto fail;
134     }
135 
136     if (header->type != ZIPL_COMP_HEADER_IPL) {
137         goto fail;
138     }
139 
140     dputs("start loading images\n");
141 
142     /* Load image(s) into RAM */
143     entry = (struct component_entry *)(&header[1]);
144     while (entry->component_type == ZIPL_COMP_ENTRY_LOAD) {
145         if (zipl_load_segment(entry) < 0) {
146             goto fail;
147         }
148 
149         entry++;
150 
151         if ((uint8_t*)(&entry[1]) > (tmp_sec + SECTOR_SIZE)) {
152             goto fail;
153         }
154     }
155 
156     if (entry->component_type != ZIPL_COMP_ENTRY_EXEC) {
157         goto fail;
158     }
159 
160     /* Ensure the guest output starts fresh */
161     sclp_print("\n");
162 
163     /* And run the OS! */
164     ipl = (void*)(entry->load_address & 0x7fffffff);
165     debug_print_addr("set IPL addr to", ipl);
166     /* should not return */
167     ipl();
168 
169     return 0;
170 
171 fail:
172     sclp_print("failed running zipl\n");
173     return -1;
174 }
175 
176 int zipl_load(void)
177 {
178     struct mbr *mbr = (void*)sec;
179     uint8_t *ns, *ns_end;
180     int program_table_entries = 0;
181     int pte_len = sizeof(struct scsi_blockptr);
182     struct scsi_blockptr *prog_table_entry;
183     const char *error = "";
184 
185     /* Grab the MBR */
186     virtio_read(0, (void*)mbr);
187 
188     dputs("checking magic\n");
189 
190     if (!zipl_magic(mbr->magic)) {
191         error = "zipl_magic 1";
192         goto fail;
193     }
194 
195     debug_print_int("program table", mbr->blockptr.blockno);
196 
197     /* Parse the program table */
198     if (virtio_read(mbr->blockptr.blockno, sec)) {
199         error = "virtio_read";
200         goto fail;
201     }
202 
203     if (!zipl_magic(sec)) {
204         error = "zipl_magic 2";
205         goto fail;
206     }
207 
208     ns_end = sec + SECTOR_SIZE;
209     for (ns = (sec + pte_len); (ns + pte_len) < ns_end; ns++) {
210         prog_table_entry = (struct scsi_blockptr *)ns;
211         if (!prog_table_entry->blockno) {
212             break;
213         }
214 
215         program_table_entries++;
216     }
217 
218     debug_print_int("program table entries", program_table_entries);
219 
220     if (!program_table_entries) {
221         goto fail;
222     }
223 
224     /* Run the default entry */
225 
226     prog_table_entry = (struct scsi_blockptr *)(sec + pte_len);
227 
228     return zipl_run(prog_table_entry);
229 
230 fail:
231     sclp_print("failed loading zipl: ");
232     sclp_print(error);
233     sclp_print("\n");
234     return -1;
235 }
236