pc-bios/s390-ccw: do a subsystem reset before running the guest
[qemu.git] / pc-bios / s390-ccw / bootmap.c
blobc07553ba2ab23fe05cf0952a6643d81d2f691076
1 /*
2 * QEMU S390 bootmap interpreter
4 * Copyright (c) 2009 Alexander Graf <agraf@suse.de>
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 */
11 #include "s390-ccw.h"
13 // #define DEBUG_FALLBACK
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
23 struct scsi_blockptr {
24 uint64_t blockno;
25 uint16_t size;
26 uint16_t blockct;
27 uint8_t reserved[4];
28 } __attribute__ ((packed));
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));
37 struct component_header {
38 uint8_t magic[4];
39 uint8_t type;
40 uint8_t reserved[27];
41 } __attribute((packed));
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));
50 #define ZIPL_MAGIC "zIPL"
52 #define ZIPL_COMP_HEADER_IPL 0x00
53 #define ZIPL_COMP_HEADER_DUMP 0x01
55 #define ZIPL_COMP_ENTRY_LOAD 0x02
56 #define ZIPL_COMP_ENTRY_EXEC 0x01
58 /* Scratch space */
59 static uint8_t sec[SECTOR_SIZE] __attribute__((__aligned__(SECTOR_SIZE)));
61 typedef struct ResetInfo {
62 uint32_t ipl_mask;
63 uint32_t ipl_addr;
64 uint32_t ipl_continue;
65 } ResetInfo;
67 ResetInfo save;
69 static void jump_to_IPL_2(void)
71 ResetInfo *current = 0;
73 void (*ipl)(void) = (void *) (uint64_t) current->ipl_continue;
74 debug_print_addr("set IPL addr to", ipl);
76 /* Ensure the guest output starts fresh */
77 sclp_print("\n");
79 *current = save;
80 ipl(); /* should not return */
83 static void jump_to_IPL_code(uint64_t address)
86 * The IPL PSW is at address 0. We also must not overwrite the
87 * content of non-BIOS memory after we loaded the guest, so we
88 * save the original content and restore it in jump_to_IPL_2.
90 ResetInfo *current = 0;
92 save = *current;
93 current->ipl_addr = (uint32_t) (uint64_t) &jump_to_IPL_2;
94 current->ipl_continue = address & 0x7fffffff;
97 * HACK ALERT.
98 * We use the load normal reset to keep r15 unchanged. jump_to_IPL_2
99 * can then use r15 as its stack pointer.
101 asm volatile("lghi 1,1\n\t"
102 "diag 1,1,0x308\n\t"
103 : : : "1", "memory");
104 virtio_panic("\n! IPL returns !\n");
107 /* Check for ZIPL magic. Returns 0 if not matched. */
108 static int zipl_magic(uint8_t *ptr)
110 uint32_t *p = (void*)ptr;
111 uint32_t *z = (void*)ZIPL_MAGIC;
113 if (*p != *z) {
114 debug_print_int("invalid magic", *p);
115 virtio_panic("invalid magic");
118 return 1;
121 static int zipl_load_segment(struct component_entry *entry)
123 const int max_entries = (SECTOR_SIZE / sizeof(struct scsi_blockptr));
124 struct scsi_blockptr *bprs = (void*)sec;
125 uint64_t blockno;
126 long address;
127 int i;
129 blockno = entry->data.blockno;
130 address = entry->load_address;
132 debug_print_int("loading segment at block", blockno);
133 debug_print_int("addr", address);
135 do {
136 if (virtio_read(blockno, (uint8_t *)bprs)) {
137 debug_print_int("failed reading bprs at", blockno);
138 goto fail;
141 for (i = 0;; i++) {
142 u64 *cur_desc = (void*)&bprs[i];
144 blockno = bprs[i].blockno;
145 if (!blockno)
146 break;
148 /* we need the updated blockno for the next indirect entry in the
149 chain, but don't want to advance address */
150 if (i == (max_entries - 1))
151 break;
153 address = virtio_load_direct(cur_desc[0], cur_desc[1], 0,
154 (void*)address);
155 if (address == -1)
156 goto fail;
158 } while (blockno);
160 return 0;
162 fail:
163 sclp_print("failed loading segment\n");
164 return -1;
167 /* Run a zipl program */
168 static int zipl_run(struct scsi_blockptr *pte)
170 struct component_header *header;
171 struct component_entry *entry;
172 uint8_t tmp_sec[SECTOR_SIZE];
174 virtio_read(pte->blockno, tmp_sec);
175 header = (struct component_header *)tmp_sec;
177 if (!zipl_magic(tmp_sec)) {
178 goto fail;
181 if (header->type != ZIPL_COMP_HEADER_IPL) {
182 goto fail;
185 dputs("start loading images\n");
187 /* Load image(s) into RAM */
188 entry = (struct component_entry *)(&header[1]);
189 while (entry->component_type == ZIPL_COMP_ENTRY_LOAD) {
190 if (zipl_load_segment(entry) < 0) {
191 goto fail;
194 entry++;
196 if ((uint8_t*)(&entry[1]) > (tmp_sec + SECTOR_SIZE)) {
197 goto fail;
201 if (entry->component_type != ZIPL_COMP_ENTRY_EXEC) {
202 goto fail;
205 /* should not return */
206 jump_to_IPL_code(entry->load_address);
208 return 0;
210 fail:
211 sclp_print("failed running zipl\n");
212 return -1;
215 int zipl_load(void)
217 struct mbr *mbr = (void*)sec;
218 uint8_t *ns, *ns_end;
219 int program_table_entries = 0;
220 int pte_len = sizeof(struct scsi_blockptr);
221 struct scsi_blockptr *prog_table_entry;
222 const char *error = "";
224 /* Grab the MBR */
225 virtio_read(0, (void*)mbr);
227 dputs("checking magic\n");
229 if (!zipl_magic(mbr->magic)) {
230 error = "zipl_magic 1";
231 goto fail;
234 debug_print_int("program table", mbr->blockptr.blockno);
236 /* Parse the program table */
237 if (virtio_read(mbr->blockptr.blockno, sec)) {
238 error = "virtio_read";
239 goto fail;
242 if (!zipl_magic(sec)) {
243 error = "zipl_magic 2";
244 goto fail;
247 ns_end = sec + SECTOR_SIZE;
248 for (ns = (sec + pte_len); (ns + pte_len) < ns_end; ns++) {
249 prog_table_entry = (struct scsi_blockptr *)ns;
250 if (!prog_table_entry->blockno) {
251 break;
254 program_table_entries++;
257 debug_print_int("program table entries", program_table_entries);
259 if (!program_table_entries) {
260 goto fail;
263 /* Run the default entry */
265 prog_table_entry = (struct scsi_blockptr *)(sec + pte_len);
267 return zipl_run(prog_table_entry);
269 fail:
270 sclp_print("failed loading zipl: ");
271 sclp_print(error);
272 sclp_print("\n");
273 return -1;