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/memmap.h>
00042
00043 struct image_type com32_image_type __image_type ( PROBE_NORMAL );
00044
00045
00046
00047
00048
00049
00050
00051 static int com32_exec ( struct image *image ) {
00052 struct memory_map memmap;
00053 unsigned int i;
00054 int state;
00055 uint32_t avail_mem_top;
00056
00057 state = rmsetjmp ( comboot_return );
00058
00059 switch ( state ) {
00060 case 0:
00061
00062
00063 get_memmap ( &memmap );
00064
00065
00066 for ( i = 0, avail_mem_top = 0 ; i < memmap.count ; i++ ) {
00067 if ( (memmap.regions[i].start <= COM32_START_PHYS) &&
00068 (memmap.regions[i].end > COM32_START_PHYS + image->len) ) {
00069 avail_mem_top = memmap.regions[i].end;
00070 break;
00071 }
00072 }
00073
00074 DBGC ( image, "COM32 %p: available memory top = 0x%x\n",
00075 image, avail_mem_top );
00076
00077 assert ( avail_mem_top != 0 );
00078
00079 com32_external_esp = phys_to_virt ( avail_mem_top );
00080
00081
00082 hook_comboot_interrupts();
00083
00084
00085
00086
00087
00088
00089 unregister_image ( image );
00090
00091 __asm__ __volatile__ (
00092 "movl %%esp, (com32_internal_esp)\n\t"
00093 "movl (com32_external_esp), %%esp\n\t"
00094 "call _virt_to_phys\n\t"
00095 "pushl %0\n\t"
00096 "pushl %1\n\t"
00097 "pushl %2\n\t"
00098 "pushl %3\n\t"
00099 "pushl %4\n\t"
00100 "pushl %5\n\t"
00101 "pushl $6\n\t"
00102 "call *%6\n\t"
00103 "call _phys_to_virt\n\t"
00104 "movl (com32_internal_esp), %%esp\n\t"
00105 :
00106 :
00107 "r" ( virt_to_phys ( com32_cfarcall_wrapper ) ),
00108 "r" ( virt_to_phys ( com32_farcall_wrapper ) ),
00109 "r" ( get_fbms() * 1024 - (COM32_BOUNCE_SEG << 4) ),
00110 "i" ( COM32_BOUNCE_SEG << 4 ),
00111 "r" ( virt_to_phys ( com32_intcall_wrapper ) ),
00112 "r" ( virt_to_phys ( image->cmdline ) ),
00113 "r" ( COM32_START_PHYS )
00114 :
00115 "memory" );
00116 DBGC ( image, "COM32 %p: returned\n", image );
00117 break;
00118
00119 case COMBOOT_EXIT:
00120 DBGC ( image, "COM32 %p: exited\n", image );
00121 break;
00122
00123 case COMBOOT_EXIT_RUN_KERNEL:
00124 DBGC ( image, "COM32 %p: exited to run kernel %p\n",
00125 image, comboot_replacement_image );
00126 image->replacement = comboot_replacement_image;
00127 comboot_replacement_image = NULL;
00128 image_autoload ( image->replacement );
00129 break;
00130
00131 case COMBOOT_EXIT_COMMAND:
00132 DBGC ( image, "COM32 %p: exited after executing command\n",
00133 image );
00134 break;
00135
00136 default:
00137 assert ( 0 );
00138 break;
00139 }
00140
00141 unhook_comboot_interrupts();
00142 comboot_force_text_mode();
00143
00144 return 0;
00145 }
00146
00147
00148
00149
00150
00151
00152
00153 static int com32_identify ( struct image *image ) {
00154 const char *ext;
00155 static const uint8_t magic[] = { 0xB8, 0xFF, 0x4C, 0xCD, 0x21 };
00156 uint8_t buf[5];
00157
00158 if ( image->len >= 5 ) {
00159
00160
00161
00162
00163 copy_from_user ( buf, image->data, 0, sizeof(buf) );
00164 if ( ! memcmp ( buf, magic, sizeof(buf) ) ) {
00165 DBGC ( image, "COM32 %p: found magic number\n",
00166 image );
00167 return 0;
00168 }
00169 }
00170
00171
00172
00173 ext = strrchr( image->name, '.' );
00174
00175 if ( ! ext ) {
00176 DBGC ( image, "COM32 %p: no extension\n",
00177 image );
00178 return -ENOEXEC;
00179 }
00180
00181 ++ext;
00182
00183 if ( strcasecmp( ext, "c32" ) ) {
00184 DBGC ( image, "COM32 %p: unrecognized extension %s\n",
00185 image, ext );
00186 return -ENOEXEC;
00187 }
00188
00189 return 0;
00190 }
00191
00192
00193
00194
00195
00196
00197
00198 static int comboot_load_image ( struct image *image ) {
00199 size_t filesz, memsz;
00200 userptr_t buffer;
00201 int rc;
00202
00203 filesz = image->len;
00204 memsz = filesz;
00205 buffer = phys_to_user ( COM32_START_PHYS );
00206 if ( ( rc = prep_segment ( buffer, filesz, memsz ) ) != 0 ) {
00207 DBGC ( image, "COM32 %p: could not prepare segment: %s\n",
00208 image, strerror ( rc ) );
00209 return rc;
00210 }
00211
00212
00213 memcpy_user ( buffer, 0, image->data, 0, filesz );
00214
00215 return 0;
00216 }
00217
00218
00219
00220
00221
00222
00223 static int comboot_prepare_bounce_buffer ( struct image * image ) {
00224 unsigned int seg;
00225 userptr_t seg_userptr;
00226 size_t filesz, memsz;
00227 int rc;
00228
00229 seg = COM32_BOUNCE_SEG;
00230 seg_userptr = real_to_user ( seg, 0 );
00231
00232
00233 memsz = 0xFFFF;
00234 filesz = 0;
00235
00236
00237 if ( ( rc = prep_segment ( seg_userptr, filesz, memsz ) ) != 0 ) {
00238 DBGC ( image, "COM32 %p: could not prepare bounce buffer segment: %s\n",
00239 image, strerror ( rc ) );
00240 return rc;
00241 }
00242
00243 return 0;
00244 }
00245
00246
00247
00248
00249
00250
00251
00252 static int com32_load ( struct image *image ) {
00253 int rc;
00254
00255 DBGC ( image, "COM32 %p: name '%s', cmdline '%s'\n",
00256 image, image->name, image->cmdline );
00257
00258
00259 if ( ( rc = com32_identify ( image ) ) != 0 ) {
00260 return rc;
00261 }
00262
00263
00264 if ( ! image->type )
00265 image->type = &com32_image_type;
00266
00267
00268 if ( ( rc = comboot_load_image ( image ) ) != 0 ) {
00269 return rc;
00270 }
00271
00272
00273 if ( ( rc = comboot_prepare_bounce_buffer ( image ) ) != 0 ) {
00274 return rc;
00275 }
00276
00277 return 0;
00278 }
00279
00280
00281 struct image_type com32_image_type __image_type ( PROBE_NORMAL ) = {
00282 .name = "COM32",
00283 .load = com32_load,
00284 .exec = com32_exec,
00285 };