2 /* ----------------------------------------------------------------------- *
4 * Copyright 2001 H. Peter Anvin - All Rights Reserved
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, Inc., 53 Temple Place Ste 330,
9 * Bostom MA 02111-1307, USA; either version 2 of the License, or
10 * (at your option) any later version; incorporated herein by reference.
12 * ----------------------------------------------------------------------- */
17 * Initialization code for memory-based disk
23 static inline int get_e820(void)
29 } __attribute__((packed));
36 asm volatile("int $0x15 ; "
38 "cmpl $0x534d4150, %%eax ; "
43 : "=c" (copied), "=&b" (lastptr)
44 : "a" (0x0000e820), "d" (0x534d4150),
51 insertrange(buf.base, buf.len, buf.type);
59 static inline void get_dos_mem(void)
63 asm volatile("int $0x12" : "=a" (dos_kb)
64 :: "ebx", "ecx", "edx", "esi", "edi", "ebp");
66 insertrange(0, (uint64_t)((uint32_t)dos_kb << 10), 1);
69 static inline int get_e881(void)
75 asm volatile("movw $0xe881, %%ax ; "
78 : "=a" (low_mem), "=b" (high_mem), "=d" (err)
79 :: "ecx", "esi", "edi", "ebp");
83 insertrange(0x100000, (uint64_t)low_mem << 10, 1);
86 insertrange(0x1000000, (uint64_t)high_mem << 16, 1);
93 static inline int get_e801(void)
99 asm volatile("movw $0xe801, %%ax ; "
102 : "=a" (low_mem), "=b" (high_mem), "=d" (err)
103 :: "ecx", "esi", "edi", "ebp");
107 insertrange(0x100000, (uint64_t)((uint32_t)low_mem << 10), 1);
110 insertrange(0x1000000, (uint64_t)((uint32_t)high_mem << 16), 1);
117 static inline int get_88(void)
122 asm volatile("movb $0x88,%%ah ; "
125 : "=a" (low_mem), "=d" (err)
126 :: "ebx", "ecx", "esi", "edi", "ebp");
130 insertrange(0x100000, (uint64_t)((uint32_t)low_mem << 10), 1);
137 uint32_t dos_mem = 0; /* 0-1MB */
138 uint32_t low_mem = 0; /* 1-16MB */
139 uint32_t high_mem = 0; /* 16+ MB */
148 /* Running out of ideas here... */
157 struct e820range *ep;
159 /* Derive "dos mem", "high mem", and "low mem" from the range array */
160 for ( ep = ranges ; ep->type != -1 ; ep++ ) {
161 if ( ep->type == 1 ) {
162 /* Only look at memory ranges */
163 if ( ep->start == 0 ) {
164 if ( ep[1].start > 0x100000 )
167 dos_mem = ep[1].start;
169 if ( ep->start <= 0x100000 && ep[1].start > 0x100000 ) {
170 if ( ep[1].start > 0x1000000 )
171 low_mem = 0x1000000 - ep->start;
173 low_mem = ep[1].start - ep->start;
175 if ( ep->start <= 0x1000000 && ep[1].start > 0x1000000 ) {
176 if ( ep[1].start > 0x100000000 )
177 high_mem = 0x100000000 - ep->start;
179 high_mem = ep[1].start - ep->start;
185 extern const char _binary_memdisk_bin_start[], _binary_memdisk_bin_end[];
186 extern const char _binary_memdisk_bin_size[]; /* Weird, I know */
187 struct memdisk_header {
215 /* Access to objects in the zero page */
217 wrz_8(uint32_t addr, uint8_t data)
219 asm volatile("movb %0,%%fs:%1" :: "ri" (data), "m" (*(uint8_t *)addr));
222 wrz_16(uint32_t addr, uint16_t data)
224 asm volatile("movw %0,%%fs:%1" :: "ri" (data), "m" (*(uint16_t *)addr));
227 wrz_32(uint32_t addr, uint16_t data)
229 asm volatile("movl %0,%%fs:%1" :: "ri" (data), "m" (*(uint32_t *)addr));
231 static inline uint8_t
235 asm volatile("movb %%fs:%1,%0" : "=r" (data) : "m" (*(uint8_t *)addr));
238 static inline uint16_t
239 rdz_16(uint32_t addr)
242 asm volatile("movw %%fs:%1,%0" : "=r" (data) : "m" (*(uint16_t *)addr));
245 static inline uint8_t
246 rdz_32(uint32_t addr)
249 asm volatile("movl %%fs:%1,%0" : "=r" (data) : "m" (*(uint32_t *)addr));
253 /* Addresses in the zero page */
254 #define BIOS_INT13 (0x13*4) /* INT 13h vector */
255 #define BIOS_INT15 (0x15*4) /* INT 13h vector */
256 #define BIOS_BASEMEM 0x413 /* Amount of DOS memory */
260 unsigned int size = (int) &_binary_memdisk_bin_size;
261 struct memdisk_header *hptr;
262 struct patch_area *pptr;
264 uint32_t driverptr, driveraddr;
269 /* Point %fs to the zero page */
270 asm volatile("movw %0,%%fs" :: "r" (0));
275 /* Figure out where it needs to go */
276 hptr = (struct memdisk_header *) &_binary_memdisk_bin_start;
277 pptr = (struct patch_area *)(_binary_memdisk_bin_start + hptr->patch_offs);
279 if ( hptr->total_size > dos_mem ) {
283 pptr->olddosmem = rdz_16(BIOS_BASEMEM);
285 driveraddr = dos_mem - hptr->total_size;
286 driveraddr &= ~0x3FF;
288 /* Reserve this range of memory */
289 insertrange(driveraddr, dos_mem-driveraddr, 2);
292 pptr->mem1mb = low_mem >> 10;
293 pptr->mem16mb = high_mem >> 16;
294 pptr->memint1588 = (low_mem == 0xf00000)
295 ? ((high_mem > 0x30ffc00) ? 0xffff : (high_mem >> 10)+0x3c00)
298 driverseg = driveraddr >> 4;
299 driverptr = driverseg << 16;
301 pptr->oldint13 = rdz_32(BIOS_INT13);
302 pptr->oldint15 = rdz_32(BIOS_INT15);
304 /* Claim the memory and copy the driver into place */
305 wrz_16(BIOS_BASEMEM, dos_mem >> 10);
307 asm volatile("pushw %%es ; "
309 "rep ; movsl %%ds:(%%si), %%es:(%%di) ; "
313 "S" (&_binary_memdisk_bin_start),
316 /* Install the interrupt handlers */
317 wrz_32(BIOS_INT13, driverptr+hptr->int13_offs);
318 wrz_32(BIOS_INT15, driverptr+hptr->int15_offs);
320 /* Reboot into the new "disk" */
321 asm volatile("pushw %%es ; "
325 "movw $0x0201,%%ax ; "
326 "movw $0x7c00,%%bx ; "
330 : "=r" (status), "=a" (exitcode)
331 : "d" ((uint16_t)driveno)
332 : "ebx", "ecx", "edx", "esi", "edi", "ebp");
338 /* On return the assembly code will jump to the boot vector */