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., 51 Franklin Street, Fifth Floor, Boston, MA
23
* SYSLINUX COM32 image format
27
FILE_LICENCE ( GPL2_OR_LATER );
38
#include <ipxe/uaccess.h>
39
#include <ipxe/image.h>
40
#include <ipxe/segment.h>
41
#include <ipxe/init.h>
43
#include <ipxe/console.h>
46
* Execute COMBOOT image
48
* @v image COM32 image
49
* @ret rc Return status code
51
static int com32_exec_loop ( struct image *image ) {
52
struct memory_map memmap;
55
uint32_t avail_mem_top;
57
state = rmsetjmp ( comboot_return );
60
case 0: /* First time through; invoke COM32 program */
63
get_memmap ( &memmap );
65
/* Find end of block covering COM32 image loading area */
66
for ( i = 0, avail_mem_top = 0 ; i < memmap.count ; i++ ) {
67
if ( (memmap.regions[i].start <= COM32_START_PHYS) &&
68
(memmap.regions[i].end > COM32_START_PHYS + image->len) ) {
69
avail_mem_top = memmap.regions[i].end;
74
DBGC ( image, "COM32 %p: available memory top = 0x%x\n",
75
image, avail_mem_top );
77
assert ( avail_mem_top != 0 );
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__ ( PHYS_CODE (
90
/* Preserve registers */
92
/* Preserve stack pointer */
94
"movl %%esp, (%k0)\n\t"
95
/* Switch to COM32 stack */
97
/* Enable interrupts */
99
/* Construct stack frame */
107
/* Call COM32 entry point */
110
/* Disable interrupts */
112
/* Restore stack pointer */
113
"movl 24(%%esp), %%esp\n\t"
114
/* Restore registers */
117
: "r" ( avail_mem_top ),
118
"r" ( virt_to_phys ( com32_cfarcall_wrapper ) ),
119
"r" ( virt_to_phys ( com32_farcall_wrapper ) ),
120
"r" ( get_fbms() * 1024 - ( COM32_BOUNCE_SEG << 4 ) ),
121
"i" ( COM32_BOUNCE_SEG << 4 ),
122
"r" ( virt_to_phys ( com32_intcall_wrapper ) ),
123
"r" ( virt_to_phys ( image->cmdline ?
124
image->cmdline : "" ) ),
125
"i" ( COM32_START_PHYS )
127
DBGC ( image, "COM32 %p: returned\n", image );
131
DBGC ( image, "COM32 %p: exited\n", image );
134
case COMBOOT_EXIT_RUN_KERNEL:
135
assert ( image->replacement );
136
DBGC ( image, "COM32 %p: exited to run kernel %s\n",
137
image, image->replacement->name );
140
case COMBOOT_EXIT_COMMAND:
141
DBGC ( image, "COM32 %p: exited after executing command\n",
150
unhook_comboot_interrupts();
151
comboot_force_text_mode();
157
* Check image name extension
159
* @v image COM32 image
160
* @ret rc Return status code
162
static int com32_identify ( struct image *image ) {
164
static const uint8_t magic[] = { 0xB8, 0xFF, 0x4C, 0xCD, 0x21 };
167
if ( image->len >= 5 ) {
168
/* Check for magic number
172
copy_from_user ( buf, image->data, 0, sizeof(buf) );
173
if ( ! memcmp ( buf, magic, sizeof(buf) ) ) {
174
DBGC ( image, "COM32 %p: found magic number\n",
180
/* Magic number not found; check filename extension */
182
ext = strrchr( image->name, '.' );
185
DBGC ( image, "COM32 %p: no extension\n",
192
if ( strcasecmp( ext, "c32" ) ) {
193
DBGC ( image, "COM32 %p: unrecognized extension %s\n",
203
* Load COM32 image into memory
204
* @v image COM32 image
205
* @ret rc Return status code
207
static int com32_load_image ( struct image *image ) {
208
size_t filesz, memsz;
214
buffer = phys_to_user ( COM32_START_PHYS );
215
if ( ( rc = prep_segment ( buffer, filesz, memsz ) ) != 0 ) {
216
DBGC ( image, "COM32 %p: could not prepare segment: %s\n",
217
image, strerror ( rc ) );
221
/* Copy image to segment */
222
memcpy_user ( buffer, 0, image->data, 0, filesz );
228
* Prepare COM32 low memory bounce buffer
229
* @v image COM32 image
230
* @ret rc Return status code
232
static int com32_prepare_bounce_buffer ( struct image * image ) {
234
userptr_t seg_userptr;
235
size_t filesz, memsz;
238
seg = COM32_BOUNCE_SEG;
239
seg_userptr = real_to_user ( seg, 0 );
241
/* Ensure the entire 64k segment is free */
245
/* Prepare, verify, and load the real-mode segment */
246
if ( ( rc = prep_segment ( seg_userptr, filesz, memsz ) ) != 0 ) {
247
DBGC ( image, "COM32 %p: could not prepare bounce buffer segment: %s\n",
248
image, strerror ( rc ) );
258
* @v image COM32 image
259
* @ret rc Return status code
261
static int com32_probe ( struct image *image ) {
264
DBGC ( image, "COM32 %p: name '%s'\n", image, image->name );
266
/* Check if this is a COMBOOT image */
267
if ( ( rc = com32_identify ( image ) ) != 0 ) {
275
* Execute COMBOOT image
277
* @v image COM32 image
278
* @ret rc Return status code
280
static int com32_exec ( struct image *image ) {
284
if ( ( rc = com32_load_image ( image ) ) != 0 ) {
288
/* Prepare bounce buffer segment */
289
if ( ( rc = com32_prepare_bounce_buffer ( image ) ) != 0 ) {
296
return com32_exec_loop ( image );
299
/** SYSLINUX COM32 image type */
300
struct image_type com32_image_type __image_type ( PROBE_NORMAL ) = {
302
.probe = com32_probe,