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

syslinux/iso2exe: add loram support
author Pascal Bellard <pascal.bellard@slitaz.org>
date Tue Dec 18 16:09:07 2012 +0100 (2012-12-18)
parents d47403fdd900
children 72b5cd3cb23a
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 BUFFERSZ 2*1024
26 static char buffer[BUFFERSZ];
27 static unsigned long initrd_addr, initrd_size;
29 static int may_exit_dos = 1;
30 static void die(char *msg)
31 {
32 printf("%s.\n", msg);
33 if (may_exit_dos)
34 exit(1);
35 while (1);
36 }
38 static int vm86(void)
39 {
40 #asm
41 smsw ax
42 and ax, #1 // 0:realmode 1:vm86
43 #endasm
44 }
46 static struct mem {
47 unsigned long base;
48 int align;
49 } kernelmem = { 0x100000, 0 };
51 #define initrdmem kernelmem
53 static void movehi(void)
54 {
55 #asm
56 pusha
57 xor di, di // 30
58 mov cx, #9 // 2E..1E
59 zero1:
60 push di
61 loop zero1
62 push dword [_kernelmem] // 1A p->base
63 push #-1 // 18
64 push di // 16
65 xor eax, eax
66 cdq
67 mov dx, ds
68 shl edx, #4
69 mov ax, #_buffer
70 add edx, eax
71 push edx // 12 linear_address(buffer)
72 push #-1 // 10
73 mov cl, #8 // 0E..00
74 zero2:
75 push di
76 loop zero2
77 mov ch, #BUFFERSZ/512
78 push ss
79 pop es
80 mov si, sp
81 mov ax, #0x8793
82 mov [si+0x15], al
83 xchg [si+0x1D], al
84 mov [si+0x1F], al // bits 24..31, doesn't work for me :(
85 int 0x15
86 add sp, #0x30
87 popa
88 #endasm
89 }
91 static int versiondos;
92 static int dosversion(void)
93 {
94 #asm
95 mov ah, #0x30
96 int 0x21
97 cbw
98 mov _versiondos, ax
99 #endasm
100 }
102 static void load(struct mem *p, unsigned long size)
103 {
104 if (vm86())
105 die("Need real mode");
106 switch (p->align) {
107 case 0: // kernel
108 switch (dosversion()) {
109 case 3: case 4: case 6: break;
110 default:
111 printf("DOS %d not supported.\nTrying anyway...\n",
112 versiondos);
113 }
114 p->align = 4096;
115 break;
116 case 4096: // first initrd
117 initrd_addr = p->base;
118 p->align = 4;
119 }
120 while (size) {
121 int n, s = sizeof(buffer);
122 for (n = 0; n < s; n++) buffer[n] = 0;
123 if (s > size) s = size;
124 n = isoread(buffer, s);
125 movehi();
126 if (n != -1) {
127 p->base += n;
128 size -= n;
129 }
130 if (s != n) break;
131 }
132 initrd_size = p->base - initrd_addr;
133 p->base += p->align - 1;
134 p->base &= - p->align;
135 }
137 static unsigned setupofs = 0;
139 void movesetup(void)
140 {
141 #asm
142 pusha
143 push #SETUP_SEGMENT
144 pop es
145 mov si, #_buffer
146 mov di, _setupofs
147 mov cx, #BUFFERSZ/2
148 rep
149 movsw
150 mov _setupofs, di
151 popa
152 #endasm
153 }
155 void loadkernel(void)
156 {
157 unsigned setup, n = BUFFERSZ;
158 unsigned long syssize = 0;
160 do {
161 isoread(buffer, n);
162 if (setupofs == 0) {
163 if (* (unsigned short *) (buffer + BOOTFLAG) != 0xAA55)
164 die("The kernel is not bootable");
165 setup = (1 + buffer[SETUPSECTORS]) << 9;
166 if (setup == 512) setup = 5 << 9;
167 syssize = * (unsigned long *) (buffer + SYSSIZE) << 4;
168 version = * (unsigned short *) (buffer + VERSION);
169 #define HDRS 0x53726448
170 if (* (unsigned long *) (buffer + HEADER) != HDRS)
171 version = 0;
172 if (!version || !(buffer[LOADFLAGS] & 1)) {
173 #undef ZIMAGE_SUPPORT /* Does not work... */
174 #ifdef ZIMAGE_SUPPORT
175 #asm
176 pusha
177 mov cx, #0x8000
178 mov es, cx
179 xor si, si
180 xor di, di
181 rep
182 movsw // move 64K data
183 push es
184 pop ds
185 push es
186 pop ss
187 mov ch, #0x70
188 mov es, cx
189 mov ch, #0x80
190 rep
191 seg cs
192 movsw // move 64K code
193 popa
194 jmpi relocated, #0x7000
195 relocated:
196 #endasm
197 kernelmem.base = 0x10000;
198 if (syssize > 0x60000) /* 384K max */
199 #endif
200 die("Not a bzImage format");
201 }
202 if (version < 0x204)
203 syssize &= 0x000FFFFFUL;
204 if (version) {
205 #ifdef REALMODE_SWITCH
206 * (unsigned short *) (buffer + RMSWOFS) =
207 realmode_switch;
208 * (unsigned short *) (buffer + RMSWSEG) =
209 getcs();
210 #endif
211 * (unsigned short *) (buffer + HEAPPTR) =
212 0x9B00;
213 // buffer[LOADFLAGS] |= 0x80;
214 * (unsigned short *) (buffer + LOADERTYPE) |=
215 0x80FF;
216 }
217 }
218 movesetup();
219 setup -= n;
220 n = (setup > BUFFERSZ) ? BUFFERSZ : setup;
221 } while (setup > 0);
223 load(&kernelmem, syssize);
224 }
226 void loadinitrd(void)
227 {
228 if (version)
229 load(&initrdmem, isofilesize);
230 }
232 void bootlinux(char *cmdline)
233 {
234 #asm
235 push #SETUP_SEGMENT
236 pop es
237 mov eax, _initrd_addr
238 or eax, eax
239 jz no_initrd
240 mov di, #0x218
241 stosd
242 mov eax, _initrd_size
243 stosd
244 no_initrd:
245 #endasm
246 if (cmdline) {
247 if (version <= 0x201) {
248 #asm
249 mov di, #0x0020
250 mov ax, #0xA33F
251 stosw
252 mov ax, #CMDLINE_OFFSET
253 stosw
254 #endasm
255 }
256 else {
257 #asm
258 mov di, #0x0228
259 mov eax, #SETUP_SEGMENT*16+CMDLINE_OFFSET
260 stosd
261 #endasm
262 }
263 #asm
264 xchg ax, di
265 mov si, .bootlinux.cmdline[bp]
266 copy:
267 lodsb
268 stosb
269 or al,al
270 jne copy
271 #endasm
272 }
273 #asm
274 push es
275 pop ds
276 push ds
277 pop ss
278 mov sp, #CMDLINE_OFFSET
279 jmpi 0, #0x9020
280 #endasm
281 }