2 * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
3 * Copyright (C) 2020 longpanda <admin@ventoy.net>.
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or any later version.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 * You can also choose to distribute this program under the terms of
21 * the Unmodified Binary Distribution Licence (as given in the file
22 * COPYING.UBDL), provided that you have satisfied its requirements.
25 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL
);
34 #include <ipxe/blockdev.h>
36 #include <ipxe/acpi.h>
37 #include <ipxe/sanboot.h>
38 #include <ipxe/device.h>
40 #include <ipxe/timer.h>
41 #include <ipxe/eltorito.h>
42 #include <ipxe/umalloc.h>
43 #include <ipxe/acpi.h>
44 #include <ipxe/ibft.h>
48 #include <bootsector.h>
51 #include "ventoy_int13.h"
53 static unsigned int g_drive_map1
= 0;
54 static unsigned int g_drive_map2
= 0;
60 * This module provides a mechanism for exporting block devices via
61 * the BIOS INT 13 disk interrupt interface.
65 /** INT 13 SAN device private data */
67 /** BIOS natural drive number (0x00-0xff)
69 * This is the drive number that would have been assigned by
70 * 'naturally' appending the drive to the end of the BIOS
73 * If the emulated drive replaces a preexisting drive, this is
74 * the drive number that the preexisting drive gets remapped
77 unsigned int natural_drive
;
79 /** Number of cylinders
81 * The cylinder number field in an INT 13 call is ten bits
82 * wide, giving a maximum of 1024 cylinders. Conventionally,
83 * when the 7.8GB limit of a CHS address is exceeded, it is
84 * the number of cylinders that is increased beyond the
87 unsigned int cylinders
;
90 * The head number field in an INT 13 call is eight bits wide,
91 * giving a maximum of 256 heads. However, apparently all
92 * versions of MS-DOS up to and including Win95 fail with 256
93 * heads, so the maximum encountered in practice is 255.
96 /** Number of sectors per track
98 * The sector number field in an INT 13 call is six bits wide,
99 * giving a maximum of 63 sectors, since sector numbering
100 * (unlike head and cylinder numbering) starts at 1, not 0.
102 unsigned int sectors_per_track
;
104 /** Address of El Torito boot catalog (if any) */
105 unsigned int boot_catalog
;
106 /** Status of last operation */
110 /** Vector for chaining to other INT 13 handlers */
111 static struct segoff
__text16 ( int13_vector
);
112 #define int13_vector __use_text16 ( int13_vector )
114 /** Assembly wrapper */
115 extern void int13_wrapper ( void );
117 /** Dummy floppy disk parameter table */
118 static struct int13_fdd_parameters
__data16 ( int13_fdd_params
) = {
119 /* 512 bytes per sector */
120 .bytes_per_sector
= 0x02,
121 /* Highest sectors per track that we ever return */
122 .sectors_per_track
= 48,
124 #define int13_fdd_params __use_data16 ( int13_fdd_params )
129 * This is a cached copy of the BIOS Data Area equipment word at
132 static uint16_t equipment_word
;
135 * Number of BIOS floppy disk drives
137 * This is derived from the equipment word. It is held in .text16 to
138 * allow for easy access by the INT 13,08 wrapper.
140 static uint8_t __text16 ( num_fdds
);
141 #define num_fdds __use_text16 ( num_fdds )
144 * Number of BIOS hard disk drives
146 * This is a cached copy of the BIOS Data Area number of hard disk
147 * drives at 40:75. It is held in .text16 to allow for easy access by
148 * the INT 13,08 wrapper.
150 static uint8_t __text16 ( num_drives
);
151 #define num_drives __use_text16 ( num_drives )
152 static struct san_device
*g_sandev
;
155 * Calculate SAN device capacity (limited to 32 bits)
157 * @v sandev SAN device
158 * @ret blocks Number of blocks
160 static inline uint32_t int13_capacity32 ( struct san_device
*sandev
) {
161 uint64_t capacity
= sandev_capacity ( sandev
);
162 return ( ( capacity
<= 0xffffffffUL
) ? capacity
: 0xffffffff );
166 * Test if SAN device is a floppy disk drive
168 * @v sandev SAN device
169 * @ret is_fdd SAN device is a floppy disk drive
171 static inline int int13_is_fdd ( struct san_device
*sandev
) {
178 * Guess INT 13 hard disk drive geometry
180 * @v sandev SAN device
181 * @v scratch Scratch area for single-sector reads
182 * @ret heads Guessed number of heads
183 * @ret sectors Guessed number of sectors per track
184 * @ret rc Return status code
186 * Guesses the drive geometry by inspecting the partition table.
188 static int int13_guess_geometry_hdd ( struct san_device
*sandev
, void *scratch
,
190 unsigned int *sectors
) {
191 struct master_boot_record
*mbr
= scratch
;
192 struct partition_table_entry
*partition
;
194 unsigned int start_cylinder
;
195 unsigned int start_head
;
196 unsigned int start_sector
;
197 unsigned int end_head
;
198 unsigned int end_sector
;
201 /* Read partition table */
202 if ( ( rc
= sandev_read ( sandev
, 0, 1, virt_to_user ( mbr
) ) ) != 0 ) {
203 DBGC ( sandev
, "INT13 drive %02x could not read "
204 "partition table to guess geometry: %s\n",
205 sandev
->drive
, strerror ( rc
) );
208 DBGC2 ( sandev
, "INT13 drive %02x has MBR:\n", sandev
->drive
);
209 DBGC2_HDA ( sandev
, 0, mbr
, sizeof ( *mbr
) );
210 DBGC ( sandev
, "INT13 drive %02x has signature %08x\n",
211 sandev
->drive
, mbr
->signature
);
213 /* Scan through partition table and modify guesses for
214 * heads and sectors_per_track if we find any used
219 for ( i
= 0 ; i
< 4 ; i
++ ) {
221 /* Skip empty partitions */
222 partition
= &mbr
->partitions
[i
];
223 if ( ! partition
->type
)
226 /* If partition starts on cylinder 0 then we can
227 * unambiguously determine the number of sectors.
229 start_cylinder
= PART_CYLINDER ( partition
->chs_start
);
230 start_head
= PART_HEAD ( partition
->chs_start
);
231 start_sector
= PART_SECTOR ( partition
->chs_start
);
232 if ( ( start_cylinder
== 0 ) && ( start_head
!= 0 ) ) {
233 *sectors
= ( ( partition
->start
+ 1 - start_sector
) /
235 DBGC ( sandev
, "INT13 drive %02x guessing C/H/S "
236 "xx/xx/%d based on partition %d\n",
237 sandev
->drive
, *sectors
, ( i
+ 1 ) );
240 /* If partition ends on a higher head or sector number
241 * than our current guess, then increase the guess.
243 end_head
= PART_HEAD ( partition
->chs_end
);
244 end_sector
= PART_SECTOR ( partition
->chs_end
);
245 if ( ( end_head
+ 1 ) > *heads
) {
246 *heads
= ( end_head
+ 1 );
247 DBGC ( sandev
, "INT13 drive %02x guessing C/H/S "
248 "xx/%d/xx based on partition %d\n",
249 sandev
->drive
, *heads
, ( i
+ 1 ) );
251 if ( end_sector
> *sectors
) {
252 *sectors
= end_sector
;
253 DBGC ( sandev
, "INT13 drive %02x guessing C/H/S "
254 "xx/xx/%d based on partition %d\n",
255 sandev
->drive
, *sectors
, ( i
+ 1 ) );
259 /* Default guess is xx/255/63 */
268 /** Recognised floppy disk geometries */
269 static const struct int13_fdd_geometry int13_fdd_geometries
[] = {
270 INT13_FDD_GEOMETRY ( 40, 1, 8 ),
271 INT13_FDD_GEOMETRY ( 40, 1, 9 ),
272 INT13_FDD_GEOMETRY ( 40, 2, 8 ),
273 INT13_FDD_GEOMETRY ( 40, 1, 9 ),
274 INT13_FDD_GEOMETRY ( 80, 2, 8 ),
275 INT13_FDD_GEOMETRY ( 80, 2, 9 ),
276 INT13_FDD_GEOMETRY ( 80, 2, 15 ),
277 INT13_FDD_GEOMETRY ( 80, 2, 18 ),
278 INT13_FDD_GEOMETRY ( 80, 2, 20 ),
279 INT13_FDD_GEOMETRY ( 80, 2, 21 ),
280 INT13_FDD_GEOMETRY ( 82, 2, 21 ),
281 INT13_FDD_GEOMETRY ( 83, 2, 21 ),
282 INT13_FDD_GEOMETRY ( 80, 2, 22 ),
283 INT13_FDD_GEOMETRY ( 80, 2, 23 ),
284 INT13_FDD_GEOMETRY ( 80, 2, 24 ),
285 INT13_FDD_GEOMETRY ( 80, 2, 36 ),
286 INT13_FDD_GEOMETRY ( 80, 2, 39 ),
287 INT13_FDD_GEOMETRY ( 80, 2, 40 ),
288 INT13_FDD_GEOMETRY ( 80, 2, 44 ),
289 INT13_FDD_GEOMETRY ( 80, 2, 48 ),
293 * Guess INT 13 floppy disk drive geometry
295 * @v sandev SAN device
296 * @ret heads Guessed number of heads
297 * @ret sectors Guessed number of sectors per track
298 * @ret rc Return status code
300 * Guesses the drive geometry by inspecting the disk size.
302 static int int13_guess_geometry_fdd ( struct san_device
*sandev
,
304 unsigned int *sectors
) {
305 unsigned int blocks
= sandev_capacity ( sandev
);
306 const struct int13_fdd_geometry
*geometry
;
307 unsigned int cylinders
;
310 /* Look for a match against a known geometry */
311 for ( i
= 0 ; i
< ( sizeof ( int13_fdd_geometries
) /
312 sizeof ( int13_fdd_geometries
[0] ) ) ; i
++ ) {
313 geometry
= &int13_fdd_geometries
[i
];
314 cylinders
= INT13_FDD_CYLINDERS ( geometry
);
315 *heads
= INT13_FDD_HEADS ( geometry
);
316 *sectors
= INT13_FDD_SECTORS ( geometry
);
317 if ( ( cylinders
* (*heads
) * (*sectors
) ) == blocks
) {
318 DBGC ( sandev
, "INT13 drive %02x guessing C/H/S "
319 "%d/%d/%d based on size %dK\n", sandev
->drive
,
320 cylinders
, *heads
, *sectors
, ( blocks
/ 2 ) );
325 /* Otherwise, assume a partial disk image in the most common
326 * format (1440K, 80/2/18).
330 DBGC ( sandev
, "INT13 drive %02x guessing C/H/S xx/%d/%d based on size "
331 "%dK\n", sandev
->drive
, *heads
, *sectors
, ( blocks
/ 2 ) );
336 * Guess INT 13 drive geometry
338 * @v sandev SAN device
339 * @v scratch Scratch area for single-sector reads
340 * @ret rc Return status code
342 static int int13_guess_geometry ( struct san_device
*sandev
, void *scratch
) {
343 struct int13_data
*int13
= sandev
->priv
;
344 unsigned int guessed_heads
;
345 unsigned int guessed_sectors
;
347 unsigned int blocks_per_cyl
;
350 /* Guess geometry according to drive type */
351 if ( int13_is_fdd ( sandev
) ) {
352 if ( ( rc
= int13_guess_geometry_fdd ( sandev
, &guessed_heads
,
353 &guessed_sectors
)) != 0)
356 if ( ( rc
= int13_guess_geometry_hdd ( sandev
, scratch
,
358 &guessed_sectors
)) != 0)
362 /* Apply guesses if no geometry already specified */
363 if ( ! int13
->heads
)
364 int13
->heads
= guessed_heads
;
365 if ( ! int13
->sectors_per_track
)
366 int13
->sectors_per_track
= guessed_sectors
;
367 if ( ! int13
->cylinders
) {
368 /* Avoid attempting a 64-bit divide on a 32-bit system */
369 blocks
= int13_capacity32 ( sandev
);
370 blocks_per_cyl
= ( int13
->heads
* int13
->sectors_per_track
);
371 assert ( blocks_per_cyl
!= 0 );
372 int13
->cylinders
= ( blocks
/ blocks_per_cyl
);
373 if ( int13
->cylinders
> 1024 )
374 int13
->cylinders
= 1024;
382 * Update BIOS drive count
384 void int13_sync_num_drives ( void ) {
385 struct san_device
*sandev
;
386 struct int13_data
*int13
;
391 /* Get current drive counts */
392 get_real ( equipment_word
, BDA_SEG
, BDA_EQUIPMENT_WORD
);
393 get_real ( num_drives
, BDA_SEG
, BDA_NUM_DRIVES
);
394 num_fdds
= ( ( equipment_word
& 0x0001 ) ?
395 ( ( ( equipment_word
>> 6 ) & 0x3 ) + 1 ) : 0 );
397 /* Ensure count is large enough to cover all of our SAN devices */
398 for_each_sandev ( sandev
) {
399 int13
= sandev
->priv
;
400 counter
= ( int13_is_fdd ( sandev
) ? &num_fdds
: &num_drives
);
401 max_drive
= sandev
->drive
;
402 if ( max_drive
< int13
->natural_drive
)
403 max_drive
= int13
->natural_drive
;
404 required
= ( ( max_drive
& 0x7f ) + 1 );
405 if ( *counter
< required
) {
407 DBGC ( sandev
, "INT13 drive %02x added to drive count: "
408 "%d HDDs, %d FDDs\n",
409 sandev
->drive
, num_drives
, num_fdds
);
413 /* Update current drive count */
414 equipment_word
&= ~( ( 0x3 << 6 ) | 0x0001 );
416 equipment_word
|= ( 0x0001 |
417 ( ( ( num_fdds
- 1 ) & 0x3 ) << 6 ) );
419 put_real ( equipment_word
, BDA_SEG
, BDA_EQUIPMENT_WORD
);
420 put_real ( num_drives
, BDA_SEG
, BDA_NUM_DRIVES
);
424 * Check number of drives
426 void int13_check_num_drives ( void ) {
427 uint16_t check_equipment_word
;
428 uint8_t check_num_drives
;
430 get_real ( check_equipment_word
, BDA_SEG
, BDA_EQUIPMENT_WORD
);
431 get_real ( check_num_drives
, BDA_SEG
, BDA_NUM_DRIVES
);
432 if ( ( check_equipment_word
!= equipment_word
) ||
433 ( check_num_drives
!= num_drives
) ) {
434 int13_sync_num_drives();
439 * INT 13, 00 - Reset disk system
441 * @v sandev SAN device
442 * @ret status Status code
444 static int int13_reset ( struct san_device
*sandev
,
445 struct i386_all_regs
*ix86 __unused
) {
448 DBGC2 ( sandev
, "Reset drive\n" );
450 /* Reset SAN device */
451 if ( ( rc
= sandev_reset ( sandev
) ) != 0 )
452 return -INT13_STATUS_RESET_FAILED
;
458 * INT 13, 01 - Get status of last operation
460 * @v sandev SAN device
461 * @ret status Status code
463 static int int13_get_last_status ( struct san_device
*sandev
,
464 struct i386_all_regs
*ix86 __unused
) {
465 struct int13_data
*int13
= sandev
->priv
;
467 DBGC2 ( sandev
, "Get status of last operation\n" );
468 return int13
->last_status
;
472 * Read / write sectors
474 * @v sandev SAN device
475 * @v al Number of sectors to read or write (must be nonzero)
476 * @v ch Low bits of cylinder number
477 * @v cl (bits 7:6) High bits of cylinder number
478 * @v cl (bits 5:0) Sector number
480 * @v es:bx Data buffer
481 * @v sandev_rw SAN device read/write method
482 * @ret status Status code
483 * @ret al Number of sectors read or written
485 static int int13_rw_sectors ( struct san_device
*sandev
,
486 struct i386_all_regs
*ix86
,
487 int ( * sandev_rw
) ( struct san_device
*sandev
,
490 userptr_t buffer
) ) {
491 struct int13_data
*int13
= sandev
->priv
;
492 unsigned int cylinder
, head
, sector
;
498 /* Validate blocksize */
499 if ( sandev_blksize ( sandev
) != INT13_BLKSIZE
) {
500 DBGC ( sandev
, "\nINT 13 drive %02x invalid blocksize (%zd) "
501 "for non-extended read/write\n",
502 sandev
->drive
, sandev_blksize ( sandev
) );
503 return -INT13_STATUS_INVALID
;
506 /* Calculate parameters */
507 cylinder
= ( ( ( ix86
->regs
.cl
& 0xc0 ) << 2 ) | ix86
->regs
.ch
);
508 head
= ix86
->regs
.dh
;
509 sector
= ( ix86
->regs
.cl
& 0x3f );
510 if ( ( cylinder
>= int13
->cylinders
) ||
511 ( head
>= int13
->heads
) ||
512 ( sector
< 1 ) || ( sector
> int13
->sectors_per_track
) ) {
513 DBGC ( sandev
, "C/H/S %d/%d/%d out of range for geometry "
514 "%d/%d/%d\n", cylinder
, head
, sector
, int13
->cylinders
,
515 int13
->heads
, int13
->sectors_per_track
);
516 return -INT13_STATUS_INVALID
;
518 lba
= ( ( ( ( cylinder
* int13
->heads
) + head
)
519 * int13
->sectors_per_track
) + sector
- 1 );
520 count
= ix86
->regs
.al
;
521 buffer
= real_to_user ( ix86
->segs
.es
, ix86
->regs
.bx
);
523 DBGC2 ( sandev
, "C/H/S %d/%d/%d = LBA %08lx <-> %04x:%04x (count %d)\n",
524 cylinder
, head
, sector
, lba
, ix86
->segs
.es
, ix86
->regs
.bx
,
527 /* Read from / write to block device */
528 if ( ( rc
= sandev_rw ( sandev
, lba
, count
, buffer
) ) != 0 ){
529 DBGC ( sandev
, "INT13 drive %02x I/O failed: %s\n",
530 sandev
->drive
, strerror ( rc
) );
531 return -INT13_STATUS_READ_ERROR
;
538 * INT 13, 02 - Read sectors
540 * @v sandev SAN device
541 * @v al Number of sectors to read (must be nonzero)
542 * @v ch Low bits of cylinder number
543 * @v cl (bits 7:6) High bits of cylinder number
544 * @v cl (bits 5:0) Sector number
546 * @v es:bx Data buffer
547 * @ret status Status code
548 * @ret al Number of sectors read
550 static int int13_read_sectors ( struct san_device
*sandev
,
551 struct i386_all_regs
*ix86
) {
553 DBGC2 ( sandev
, "Read: " );
554 return int13_rw_sectors ( sandev
, ix86
, sandev_read
);
558 * INT 13, 03 - Write sectors
560 * @v sandev SAN device
561 * @v al Number of sectors to write (must be nonzero)
562 * @v ch Low bits of cylinder number
563 * @v cl (bits 7:6) High bits of cylinder number
564 * @v cl (bits 5:0) Sector number
566 * @v es:bx Data buffer
567 * @ret status Status code
568 * @ret al Number of sectors written
570 static int int13_write_sectors ( struct san_device
*sandev
,
571 struct i386_all_regs
*ix86
) {
573 DBGC2 ( sandev
, "Write: " );
574 return int13_rw_sectors ( sandev
, ix86
, sandev_write
);
578 * INT 13, 08 - Get drive parameters
580 * @v sandev SAN device
581 * @ret status Status code
582 * @ret ch Low bits of maximum cylinder number
583 * @ret cl (bits 7:6) High bits of maximum cylinder number
584 * @ret cl (bits 5:0) Maximum sector number
585 * @ret dh Maximum head number
586 * @ret dl Number of drives
588 static int int13_get_parameters ( struct san_device
*sandev
,
589 struct i386_all_regs
*ix86
) {
590 struct int13_data
*int13
= sandev
->priv
;
591 unsigned int max_cylinder
= int13
->cylinders
- 1;
592 unsigned int max_head
= int13
->heads
- 1;
593 unsigned int max_sector
= int13
->sectors_per_track
; /* sic */
595 DBGC2 ( sandev
, "Get drive parameters\n" );
597 /* Validate blocksize */
598 if ( sandev_blksize ( sandev
) != INT13_BLKSIZE
) {
599 DBGC ( sandev
, "\nINT 13 drive %02x invalid blocksize (%zd) "
600 "for non-extended parameters\n",
601 sandev
->drive
, sandev_blksize ( sandev
) );
602 return -INT13_STATUS_INVALID
;
605 /* Common parameters */
606 ix86
->regs
.ch
= ( max_cylinder
& 0xff );
607 ix86
->regs
.cl
= ( ( ( max_cylinder
>> 8 ) << 6 ) | max_sector
);
608 ix86
->regs
.dh
= max_head
;
609 ix86
->regs
.dl
= ( int13_is_fdd ( sandev
) ? num_fdds
: num_drives
);
611 /* Floppy-specific parameters */
612 if ( int13_is_fdd ( sandev
) ) {
613 ix86
->regs
.bl
= INT13_FDD_TYPE_1M44
;
614 ix86
->segs
.es
= rm_ds
;
615 ix86
->regs
.di
= __from_data16 ( &int13_fdd_params
);
622 * INT 13, 15 - Get disk type
624 * @v sandev SAN device
626 * @ret cx:dx Sector count
627 * @ret status Status code / disk type
629 static int int13_get_disk_type ( struct san_device
*sandev
,
630 struct i386_all_regs
*ix86
) {
633 DBGC2 ( sandev
, "Get disk type\n" );
635 if ( int13_is_fdd ( sandev
) ) {
636 return INT13_DISK_TYPE_FDD
;
638 blocks
= int13_capacity32 ( sandev
);
639 ix86
->regs
.cx
= ( blocks
>> 16 );
640 ix86
->regs
.dx
= ( blocks
& 0xffff );
641 return INT13_DISK_TYPE_HDD
;
646 * INT 13, 41 - Extensions installation check
648 * @v sandev SAN device
651 * @ret cx Extensions API support bitmap
652 * @ret status Status code / API version
654 static int int13_extension_check ( struct san_device
*sandev __unused
,
655 struct i386_all_regs
*ix86
) {
657 if ( ix86
->regs
.bx
== 0x55aa ) {
658 DBGC2 ( sandev
, "INT13 extensions installation check\n" );
659 ix86
->regs
.bx
= 0xaa55;
660 ix86
->regs
.cx
= ( INT13_EXTENSION_LINEAR
|
661 INT13_EXTENSION_EDD
|
662 INT13_EXTENSION_64BIT
);
663 return INT13_EXTENSION_VER_3_0
;
665 return -INT13_STATUS_INVALID
;
670 * Extended read / write
672 * @v sandev SAN device
673 * @v ds:si Disk address packet
674 * @v sandev_rw SAN device read/write method
675 * @ret status Status code
677 static int int13_extended_rw ( struct san_device
*sandev
,
678 struct i386_all_regs
*ix86
,
679 int ( * sandev_rw
) ( struct san_device
*sandev
,
682 userptr_t buffer
) ) {
683 struct int13_disk_address addr
;
690 /* Extended reads are not allowed on floppy drives.
691 * ELTORITO.SYS seems to assume that we are really a CD-ROM if
692 * we support extended reads for a floppy drive.
694 if ( int13_is_fdd ( sandev
) )
695 return -INT13_STATUS_INVALID
;
697 /* Get buffer size */
698 get_real ( bufsize
, ix86
->segs
.ds
,
699 ( ix86
->regs
.si
+ offsetof ( typeof ( addr
), bufsize
) ) );
700 if ( bufsize
< offsetof ( typeof ( addr
), buffer_phys
) ) {
701 DBGC2 ( sandev
, "<invalid buffer size %#02x\n>\n", bufsize
);
702 return -INT13_STATUS_INVALID
;
705 /* Read parameters from disk address structure */
706 memset ( &addr
, 0, sizeof ( addr
) );
707 copy_from_real ( &addr
, ix86
->segs
.ds
, ix86
->regs
.si
, bufsize
);
709 DBGC2 ( sandev
, "LBA %08llx <-> ", ( ( unsigned long long ) lba
) );
710 if ( ( addr
.count
== 0xff ) ||
711 ( ( addr
.buffer
.segment
== 0xffff ) &&
712 ( addr
.buffer
.offset
== 0xffff ) ) ) {
713 buffer
= phys_to_user ( addr
.buffer_phys
);
714 DBGC2 ( sandev
, "%08llx",
715 ( ( unsigned long long ) addr
.buffer_phys
) );
717 buffer
= real_to_user ( addr
.buffer
.segment
,
718 addr
.buffer
.offset
);
719 DBGC2 ( sandev
, "%04x:%04x", addr
.buffer
.segment
,
720 addr
.buffer
.offset
);
722 if ( addr
.count
<= 0x7f ) {
724 } else if ( addr
.count
== 0xff ) {
725 count
= addr
.long_count
;
727 DBGC2 ( sandev
, " <invalid count %#02x>\n", addr
.count
);
728 return -INT13_STATUS_INVALID
;
730 DBGC2 ( sandev
, " (count %ld)\n", count
);
732 /* Read from / write to block device */
733 if ( ( rc
= sandev_rw ( sandev
, lba
, count
, buffer
) ) != 0 ) {
734 DBGC ( sandev
, "INT13 drive %02x extended I/O failed: %s\n",
735 sandev
->drive
, strerror ( rc
) );
736 /* Record that no blocks were transferred successfully */
738 put_real ( addr
.count
, ix86
->segs
.ds
,
740 offsetof ( typeof ( addr
), count
) ) );
741 return -INT13_STATUS_READ_ERROR
;
744 copy_to_real (ix86
->segs
.ds
, ix86
->regs
.si
, &addr
, bufsize
);
750 * INT 13, 42 - Extended read
752 * @v sandev SAN device
753 * @v ds:si Disk address packet
754 * @ret status Status code
756 static int int13_extended_read ( struct san_device
*sandev
,
757 struct i386_all_regs
*ix86
) {
759 DBGC2 ( sandev
, "Extended read: " );
760 return int13_extended_rw ( sandev
, ix86
, sandev_read
);
764 * INT 13, 43 - Extended write
766 * @v sandev SAN device
767 * @v ds:si Disk address packet
768 * @ret status Status code
770 static int int13_extended_write ( struct san_device
*sandev
,
771 struct i386_all_regs
*ix86
) {
773 DBGC2 ( sandev
, "Extended write: " );
774 return int13_extended_rw ( sandev
, ix86
, sandev_write
);
778 * INT 13, 44 - Verify sectors
780 * @v sandev SAN device
781 * @v ds:si Disk address packet
782 * @ret status Status code
784 static int int13_extended_verify ( struct san_device
*sandev
,
785 struct i386_all_regs
*ix86
) {
786 struct int13_disk_address addr
;
790 /* Read parameters from disk address structure */
792 copy_from_real ( &addr
, ix86
->segs
.ds
, ix86
->regs
.si
,
796 DBGC2 ( sandev
, "Verify: LBA %08llx (count %ld)\n",
797 ( ( unsigned long long ) lba
), count
);
800 /* We have no mechanism for verifying sectors */
801 return -INT13_STATUS_INVALID
;
805 * INT 13, 44 - Extended seek
807 * @v sandev SAN device
808 * @v ds:si Disk address packet
809 * @ret status Status code
811 static int int13_extended_seek ( struct san_device
*sandev
,
812 struct i386_all_regs
*ix86
) {
813 struct int13_disk_address addr
;
817 /* Read parameters from disk address structure */
819 copy_from_real ( &addr
, ix86
->segs
.ds
, ix86
->regs
.si
,
823 DBGC2 ( sandev
, "Seek: LBA %08llx (count %ld)\n",
824 ( ( unsigned long long ) lba
), count
);
827 /* Ignore and return success */
832 * Build device path information
834 * @v sandev SAN device
835 * @v dpi Device path information
836 * @ret rc Return status code
838 static int int13_device_path_info ( struct san_device
*sandev
,
839 struct edd_device_path_information
*dpi
) {
840 struct san_path
*sanpath
;
841 struct device
*device
;
842 struct device_description
*desc
;
847 /* Reopen block device if necessary */
848 if ( sandev_needs_reopen ( sandev
) &&
849 ( ( rc
= sandev_reopen ( sandev
) ) != 0 ) )
851 sanpath
= sandev
->active
;
852 assert ( sanpath
!= NULL
);
854 /* Get underlying hardware device */
855 device
= identify_device ( &sanpath
->block
);
857 DBGC ( sandev
, "INT13 drive %02x cannot identify hardware "
858 "device\n", sandev
->drive
);
862 /* Fill in bus type and interface path */
863 desc
= &device
->desc
;
864 switch ( desc
->bus_type
) {
866 dpi
->host_bus_type
.type
= EDD_BUS_TYPE_PCI
;
867 dpi
->interface_path
.pci
.bus
= PCI_BUS ( desc
->location
);
868 dpi
->interface_path
.pci
.slot
= PCI_SLOT ( desc
->location
);
869 dpi
->interface_path
.pci
.function
= PCI_FUNC ( desc
->location
);
870 dpi
->interface_path
.pci
.channel
= 0xff; /* unused */
873 DBGC ( sandev
, "INT13 drive %02x unrecognised bus type %d\n",
874 sandev
->drive
, desc
->bus_type
);
878 /* Get EDD block device description */
879 if ( ( rc
= edd_describe ( &sanpath
->block
, &dpi
->interface_type
,
880 &dpi
->device_path
) ) != 0 ) {
881 DBGC ( sandev
, "INT13 drive %02x cannot identify block device: "
882 "%s\n", sandev
->drive
, strerror ( rc
) );
886 /* Fill in common fields and fix checksum */
887 dpi
->key
= EDD_DEVICE_PATH_INFO_KEY
;
888 dpi
->len
= sizeof ( *dpi
);
889 for ( i
= 0 ; i
< sizeof ( *dpi
) ; i
++ )
890 sum
+= *( ( ( uint8_t * ) dpi
) + i
);
891 dpi
->checksum
-= sum
;
897 * INT 13, 48 - Get extended parameters
899 * @v sandev SAN device
900 * @v ds:si Drive parameter table
901 * @ret status Status code
903 static int int13_get_extended_parameters ( struct san_device
*sandev
,
904 struct i386_all_regs
*ix86
) {
905 struct int13_data
*int13
= sandev
->priv
;
906 struct int13_disk_parameters params
;
907 struct segoff address
;
908 size_t len
= sizeof ( params
);
912 /* Get buffer size */
913 get_real ( bufsize
, ix86
->segs
.ds
,
914 ( ix86
->regs
.si
+ offsetof ( typeof ( params
), bufsize
)));
916 DBGC2 ( sandev
, "Get extended drive parameters to %04x:%04x+%02x\n",
917 ix86
->segs
.ds
, ix86
->regs
.si
, bufsize
);
919 /* Build drive parameters */
920 memset ( ¶ms
, 0, sizeof ( params
) );
921 params
.flags
= INT13_FL_DMA_TRANSPARENT
;
922 if ( ( int13
->cylinders
< 1024 ) &&
923 ( sandev_capacity ( sandev
) <= INT13_MAX_CHS_SECTORS
) ) {
924 params
.flags
|= INT13_FL_CHS_VALID
;
926 params
.cylinders
= int13
->cylinders
;
927 params
.heads
= int13
->heads
;
928 params
.sectors_per_track
= int13
->sectors_per_track
;
929 params
.sectors
= sandev_capacity ( sandev
);
930 params
.sector_size
= sandev_blksize ( sandev
);
931 memset ( ¶ms
.dpte
, 0xff, sizeof ( params
.dpte
) );
932 if ( ( rc
= int13_device_path_info ( sandev
, ¶ms
.dpi
) ) != 0 ) {
933 DBGC ( sandev
, "INT13 drive %02x could not provide device "
934 "path information: %s\n",
935 sandev
->drive
, strerror ( rc
) );
936 len
= offsetof ( typeof ( params
), dpi
);
939 /* Calculate returned "buffer size" (which will be less than
940 * the length actually copied if device path information is
943 if ( bufsize
< offsetof ( typeof ( params
), dpte
) )
944 return -INT13_STATUS_INVALID
;
945 if ( bufsize
< offsetof ( typeof ( params
), dpi
) ) {
946 params
.bufsize
= offsetof ( typeof ( params
), dpte
);
948 params
.bufsize
= offsetof ( typeof ( params
), dpi
);
951 DBGC ( sandev
, "INT 13 drive %02x described using extended "
952 "parameters:\n", sandev
->drive
);
953 address
.segment
= ix86
->segs
.ds
;
954 address
.offset
= ix86
->regs
.si
;
955 DBGC_HDA ( sandev
, address
, ¶ms
, len
);
957 /* Return drive parameters */
960 copy_to_real ( ix86
->segs
.ds
, ix86
->regs
.si
, ¶ms
, len
);
966 * INT 13, 4b - Get status or terminate CD-ROM emulation
968 * @v sandev SAN device
969 * @v ds:si Specification packet
970 * @ret status Status code
972 static int int13_cdrom_status_terminate ( struct san_device
*sandev
,
973 struct i386_all_regs
*ix86
) {
974 struct int13_cdrom_specification specification
;
976 DBGC2 ( sandev
, "Get CD-ROM emulation status to %04x:%04x%s\n",
977 ix86
->segs
.ds
, ix86
->regs
.si
,
978 ( ix86
->regs
.al
? "" : " and terminate" ) );
980 /* Fail if we are not a CD-ROM */
981 if ( ! sandev
->is_cdrom
) {
982 DBGC ( sandev
, "INT13 drive %02x is not a CD-ROM\n",
984 return -INT13_STATUS_INVALID
;
987 /* Build specification packet */
988 memset ( &specification
, 0, sizeof ( specification
) );
989 specification
.size
= sizeof ( specification
);
990 specification
.drive
= sandev
->drive
;
992 /* Return specification packet */
993 copy_to_real ( ix86
->segs
.ds
, ix86
->regs
.si
, &specification
,
994 sizeof ( specification
) );
1001 * INT 13, 4d - Read CD-ROM boot catalog
1003 * @v sandev SAN device
1004 * @v ds:si Command packet
1005 * @ret status Status code
1007 static int int13_cdrom_read_boot_catalog ( struct san_device
*sandev
,
1008 struct i386_all_regs
*ix86
) {
1009 struct int13_data
*int13
= sandev
->priv
;
1010 struct int13_cdrom_boot_catalog_command command
;
1014 /* Read parameters from command packet */
1015 copy_from_real ( &command
, ix86
->segs
.ds
, ix86
->regs
.si
,
1016 sizeof ( command
) );
1017 DBGC2 ( sandev
, "Read CD-ROM boot catalog to %08x\n", command
.buffer
);
1019 /* Fail if we have no boot catalog */
1020 if ( ! int13
->boot_catalog
) {
1021 DBGC ( sandev
, "INT13 drive %02x has no boot catalog\n",
1023 return -INT13_STATUS_INVALID
;
1025 start
= ( int13
->boot_catalog
+ command
.start
);
1027 /* Read from boot catalog */
1028 if ( ( rc
= sandev_read ( sandev
, start
, command
.count
,
1029 phys_to_user ( command
.buffer
) ) ) != 0 ) {
1030 DBGC ( sandev
, "INT13 drive %02x could not read boot catalog: "
1031 "%s\n", sandev
->drive
, strerror ( rc
) );
1032 return -INT13_STATUS_READ_ERROR
;
1044 static __asmcall
void int13 ( struct i386_all_regs
*ix86
) {
1045 int command
= ix86
->regs
.ah
;
1046 unsigned int bios_drive
= ix86
->regs
.dl
;
1047 struct san_device
*sandev
;
1048 struct int13_data
*int13
;
1051 /* We simulate a cdrom, so no need to sync hd drive number */
1052 //int13_check_num_drives();
1054 if (bios_drive
== VENTOY_BIOS_FAKE_DRIVE
)
1056 ix86
->regs
.dl
= g_sandev
->exdrive
;
1061 if (g_drive_map1
>= 0x80 && g_drive_map2
>= 0x80)
1063 if (bios_drive
== g_drive_map1
)
1065 ix86
->regs
.dl
= g_drive_map2
;
1068 else if (bios_drive
== g_drive_map2
)
1070 ix86
->regs
.dl
= g_drive_map1
;
1075 for_each_sandev ( sandev
) {
1077 int13
= sandev
->priv
;
1078 if ( bios_drive
!= sandev
->drive
) {
1079 /* Remap any accesses to this drive's natural number */
1080 if ( bios_drive
== int13
->natural_drive
) {
1081 DBGC2 ( sandev
, "INT13,%02x (%02x) remapped to "
1082 "(%02x)\n", ix86
->regs
.ah
,
1083 bios_drive
, sandev
->drive
);
1084 ix86
->regs
.dl
= sandev
->drive
;
1086 } else if ( ( ( bios_drive
& 0x7f ) == 0x7f ) &&
1087 ( command
== INT13_CDROM_STATUS_TERMINATE
)
1088 && sandev
->is_cdrom
) {
1090 /* Catch non-drive-specific CD-ROM calls */
1096 sandev
->int13_command
= command
;
1097 sandev
->x86_regptr
= ix86
;
1099 DBGC2 ( sandev
, "INT13,%02x (%02x): ",
1100 ix86
->regs
.ah
, bios_drive
);
1102 switch ( command
) {
1104 status
= int13_reset ( sandev
, ix86
);
1106 case INT13_GET_LAST_STATUS
:
1107 status
= int13_get_last_status ( sandev
, ix86
);
1109 case INT13_READ_SECTORS
:
1110 status
= int13_read_sectors ( sandev
, ix86
);
1112 case INT13_WRITE_SECTORS
:
1113 status
= int13_write_sectors ( sandev
, ix86
);
1115 case INT13_GET_PARAMETERS
:
1116 status
= int13_get_parameters ( sandev
, ix86
);
1118 case INT13_GET_DISK_TYPE
:
1119 status
= int13_get_disk_type ( sandev
, ix86
);
1121 case INT13_EXTENSION_CHECK
:
1122 status
= int13_extension_check ( sandev
, ix86
);
1124 case INT13_EXTENDED_READ
:
1125 status
= int13_extended_read ( sandev
, ix86
);
1127 case INT13_EXTENDED_WRITE
:
1128 status
= int13_extended_write ( sandev
, ix86
);
1130 case INT13_EXTENDED_VERIFY
:
1131 status
= int13_extended_verify ( sandev
, ix86
);
1133 case INT13_EXTENDED_SEEK
:
1134 status
= int13_extended_seek ( sandev
, ix86
);
1136 case INT13_GET_EXTENDED_PARAMETERS
:
1137 status
= int13_get_extended_parameters ( sandev
, ix86
);
1139 case INT13_CDROM_STATUS_TERMINATE
:
1140 status
= int13_cdrom_status_terminate ( sandev
, ix86
);
1142 case INT13_CDROM_READ_BOOT_CATALOG
:
1143 status
= int13_cdrom_read_boot_catalog ( sandev
, ix86
);
1146 DBGC2 ( sandev
, "*** Unrecognised INT13 ***\n" );
1147 status
= -INT13_STATUS_INVALID
;
1151 /* Store status for INT 13,01 */
1152 int13
->last_status
= status
;
1154 /* Negative status indicates an error */
1157 DBGC ( sandev
, "INT13,%02x (%02x) failed with status "
1158 "%02x\n", ix86
->regs
.ah
, sandev
->drive
, status
);
1162 ix86
->regs
.ah
= status
;
1164 /* Set OF to indicate to wrapper not to chain this call */
1172 * Hook INT 13 handler
1175 static void int13_hook_vector ( void ) {
1176 /* Assembly wrapper to call int13(). int13() sets OF if we
1177 * should not chain to the previous handler. (The wrapper
1178 * clears CF and OF before calling int13()).
1180 __asm__
__volatile__ (
1181 TEXT16_CODE ( "\nint13_wrapper:\n\t"
1182 /* Preserve %ax and %dx for future reference */
1184 "movw %%sp, %%bp\n\t"
1187 /* Clear OF, set CF, call int13() */
1191 /* Chain if OF not set */
1194 "lcall *%%cs:int13_vector\n\t"
1196 /* Overwrite flags for iret */
1201 * INT 13,15 : do nothing if hard disk
1202 * INT 13,08 : load with number of drives
1203 * all others: restore original value
1205 "cmpb $0x15, -1(%%bp)\n\t"
1207 "testb $0x80, -4(%%bp)\n\t"
1210 "movb -4(%%bp), %%dl\n\t"
1211 "cmpb $0x08, -1(%%bp)\n\t"
1213 "testb $0x80, %%dl\n\t"
1214 "movb %%cs:num_drives, %%dl\n\t"
1216 "movb %%cs:num_fdds, %%dl\n\t"
1219 "movw %%bp, %%sp\n\t"
1223 hook_bios_interrupt ( 0x13, ( intptr_t ) int13_wrapper
, &int13_vector
);
1229 * Load and verify master boot record from INT 13 drive
1231 * @v drive Drive number
1232 * @v address Boot code address to fill in
1233 * @ret rc Return status code
1235 static int int13_load_mbr ( unsigned int drive
, struct segoff
*address
) {
1237 int discard_b
, discard_c
, discard_d
;
1240 /* Use INT 13, 02 to read the MBR */
1241 address
->segment
= 0;
1242 address
->offset
= 0x7c00;
1243 __asm__
__volatile__ ( REAL_CODE ( "pushw %%es\n\t"
1250 "sti\n\t" /* BIOS bugs */
1252 "xorw %%ax, %%ax\n\t"
1255 : "=a" ( status
), "=b" ( discard_b
),
1256 "=c" ( discard_c
), "=d" ( discard_d
)
1257 : "a" ( 0x0201 ), "b" ( *address
),
1258 "c" ( 1 ), "d" ( drive
) );
1260 DBG ( "INT13 drive %02x could not read MBR (status %04x)\n",
1265 /* Check magic signature */
1266 get_real ( magic
, address
->segment
,
1268 offsetof ( struct master_boot_record
, magic
) ) );
1269 if ( magic
!= INT13_MBR_MAGIC
) {
1270 DBG ( "INT13 drive %02x does not contain a valid MBR\n",
1278 /** El Torito boot catalog command packet */
1279 static struct int13_cdrom_boot_catalog_command
__data16 ( eltorito_cmd
) = {
1280 .size
= sizeof ( struct int13_cdrom_boot_catalog_command
),
1285 #define eltorito_cmd __use_data16 ( eltorito_cmd )
1287 /** El Torito disk address packet */
1288 static struct int13_disk_address
__bss16 ( eltorito_address
);
1289 #define eltorito_address __use_data16 ( eltorito_address )
1292 * Load and verify El Torito boot record from INT 13 drive
1294 * @v drive Drive number
1295 * @v address Boot code address to fill in
1296 * @ret rc Return status code
1298 static int int13_load_eltorito ( unsigned int drive
, struct segoff
*address
) {
1300 struct eltorito_validation_entry valid
;
1301 struct eltorito_boot_entry boot
;
1302 } __attribute__ (( packed
)) catalog
;
1305 if (g_sandev
&& g_sandev
->drive
== drive
)
1307 copy_to_user(phys_to_user ( eltorito_cmd
.buffer
), 0, g_sandev
->boot_catalog_sector
, sizeof(g_sandev
->boot_catalog_sector
));
1311 /* Use INT 13, 4d to read the boot catalog */
1312 __asm__
__volatile__ ( REAL_CODE ( "stc\n\t"
1315 "sti\n\t" /* BIOS bugs */
1317 "xorw %%ax, %%ax\n\t"
1320 : "a" ( 0x4d00 ), "d" ( drive
),
1321 "S" ( __from_data16 ( &eltorito_cmd
) ) );
1323 DBG ( "INT13 drive %02x could not read El Torito boot catalog "
1324 "(status %04x)\n", drive
, status
);
1329 copy_from_user ( &catalog
, phys_to_user ( eltorito_cmd
.buffer
), 0,
1330 sizeof ( catalog
) );
1333 if ( catalog
.valid
.platform_id
!= ELTORITO_PLATFORM_X86
) {
1334 DBG ( "INT13 drive %02x El Torito specifies unknown platform "
1335 "%02x\n", drive
, catalog
.valid
.platform_id
);
1338 if ( catalog
.boot
.indicator
!= ELTORITO_BOOTABLE
) {
1339 DBG ( "INT13 drive %02x El Torito is not bootable\n", drive
);
1342 if ( catalog
.boot
.media_type
!= ELTORITO_NO_EMULATION
) {
1343 DBG ( "INT13 drive %02x El Torito requires emulation "
1344 "type %02x\n", drive
, catalog
.boot
.media_type
);
1347 DBG ( "INT13 drive %02x El Torito boot image at LBA %08x (count %d)\n",
1348 drive
, catalog
.boot
.start
, catalog
.boot
.length
);
1349 address
->segment
= ( catalog
.boot
.load_segment
?
1350 catalog
.boot
.load_segment
: 0x7c0 );
1351 address
->offset
= 0;
1352 DBG ( "INT13 drive %02x El Torito boot image loads at %04x:%04x\n",
1353 drive
, address
->segment
, address
->offset
);
1355 /* Use INT 13, 42 to read the boot image */
1356 eltorito_address
.bufsize
=
1357 offsetof ( typeof ( eltorito_address
), buffer_phys
);
1358 eltorito_address
.count
= catalog
.boot
.length
;
1359 eltorito_address
.buffer
= *address
;
1360 eltorito_address
.lba
= catalog
.boot
.start
;
1361 __asm__
__volatile__ ( REAL_CODE ( "stc\n\t"
1364 "sti\n\t" /* BIOS bugs */
1366 "xorw %%ax, %%ax\n\t"
1369 : "a" ( 0x4200 ), "d" ( drive
),
1370 "S" ( __from_data16 ( &eltorito_address
) ) );
1372 DBG ( "INT13 drive %02x could not read El Torito boot image "
1373 "(status %04x)\n", drive
, status
);
1381 * Hook INT 13 SAN device
1383 * @v drive Drive number
1384 * @v uris List of URIs
1385 * @v count Number of URIs
1387 * @ret drive Drive number, or negative error
1389 * Registers the drive with the INT 13 emulation subsystem, and hooks
1390 * the INT 13 interrupt vector (if not already hooked).
1392 unsigned int ventoy_int13_hook (ventoy_chain_head
*chain
)
1394 unsigned int blocks
;
1395 unsigned int blocks_per_cyl
;
1396 unsigned int natural_drive
;
1397 struct int13_data
*int13
;
1399 /* We simulate a cdrom, so no need to sync hd drive number */
1400 //int13_sync_num_drives();
1402 /* hook will copy num_drives to dl when int13 08 was called, so must initialize it's value */
1403 get_real(num_drives
, BDA_SEG
, BDA_NUM_DRIVES
);
1405 //natural_drive = num_drives | 0x80;
1406 natural_drive
= 0xE0; /* just set a cdrom drive number 224 */
1408 if (chain
->disk_drive
>= 0x80 && chain
->drive_map
>= 0x80)
1410 g_drive_map1
= chain
->disk_drive
;
1411 g_drive_map2
= chain
->drive_map
;
1415 g_sandev
= zalloc(sizeof(struct san_device
) + sizeof(struct int13_data
));
1416 g_sandev
->priv
= int13
= (struct int13_data
*)(g_sandev
+ 1);
1417 g_sandev
->drive
= int13
->natural_drive
= natural_drive
;
1418 g_sandev
->is_cdrom
= 1;
1419 g_sandev
->blksize_shift
= 2;
1420 g_sandev
->capacity
.blksize
= 512;
1421 g_sandev
->capacity
.blocks
= chain
->virt_img_size_in_bytes
/ 512;
1422 g_sandev
->exdrive
= chain
->disk_drive
;
1423 int13
->boot_catalog
= chain
->boot_catalog
;
1424 memcpy(g_sandev
->boot_catalog_sector
, chain
->boot_catalog_sector
, sizeof(chain
->boot_catalog_sector
));
1427 /* Apply guesses if no geometry already specified */
1428 if ( ! int13
->heads
)
1430 if ( ! int13
->sectors_per_track
)
1431 int13
->sectors_per_track
= 63;
1432 if ( ! int13
->cylinders
) {
1433 /* Avoid attempting a 64-bit divide on a 32-bit system */
1434 blocks
= int13_capacity32 ( g_sandev
);
1435 blocks_per_cyl
= ( int13
->heads
* int13
->sectors_per_track
);
1437 int13
->cylinders
= ( blocks
/ blocks_per_cyl
);
1438 if ( int13
->cylinders
> 1024 )
1439 int13
->cylinders
= 1024;
1442 /* Hook INT 13 vector if not already hooked */
1443 int13_hook_vector();
1445 /* Update BIOS drive count */
1446 //int13_sync_num_drives();
1448 return natural_drive
;
1451 static uint8_t __bss16_array ( xbftab
, [512 + 128])
1452 __attribute__ (( aligned ( 16 ) ));
1453 #define xbftab __use_data16 ( xbftab )
1455 void * ventoy_get_runtime_addr(void)
1457 return (void *)user_to_phys((userptr_t
)(&xbftab
), 0);
1461 * Attempt to boot from an INT 13 drive
1463 * @v drive Drive number
1464 * @v filename Filename (or NULL to use default)
1465 * @ret rc Return status code
1467 * This boots from the specified INT 13 drive by loading the Master
1468 * Boot Record to 0000:7c00 and jumping to it. INT 18 is hooked to
1469 * capture an attempt by the MBR to boot the next device. (This is
1470 * the closest thing to a return path from an MBR).
1472 * Note that this function can never return success, by definition.
1474 int ventoy_int13_boot ( unsigned int drive
, void *imginfo
, const char *cmdline
) {
1475 //struct memory_map memmap;
1478 struct segoff address
;
1479 struct acpi_header
*acpi
= NULL
;
1480 struct ibft_table
*ibft
= NULL
;
1482 /* Look for a usable boot sector */
1483 if ( ( ( rc
= int13_load_eltorito ( drive
, &address
) ) != 0 ) &&
1484 ( ( rc
= int13_load_mbr ( drive
, &address
) ) != 0 ))
1489 if (strstr(cmdline
, "ibft"))
1492 ibft
= (struct ibft_table
*)(&xbftab
);
1493 acpi
= &(ibft
->acpi
);
1494 memset(ibft
, 0, headlen
);
1496 acpi
->signature
= IBFT_SIG
;
1497 acpi
->length
= headlen
+ sizeof(ventoy_os_param
);
1499 strncpy(acpi
->oem_id
, "ventoy", sizeof(acpi
->oem_id
));
1500 strncpy(acpi
->oem_table_id
, "runtime", sizeof(acpi
->oem_table_id
));
1501 memcpy((uint8_t *)ibft
+ headlen
, imginfo
, sizeof(ventoy_os_param
));
1502 acpi_fix_checksum(acpi
);
1506 memcpy((&xbftab
), imginfo
, sizeof(ventoy_os_param
));
1510 /* Dump out memory map prior to boot, if memmap debugging is
1511 * enabled. Not required for program flow, but we have so
1512 * many problems that turn out to be memory-map related that
1515 //get_memmap ( &memmap );
1517 DBGC(g_sandev
, "start to boot ...\n");
1519 /* Jump to boot sector */
1520 if ( ( rc
= call_bootsector ( address
.segment
, address
.offset
,
1525 return -ECANCELED
; /* -EIMPOSSIBLE */