|
|
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 COMBOOT (16-bit) 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/features.h>
42:
43: FEATURE ( FEATURE_IMAGE, "COMBOOT", DHCP_EB_FEATURE_COMBOOT, 1 );
44:
45: /**
46: * COMBOOT PSP, copied to offset 0 of code segment
47: */
48: struct comboot_psp {
49: /** INT 20 instruction, executed if COMBOOT image returns with RET */
50: uint16_t int20;
51: /** Segment of first non-free paragraph of memory */
52: uint16_t first_non_free_para;
53: };
54:
55: /** Offset in PSP of command line */
56: #define COMBOOT_PSP_CMDLINE_OFFSET 0x81
57:
58: /** Maximum length of command line in PSP
59: * (127 bytes minus space and CR) */
60: #define COMBOOT_MAX_CMDLINE_LEN 125
61:
62:
63: /**
64: * Copy command line to PSP
65: *
66: * @v image COMBOOT image
67: */
68: static void comboot_copy_cmdline ( struct image * image, userptr_t seg_userptr ) {
69: const char *cmdline = ( image->cmdline ? image->cmdline : "" );
70: int cmdline_len = strlen ( cmdline );
71: if( cmdline_len > COMBOOT_MAX_CMDLINE_LEN )
72: cmdline_len = COMBOOT_MAX_CMDLINE_LEN;
73: uint8_t len_byte = cmdline_len;
74: char spc = ' ', cr = '\r';
75:
76: /* Copy length to byte before command line */
77: copy_to_user ( seg_userptr, COMBOOT_PSP_CMDLINE_OFFSET - 1,
78: &len_byte, 1 );
79:
80: /* Command line starts with space */
81: copy_to_user ( seg_userptr,
82: COMBOOT_PSP_CMDLINE_OFFSET,
83: &spc, 1 );
84:
85: /* Copy command line */
86: copy_to_user ( seg_userptr,
87: COMBOOT_PSP_CMDLINE_OFFSET + 1,
88: cmdline, cmdline_len );
89:
90: /* Command line ends with CR */
91: copy_to_user ( seg_userptr,
92: COMBOOT_PSP_CMDLINE_OFFSET + cmdline_len + 1,
93: &cr, 1 );
94: }
95:
96: /**
97: * Initialize PSP
98: *
99: * @v image COMBOOT image
100: * @v seg_userptr segment to initialize
101: */
102: static void comboot_init_psp ( struct image * image, userptr_t seg_userptr ) {
103: struct comboot_psp psp;
104:
105: /* Fill PSP */
106:
107: /* INT 20h instruction, byte order reversed */
108: psp.int20 = 0x20CD;
109:
110: /* get_fbms() returns BIOS free base memory counter, which is in
111: * kilobytes; x * 1024 / 16 == x * 64 == x << 6 */
112: psp.first_non_free_para = get_fbms() << 6;
113:
114: DBGC ( image, "COMBOOT %p: first non-free paragraph = 0x%x\n",
115: image, psp.first_non_free_para );
116:
117: /* Copy the PSP to offset 0 of segment.
118: * The rest of the PSP was already zeroed by
119: * comboot_prepare_segment. */
120: copy_to_user ( seg_userptr, 0, &psp, sizeof( psp ) );
121:
122: /* Copy the command line to the PSP */
123: comboot_copy_cmdline ( image, seg_userptr );
124: }
125:
126: /**
127: * Execute COMBOOT image
128: *
129: * @v image COMBOOT image
130: * @ret rc Return status code
131: */
132: static int comboot_exec_loop ( struct image *image ) {
133: userptr_t seg_userptr = real_to_user ( COMBOOT_PSP_SEG, 0 );
134: int state;
135:
136: state = rmsetjmp ( comboot_return );
137:
138: switch ( state ) {
139: case 0: /* First time through; invoke COMBOOT program */
140:
141: /* Initialize PSP */
142: comboot_init_psp ( image, seg_userptr );
143:
144: /* Hook COMBOOT API interrupts */
145: hook_comboot_interrupts();
146:
147: DBGC ( image, "executing 16-bit COMBOOT image at %4x:0100\n",
148: COMBOOT_PSP_SEG );
149:
150: /* Unregister image, so that a "boot" command doesn't
151: * throw us into an execution loop. We never
152: * reregister ourselves; COMBOOT images expect to be
153: * removed on exit.
154: */
155: unregister_image ( image );
156:
157: /* Store stack segment at 0x38 and stack pointer at 0x3A
158: * in the PSP and jump to the image */
159: __asm__ __volatile__ (
160: REAL_CODE ( /* Save return address with segment on old stack */
161: "popw %%ax\n\t"
162: "pushw %%cs\n\t"
163: "pushw %%ax\n\t"
164: /* Set DS=ES=segment with image */
165: "movw %w0, %%ds\n\t"
166: "movw %w0, %%es\n\t"
167: /* Set SS:SP to new stack (end of image segment) */
168: "movw %w0, %%ss\n\t"
169: "xor %%sp, %%sp\n\t"
170: "pushw $0\n\t"
171: "pushw %w0\n\t"
172: "pushw $0x100\n\t"
173: /* Zero registers (some COM files assume GP regs are 0) */
174: "xorw %%ax, %%ax\n\t"
175: "xorw %%bx, %%bx\n\t"
176: "xorw %%cx, %%cx\n\t"
177: "xorw %%dx, %%dx\n\t"
178: "xorw %%si, %%si\n\t"
179: "xorw %%di, %%di\n\t"
180: "xorw %%bp, %%bp\n\t"
181: "lret\n\t" )
182: : : "r" ( COMBOOT_PSP_SEG ) : "eax" );
183: DBGC ( image, "COMBOOT %p: returned\n", image );
184: break;
185:
186: case COMBOOT_EXIT:
187: DBGC ( image, "COMBOOT %p: exited\n", image );
188: break;
189:
190: case COMBOOT_EXIT_RUN_KERNEL:
191: assert ( image->replacement );
192: DBGC ( image, "COMBOOT %p: exited to run kernel %s\n",
193: image, image->replacement->name );
194: break;
195:
196: case COMBOOT_EXIT_COMMAND:
197: DBGC ( image, "COMBOOT %p: exited after executing command\n",
198: image );
199: break;
200:
201: default:
202: assert ( 0 );
203: break;
204: }
205:
206: unhook_comboot_interrupts();
207: comboot_force_text_mode();
208:
209: return 0;
210: }
211:
212: /**
213: * Check image name extension
214: *
215: * @v image COMBOOT image
216: * @ret rc Return status code
217: */
218: static int comboot_identify ( struct image *image ) {
219: const char *ext;
220:
221: ext = strrchr( image->name, '.' );
222:
223: if ( ! ext ) {
224: DBGC ( image, "COMBOOT %p: no extension\n",
225: image );
226: return -ENOEXEC;
227: }
228:
229: ++ext;
230:
231: if ( strcasecmp( ext, "com" ) && strcasecmp( ext, "cbt" ) ) {
232: DBGC ( image, "COMBOOT %p: unrecognized extension %s\n",
233: image, ext );
234: return -ENOEXEC;
235: }
236:
237: return 0;
238: }
239:
240: /**
241: * Load COMBOOT image into memory, preparing a segment and returning it
242: * @v image COMBOOT image
243: * @ret rc Return status code
244: */
245: static int comboot_prepare_segment ( struct image *image )
246: {
247: userptr_t seg_userptr;
248: size_t filesz, memsz;
249: int rc;
250:
251: /* Load image in segment */
252: seg_userptr = real_to_user ( COMBOOT_PSP_SEG, 0 );
253:
254: /* Allow etra 0x100 bytes before image for PSP */
255: filesz = image->len + 0x100;
256:
257: /* Ensure the entire 64k segment is free */
258: memsz = 0xFFFF;
259:
260: /* Prepare, verify, and load the real-mode segment */
261: if ( ( rc = prep_segment ( seg_userptr, filesz, memsz ) ) != 0 ) {
262: DBGC ( image, "COMBOOT %p: could not prepare segment: %s\n",
263: image, strerror ( rc ) );
264: return rc;
265: }
266:
267: /* Zero PSP */
268: memset_user ( seg_userptr, 0, 0, 0x100 );
269:
270: /* Copy image to segment:0100 */
271: memcpy_user ( seg_userptr, 0x100, image->data, 0, image->len );
272:
273: return 0;
274: }
275:
276: /**
277: * Probe COMBOOT image
278: *
279: * @v image COMBOOT image
280: * @ret rc Return status code
281: */
282: static int comboot_probe ( struct image *image ) {
283: int rc;
284:
285: DBGC ( image, "COMBOOT %p: name '%s'\n",
286: image, image->name );
287:
288: /* Check if this is a COMBOOT image */
289: if ( ( rc = comboot_identify ( image ) ) != 0 ) {
290:
291: return rc;
292: }
293:
294: return 0;
295: }
296:
297: /**
298: * Execute COMBOOT image
299: *
300: * @v image COMBOOT image
301: * @ret rc Return status code
302: */
303: static int comboot_exec ( struct image *image ) {
304: int rc;
305:
306: /* Sanity check for filesize */
307: if( image->len >= 0xFF00 ) {
308: DBGC( image, "COMBOOT %p: image too large\n",
309: image );
310: return -ENOEXEC;
311: }
312:
313: /* Prepare segment and load image */
314: if ( ( rc = comboot_prepare_segment ( image ) ) != 0 ) {
315: return rc;
316: }
317:
318: return comboot_exec_loop ( image );
319: }
320:
321: /** SYSLINUX COMBOOT (16-bit) image type */
322: struct image_type comboot_image_type __image_type ( PROBE_NORMAL ) = {
323: .name = "COMBOOT",
324: .probe = comboot_probe,
325: .exec = comboot_exec,
326: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.