Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[comboot] Add COMBOOT and COM32 support
- Loading branch information
1 parent
aa28544
commit e8b22f2
Showing
15 changed files
with
1,816 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,275 @@ | ||
/* | ||
* Copyright (C) 2008 Daniel Verkamp <daniel@drv.nu>. | ||
* | ||
* This program is free software; you can redistribute it and/or | ||
* modify it under the terms of the GNU General Public License as | ||
* published by the Free Software Foundation; either version 2 of the | ||
* License, or any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, but | ||
* WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
* General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program; if not, write to the Free Software | ||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
*/ | ||
|
||
/** | ||
* @file | ||
* | ||
* SYSLINUX COM32 image format | ||
* | ||
*/ | ||
|
||
#include <stdint.h> | ||
#include <stdlib.h> | ||
#include <string.h> | ||
#include <strings.h> | ||
#include <errno.h> | ||
#include <assert.h> | ||
#include <realmode.h> | ||
#include <basemem.h> | ||
#include <comboot.h> | ||
#include <gpxe/uaccess.h> | ||
#include <gpxe/image.h> | ||
#include <gpxe/segment.h> | ||
#include <gpxe/init.h> | ||
#include <gpxe/memmap.h> | ||
|
||
struct image_type com32_image_type __image_type ( PROBE_NORMAL ); | ||
|
||
/** | ||
* Execute COMBOOT image | ||
* | ||
* @v image COM32 image | ||
* @ret rc Return status code | ||
*/ | ||
static int com32_exec ( struct image *image ) { | ||
struct memory_map memmap; | ||
unsigned int i; | ||
int state; | ||
uint32_t avail_mem_top; | ||
|
||
state = setjmp ( comboot_return ); | ||
|
||
switch ( state ) { | ||
case 0: /* First time through; invoke COM32 program */ | ||
|
||
/* Get memory map */ | ||
get_memmap ( &memmap ); | ||
|
||
/* Find end of block covering COM32 image loading area */ | ||
for ( i = 0, avail_mem_top = 0 ; i < memmap.count ; i++ ) { | ||
if ( (memmap.regions[i].start <= COM32_START_PHYS) && | ||
(memmap.regions[i].end > COM32_START_PHYS + image->len) ) { | ||
avail_mem_top = memmap.regions[i].end; | ||
break; | ||
} | ||
} | ||
|
||
DBGC ( image, "COM32 %p: available memory top = 0x%x\n", | ||
image, (int)avail_mem_top ); | ||
|
||
assert ( avail_mem_top != 0 ); | ||
|
||
com32_external_esp = phys_to_virt ( avail_mem_top ); | ||
|
||
/* Hook COMBOOT API interrupts */ | ||
hook_comboot_interrupts( ); | ||
|
||
/* Temporarily de-register image, so that a "boot" command | ||
* doesn't throw us into an execution loop. Hold a reference | ||
* to avoid the image's being freed. | ||
*/ | ||
image_get ( image ); | ||
unregister_image ( image ); | ||
|
||
__asm__ __volatile__ ( | ||
"movl %%esp, (com32_internal_esp)\n\t" /* Save internal virtual address space ESP */ | ||
"movl (com32_external_esp), %%esp\n\t" /* Switch to COM32 ESP (top of available memory) */ | ||
"call _virt_to_phys\n\t" /* Switch to flat physical address space */ | ||
"pushl %0\n\t" /* Pointer to CDECL helper function */ | ||
"pushl %1\n\t" /* Pointer to FAR call helper function */ | ||
"pushl %2\n\t" /* Size of low memory bounce buffer */ | ||
"pushl %3\n\t" /* Pointer to low memory bounce buffer */ | ||
"pushl %4\n\t" /* Pointer to INT call helper function */ | ||
"pushl %5\n\t" /* Pointer to the command line arguments */ | ||
"pushl $6\n\t" /* Number of additional arguments */ | ||
"call *%6\n\t" /* Execute image */ | ||
"call _phys_to_virt\n\t" /* Switch back to internal virtual address space */ | ||
"movl (com32_internal_esp), %%esp\n\t" /* Switch back to internal stack */ | ||
: | ||
: | ||
/* %0 */ "r" ( virt_to_phys ( com32_cfarcall_wrapper ) ), | ||
/* %1 */ "r" ( virt_to_phys ( com32_farcall_wrapper ) ), | ||
/* %2 */ "r" ( get_fbms() * 1024 - (COM32_BOUNCE_SEG << 4) ), | ||
/* %3 */ "i" ( COM32_BOUNCE_SEG << 4 ), | ||
/* %4 */ "r" ( virt_to_phys ( com32_intcall_wrapper ) ), | ||
/* %5 */ "r" ( virt_to_phys ( image->cmdline ) ), | ||
/* %6 */ "r" ( COM32_START_PHYS ) | ||
: | ||
"memory" ); | ||
break; | ||
|
||
case COMBOOT_RETURN_RUN_KERNEL: | ||
DBGC ( image, "COM32 %p: returned to run kernel...\n", image ); | ||
comboot_run_kernel ( ); | ||
break; | ||
|
||
case COMBOOT_RETURN_EXIT: | ||
break; | ||
|
||
} | ||
|
||
comboot_force_text_mode ( ); | ||
|
||
DBGC ( image, "COM32 %p returned\n", image ); | ||
|
||
/* Re-register image and return */ | ||
register_image ( image ); | ||
image_put ( image ); | ||
|
||
return 0; | ||
} | ||
|
||
/** | ||
* Check image name extension | ||
* | ||
* @v image COM32 image | ||
* @ret rc Return status code | ||
*/ | ||
static int com32_identify ( struct image *image ) { | ||
const char *ext; | ||
static const uint8_t magic[] = { 0xB8, 0xFF, 0x4C, 0xCD, 0x21 }; | ||
uint8_t buf[5]; | ||
|
||
if ( image->len >= 5 ) { | ||
/* Check for magic number | ||
* mov eax,21cd4cffh | ||
* B8 FF 4C CD 21 | ||
*/ | ||
copy_from_user ( buf, image->data, 0, sizeof(buf) ); | ||
if ( ! memcmp ( buf, magic, sizeof(buf) ) ) { | ||
DBGC ( image, "COM32 %p: found magic number\n", | ||
image ); | ||
return 0; | ||
} | ||
} | ||
|
||
/* Magic number not found; check filename extension */ | ||
|
||
ext = strrchr( image->name, '.' ); | ||
|
||
if ( ! ext ) { | ||
DBGC ( image, "COM32 %p: no extension\n", | ||
image ); | ||
return -ENOEXEC; | ||
} | ||
|
||
++ext; | ||
|
||
if ( strcasecmp( ext, "c32" ) ) { | ||
DBGC ( image, "COM32 %p: unrecognized extension %s\n", | ||
image, ext ); | ||
return -ENOEXEC; | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
|
||
/** | ||
* Load COM32 image into memory | ||
* @v image COM32 image | ||
* @ret rc Return status code | ||
*/ | ||
static int comboot_load_image ( struct image *image ) { | ||
size_t filesz, memsz; | ||
userptr_t buffer; | ||
int rc; | ||
|
||
filesz = image->len; | ||
memsz = filesz; | ||
buffer = phys_to_user ( COM32_START_PHYS ); | ||
if ( ( rc = prep_segment ( buffer, filesz, memsz ) ) != 0 ) { | ||
DBGC ( image, "COM32 %p: could not prepare segment: %s\n", | ||
image, strerror ( rc ) ); | ||
return rc; | ||
} | ||
|
||
/* Copy image to segment */ | ||
memcpy_user ( buffer, 0, image->data, 0, filesz ); | ||
|
||
return 0; | ||
} | ||
|
||
/** | ||
* Prepare COM32 low memory bounce buffer | ||
* @v image COM32 image | ||
* @ret rc Return status code | ||
*/ | ||
static int comboot_prepare_bounce_buffer ( struct image * image ) { | ||
unsigned int seg; | ||
userptr_t seg_userptr; | ||
size_t filesz, memsz; | ||
int rc; | ||
|
||
seg = COM32_BOUNCE_SEG; | ||
seg_userptr = real_to_user ( seg, 0 ); | ||
|
||
/* Ensure the entire 64k segment is free */ | ||
memsz = 0xFFFF; | ||
filesz = 0; | ||
|
||
/* Prepare, verify, and load the real-mode segment */ | ||
if ( ( rc = prep_segment ( seg_userptr, filesz, memsz ) ) != 0 ) { | ||
DBGC ( image, "COM32 %p: could not prepare bounce buffer segment: %s\n", | ||
image, strerror ( rc ) ); | ||
return rc; | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
/** | ||
* Load COM32 image into memory | ||
* | ||
* @v image COM32 image | ||
* @ret rc Return status code | ||
*/ | ||
static int com32_load ( struct image *image ) { | ||
int rc; | ||
|
||
DBGC ( image, "COM32 %p: name '%s', cmdline '%s'\n", | ||
image, image->name, image->cmdline ); | ||
|
||
/* Check if this is a COMBOOT image */ | ||
if ( ( rc = com32_identify ( image ) ) != 0 ) { | ||
return rc; | ||
} | ||
|
||
/* This is a COM32 image, valid or otherwise */ | ||
if ( ! image->type ) | ||
image->type = &com32_image_type; | ||
|
||
/* Load image */ | ||
if ( ( rc = comboot_load_image ( image ) ) != 0 ) { | ||
return rc; | ||
} | ||
|
||
/* Prepare bounce buffer segment */ | ||
if ( ( rc = comboot_prepare_bounce_buffer ( image ) ) != 0 ) { | ||
return rc; | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
/** SYSLINUX COM32 image type */ | ||
struct image_type com32_image_type __image_type ( PROBE_NORMAL ) = { | ||
.name = "COM32", | ||
.load = com32_load, | ||
.exec = com32_exec, | ||
}; |
Oops, something went wrong.