convert gitignore files to hgignore files
[hvf.git] / installer / loader_c.c
blob192244f51a9cfa1337f69b5d1add41d0bedd552e
1 /*
2 * Copyright (c) 2007-2011 Josef 'Jeff' Sipek
3 */
5 #include "loader.h"
6 #include <binfmt_elf.h>
7 #include <string.h>
8 #include <ebcdic.h>
10 static unsigned char seek_data[6];
11 static unsigned char search_data[5];
13 extern struct orb ORB;
15 static u8 *buf = (u8*) (16 * 1024);
16 static u32 *ptrbuf = (u32*) (20 * 1024);
18 static u64 pgm_new_psw_diswait[2] = {
19 0x0002000180000000ULL, 0,
22 static u64 io_new_psw[2] = {
23 0x0000000180000000ULL, (u64) &IOHANDLER,
26 static u64 pgm_new_psw[2] = {
27 0x0000000180000000ULL, (u64) &PGMHANDLER,
30 u64 ipl_sch;
31 u64 con_sch;
32 u64 dasd_sch;
34 void __readwrite_blk(void *ptr, u32 lba, int rwccw)
36 struct ccw ccw[4];
38 u16 cc, hh, r;
40 if (lba < 1)
41 die();
43 memset(ccw, 0, sizeof(ccw));
45 lba--;
46 cc = lba / RECORDS_PER_CYL;
47 hh = (lba % RECORDS_PER_CYL) / RECORDS_PER_TRACK;
48 r = (lba % RECORDS_PER_CYL) % RECORDS_PER_TRACK;
49 r++;
51 ORB.addr = ADDR31(ccw);
53 /* SEEK */
54 ccw[0].cmd = 0x07;
55 ccw[0].flags = CCW_FLAG_CC | CCW_FLAG_SLI;
56 ccw[0].count = 6;
57 ccw[0].addr = ADDR31(seek_data);
59 seek_data[0] = 0; /* zero */
60 seek_data[1] = 0; /* zero */
61 seek_data[2] = cc >> 8; /* Cc */
62 seek_data[3] = cc & 0xff; /* cC */
63 seek_data[4] = hh >> 8; /* Hh */
64 seek_data[5] = hh & 0xff; /* hH */
66 /* SEARCH */
67 ccw[1].cmd = 0x31;
68 ccw[1].flags = CCW_FLAG_CC | CCW_FLAG_SLI;
69 ccw[1].count = 5;
70 ccw[1].addr = ADDR31(search_data);
72 search_data[0] = cc >> 8;
73 search_data[1] = cc & 0xff;
74 search_data[2] = hh >> 8;
75 search_data[3] = hh & 0xff;
76 search_data[4] = r;
78 /* TIC */
79 ccw[2].cmd = 0x08;
80 ccw[2].flags = 0;
81 ccw[2].count = 0;
82 ccw[2].addr = ADDR31(&ccw[1]);
84 /* READ/WRITE DATA */
85 ccw[3].cmd = rwccw;
86 ccw[3].flags = 0;
87 ccw[3].count = 4096;
88 ccw[3].addr = ADDR31(ptr);
91 * issue IO
93 if (__do_io(dasd_sch))
94 die();
97 struct senseid_struct {
98 u8 __reserved;
99 u16 cu_type;
100 u8 cu_model;
101 u16 dev_type;
102 u8 dev_model;
103 } __attribute__((packed));
106 static int dev_dasd(void)
108 int ret;
109 struct ccw ccw;
110 struct senseid_struct id;
112 ccw.cmd = 0xe4;
113 ccw.flags = CCW_FLAG_SLI;
114 ccw.count = sizeof(struct senseid_struct);
115 ccw.addr = ADDR31(&id);
117 ORB.param = 0x12345678,
118 ORB.f = 1,
119 ORB.lpm = 0xff,
120 ORB.addr = ADDR31(&ccw);
122 ret = __do_io(dasd_sch);
123 if (ret)
124 die();
126 if ((id.dev_type == 0x3390) &&
127 (id.dev_model == 0x0A) &&
128 (id.cu_type == 0x3990) &&
129 (id.cu_model == 0xC2))
130 return 0; // ECKD 3390-3 that we know how to use
132 return -1; // not a DASD
135 static u64 atoi(char *s, int len)
137 u64 i = 0;
139 while(len) {
140 if ((*s >= '0') && (*s <= '9'))
141 i = (i * 16) + (*s - '0');
142 else if ((*s >= 'A') && (*s <= 'F'))
143 i = (i * 16) + (*s - 'A' + 10);
144 else if ((*s >= 'a') && (*s <= 'f'))
145 i = (i * 16) + (*s - 'a' + 10);
146 else
147 break;
148 len--;
149 s++;
152 return i;
155 static u64 find_devnum(u64 devnum)
157 struct schib schib;
158 u64 sch;
160 if (devnum > 0xffff)
161 die();
163 memset(&schib, 0, sizeof(struct schib));
166 * For each possible subchannel id...
168 for(sch = 0x10000; sch <= 0x1ffff; sch++) {
170 * ...call store subchannel, to find out whether or not
171 * there is a device
173 if (store_sch(sch, &schib))
174 continue;
176 if (!schib.pmcw.v)
177 continue;
179 if (schib.pmcw.dev_num != devnum)
180 continue;
182 schib.pmcw.e = 1;
184 if (modify_sch(sch, &schib))
185 die();
187 return sch;
190 return ~0;
193 void wto(char *str)
195 int ret;
196 struct ccw ccw;
197 char buf[160];
199 strncpy(buf, str, 160);
200 buf[159] = '\0';
202 ascii2ebcdic((u8*)buf, 160);
204 ccw.cmd = 0x01;
205 ccw.flags = 0;
206 ccw.count = strlen(str);
207 ccw.addr = ADDR31(buf);
209 ORB.param = 0x12345678,
210 ORB.f = 1,
211 ORB.lpm = 0xff,
212 ORB.addr = ADDR31(&ccw);
214 ret = __do_io(con_sch);
215 if (ret)
216 die();
219 void wtor(char *str, char *inp, int buflen)
221 int ret;
222 struct ccw ccw;
224 wto(str);
226 /* wait for user input */
227 __wait_for_attn();
229 /* read user input */
230 ccw.cmd = 0x0a;
231 ccw.flags = CCW_FLAG_SLI;
232 ccw.count = buflen;
233 ccw.addr = ADDR31(inp);
235 ORB.param = 0x12345678,
236 ORB.f = 1,
237 ORB.lpm = 0xff,
238 ORB.addr = ADDR31(&ccw);
240 ret = __do_io(con_sch);
241 if (ret)
242 die();
244 ebcdic2ascii((u8*)inp, buflen);
247 static void init_io(void)
249 u64 cr6;
251 /* enable all I/O interrupt classes */
252 asm volatile(
253 "stctg 6,6,%0\n" /* get cr6 */
254 "oi %1,0xff\n" /* enable all */
255 "lctlg 6,6,%0\n" /* reload cr6 */
256 : /* output */
257 : /* input */
258 "m" (cr6),
259 "m" (*(u64*) (((u8*)&cr6) + 4))
263 void load_nucleus(void)
265 char inp[160];
267 /* Save the IPL device subchannel id */
268 ipl_sch = *((u32*) 0xb8);
270 memcpy((void*) 0x1d0, pgm_new_psw_diswait, 16);
271 memcpy((void*) 0x1f0, io_new_psw, 16);
273 init_io();
276 * try to find the console on 0009
278 con_sch = find_devnum(CON_DEVNUM);
279 if (con_sch > 0x1ffff)
280 die();
283 * greet the user on the console
285 wto("HVF installer\n\n");
287 for(;;) {
289 * ask the user for target dasd
291 wtor("Specify target device (1-4 hex digits):\n", inp, 160);
293 dasd_sch = find_devnum(atoi(inp, 160));
294 if ((dasd_sch < 0x10000) || (dasd_sch > 0x1ffff)) {
295 wto("Invalid device number.\n\n");
296 continue;
299 wto("Device found.\n\n");
300 if (dev_dasd()) {
301 wto("Need a DASD.\n\n");
302 continue;
305 break;
308 inp[0] = 'n';
309 wtor("Format volume? [y/n]\n", inp, 160);
311 if ((inp[0] == 'y') || (inp[0] == 'Y')) {
312 wto("Formating volume...\n");
315 * FIXME:
316 * 1) format the volume
317 * 2) setup EDF
320 wto("done. (Not yet implemented)\n");
321 die();
322 } else
323 wto("Formatting skipped.\n");
326 * initialize the memory allocator
328 init_malloc(TEMP_BASE);
331 * mount the EDF volume
333 mount_fs();
336 * read through the archive and decide what to do with each file
338 unload_archive();
341 * currently, we haven't written anything to disk; flush everything
343 writeback_buffers();
346 * FIXME: inform the user that we're done, and load a psw with the
347 * right magic
350 wto("\nInstallation complete.\n");
351 wto("You can now IPL from the DASD.\n");
353 asm volatile(
354 "lpswe %0\n"
355 : /* output */
356 : /* input */
357 "m" (pgm_new_psw_diswait[0])
360 die();