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

Add xdigger
author Pascal Bellard <pascal.bellard@slitaz.org>
date Tue Dec 25 16:40:45 2012 +0100 (2012-12-25)
parents 58b695f73790
children 65b3fd0022ed
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 void loadkernel(void)
160 {
161 unsigned setup, n = BUFFERSZ;
162 unsigned long syssize = 0;
164 do {
165 isoread(buffer, n);
166 if (setupofs == 0) {
167 if (* (unsigned short *) (buffer + BOOTFLAG) != 0xAA55)
168 die("The kernel is not bootable");
169 setup = (1 + buffer[SETUPSECTORS]) << 9;
170 if (setup == 512) setup = 5 << 9;
171 syssize = * (unsigned long *) (buffer + SYSSIZE) << 4;
172 version = * (unsigned short *) (buffer + VERSION);
173 #define HDRS 0x53726448
174 if (* (unsigned long *) (buffer + HEADER) != HDRS)
175 version = 0;
176 if (version < 0x204)
177 syssize &= 0x000FFFFFUL;
178 if (version) {
179 #ifdef REALMODE_SWITCH
180 extern int far_realmode_switch();
181 #asm
182 jmp end_realmode_switch
183 _far_realmode_switch:
184 call _realmode_switch
185 cli
186 mov al, #0x80 // Disable NMI
187 out 0x70, al
188 retf
189 end_realmode_switch:
190 #endasm
191 * (unsigned short *) (buffer + RMSWOFS) =
192 far_realmode_switch;
193 * (unsigned short *) (buffer + RMSWSEG) =
194 getcs();
195 #endif
196 kernelmem.base =
197 * (unsigned long *) (buffer + SYSTEMCODE);
198 * (unsigned short *) (buffer + HEAPPTR) =
199 0x9B00;
200 // buffer[LOADFLAGS] |= 0x80;
201 * (unsigned short *) (buffer + LOADERTYPE) |=
202 0x80FF;
203 }
204 if (!version || !(buffer[LOADFLAGS] & 1)) {
205 #ifdef ZIMAGE_SUPPORT
206 #asm
207 pusha
208 mov cx, #0x8000
209 mov es, cx
210 xor si, si
211 xor di, di
212 rep
213 movsw // move 64K data
214 push es
215 pop ds
216 push es
217 pop ss
218 mov ch, #0x70
219 mov es, cx
220 mov ch, #0x80
221 rep
222 seg cs
223 movsw // move 64K code
224 popa
225 jmpi relocated, #0x7000
226 relocated:
227 #endasm
228 kernelmem.base = 0x10000;
229 if (syssize > 0x60000) /* 384K max */
230 #endif
231 die("Not a bzImage format");
232 }
233 }
234 movesetup();
235 setup -= n;
236 n = (setup > BUFFERSZ) ? BUFFERSZ : setup;
237 } while (setup > 0);
239 load(&kernelmem, syssize);
240 }
242 void loadinitrd(void)
243 {
244 if (version)
245 load(&initrdmem, isofilesize);
246 }
248 void bootlinux(char *cmdline)
249 {
250 #asm
251 push #SETUP_SEGMENT
252 pop es
253 mov eax, _initrd_addr
254 or eax, eax
255 jz no_initrd
256 mov di, #0x218
257 stosd
258 mov eax, _initrd_size
259 stosd
260 no_initrd:
261 #endasm
262 if (cmdline) {
263 if (version <= 0x201) {
264 #asm
265 mov di, #0x0020
266 mov ax, #0xA33F
267 stosw
268 mov ax, #CMDLINE_OFFSET
269 stosw
270 #endasm
271 }
272 else {
273 #asm
274 mov di, #0x0228
275 mov eax, #SETUP_SEGMENT*16+CMDLINE_OFFSET
276 stosd
277 #endasm
278 }
279 #asm
280 xchg ax, di
281 mov si, .bootlinux.cmdline[bp]
282 copy:
283 lodsb
284 stosb
285 or al,al
286 jne copy
287 #endasm
288 }
289 #asm
290 push es
291 pop ds
292 push ds
293 pop ss
294 mov sp, #CMDLINE_OFFSET
295 jmpi 0, #0x9020
296 #endasm
297 }