176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Copyright (C) 2008 Daniel Verkamp <daniel@drv.nu>. 376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This program is free software; you can redistribute it and/or 576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * modify it under the terms of the GNU General Public License as 676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * published by the Free Software Foundation; either version 2 of the 776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * License, or any later version. 876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This program is distributed in the hope that it will be useful, but 1076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * WITHOUT ANY WARRANTY; without even the implied warranty of 1176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * General Public License for more details. 1376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 1476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * You should have received a copy of the GNU General Public License 1576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * along with this program; if not, write to the Free Software 1676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 1776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 1876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 1976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 2076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @file 2176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 2276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * SYSLINUX COMBOOT (16-bit) image format 2376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 2476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 2576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 2676d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanFILE_LICENCE ( GPL2_OR_LATER ); 2776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 2876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <stdint.h> 2976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <stdlib.h> 3076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <string.h> 3176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <strings.h> 3276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <errno.h> 3376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <assert.h> 3476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <realmode.h> 3576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <basemem.h> 3676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <comboot.h> 3776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/uaccess.h> 3876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/image.h> 3976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/segment.h> 4076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/init.h> 4176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/features.h> 4276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 4376d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanFEATURE ( FEATURE_IMAGE, "COMBOOT", DHCP_EB_FEATURE_COMBOOT, 1 ); 4476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 4576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct image_type comboot_image_type __image_type ( PROBE_NORMAL ); 4676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 4776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 4876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * COMBOOT PSP, copied to offset 0 of code segment 4976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 5076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct comboot_psp { 5176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /** INT 20 instruction, executed if COMBOOT image returns with RET */ 5276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint16_t int20; 5376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /** Segment of first non-free paragraph of memory */ 5476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint16_t first_non_free_para; 5576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}; 5676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 5776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** Offset in PSP of command line */ 5876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define COMBOOT_PSP_CMDLINE_OFFSET 0x81 5976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 6076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** Maximum length of command line in PSP 6176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * (127 bytes minus space and CR) */ 6276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define COMBOOT_MAX_CMDLINE_LEN 125 6376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 6476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 6576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 6676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Copy command line to PSP 6776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 6876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v image COMBOOT image 6976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 7076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void comboot_copy_cmdline ( struct image * image, userptr_t seg_userptr ) { 7176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const char *cmdline = ( image->cmdline ? image->cmdline : "" ); 7276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int cmdline_len = strlen ( cmdline ); 7376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if( cmdline_len > COMBOOT_MAX_CMDLINE_LEN ) 7476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman cmdline_len = COMBOOT_MAX_CMDLINE_LEN; 7576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t len_byte = cmdline_len; 7676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman char spc = ' ', cr = '\r'; 7776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 7876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Copy length to byte before command line */ 7976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman copy_to_user ( seg_userptr, COMBOOT_PSP_CMDLINE_OFFSET - 1, 8076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman &len_byte, 1 ); 8176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 8276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Command line starts with space */ 8376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman copy_to_user ( seg_userptr, 8476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman COMBOOT_PSP_CMDLINE_OFFSET, 8576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman &spc, 1 ); 8676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 8776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Copy command line */ 8876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman copy_to_user ( seg_userptr, 8976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman COMBOOT_PSP_CMDLINE_OFFSET + 1, 9076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman cmdline, cmdline_len ); 9176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 9276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Command line ends with CR */ 9376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman copy_to_user ( seg_userptr, 9476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman COMBOOT_PSP_CMDLINE_OFFSET + cmdline_len + 1, 9576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman &cr, 1 ); 9676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 9776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 9876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 9976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Initialize PSP 10076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 10176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v image COMBOOT image 10276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v seg_userptr segment to initialize 10376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 10476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void comboot_init_psp ( struct image * image, userptr_t seg_userptr ) { 10576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct comboot_psp psp; 10676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 10776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Fill PSP */ 10876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 10976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* INT 20h instruction, byte order reversed */ 11076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman psp.int20 = 0x20CD; 11176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 11276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* get_fbms() returns BIOS free base memory counter, which is in 11376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * kilobytes; x * 1024 / 16 == x * 64 == x << 6 */ 11476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman psp.first_non_free_para = get_fbms() << 6; 11576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 11676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGC ( image, "COMBOOT %p: first non-free paragraph = 0x%x\n", 11776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman image, psp.first_non_free_para ); 11876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 11976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Copy the PSP to offset 0 of segment. 12076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * The rest of the PSP was already zeroed by 12176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * comboot_prepare_segment. */ 12276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman copy_to_user ( seg_userptr, 0, &psp, sizeof( psp ) ); 12376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 12476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Copy the command line to the PSP */ 12576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman comboot_copy_cmdline ( image, seg_userptr ); 12676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 12776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 12876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 12976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Execute COMBOOT image 13076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 13176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v image COMBOOT image 13276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret rc Return status code 13376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 13476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int comboot_exec ( struct image *image ) { 13576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman userptr_t seg_userptr = real_to_user ( COMBOOT_PSP_SEG, 0 ); 13676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int state; 13776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 13876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman state = rmsetjmp ( comboot_return ); 13976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 14076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman switch ( state ) { 14176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case 0: /* First time through; invoke COMBOOT program */ 14276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 14376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Initialize PSP */ 14476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman comboot_init_psp ( image, seg_userptr ); 14576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 14676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Hook COMBOOT API interrupts */ 14776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman hook_comboot_interrupts(); 14876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 14976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGC ( image, "executing 16-bit COMBOOT image at %4x:0100\n", 15076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman COMBOOT_PSP_SEG ); 15176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 15276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Unregister image, so that a "boot" command doesn't 15376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * throw us into an execution loop. We never 15476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * reregister ourselves; COMBOOT images expect to be 15576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * removed on exit. 15676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 15776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unregister_image ( image ); 15876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 15976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Store stack segment at 0x38 and stack pointer at 0x3A 16076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * in the PSP and jump to the image */ 16176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman __asm__ __volatile__ ( 16276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman REAL_CODE ( /* Save return address with segment on old stack */ 16376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "popw %%ax\n\t" 16476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "pushw %%cs\n\t" 16576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "pushw %%ax\n\t" 16676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Set DS=ES=segment with image */ 16776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "movw %w0, %%ds\n\t" 16876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "movw %w0, %%es\n\t" 16976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Set SS:SP to new stack (end of image segment) */ 17076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "movw %w0, %%ss\n\t" 17176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "xor %%sp, %%sp\n\t" 17276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "pushw $0\n\t" 17376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "pushw %w0\n\t" 17476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "pushw $0x100\n\t" 17576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Zero registers (some COM files assume GP regs are 0) */ 17676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "xorw %%ax, %%ax\n\t" 17776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "xorw %%bx, %%bx\n\t" 17876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "xorw %%cx, %%cx\n\t" 17976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "xorw %%dx, %%dx\n\t" 18076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "xorw %%si, %%si\n\t" 18176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "xorw %%di, %%di\n\t" 18276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "xorw %%bp, %%bp\n\t" 18376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "lret\n\t" ) 18476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman : : "r" ( COMBOOT_PSP_SEG ) : "eax" ); 18576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGC ( image, "COMBOOT %p: returned\n", image ); 18676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 18776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 18876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case COMBOOT_EXIT: 18976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGC ( image, "COMBOOT %p: exited\n", image ); 19076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 19176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 19276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case COMBOOT_EXIT_RUN_KERNEL: 19376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGC ( image, "COMBOOT %p: exited to run kernel %p\n", 19476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman image, comboot_replacement_image ); 19576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman image->replacement = comboot_replacement_image; 19676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman comboot_replacement_image = NULL; 19776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman image_autoload ( image->replacement ); 19876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 19976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 20076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case COMBOOT_EXIT_COMMAND: 20176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGC ( image, "COMBOOT %p: exited after executing command\n", 20276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman image ); 20376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 20476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 20576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman default: 20676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman assert ( 0 ); 20776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 20876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 20976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 21076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unhook_comboot_interrupts(); 21176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman comboot_force_text_mode(); 21276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 21376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 21476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 21576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 21676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 21776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Check image name extension 21876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 21976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v image COMBOOT image 22076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret rc Return status code 22176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 22276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int comboot_identify ( struct image *image ) { 22376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const char *ext; 22476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 22576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ext = strrchr( image->name, '.' ); 22676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 22776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( ! ext ) { 22876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGC ( image, "COMBOOT %p: no extension\n", 22976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman image ); 23076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -ENOEXEC; 23176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 23276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 23376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ++ext; 23476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 23576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( strcasecmp( ext, "com" ) && strcasecmp( ext, "cbt" ) ) { 23676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGC ( image, "COMBOOT %p: unrecognized extension %s\n", 23776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman image, ext ); 23876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -ENOEXEC; 23976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 24076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 24176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 24276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 24376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 24476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 24576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Load COMBOOT image into memory, preparing a segment and returning it 24676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v image COMBOOT image 24776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret rc Return status code 24876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 24976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int comboot_prepare_segment ( struct image *image ) 25076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 25176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman userptr_t seg_userptr; 25276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman size_t filesz, memsz; 25376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int rc; 25476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 25576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Load image in segment */ 25676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman seg_userptr = real_to_user ( COMBOOT_PSP_SEG, 0 ); 25776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 25876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Allow etra 0x100 bytes before image for PSP */ 25976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman filesz = image->len + 0x100; 26076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 26176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Ensure the entire 64k segment is free */ 26276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman memsz = 0xFFFF; 26376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 26476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Prepare, verify, and load the real-mode segment */ 26576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( ( rc = prep_segment ( seg_userptr, filesz, memsz ) ) != 0 ) { 26676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGC ( image, "COMBOOT %p: could not prepare segment: %s\n", 26776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman image, strerror ( rc ) ); 26876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return rc; 26976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 27076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 27176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Zero PSP */ 27276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman memset_user ( seg_userptr, 0, 0, 0x100 ); 27376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 27476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Copy image to segment:0100 */ 27576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman memcpy_user ( seg_userptr, 0x100, image->data, 0, image->len ); 27676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 27776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 27876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 27976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 28076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 28176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Load COMBOOT image into memory 28276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 28376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v image COMBOOT image 28476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret rc Return status code 28576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 28676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int comboot_load ( struct image *image ) { 28776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int rc; 28876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 28976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGC ( image, "COMBOOT %p: name '%s'\n", 29076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman image, image->name ); 29176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 29276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Check if this is a COMBOOT image */ 29376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( ( rc = comboot_identify ( image ) ) != 0 ) { 29476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 29576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return rc; 29676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 29776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 29876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* This is a 16-bit COMBOOT image, valid or otherwise */ 29976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( ! image->type ) 30076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman image->type = &comboot_image_type; 30176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 30276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Sanity check for filesize */ 30376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if( image->len >= 0xFF00 ) { 30476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGC( image, "COMBOOT %p: image too large\n", 30576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman image ); 30676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -ENOEXEC; 30776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 30876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 30976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Prepare segment and load image */ 31076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( ( rc = comboot_prepare_segment ( image ) ) != 0 ) { 31176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return rc; 31276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 31376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 31476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 31576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 31676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 31776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** SYSLINUX COMBOOT (16-bit) image type */ 31876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct image_type comboot_image_type __image_type ( PROBE_NORMAL ) = { 31976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .name = "COMBOOT", 32076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .load = comboot_load, 32176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .exec = comboot_exec, 32276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}; 323