]> Git Repo - qemu.git/blob - pc-bios/s390-ccw/bootmap.c
pc-bios/s390-ccw: add some utility code
[qemu.git] / pc-bios / s390-ccw / bootmap.c
1 /*
2  * QEMU S390 bootmap interpreter
3  *
4  * Copyright (c) 2009 Alexander Graf <[email protected]>
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 #include "bootmap.h"
13 #include "virtio.h"
14
15 /* #define DEBUG_FALLBACK */
16
17 #ifdef DEBUG_FALLBACK
18 #define dputs(txt) \
19     do { sclp_print("zipl: " txt); } while (0)
20 #else
21 #define dputs(fmt, ...) \
22     do { } while (0)
23 #endif
24
25 /* Scratch space */
26 static uint8_t sec[MAX_SECTOR_SIZE]
27 __attribute__((__aligned__(MAX_SECTOR_SIZE)));
28
29 typedef struct ResetInfo {
30     uint32_t ipl_mask;
31     uint32_t ipl_addr;
32     uint32_t ipl_continue;
33 } ResetInfo;
34
35 ResetInfo save;
36
37 static void jump_to_IPL_2(void)
38 {
39     ResetInfo *current = 0;
40
41     void (*ipl)(void) = (void *) (uint64_t) current->ipl_continue;
42     debug_print_addr("set IPL addr to", ipl);
43
44     /* Ensure the guest output starts fresh */
45     sclp_print("\n");
46
47     *current = save;
48     ipl(); /* should not return */
49 }
50
51 static void jump_to_IPL_code(uint64_t address)
52 {
53     /*
54      * The IPL PSW is at address 0. We also must not overwrite the
55      * content of non-BIOS memory after we loaded the guest, so we
56      * save the original content and restore it in jump_to_IPL_2.
57      */
58     ResetInfo *current = 0;
59
60     save = *current;
61     current->ipl_addr = (uint32_t) (uint64_t) &jump_to_IPL_2;
62     current->ipl_continue = address & 0x7fffffff;
63
64     /*
65      * HACK ALERT.
66      * We use the load normal reset to keep r15 unchanged. jump_to_IPL_2
67      * can then use r15 as its stack pointer.
68      */
69     asm volatile("lghi 1,1\n\t"
70                  "diag 1,1,0x308\n\t"
71                  : : : "1", "memory");
72     virtio_panic("\n! IPL returns !\n");
73 }
74
75 /* Check for ZIPL magic. Returns 0 if not matched. */
76 static int zipl_magic(uint8_t *ptr)
77 {
78     uint32_t *p = (void *)ptr;
79     uint32_t *z = (void *)ZIPL_MAGIC;
80
81     if (*p != *z) {
82         debug_print_int("invalid magic", *p);
83         virtio_panic("invalid magic");
84     }
85
86     return 1;
87 }
88
89 static int zipl_load_segment(ComponentEntry *entry)
90 {
91     const int max_entries = (MAX_SECTOR_SIZE / sizeof(ScsiBlockPtr));
92     ScsiBlockPtr *bprs = (void *)sec;
93     const int bprs_size = sizeof(sec);
94     block_number_t blockno;
95     long address;
96     int i;
97
98     blockno = entry->data.blockno;
99     address = entry->load_address;
100
101     debug_print_int("loading segment at block", blockno);
102     debug_print_int("addr", address);
103
104     do {
105         memset(bprs, FREE_SPACE_FILLER, bprs_size);
106         if (virtio_read(blockno, (uint8_t *)bprs)) {
107             debug_print_int("failed reading bprs at", blockno);
108             goto fail;
109         }
110
111         for (i = 0;; i++) {
112             u64 *cur_desc = (void *)&bprs[i];
113
114             blockno = bprs[i].blockno;
115             if (!blockno) {
116                 break;
117             }
118
119             /* we need the updated blockno for the next indirect entry in the
120                chain, but don't want to advance address */
121             if (i == (max_entries - 1)) {
122                 break;
123             }
124
125             if (bprs[i].blockct == 0 && unused_space(&bprs[i + 1],
126                 sizeof(ScsiBlockPtr))) {
127                 /* This is a "continue" pointer.
128                  * This ptr is the last one in the current script section.
129                  * I.e. the next ptr must point to the unused memory area.
130                  * The blockno is not zero, so the upper loop must continue
131                  * reading next section of BPRS.
132                  */
133                 break;
134             }
135             address = virtio_load_direct(cur_desc[0], cur_desc[1], 0,
136                                          (void *)address);
137             if (address == -1) {
138                 goto fail;
139             }
140         }
141     } while (blockno);
142
143     return 0;
144
145 fail:
146     sclp_print("failed loading segment\n");
147     return -1;
148 }
149
150 /* Run a zipl program */
151 static int zipl_run(ScsiBlockPtr *pte)
152 {
153     ComponentHeader *header;
154     ComponentEntry *entry;
155     uint8_t tmp_sec[MAX_SECTOR_SIZE];
156
157     virtio_read(pte->blockno, tmp_sec);
158     header = (ComponentHeader *)tmp_sec;
159
160     if (!zipl_magic(tmp_sec)) {
161         goto fail;
162     }
163
164     if (header->type != ZIPL_COMP_HEADER_IPL) {
165         goto fail;
166     }
167
168     dputs("start loading images\n");
169
170     /* Load image(s) into RAM */
171     entry = (ComponentEntry *)(&header[1]);
172     while (entry->component_type == ZIPL_COMP_ENTRY_LOAD) {
173         if (zipl_load_segment(entry) < 0) {
174             goto fail;
175         }
176
177         entry++;
178
179         if ((uint8_t *)(&entry[1]) > (tmp_sec + MAX_SECTOR_SIZE)) {
180             goto fail;
181         }
182     }
183
184     if (entry->component_type != ZIPL_COMP_ENTRY_EXEC) {
185         goto fail;
186     }
187
188     /* should not return */
189     jump_to_IPL_code(entry->load_address);
190
191     return 0;
192
193 fail:
194     sclp_print("failed running zipl\n");
195     return -1;
196 }
197
198 int zipl_load(void)
199 {
200     ScsiMbr *mbr = (void *)sec;
201     uint8_t *ns, *ns_end;
202     int program_table_entries = 0;
203     const int pte_len = sizeof(ScsiBlockPtr);
204     ScsiBlockPtr *prog_table_entry;
205     const char *error = "";
206
207     /* Grab the MBR */
208     virtio_read(0, (void *)mbr);
209
210     dputs("checking magic\n");
211
212     if (!zipl_magic(mbr->magic)) {
213         error = "zipl_magic 1";
214         goto fail;
215     }
216
217     debug_print_int("program table", mbr->blockptr.blockno);
218
219     /* Parse the program table */
220     if (virtio_read(mbr->blockptr.blockno, sec)) {
221         error = "virtio_read";
222         goto fail;
223     }
224
225     if (!zipl_magic(sec)) {
226         error = "zipl_magic 2";
227         goto fail;
228     }
229
230     ns_end = sec + virtio_get_block_size();
231     for (ns = (sec + pte_len); (ns + pte_len) < ns_end; ns++) {
232         prog_table_entry = (ScsiBlockPtr *)ns;
233         if (!prog_table_entry->blockno) {
234             break;
235         }
236
237         program_table_entries++;
238     }
239
240     debug_print_int("program table entries", program_table_entries);
241
242     if (!program_table_entries) {
243         goto fail;
244     }
245
246     /* Run the default entry */
247
248     prog_table_entry = (ScsiBlockPtr *)(sec + pte_len);
249
250     return zipl_run(prog_table_entry);
251
252 fail:
253     sclp_print("failed loading zipl: ");
254     sclp_print(error);
255     sclp_print("\n");
256     return -1;
257 }
This page took 0.038828 seconds and 4 git commands to generate.