wok view syslinux/stuff/iso2exe/bootlinux.c @ rev 16002

syslinux/iso2exe: fix 16M hole
author Pascal Bellard <pascal.bellard@slitaz.org>
date Tue Mar 04 09:23:30 2014 +0000 (2014-03-04)
parents 3f0b08dbc9d3
children 825165c08d25
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
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 unsigned extendedramsizeinkb(void)
107 {
108 #asm
109 mov ah, #0x88
110 int 0x15
111 jnc gottop
112 xor ax, ax
113 gottop:
114 #endasm
115 }
117 static void load(struct mem *p, unsigned long size)
118 {
119 if (vm86())
120 die("Need real mode");
121 switch (p->align) {
122 case 0: // kernel
123 switch (dosversion()) {
124 case 3: case 4: case 6: break;
125 default:
126 printf("DOS %d not supported.\nTrying anyway...\n",
127 versiondos);
128 }
129 p->align = PAGE_SIZE;
130 break;
131 case PAGE_SIZE: // first initrd : skip mapping hole before 16M
132 if (extendedramsizeinkb() > 24000U && p->base < 0x1000000)
133 p->base = 0x1000000;
134 initrd_addr = p->base;
135 p->align = 4;
136 }
137 while (size) {
138 int n, s = sizeof(buffer);
139 for (n = 0; n < s; n++) buffer[n] = 0;
140 if (s > size) s = size;
141 n = isoread(buffer, s);
142 movehi();
143 if (n != -1) {
144 p->base += n;
145 size -= n;
146 }
147 if (s != n) break;
148 }
149 initrd_size = p->base - initrd_addr;
150 p->base += p->align - 1;
151 p->base &= - p->align;
152 }
154 static unsigned setupofs = 0;
156 void movesetup(void)
157 {
158 #asm
159 pusha
160 push #SETUP_SEGMENT
161 pop es
162 mov si, #_buffer
163 mov di, _setupofs
164 mov cx, #BUFFERSZ/2
165 rep
166 movsw
167 mov _setupofs, di
168 popa
169 #endasm
170 }
172 static unsigned getcs(void)
173 {
174 #asm
175 mov ax, cs
176 #endasm
177 }
179 unsigned long loadkernel(void)
180 {
181 unsigned setup, n = BUFFERSZ;
182 unsigned long syssize = 0, kernel_version = 0;
184 do {
185 isoread(buffer, n);
186 if (setupofs == 0) {
187 if (* (unsigned short *) (buffer + BOOTFLAG) != 0xAA55)
188 die("The kernel is not bootable");
189 setup = (1 + buffer[SETUPSECTORS]) << 9;
190 if (setup == 512) setup = 5 << 9;
191 syssize = * (unsigned long *) (buffer + SYSSIZE) << 4;
192 version = * (unsigned short *) (buffer + VERSION);
193 #define HDRS 0x53726448
194 if (* (unsigned long *) (buffer + HEADER) != HDRS)
195 version = 0;
196 if (version < 0x204)
197 syssize &= 0x000FFFFFUL;
198 if (version) {
199 #ifdef REALMODE_SWITCH
200 extern int far_realmode_switch();
201 #asm
202 jmp end_realmode_switch
203 _far_realmode_switch:
204 call REALMODE_SWITCH
205 cli
206 mov al, #0x80 // Disable NMI
207 out 0x70, al
208 retf
209 end_realmode_switch:
210 #endasm
211 * (unsigned short *) (buffer + RMSWOFS) =
212 far_realmode_switch;
213 * (unsigned short *) (buffer + RMSWSEG) =
214 getcs();
215 #endif
216 kernelmem.base =
217 * (unsigned long *) (buffer + SYSTEMCODE);
218 * (unsigned short *) (buffer + HEAPPTR) =
219 0x9B00;
220 // buffer[LOADFLAGS] |= 0x80;
221 * (unsigned short *) (buffer + LOADERTYPE) |=
222 0x80FF;
223 }
224 if (!version || !(buffer[LOADFLAGS] & 1)) {
225 #ifdef ZIMAGE_SUPPORT
226 #asm
227 pusha
228 mov cx, #0x8000
229 mov es, cx
230 xor si, si
231 xor di, di
232 rep
233 movsw // move 64K data
234 push es
235 pop ds
236 push es
237 pop ss
238 mov ch, #0x70
239 mov es, cx
240 mov ch, #0x80
241 rep
242 seg cs
243 movsw // move 64K code
244 popa
245 jmpi relocated, #0x7000
246 relocated:
247 #endasm
248 kernelmem.base = 0x10000;
249 if (syssize > 0x60000) /* 384K max */
250 #endif
251 die("Not a bzImage format");
252 }
253 }
254 movesetup();
255 setup -= n;
256 n = (setup > BUFFERSZ) ? BUFFERSZ : setup;
257 } while (setup > 0);
259 #asm
260 push ds
261 push #SETUP_SEGMENT
262 pop ds
263 mov si, #0x200
264 mov eax, #0x53726448 // HdrS
265 cdq // clear edx
266 cmp [si+2], eax
267 jne noversion
268 add si, [si+14]
269 mov cx, #3
270 xor ax, ax
271 nextdigit:
272 shl al, #4
273 shl ax, #4
274 next:
275 lodsb
276 sub al, #0x30
277 cmp al, #9
278 jbe nextdigit
279 shl eax, #16
280 shld edx, eax, #8
281 loop next
282 pop ds
283 mov .loadkernel.kernel_version[bp], edx
284 noversion:
285 #endasm
286 load(&kernelmem, syssize);
287 return kernel_version;
288 }
290 void loadinitrd(void)
291 {
292 if (version)
293 load(&initrdmem, isofilesize);
294 }
296 void bootlinux(char *cmdline)
297 {
298 #asm
299 push #SETUP_SEGMENT
300 pop es
301 mov eax, _initrd_addr
302 or eax, eax
303 jz no_initrd
304 mov di, #0x218
305 stosd
306 mov eax, _initrd_size
307 stosd
308 no_initrd:
309 #endasm
310 if (cmdline) {
311 if (version <= 0x201) {
312 #asm
313 mov di, #0x0020
314 mov ax, #0xA33F
315 stosw
316 mov ax, #CMDLINE_OFFSET
317 stosw
318 #endasm
319 }
320 else {
321 #asm
322 mov di, #0x0228
323 mov eax, #SETUP_SEGMENT*16+CMDLINE_OFFSET
324 stosd
325 #endasm
326 }
327 #asm
328 xchg ax, di
329 mov si, .bootlinux.cmdline[bp]
330 copy:
331 lodsb
332 stosb
333 or al,al
334 jne copy
335 #endasm
336 }
337 #asm
338 push es
339 pop ds
340 push ds
341 pop ss
342 mov sp, #CMDLINE_OFFSET
343 jmpi 0, #0x9020
344 #endasm
345 }