00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 FILE_LICENCE ( GPL2_OR_LATER );
00027
00028 #include <stdint.h>
00029 #include <stdlib.h>
00030 #include <string.h>
00031 #include <strings.h>
00032 #include <errno.h>
00033 #include <assert.h>
00034 #include <realmode.h>
00035 #include <basemem.h>
00036 #include <comboot.h>
00037 #include <gpxe/uaccess.h>
00038 #include <gpxe/image.h>
00039 #include <gpxe/segment.h>
00040 #include <gpxe/init.h>
00041 #include <gpxe/features.h>
00042
00043 FEATURE ( FEATURE_IMAGE, "COMBOOT", DHCP_EB_FEATURE_COMBOOT, 1 );
00044
00045 struct image_type comboot_image_type __image_type ( PROBE_NORMAL );
00046
00047
00048
00049
00050 struct comboot_psp {
00051
00052 uint16_t int20;
00053
00054 uint16_t first_non_free_para;
00055 };
00056
00057
00058 #define COMBOOT_PSP_CMDLINE_OFFSET 0x81
00059
00060
00061
00062 #define COMBOOT_MAX_CMDLINE_LEN 125
00063
00064
00065
00066
00067
00068
00069
00070 static void comboot_copy_cmdline ( struct image * image, userptr_t seg_userptr ) {
00071 const char *cmdline = ( image->cmdline ? image->cmdline : "" );
00072 int cmdline_len = strlen ( cmdline );
00073 if( cmdline_len > COMBOOT_MAX_CMDLINE_LEN )
00074 cmdline_len = COMBOOT_MAX_CMDLINE_LEN;
00075 uint8_t len_byte = cmdline_len;
00076 char spc = ' ', cr = '\r';
00077
00078
00079 copy_to_user ( seg_userptr, COMBOOT_PSP_CMDLINE_OFFSET - 1,
00080 &len_byte, 1 );
00081
00082
00083 copy_to_user ( seg_userptr,
00084 COMBOOT_PSP_CMDLINE_OFFSET,
00085 &spc, 1 );
00086
00087
00088 copy_to_user ( seg_userptr,
00089 COMBOOT_PSP_CMDLINE_OFFSET + 1,
00090 cmdline, cmdline_len );
00091
00092
00093 copy_to_user ( seg_userptr,
00094 COMBOOT_PSP_CMDLINE_OFFSET + cmdline_len + 1,
00095 &cr, 1 );
00096 }
00097
00098
00099
00100
00101
00102
00103
00104 static void comboot_init_psp ( struct image * image, userptr_t seg_userptr ) {
00105 struct comboot_psp psp;
00106
00107
00108
00109
00110 psp.int20 = 0x20CD;
00111
00112
00113
00114 psp.first_non_free_para = get_fbms() << 6;
00115
00116 DBGC ( image, "COMBOOT %p: first non-free paragraph = 0x%x\n",
00117 image, psp.first_non_free_para );
00118
00119
00120
00121
00122 copy_to_user ( seg_userptr, 0, &psp, sizeof( psp ) );
00123
00124
00125 comboot_copy_cmdline ( image, seg_userptr );
00126 }
00127
00128
00129
00130
00131
00132
00133
00134 static int comboot_exec ( struct image *image ) {
00135 userptr_t seg_userptr = real_to_user ( COMBOOT_PSP_SEG, 0 );
00136 int state;
00137
00138 state = rmsetjmp ( comboot_return );
00139
00140 switch ( state ) {
00141 case 0:
00142
00143
00144 comboot_init_psp ( image, seg_userptr );
00145
00146
00147 hook_comboot_interrupts();
00148
00149 DBGC ( image, "executing 16-bit COMBOOT image at %4x:0100\n",
00150 COMBOOT_PSP_SEG );
00151
00152
00153
00154
00155
00156
00157 unregister_image ( image );
00158
00159
00160
00161 __asm__ __volatile__ (
00162 REAL_CODE (
00163 "popw %%ax\n\t"
00164 "pushw %%cs\n\t"
00165 "pushw %%ax\n\t"
00166
00167 "movw %w0, %%ds\n\t"
00168 "movw %w0, %%es\n\t"
00169
00170 "movw %w0, %%ss\n\t"
00171 "xor %%sp, %%sp\n\t"
00172 "pushw $0\n\t"
00173 "pushw %w0\n\t"
00174 "pushw $0x100\n\t"
00175
00176 "xorw %%ax, %%ax\n\t"
00177 "xorw %%bx, %%bx\n\t"
00178 "xorw %%cx, %%cx\n\t"
00179 "xorw %%dx, %%dx\n\t"
00180 "xorw %%si, %%si\n\t"
00181 "xorw %%di, %%di\n\t"
00182 "xorw %%bp, %%bp\n\t"
00183 "lret\n\t" )
00184 : : "r" ( COMBOOT_PSP_SEG ) : "eax" );
00185 DBGC ( image, "COMBOOT %p: returned\n", image );
00186 break;
00187
00188 case COMBOOT_EXIT:
00189 DBGC ( image, "COMBOOT %p: exited\n", image );
00190 break;
00191
00192 case COMBOOT_EXIT_RUN_KERNEL:
00193 DBGC ( image, "COMBOOT %p: exited to run kernel %p\n",
00194 image, comboot_replacement_image );
00195 image->replacement = comboot_replacement_image;
00196 comboot_replacement_image = NULL;
00197 image_autoload ( image->replacement );
00198 break;
00199
00200 case COMBOOT_EXIT_COMMAND:
00201 DBGC ( image, "COMBOOT %p: exited after executing command\n",
00202 image );
00203 break;
00204
00205 default:
00206 assert ( 0 );
00207 break;
00208 }
00209
00210 unhook_comboot_interrupts();
00211 comboot_force_text_mode();
00212
00213 return 0;
00214 }
00215
00216
00217
00218
00219
00220
00221
00222 static int comboot_identify ( struct image *image ) {
00223 const char *ext;
00224
00225 ext = strrchr( image->name, '.' );
00226
00227 if ( ! ext ) {
00228 DBGC ( image, "COMBOOT %p: no extension\n",
00229 image );
00230 return -ENOEXEC;
00231 }
00232
00233 ++ext;
00234
00235 if ( strcasecmp( ext, "com" ) && strcasecmp( ext, "cbt" ) ) {
00236 DBGC ( image, "COMBOOT %p: unrecognized extension %s\n",
00237 image, ext );
00238 return -ENOEXEC;
00239 }
00240
00241 return 0;
00242 }
00243
00244
00245
00246
00247
00248
00249 static int comboot_prepare_segment ( struct image *image )
00250 {
00251 userptr_t seg_userptr;
00252 size_t filesz, memsz;
00253 int rc;
00254
00255
00256 seg_userptr = real_to_user ( COMBOOT_PSP_SEG, 0 );
00257
00258
00259 filesz = image->len + 0x100;
00260
00261
00262 memsz = 0xFFFF;
00263
00264
00265 if ( ( rc = prep_segment ( seg_userptr, filesz, memsz ) ) != 0 ) {
00266 DBGC ( image, "COMBOOT %p: could not prepare segment: %s\n",
00267 image, strerror ( rc ) );
00268 return rc;
00269 }
00270
00271
00272 memset_user ( seg_userptr, 0, 0, 0x100 );
00273
00274
00275 memcpy_user ( seg_userptr, 0x100, image->data, 0, image->len );
00276
00277 return 0;
00278 }
00279
00280
00281
00282
00283
00284
00285
00286 static int comboot_load ( struct image *image ) {
00287 int rc;
00288
00289 DBGC ( image, "COMBOOT %p: name '%s'\n",
00290 image, image->name );
00291
00292
00293 if ( ( rc = comboot_identify ( image ) ) != 0 ) {
00294
00295 return rc;
00296 }
00297
00298
00299 if ( ! image->type )
00300 image->type = &comboot_image_type;
00301
00302
00303 if( image->len >= 0xFF00 ) {
00304 DBGC( image, "COMBOOT %p: image too large\n",
00305 image );
00306 return -ENOEXEC;
00307 }
00308
00309
00310 if ( ( rc = comboot_prepare_segment ( image ) ) != 0 ) {
00311 return rc;
00312 }
00313
00314 return 0;
00315 }
00316
00317
00318 struct image_type comboot_image_type __image_type ( PROBE_NORMAL ) = {
00319 .name = "COMBOOT",
00320 .load = comboot_load,
00321 .exec = comboot_exec,
00322 };