Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging
[qemu.git] / pc-bios / s390-ccw / bootmap.c
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 }