2 * Copyright (C) 2008 Daniel Verkamp <daniel@drv.nu>.
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.
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.
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.
22 * SYSLINUX COM32 image format
35 #include <gpxe/uaccess.h>
36 #include <gpxe/image.h>
37 #include <gpxe/segment.h>
38 #include <gpxe/init.h>
39 #include <gpxe/memmap.h>
41 struct image_type com32_image_type __image_type ( PROBE_NORMAL );
44 * Execute COMBOOT image
46 * @v image COM32 image
47 * @ret rc Return status code
49 static int com32_exec ( struct image *image ) {
50 struct memory_map memmap;
53 uint32_t avail_mem_top;
55 state = setjmp ( comboot_return );
58 case 0: /* First time through; invoke COM32 program */
61 get_memmap ( &memmap );
63 /* Find end of block covering COM32 image loading area */
64 for ( i = 0, avail_mem_top = 0 ; i < memmap.count ; i++ ) {
65 if ( (memmap.regions[i].start <= COM32_START_PHYS) &&
66 (memmap.regions[i].end > COM32_START_PHYS + image->len) ) {
67 avail_mem_top = memmap.regions[i].end;
72 DBGC ( image, "COM32 %p: available memory top = 0x%x\n",
73 image, avail_mem_top );
75 assert ( avail_mem_top != 0 );
77 com32_external_esp = phys_to_virt ( avail_mem_top );
79 /* Hook COMBOOT API interrupts */
80 hook_comboot_interrupts();
82 /* Unregister image, so that a "boot" command doesn't
83 * throw us into an execution loop. We never
84 * reregister ourselves; COMBOOT images expect to be
87 unregister_image ( image );
89 __asm__ __volatile__ (
90 "movl %%esp, (com32_internal_esp)\n\t" /* Save internal virtual address space ESP */
91 "movl (com32_external_esp), %%esp\n\t" /* Switch to COM32 ESP (top of available memory) */
92 "call _virt_to_phys\n\t" /* Switch to flat physical address space */
93 "pushl %0\n\t" /* Pointer to CDECL helper function */
94 "pushl %1\n\t" /* Pointer to FAR call helper function */
95 "pushl %2\n\t" /* Size of low memory bounce buffer */
96 "pushl %3\n\t" /* Pointer to low memory bounce buffer */
97 "pushl %4\n\t" /* Pointer to INT call helper function */
98 "pushl %5\n\t" /* Pointer to the command line arguments */
99 "pushl $6\n\t" /* Number of additional arguments */
100 "call *%6\n\t" /* Execute image */
101 "call _phys_to_virt\n\t" /* Switch back to internal virtual address space */
102 "movl (com32_internal_esp), %%esp\n\t" /* Switch back to internal stack */
105 /* %0 */ "r" ( virt_to_phys ( com32_cfarcall_wrapper ) ),
106 /* %1 */ "r" ( virt_to_phys ( com32_farcall_wrapper ) ),
107 /* %2 */ "r" ( get_fbms() * 1024 - (COM32_BOUNCE_SEG << 4) ),
108 /* %3 */ "i" ( COM32_BOUNCE_SEG << 4 ),
109 /* %4 */ "r" ( virt_to_phys ( com32_intcall_wrapper ) ),
110 /* %5 */ "r" ( virt_to_phys ( image->cmdline ) ),
111 /* %6 */ "r" ( COM32_START_PHYS )
114 DBGC ( image, "COM32 %p: returned\n", image );
118 DBGC ( image, "COM32 %p: exited\n", image );
121 case COMBOOT_EXIT_RUN_KERNEL:
122 DBGC ( image, "COM32 %p: exited to run kernel %p\n",
123 image, comboot_replacement_image );
124 image->replacement = comboot_replacement_image;
125 comboot_replacement_image = NULL;
126 image_autoload ( image->replacement );
129 case COMBOOT_EXIT_COMMAND:
130 DBGC ( image, "COM32 %p: exited after executing command\n",
139 unhook_comboot_interrupts();
140 comboot_force_text_mode();
146 * Check image name extension
148 * @v image COM32 image
149 * @ret rc Return status code
151 static int com32_identify ( struct image *image ) {
153 static const uint8_t magic[] = { 0xB8, 0xFF, 0x4C, 0xCD, 0x21 };
156 if ( image->len >= 5 ) {
157 /* Check for magic number
161 copy_from_user ( buf, image->data, 0, sizeof(buf) );
162 if ( ! memcmp ( buf, magic, sizeof(buf) ) ) {
163 DBGC ( image, "COM32 %p: found magic number\n",
169 /* Magic number not found; check filename extension */
171 ext = strrchr( image->name, '.' );
174 DBGC ( image, "COM32 %p: no extension\n",
181 if ( strcasecmp( ext, "c32" ) ) {
182 DBGC ( image, "COM32 %p: unrecognized extension %s\n",
192 * Load COM32 image into memory
193 * @v image COM32 image
194 * @ret rc Return status code
196 static int comboot_load_image ( struct image *image ) {
197 size_t filesz, memsz;
203 buffer = phys_to_user ( COM32_START_PHYS );
204 if ( ( rc = prep_segment ( buffer, filesz, memsz ) ) != 0 ) {
205 DBGC ( image, "COM32 %p: could not prepare segment: %s\n",
206 image, strerror ( rc ) );
210 /* Copy image to segment */
211 memcpy_user ( buffer, 0, image->data, 0, filesz );
217 * Prepare COM32 low memory bounce buffer
218 * @v image COM32 image
219 * @ret rc Return status code
221 static int comboot_prepare_bounce_buffer ( struct image * image ) {
223 userptr_t seg_userptr;
224 size_t filesz, memsz;
227 seg = COM32_BOUNCE_SEG;
228 seg_userptr = real_to_user ( seg, 0 );
230 /* Ensure the entire 64k segment is free */
234 /* Prepare, verify, and load the real-mode segment */
235 if ( ( rc = prep_segment ( seg_userptr, filesz, memsz ) ) != 0 ) {
236 DBGC ( image, "COM32 %p: could not prepare bounce buffer segment: %s\n",
237 image, strerror ( rc ) );
245 * Load COM32 image into memory
247 * @v image COM32 image
248 * @ret rc Return status code
250 static int com32_load ( struct image *image ) {
253 DBGC ( image, "COM32 %p: name '%s', cmdline '%s'\n",
254 image, image->name, image->cmdline );
256 /* Check if this is a COMBOOT image */
257 if ( ( rc = com32_identify ( image ) ) != 0 ) {
261 /* This is a COM32 image, valid or otherwise */
263 image->type = &com32_image_type;
266 if ( ( rc = comboot_load_image ( image ) ) != 0 ) {
270 /* Prepare bounce buffer segment */
271 if ( ( rc = comboot_prepare_bounce_buffer ( image ) ) != 0 ) {
278 /** SYSLINUX COM32 image type */
279 struct image_type com32_image_type __image_type ( PROBE_NORMAL ) = {