|
|
1.1 root 1: /*
2: * Copyright (C) 2008 Daniel Verkamp <[email protected]>.
3: *
4: * This program is free software; you can redistribute it and/or
5: * modify it under the terms of the GNU General Public License as
6: * published by the Free Software Foundation; either version 2 of the
7: * License, or any later version.
8: *
9: * This program is distributed in the hope that it will be useful, but
10: * WITHOUT ANY WARRANTY; without even the implied warranty of
11: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12: * General Public License for more details.
13: *
14: * You should have received a copy of the GNU General Public License
15: * along with this program; if not, write to the Free Software
16: * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17: */
18:
19: /**
20: * @file
21: *
22: * SYSLINUX COM32 image format
23: *
24: */
25:
26: FILE_LICENCE ( GPL2_OR_LATER );
27:
28: #include <stdint.h>
29: #include <stdlib.h>
30: #include <string.h>
31: #include <strings.h>
32: #include <errno.h>
33: #include <assert.h>
34: #include <realmode.h>
35: #include <basemem.h>
36: #include <comboot.h>
37: #include <ipxe/uaccess.h>
38: #include <ipxe/image.h>
39: #include <ipxe/segment.h>
40: #include <ipxe/init.h>
41: #include <ipxe/io.h>
42:
43: struct idt_register com32_external_idtr = {
44: .limit = COM32_NUM_IDT_ENTRIES * sizeof ( struct idt_descriptor ) - 1,
45: .base = COM32_IDT
46: };
47:
48: struct idt_register com32_internal_idtr;
49:
50: /**
51: * Execute COMBOOT image
52: *
53: * @v image COM32 image
54: * @ret rc Return status code
55: */
56: static int com32_exec_loop ( struct image *image ) {
57: struct memory_map memmap;
58: unsigned int i;
59: int state;
60: uint32_t avail_mem_top;
61:
62: state = rmsetjmp ( comboot_return );
63:
64: switch ( state ) {
65: case 0: /* First time through; invoke COM32 program */
66:
67: /* Get memory map */
68: get_memmap ( &memmap );
69:
70: /* Find end of block covering COM32 image loading area */
71: for ( i = 0, avail_mem_top = 0 ; i < memmap.count ; i++ ) {
72: if ( (memmap.regions[i].start <= COM32_START_PHYS) &&
73: (memmap.regions[i].end > COM32_START_PHYS + image->len) ) {
74: avail_mem_top = memmap.regions[i].end;
75: break;
76: }
77: }
78:
79: DBGC ( image, "COM32 %p: available memory top = 0x%x\n",
80: image, avail_mem_top );
81:
82: assert ( avail_mem_top != 0 );
83:
84: com32_external_esp = phys_to_virt ( avail_mem_top );
85:
86: /* Hook COMBOOT API interrupts */
87: hook_comboot_interrupts();
88:
89: /* Unregister image, so that a "boot" command doesn't
90: * throw us into an execution loop. We never
91: * reregister ourselves; COMBOOT images expect to be
92: * removed on exit.
93: */
94: unregister_image ( image );
95:
96: __asm__ __volatile__ (
97: "sidt com32_internal_idtr\n\t"
98: "lidt com32_external_idtr\n\t" /* Set up IDT */
99: "movl %%esp, (com32_internal_esp)\n\t" /* Save internal virtual address space ESP */
100: "movl (com32_external_esp), %%esp\n\t" /* Switch to COM32 ESP (top of available memory) */
101: "call _virt_to_phys\n\t" /* Switch to flat physical address space */
102: "sti\n\t" /* Enable interrupts */
103: "pushl %0\n\t" /* Pointer to CDECL helper function */
104: "pushl %1\n\t" /* Pointer to FAR call helper function */
105: "pushl %2\n\t" /* Size of low memory bounce buffer */
106: "pushl %3\n\t" /* Pointer to low memory bounce buffer */
107: "pushl %4\n\t" /* Pointer to INT call helper function */
108: "pushl %5\n\t" /* Pointer to the command line arguments */
109: "pushl $6\n\t" /* Number of additional arguments */
110: "call *%6\n\t" /* Execute image */
111: "cli\n\t" /* Disable interrupts */
112: "call _phys_to_virt\n\t" /* Switch back to internal virtual address space */
113: "lidt com32_internal_idtr\n\t" /* Switch back to internal IDT (for debugging) */
114: "movl (com32_internal_esp), %%esp\n\t" /* Switch back to internal stack */
115: :
116: :
117: /* %0 */ "r" ( virt_to_phys ( com32_cfarcall_wrapper ) ),
118: /* %1 */ "r" ( virt_to_phys ( com32_farcall_wrapper ) ),
119: /* %2 */ "r" ( get_fbms() * 1024 - (COM32_BOUNCE_SEG << 4) ),
120: /* %3 */ "i" ( COM32_BOUNCE_SEG << 4 ),
121: /* %4 */ "r" ( virt_to_phys ( com32_intcall_wrapper ) ),
122: /* %5 */ "r" ( virt_to_phys ( image->cmdline ?
123: image->cmdline : "" ) ),
124: /* %6 */ "r" ( COM32_START_PHYS )
125: :
126: "memory" );
127: DBGC ( image, "COM32 %p: returned\n", image );
128: break;
129:
130: case COMBOOT_EXIT:
131: DBGC ( image, "COM32 %p: exited\n", image );
132: break;
133:
134: case COMBOOT_EXIT_RUN_KERNEL:
135: assert ( image->replacement );
136: DBGC ( image, "COM32 %p: exited to run kernel %s\n",
137: image, image->replacement->name );
138: break;
139:
140: case COMBOOT_EXIT_COMMAND:
141: DBGC ( image, "COM32 %p: exited after executing command\n",
142: image );
143: break;
144:
145: default:
146: assert ( 0 );
147: break;
148: }
149:
150: unhook_comboot_interrupts();
151: comboot_force_text_mode();
152:
153: return 0;
154: }
155:
156: /**
157: * Check image name extension
158: *
159: * @v image COM32 image
160: * @ret rc Return status code
161: */
162: static int com32_identify ( struct image *image ) {
163: const char *ext;
164: static const uint8_t magic[] = { 0xB8, 0xFF, 0x4C, 0xCD, 0x21 };
165: uint8_t buf[5];
166:
167: if ( image->len >= 5 ) {
168: /* Check for magic number
169: * mov eax,21cd4cffh
170: * B8 FF 4C CD 21
171: */
172: copy_from_user ( buf, image->data, 0, sizeof(buf) );
173: if ( ! memcmp ( buf, magic, sizeof(buf) ) ) {
174: DBGC ( image, "COM32 %p: found magic number\n",
175: image );
176: return 0;
177: }
178: }
179:
180: /* Magic number not found; check filename extension */
181:
182: ext = strrchr( image->name, '.' );
183:
184: if ( ! ext ) {
185: DBGC ( image, "COM32 %p: no extension\n",
186: image );
187: return -ENOEXEC;
188: }
189:
190: ++ext;
191:
192: if ( strcasecmp( ext, "c32" ) ) {
193: DBGC ( image, "COM32 %p: unrecognized extension %s\n",
194: image, ext );
195: return -ENOEXEC;
196: }
197:
198: return 0;
199: }
200:
201:
202: /**
203: * Load COM32 image into memory and set up the IDT
204: * @v image COM32 image
205: * @ret rc Return status code
206: */
207: static int com32_load_image ( struct image *image ) {
208: physaddr_t com32_irq_wrapper_phys;
209: struct idt_descriptor *idt;
210: struct ijb_entry *ijb;
211: size_t filesz, memsz;
212: userptr_t buffer;
213: int rc, i;
214:
215: /* The interrupt descriptor table, interrupt jump buffer, and
216: * image data are all contiguous in memory. Prepare them all at once.
217: */
218: filesz = image->len +
219: COM32_NUM_IDT_ENTRIES * sizeof ( struct idt_descriptor ) +
220: COM32_NUM_IDT_ENTRIES * sizeof ( struct ijb_entry );
221: memsz = filesz;
222: buffer = phys_to_user ( COM32_IDT );
223: if ( ( rc = prep_segment ( buffer, filesz, memsz ) ) != 0 ) {
224: DBGC ( image, "COM32 %p: could not prepare segment: %s\n",
225: image, strerror ( rc ) );
226: return rc;
227: }
228:
229: /* Write the IDT and IJB */
230: idt = phys_to_virt ( COM32_IDT );
231: ijb = phys_to_virt ( COM32_IJB );
232: com32_irq_wrapper_phys = virt_to_phys ( com32_irq_wrapper );
233:
234: for ( i = 0; i < COM32_NUM_IDT_ENTRIES; i++ ) {
235: uint32_t ijb_address = virt_to_phys ( &ijb[i] );
236:
237: idt[i].offset_low = ijb_address & 0xFFFF;
238: idt[i].selector = PHYSICAL_CS;
239: idt[i].flags = IDT_INTERRUPT_GATE_FLAGS;
240: idt[i].offset_high = ijb_address >> 16;
241:
242: ijb[i].pusha_instruction = IJB_PUSHA;
243: ijb[i].mov_instruction = IJB_MOV_AL_IMM8;
244: ijb[i].mov_value = i;
245: ijb[i].jump_instruction = IJB_JMP_REL32;
246: ijb[i].jump_destination = com32_irq_wrapper_phys -
247: virt_to_phys ( &ijb[i + 1] );
248: }
249:
250: /* Copy image to segment */
251: buffer = phys_to_user ( COM32_START_PHYS );
252: memcpy_user ( buffer, 0, image->data, 0, filesz );
253:
254: return 0;
255: }
256:
257: /**
258: * Prepare COM32 low memory bounce buffer
259: * @v image COM32 image
260: * @ret rc Return status code
261: */
262: static int com32_prepare_bounce_buffer ( struct image * image ) {
263: unsigned int seg;
264: userptr_t seg_userptr;
265: size_t filesz, memsz;
266: int rc;
267:
268: seg = COM32_BOUNCE_SEG;
269: seg_userptr = real_to_user ( seg, 0 );
270:
271: /* Ensure the entire 64k segment is free */
272: memsz = 0xFFFF;
273: filesz = 0;
274:
275: /* Prepare, verify, and load the real-mode segment */
276: if ( ( rc = prep_segment ( seg_userptr, filesz, memsz ) ) != 0 ) {
277: DBGC ( image, "COM32 %p: could not prepare bounce buffer segment: %s\n",
278: image, strerror ( rc ) );
279: return rc;
280: }
281:
282: return 0;
283: }
284:
285: /**
286: * Probe COM32 image
287: *
288: * @v image COM32 image
289: * @ret rc Return status code
290: */
291: static int com32_probe ( struct image *image ) {
292: int rc;
293:
294: DBGC ( image, "COM32 %p: name '%s'\n", image, image->name );
295:
296: /* Check if this is a COMBOOT image */
297: if ( ( rc = com32_identify ( image ) ) != 0 ) {
298: return rc;
299: }
300:
301: return 0;
302: }
303:
304: /**
305: * Execute COMBOOT image
306: *
307: * @v image COM32 image
308: * @ret rc Return status code
309: */
310: static int com32_exec ( struct image *image ) {
311: int rc;
312:
313: /* Load image */
314: if ( ( rc = com32_load_image ( image ) ) != 0 ) {
315: return rc;
316: }
317:
318: /* Prepare bounce buffer segment */
319: if ( ( rc = com32_prepare_bounce_buffer ( image ) ) != 0 ) {
320: return rc;
321: }
322:
323: return com32_exec_loop ( image );
324: }
325:
326: /** SYSLINUX COM32 image type */
327: struct image_type com32_image_type __image_type ( PROBE_NORMAL ) = {
328: .name = "COM32",
329: .probe = com32_probe,
330: .exec = com32_exec,
331: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.