wok-6.x view syslinux/stuff/iso2exe/bootlinux.c @ rev 14257
syslinux/iso2exe: check kernel version, add floppy bootstrap stub
author | Pascal Bellard <pascal.bellard@slitaz.org> |
---|---|
date | Thu Mar 28 11:51:42 2013 +0100 (2013-03-28) |
parents | 72b5cd3cb23a |
children | bf8be127c60b |
line source
1 #include <stdio.h>
2 #include "iso9660.h"
4 static unsigned version;
5 #define SETUPSECTORS 0x1F1
6 #define ROFLAG 0x1F2
7 #define SYSSIZE 0x1F4
8 #define VIDEOMODE 0x1FA
9 #define BOOTFLAG 0x1FE
10 #define HEADER 0x202
11 #define VERSION 0x206
12 #define RMSWOFS 0x208
13 #define RMSWSEG 0x20A
14 #define LOADERTYPE 0x210
15 #define LOADFLAGS 0x211
16 #define SYSTEMCODE 0x214
17 #define INITRDCODE 0x218
18 #define INITRDSIZE 0x21C
19 #define HEAPPTR 0x224
20 #define CMDLINE 0x228
22 #define SETUP_SEGMENT 0x9000
23 #define CMDLINE_OFFSET 0x9E00
25 #define PAGE_BITS 12
26 #define PAGE_SIZE 4096
27 #define BUFFERSZ PAGE_SIZE
28 static char buffer[BUFFERSZ];
29 static unsigned long initrd_addr, initrd_size;
31 static int may_exit_dos = 1;
32 static void die(char *msg)
33 {
34 printf("%s.\n", msg);
35 if (may_exit_dos)
36 exit(1);
37 while (1);
38 }
40 static int vm86(void)
41 {
42 #asm
43 smsw ax
44 and ax, #1 // 0:realmode 1:vm86
45 #endasm
46 }
48 static struct mem {
49 unsigned long base;
50 int align;
51 } kernelmem = { 0x100000, 0 };
53 #define initrdmem kernelmem
55 static void movehi(void)
56 {
57 #asm
58 pusha
59 xor di, di // 30
60 mov cx, #9 // 2E..1E
61 zero1:
62 push di
63 loop zero1
64 push dword [_kernelmem] // 1A p->base
65 push #-1 // 18
66 push di // 16
67 xor eax, eax
68 cdq
69 mov dx, ds
70 shl edx, #4
71 mov ax, #_buffer
72 add edx, eax
73 push edx // 12 linear_address(buffer)
74 push #-1 // 10
75 mov cl, #8 // 0E..00
76 zero2:
77 push di
78 loop zero2
79 mov ch, #BUFFERSZ/512
80 push ss
81 pop es
82 mov si, sp
83 mov ax, #0x8793
84 mov [si+0x15], al
85 xchg [si+0x1D], al
86 mov [si+0x1F], al // bits 24..31, doesn't work for me :(
87 int 0x15
88 add sp, #0x30
89 popa
90 #endasm
91 }
93 #undef ZIMAGE_SUPPORT /* Does not work... */
95 static int versiondos;
96 static int dosversion(void)
97 {
98 #asm
99 mov ah, #0x30
100 int 0x21
101 cbw
102 mov _versiondos, ax
103 #endasm
104 }
106 static void load(struct mem *p, unsigned long size)
107 {
108 if (vm86())
109 die("Need real mode");
110 switch (p->align) {
111 case 0: // kernel
112 switch (dosversion()) {
113 case 3: case 4: case 6: break;
114 default:
115 printf("DOS %d not supported.\nTrying anyway...\n",
116 versiondos);
117 }
118 p->align = PAGE_SIZE;
119 break;
120 case 4096: // first initrd
121 initrd_addr = p->base;
122 p->align = 4;
123 }
124 while (size) {
125 int n, s = sizeof(buffer);
126 for (n = 0; n < s; n++) buffer[n] = 0;
127 if (s > size) s = size;
128 n = isoread(buffer, s);
129 movehi();
130 if (n != -1) {
131 p->base += n;
132 size -= n;
133 }
134 if (s != n) break;
135 }
136 initrd_size = p->base - initrd_addr;
137 p->base += p->align - 1;
138 p->base &= - p->align;
139 }
141 static unsigned setupofs = 0;
143 void movesetup(void)
144 {
145 #asm
146 pusha
147 push #SETUP_SEGMENT
148 pop es
149 mov si, #_buffer
150 mov di, _setupofs
151 mov cx, #BUFFERSZ/2
152 rep
153 movsw
154 mov _setupofs, di
155 popa
156 #endasm
157 }
159 static unsigned getcs(void)
160 {
161 #asm
162 mov ax, cs
163 #endasm
164 }
166 unsigned long loadkernel(void)
167 {
168 unsigned setup, n = BUFFERSZ;
169 unsigned long syssize = 0, version = 0;
171 do {
172 isoread(buffer, n);
173 if (setupofs == 0) {
174 if (* (unsigned short *) (buffer + BOOTFLAG) != 0xAA55)
175 die("The kernel is not bootable");
176 setup = (1 + buffer[SETUPSECTORS]) << 9;
177 if (setup == 512) setup = 5 << 9;
178 syssize = * (unsigned long *) (buffer + SYSSIZE) << 4;
179 version = * (unsigned short *) (buffer + VERSION);
180 #define HDRS 0x53726448
181 if (* (unsigned long *) (buffer + HEADER) != HDRS)
182 version = 0;
183 if (version < 0x204)
184 syssize &= 0x000FFFFFUL;
185 if (version) {
186 #ifdef REALMODE_SWITCH
187 extern int far_realmode_switch();
188 #asm
189 jmp end_realmode_switch
190 _far_realmode_switch:
191 call REALMODE_SWITCH
192 cli
193 mov al, #0x80 // Disable NMI
194 out 0x70, al
195 retf
196 end_realmode_switch:
197 #endasm
198 * (unsigned short *) (buffer + RMSWOFS) =
199 far_realmode_switch;
200 * (unsigned short *) (buffer + RMSWSEG) =
201 getcs();
202 #endif
203 kernelmem.base =
204 * (unsigned long *) (buffer + SYSTEMCODE);
205 * (unsigned short *) (buffer + HEAPPTR) =
206 0x9B00;
207 // buffer[LOADFLAGS] |= 0x80;
208 * (unsigned short *) (buffer + LOADERTYPE) |=
209 0x80FF;
210 }
211 if (!version || !(buffer[LOADFLAGS] & 1)) {
212 #ifdef ZIMAGE_SUPPORT
213 #asm
214 pusha
215 mov cx, #0x8000
216 mov es, cx
217 xor si, si
218 xor di, di
219 rep
220 movsw // move 64K data
221 push es
222 pop ds
223 push es
224 pop ss
225 mov ch, #0x70
226 mov es, cx
227 mov ch, #0x80
228 rep
229 seg cs
230 movsw // move 64K code
231 popa
232 jmpi relocated, #0x7000
233 relocated:
234 #endasm
235 kernelmem.base = 0x10000;
236 if (syssize > 0x60000) /* 384K max */
237 #endif
238 die("Not a bzImage format");
239 }
240 }
241 movesetup();
242 setup -= n;
243 n = (setup > BUFFERSZ) ? BUFFERSZ : setup;
244 } while (setup > 0);
246 #asm
247 push ds
248 push #SETUP_SEGMENT
249 pop ds
250 mov si, #0x200
251 mov eax, #0x53726448 // HdrS
252 cdq // clear edx
253 cmp [si+2], eax
254 jne noversion
255 add si, [si+14]
256 mov cx, #3
257 xor ax, ax
258 nextdigit:
259 shl edx, #4
260 or dl, al
261 next:
262 lodsb
263 xor ah, #1
264 sub al, #0x30
265 cmp al, #9
266 jbe nextdigit
267 shr ah, #1
268 jc got2
269 mov al, #0xF
270 and al, dl
271 and dl, #0xF0
272 shl edx, #4
273 or dl, al
274 got2:
275 loop next
276 pop ds
277 mov .loadkernel.version[bp], edx
278 noversion:
279 #endasm
280 load(&kernelmem, syssize);
281 return version;
282 }
284 void loadinitrd(void)
285 {
286 if (version)
287 load(&initrdmem, isofilesize);
288 }
290 void bootlinux(char *cmdline)
291 {
292 #asm
293 push #SETUP_SEGMENT
294 pop es
295 mov eax, _initrd_addr
296 or eax, eax
297 jz no_initrd
298 mov di, #0x218
299 stosd
300 mov eax, _initrd_size
301 stosd
302 no_initrd:
303 #endasm
304 if (cmdline) {
305 if (version <= 0x201) {
306 #asm
307 mov di, #0x0020
308 mov ax, #0xA33F
309 stosw
310 mov ax, #CMDLINE_OFFSET
311 stosw
312 #endasm
313 }
314 else {
315 #asm
316 mov di, #0x0228
317 mov eax, #SETUP_SEGMENT*16+CMDLINE_OFFSET
318 stosd
319 #endasm
320 }
321 #asm
322 xchg ax, di
323 mov si, .bootlinux.cmdline[bp]
324 copy:
325 lodsb
326 stosb
327 or al,al
328 jne copy
329 #endasm
330 }
331 #asm
332 push es
333 pop ds
334 push ds
335 pop ss
336 mov sp, #CMDLINE_OFFSET
337 jmpi 0, #0x9020
338 #endasm
339 }