|
|
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.