]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - IPXE/ipxe-3fe683e/src/arch/x86/interface/pcbios/ventoy_int13.c
Update PhyDrive.c
[Ventoy.git] / IPXE / ipxe-3fe683e / src / arch / x86 / interface / pcbios / ventoy_int13.c
1 /*
2 * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
3 * Copyright (C) 2020 longpanda <admin@ventoy.net>.
4 *
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.
9 *
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.
14 *
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
18 * 02110-1301, USA.
19 *
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.
23 */
24
25 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
26
27 #include <stdio.h>
28 #include <stdint.h>
29 #include <stdlib.h>
30 #include <limits.h>
31 #include <byteswap.h>
32 #include <errno.h>
33 #include <assert.h>
34 #include <ipxe/blockdev.h>
35 #include <ipxe/io.h>
36 #include <ipxe/acpi.h>
37 #include <ipxe/sanboot.h>
38 #include <ipxe/device.h>
39 #include <ipxe/pci.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>
45 #include <realmode.h>
46 #include <bios.h>
47 #include <biosint.h>
48 #include <bootsector.h>
49 #include <int13.h>
50 #include <ventoy.h>
51 #include "ventoy_int13.h"
52
53 static unsigned int g_drive_map1 = 0;
54 static unsigned int g_drive_map2 = 0;
55
56 /** @file
57 *
58 * INT 13 emulation
59 *
60 * This module provides a mechanism for exporting block devices via
61 * the BIOS INT 13 disk interrupt interface.
62 *
63 */
64
65 /** INT 13 SAN device private data */
66 struct int13_data {
67 /** BIOS natural drive number (0x00-0xff)
68 *
69 * This is the drive number that would have been assigned by
70 * 'naturally' appending the drive to the end of the BIOS
71 * drive list.
72 *
73 * If the emulated drive replaces a preexisting drive, this is
74 * the drive number that the preexisting drive gets remapped
75 * to.
76 */
77 unsigned int natural_drive;
78
79 /** Number of cylinders
80 *
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
85 * addressable limit.
86 */
87 unsigned int cylinders;
88 /** Number of heads
89 *
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.
94 */
95 unsigned int heads;
96 /** Number of sectors per track
97 *
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.
101 */
102 unsigned int sectors_per_track;
103
104 /** Address of El Torito boot catalog (if any) */
105 unsigned int boot_catalog;
106 /** Status of last operation */
107 int last_status;
108 };
109
110 /** Vector for chaining to other INT 13 handlers */
111 static struct segoff __text16 ( int13_vector );
112 #define int13_vector __use_text16 ( int13_vector )
113
114 /** Assembly wrapper */
115 extern void int13_wrapper ( void );
116
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,
123 };
124 #define int13_fdd_params __use_data16 ( int13_fdd_params )
125
126 /**
127 * Equipment word
128 *
129 * This is a cached copy of the BIOS Data Area equipment word at
130 * 40:10.
131 */
132 static uint16_t equipment_word;
133
134 /**
135 * Number of BIOS floppy disk drives
136 *
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.
139 */
140 static uint8_t __text16 ( num_fdds );
141 #define num_fdds __use_text16 ( num_fdds )
142
143 /**
144 * Number of BIOS hard disk drives
145 *
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.
149 */
150 static uint8_t __text16 ( num_drives );
151 #define num_drives __use_text16 ( num_drives )
152 static struct san_device *g_sandev;
153
154 /**
155 * Calculate SAN device capacity (limited to 32 bits)
156 *
157 * @v sandev SAN device
158 * @ret blocks Number of blocks
159 */
160 static inline uint32_t int13_capacity32 ( struct san_device *sandev ) {
161 uint64_t capacity = sandev_capacity ( sandev );
162 return ( ( capacity <= 0xffffffffUL ) ? capacity : 0xffffffff );
163 }
164
165 /**
166 * Test if SAN device is a floppy disk drive
167 *
168 * @v sandev SAN device
169 * @ret is_fdd SAN device is a floppy disk drive
170 */
171 static inline int int13_is_fdd ( struct san_device *sandev ) {
172 (void)sandev;
173 return 0;
174 }
175
176 #if 0
177 /**
178 * Guess INT 13 hard disk drive geometry
179 *
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
185 *
186 * Guesses the drive geometry by inspecting the partition table.
187 */
188 static int int13_guess_geometry_hdd ( struct san_device *sandev, void *scratch,
189 unsigned int *heads,
190 unsigned int *sectors ) {
191 struct master_boot_record *mbr = scratch;
192 struct partition_table_entry *partition;
193 unsigned int i;
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;
199 int rc;
200
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 ) );
206 return rc;
207 }
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 );
212
213 /* Scan through partition table and modify guesses for
214 * heads and sectors_per_track if we find any used
215 * partitions.
216 */
217 *heads = 0;
218 *sectors = 0;
219 for ( i = 0 ; i < 4 ; i++ ) {
220
221 /* Skip empty partitions */
222 partition = &mbr->partitions[i];
223 if ( ! partition->type )
224 continue;
225
226 /* If partition starts on cylinder 0 then we can
227 * unambiguously determine the number of sectors.
228 */
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 ) /
234 start_head );
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 ) );
238 }
239
240 /* If partition ends on a higher head or sector number
241 * than our current guess, then increase the guess.
242 */
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 ) );
250 }
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 ) );
256 }
257 }
258
259 /* Default guess is xx/255/63 */
260 if ( ! *heads )
261 *heads = 255;
262 if ( ! *sectors )
263 *sectors = 63;
264
265 return 0;
266 }
267
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 ),
290 };
291
292 /**
293 * Guess INT 13 floppy disk drive geometry
294 *
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
299 *
300 * Guesses the drive geometry by inspecting the disk size.
301 */
302 static int int13_guess_geometry_fdd ( struct san_device *sandev,
303 unsigned int *heads,
304 unsigned int *sectors ) {
305 unsigned int blocks = sandev_capacity ( sandev );
306 const struct int13_fdd_geometry *geometry;
307 unsigned int cylinders;
308 unsigned int i;
309
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 ) );
321 return 0;
322 }
323 }
324
325 /* Otherwise, assume a partial disk image in the most common
326 * format (1440K, 80/2/18).
327 */
328 *heads = 2;
329 *sectors = 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 ) );
332 return 0;
333 }
334
335 /**
336 * Guess INT 13 drive geometry
337 *
338 * @v sandev SAN device
339 * @v scratch Scratch area for single-sector reads
340 * @ret rc Return status code
341 */
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;
346 unsigned int blocks;
347 unsigned int blocks_per_cyl;
348 int rc;
349
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)
354 return rc;
355 } else {
356 if ( ( rc = int13_guess_geometry_hdd ( sandev, scratch,
357 &guessed_heads,
358 &guessed_sectors )) != 0)
359 return rc;
360 }
361
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;
375 }
376
377 return 0;
378 }
379 #endif /* #if 0 */
380
381 /**
382 * Update BIOS drive count
383 */
384 void int13_sync_num_drives ( void ) {
385 struct san_device *sandev;
386 struct int13_data *int13;
387 uint8_t *counter;
388 uint8_t max_drive;
389 uint8_t required;
390
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 );
396
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 ) {
406 *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 );
410 }
411 }
412
413 /* Update current drive count */
414 equipment_word &= ~( ( 0x3 << 6 ) | 0x0001 );
415 if ( num_fdds ) {
416 equipment_word |= ( 0x0001 |
417 ( ( ( num_fdds - 1 ) & 0x3 ) << 6 ) );
418 }
419 put_real ( equipment_word, BDA_SEG, BDA_EQUIPMENT_WORD );
420 put_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES );
421 }
422
423 /**
424 * Check number of drives
425 */
426 void int13_check_num_drives ( void ) {
427 uint16_t check_equipment_word;
428 uint8_t check_num_drives;
429
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();
435 }
436 }
437
438 /**
439 * INT 13, 00 - Reset disk system
440 *
441 * @v sandev SAN device
442 * @ret status Status code
443 */
444 static int int13_reset ( struct san_device *sandev,
445 struct i386_all_regs *ix86 __unused ) {
446 int rc;
447
448 DBGC2 ( sandev, "Reset drive\n" );
449
450 /* Reset SAN device */
451 if ( ( rc = sandev_reset ( sandev ) ) != 0 )
452 return -INT13_STATUS_RESET_FAILED;
453
454 return 0;
455 }
456
457 /**
458 * INT 13, 01 - Get status of last operation
459 *
460 * @v sandev SAN device
461 * @ret status Status code
462 */
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;
466
467 DBGC2 ( sandev, "Get status of last operation\n" );
468 return int13->last_status;
469 }
470
471 /**
472 * Read / write sectors
473 *
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
479 * @v dh Head 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
484 */
485 static int int13_rw_sectors ( struct san_device *sandev,
486 struct i386_all_regs *ix86,
487 int ( * sandev_rw ) ( struct san_device *sandev,
488 uint64_t lba,
489 unsigned int count,
490 userptr_t buffer ) ) {
491 struct int13_data *int13 = sandev->priv;
492 unsigned int cylinder, head, sector;
493 unsigned long lba;
494 unsigned int count;
495 userptr_t buffer;
496 int rc;
497
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;
504 }
505
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;
517 }
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 );
522
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,
525 count );
526
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;
532 }
533
534 return 0;
535 }
536
537 /**
538 * INT 13, 02 - Read sectors
539 *
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
545 * @v dh Head number
546 * @v es:bx Data buffer
547 * @ret status Status code
548 * @ret al Number of sectors read
549 */
550 static int int13_read_sectors ( struct san_device *sandev,
551 struct i386_all_regs *ix86 ) {
552
553 DBGC2 ( sandev, "Read: " );
554 return int13_rw_sectors ( sandev, ix86, sandev_read );
555 }
556
557 /**
558 * INT 13, 03 - Write sectors
559 *
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
565 * @v dh Head number
566 * @v es:bx Data buffer
567 * @ret status Status code
568 * @ret al Number of sectors written
569 */
570 static int int13_write_sectors ( struct san_device *sandev,
571 struct i386_all_regs *ix86 ) {
572
573 DBGC2 ( sandev, "Write: " );
574 return int13_rw_sectors ( sandev, ix86, sandev_write );
575 }
576
577 /**
578 * INT 13, 08 - Get drive parameters
579 *
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
587 */
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 */
594
595 DBGC2 ( sandev, "Get drive parameters\n" );
596
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;
603 }
604
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 );
610
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 );
616 }
617
618 return 0;
619 }
620
621 /**
622 * INT 13, 15 - Get disk type
623 *
624 * @v sandev SAN device
625 * @ret ah Type code
626 * @ret cx:dx Sector count
627 * @ret status Status code / disk type
628 */
629 static int int13_get_disk_type ( struct san_device *sandev,
630 struct i386_all_regs *ix86 ) {
631 uint32_t blocks;
632
633 DBGC2 ( sandev, "Get disk type\n" );
634
635 if ( int13_is_fdd ( sandev ) ) {
636 return INT13_DISK_TYPE_FDD;
637 } else {
638 blocks = int13_capacity32 ( sandev );
639 ix86->regs.cx = ( blocks >> 16 );
640 ix86->regs.dx = ( blocks & 0xffff );
641 return INT13_DISK_TYPE_HDD;
642 }
643 }
644
645 /**
646 * INT 13, 41 - Extensions installation check
647 *
648 * @v sandev SAN device
649 * @v bx 0x55aa
650 * @ret bx 0xaa55
651 * @ret cx Extensions API support bitmap
652 * @ret status Status code / API version
653 */
654 static int int13_extension_check ( struct san_device *sandev __unused,
655 struct i386_all_regs *ix86 ) {
656
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;
664 } else {
665 return -INT13_STATUS_INVALID;
666 }
667 }
668
669 /**
670 * Extended read / write
671 *
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
676 */
677 static int int13_extended_rw ( struct san_device *sandev,
678 struct i386_all_regs *ix86,
679 int ( * sandev_rw ) ( struct san_device *sandev,
680 uint64_t lba,
681 unsigned int count,
682 userptr_t buffer ) ) {
683 struct int13_disk_address addr;
684 uint8_t bufsize;
685 uint64_t lba;
686 unsigned long count;
687 userptr_t buffer;
688 int rc;
689
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.
693 */
694 if ( int13_is_fdd ( sandev ) )
695 return -INT13_STATUS_INVALID;
696
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;
703 }
704
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 );
708 lba = addr.lba;
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 ) );
716 } else {
717 buffer = real_to_user ( addr.buffer.segment,
718 addr.buffer.offset );
719 DBGC2 ( sandev, "%04x:%04x", addr.buffer.segment,
720 addr.buffer.offset );
721 }
722 if ( addr.count <= 0x7f ) {
723 count = addr.count;
724 } else if ( addr.count == 0xff ) {
725 count = addr.long_count;
726 } else {
727 DBGC2 ( sandev, " <invalid count %#02x>\n", addr.count );
728 return -INT13_STATUS_INVALID;
729 }
730 DBGC2 ( sandev, " (count %ld)\n", count );
731
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 */
737 addr.count = 0;
738 put_real ( addr.count, ix86->segs.ds,
739 ( ix86->regs.si +
740 offsetof ( typeof ( addr ), count ) ) );
741 return -INT13_STATUS_READ_ERROR;
742 }
743
744 copy_to_real (ix86->segs.ds, ix86->regs.si, &addr, bufsize );
745
746 return 0;
747 }
748
749 /**
750 * INT 13, 42 - Extended read
751 *
752 * @v sandev SAN device
753 * @v ds:si Disk address packet
754 * @ret status Status code
755 */
756 static int int13_extended_read ( struct san_device *sandev,
757 struct i386_all_regs *ix86 ) {
758
759 DBGC2 ( sandev, "Extended read: " );
760 return int13_extended_rw ( sandev, ix86, sandev_read );
761 }
762
763 /**
764 * INT 13, 43 - Extended write
765 *
766 * @v sandev SAN device
767 * @v ds:si Disk address packet
768 * @ret status Status code
769 */
770 static int int13_extended_write ( struct san_device *sandev,
771 struct i386_all_regs *ix86 ) {
772
773 DBGC2 ( sandev, "Extended write: " );
774 return int13_extended_rw ( sandev, ix86, sandev_write );
775 }
776
777 /**
778 * INT 13, 44 - Verify sectors
779 *
780 * @v sandev SAN device
781 * @v ds:si Disk address packet
782 * @ret status Status code
783 */
784 static int int13_extended_verify ( struct san_device *sandev,
785 struct i386_all_regs *ix86 ) {
786 struct int13_disk_address addr;
787 uint64_t lba;
788 unsigned long count;
789
790 /* Read parameters from disk address structure */
791 if ( DBG_EXTRA ) {
792 copy_from_real ( &addr, ix86->segs.ds, ix86->regs.si,
793 sizeof ( addr ));
794 lba = addr.lba;
795 count = addr.count;
796 DBGC2 ( sandev, "Verify: LBA %08llx (count %ld)\n",
797 ( ( unsigned long long ) lba ), count );
798 }
799
800 /* We have no mechanism for verifying sectors */
801 return -INT13_STATUS_INVALID;
802 }
803
804 /**
805 * INT 13, 44 - Extended seek
806 *
807 * @v sandev SAN device
808 * @v ds:si Disk address packet
809 * @ret status Status code
810 */
811 static int int13_extended_seek ( struct san_device *sandev,
812 struct i386_all_regs *ix86 ) {
813 struct int13_disk_address addr;
814 uint64_t lba;
815 unsigned long count;
816
817 /* Read parameters from disk address structure */
818 if ( DBG_EXTRA ) {
819 copy_from_real ( &addr, ix86->segs.ds, ix86->regs.si,
820 sizeof ( addr ));
821 lba = addr.lba;
822 count = addr.count;
823 DBGC2 ( sandev, "Seek: LBA %08llx (count %ld)\n",
824 ( ( unsigned long long ) lba ), count );
825 }
826
827 /* Ignore and return success */
828 return 0;
829 }
830
831 /**
832 * Build device path information
833 *
834 * @v sandev SAN device
835 * @v dpi Device path information
836 * @ret rc Return status code
837 */
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;
843 unsigned int i;
844 uint8_t sum = 0;
845 int rc;
846 return -ECANCELED;
847 /* Reopen block device if necessary */
848 if ( sandev_needs_reopen ( sandev ) &&
849 ( ( rc = sandev_reopen ( sandev ) ) != 0 ) )
850 return rc;
851 sanpath = sandev->active;
852 assert ( sanpath != NULL );
853
854 /* Get underlying hardware device */
855 device = identify_device ( &sanpath->block );
856 if ( ! device ) {
857 DBGC ( sandev, "INT13 drive %02x cannot identify hardware "
858 "device\n", sandev->drive );
859 return -ENODEV;
860 }
861
862 /* Fill in bus type and interface path */
863 desc = &device->desc;
864 switch ( desc->bus_type ) {
865 case BUS_TYPE_PCI:
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 */
871 break;
872 default:
873 DBGC ( sandev, "INT13 drive %02x unrecognised bus type %d\n",
874 sandev->drive, desc->bus_type );
875 return -ENOTSUP;
876 }
877
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 ) );
883 return rc;
884 }
885
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;
892
893 return 0;
894 }
895
896 /**
897 * INT 13, 48 - Get extended parameters
898 *
899 * @v sandev SAN device
900 * @v ds:si Drive parameter table
901 * @ret status Status code
902 */
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 );
909 uint16_t bufsize;
910 int rc;
911
912 /* Get buffer size */
913 get_real ( bufsize, ix86->segs.ds,
914 ( ix86->regs.si + offsetof ( typeof ( params ), bufsize )));
915
916 DBGC2 ( sandev, "Get extended drive parameters to %04x:%04x+%02x\n",
917 ix86->segs.ds, ix86->regs.si, bufsize );
918
919 /* Build drive parameters */
920 memset ( &params, 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;
925 }
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 ( &params.dpte, 0xff, sizeof ( params.dpte ) );
932 if ( ( rc = int13_device_path_info ( sandev, &params.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 );
937 }
938
939 /* Calculate returned "buffer size" (which will be less than
940 * the length actually copied if device path information is
941 * present).
942 */
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 );
947 } else {
948 params.bufsize = offsetof ( typeof ( params ), dpi );
949 }
950
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, &params, len );
956
957 /* Return drive parameters */
958 if ( len > bufsize )
959 len = bufsize;
960 copy_to_real ( ix86->segs.ds, ix86->regs.si, &params, len );
961
962 return 0;
963 }
964
965 /**
966 * INT 13, 4b - Get status or terminate CD-ROM emulation
967 *
968 * @v sandev SAN device
969 * @v ds:si Specification packet
970 * @ret status Status code
971 */
972 static int int13_cdrom_status_terminate ( struct san_device *sandev,
973 struct i386_all_regs *ix86 ) {
974 struct int13_cdrom_specification specification;
975
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" ) );
979
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",
983 sandev->drive );
984 return -INT13_STATUS_INVALID;
985 }
986
987 /* Build specification packet */
988 memset ( &specification, 0, sizeof ( specification ) );
989 specification.size = sizeof ( specification );
990 specification.drive = sandev->drive;
991
992 /* Return specification packet */
993 copy_to_real ( ix86->segs.ds, ix86->regs.si, &specification,
994 sizeof ( specification ) );
995
996 return 0;
997 }
998
999
1000 /**
1001 * INT 13, 4d - Read CD-ROM boot catalog
1002 *
1003 * @v sandev SAN device
1004 * @v ds:si Command packet
1005 * @ret status Status code
1006 */
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;
1011 unsigned int start;
1012 int rc;
1013
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 );
1018
1019 /* Fail if we have no boot catalog */
1020 if ( ! int13->boot_catalog ) {
1021 DBGC ( sandev, "INT13 drive %02x has no boot catalog\n",
1022 sandev->drive );
1023 return -INT13_STATUS_INVALID;
1024 }
1025 start = ( int13->boot_catalog + command.start );
1026
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;
1033 }
1034
1035 return 0;
1036 }
1037
1038
1039
1040 /**
1041 * INT 13 handler
1042 *
1043 */
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;
1049 int status;
1050
1051 /* We simulate a cdrom, so no need to sync hd drive number */
1052 //int13_check_num_drives();
1053
1054 if (bios_drive == VENTOY_BIOS_FAKE_DRIVE)
1055 {
1056 ix86->regs.dl = g_sandev->exdrive;
1057 return;
1058 }
1059
1060 // drive swap
1061 if (g_drive_map1 >= 0x80 && g_drive_map2 >= 0x80)
1062 {
1063 if (bios_drive == g_drive_map1)
1064 {
1065 ix86->regs.dl = g_drive_map2;
1066 return;
1067 }
1068 else if (bios_drive == g_drive_map2)
1069 {
1070 ix86->regs.dl = g_drive_map1;
1071 return;
1072 }
1073 }
1074
1075 for_each_sandev ( sandev ) {
1076
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;
1085 return;
1086 } else if ( ( ( bios_drive & 0x7f ) == 0x7f ) &&
1087 ( command == INT13_CDROM_STATUS_TERMINATE )
1088 && sandev->is_cdrom ) {
1089
1090 /* Catch non-drive-specific CD-ROM calls */
1091 } else {
1092 return;
1093 }
1094 }
1095
1096 sandev->int13_command = command;
1097 sandev->x86_regptr = ix86;
1098
1099 DBGC2 ( sandev, "INT13,%02x (%02x): ",
1100 ix86->regs.ah, bios_drive );
1101
1102 switch ( command ) {
1103 case INT13_RESET:
1104 status = int13_reset ( sandev, ix86 );
1105 break;
1106 case INT13_GET_LAST_STATUS:
1107 status = int13_get_last_status ( sandev, ix86 );
1108 break;
1109 case INT13_READ_SECTORS:
1110 status = int13_read_sectors ( sandev, ix86 );
1111 break;
1112 case INT13_WRITE_SECTORS:
1113 status = int13_write_sectors ( sandev, ix86 );
1114 break;
1115 case INT13_GET_PARAMETERS:
1116 status = int13_get_parameters ( sandev, ix86 );
1117 break;
1118 case INT13_GET_DISK_TYPE:
1119 status = int13_get_disk_type ( sandev, ix86 );
1120 break;
1121 case INT13_EXTENSION_CHECK:
1122 status = int13_extension_check ( sandev, ix86 );
1123 break;
1124 case INT13_EXTENDED_READ:
1125 status = int13_extended_read ( sandev, ix86 );
1126 break;
1127 case INT13_EXTENDED_WRITE:
1128 status = int13_extended_write ( sandev, ix86 );
1129 break;
1130 case INT13_EXTENDED_VERIFY:
1131 status = int13_extended_verify ( sandev, ix86 );
1132 break;
1133 case INT13_EXTENDED_SEEK:
1134 status = int13_extended_seek ( sandev, ix86 );
1135 break;
1136 case INT13_GET_EXTENDED_PARAMETERS:
1137 status = int13_get_extended_parameters ( sandev, ix86 );
1138 break;
1139 case INT13_CDROM_STATUS_TERMINATE:
1140 status = int13_cdrom_status_terminate ( sandev, ix86 );
1141 break;
1142 case INT13_CDROM_READ_BOOT_CATALOG:
1143 status = int13_cdrom_read_boot_catalog ( sandev, ix86 );
1144 break;
1145 default:
1146 DBGC2 ( sandev, "*** Unrecognised INT13 ***\n" );
1147 status = -INT13_STATUS_INVALID;
1148 break;
1149 }
1150
1151 /* Store status for INT 13,01 */
1152 int13->last_status = status;
1153
1154 /* Negative status indicates an error */
1155 if ( status < 0 ) {
1156 status = -status;
1157 DBGC ( sandev, "INT13,%02x (%02x) failed with status "
1158 "%02x\n", ix86->regs.ah, sandev->drive, status );
1159 } else {
1160 ix86->flags &= ~CF;
1161 }
1162 ix86->regs.ah = status;
1163
1164 /* Set OF to indicate to wrapper not to chain this call */
1165 ix86->flags |= OF;
1166
1167 return;
1168 }
1169 }
1170
1171 /**
1172 * Hook INT 13 handler
1173 *
1174 */
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()).
1179 */
1180 __asm__ __volatile__ (
1181 TEXT16_CODE ( "\nint13_wrapper:\n\t"
1182 /* Preserve %ax and %dx for future reference */
1183 "pushw %%bp\n\t"
1184 "movw %%sp, %%bp\n\t"
1185 "pushw %%ax\n\t"
1186 "pushw %%dx\n\t"
1187 /* Clear OF, set CF, call int13() */
1188 "orb $0, %%al\n\t"
1189 "stc\n\t"
1190 VIRT_CALL ( int13 )
1191 /* Chain if OF not set */
1192 "jo 1f\n\t"
1193 "pushfw\n\t"
1194 "lcall *%%cs:int13_vector\n\t"
1195 "\n1:\n\t"
1196 /* Overwrite flags for iret */
1197 "pushfw\n\t"
1198 "popw 6(%%bp)\n\t"
1199 /* Fix up %dl:
1200 *
1201 * INT 13,15 : do nothing if hard disk
1202 * INT 13,08 : load with number of drives
1203 * all others: restore original value
1204 */
1205 "cmpb $0x15, -1(%%bp)\n\t"
1206 "jne 2f\n\t"
1207 "testb $0x80, -4(%%bp)\n\t"
1208 "jnz 3f\n\t"
1209 "\n2:\n\t"
1210 "movb -4(%%bp), %%dl\n\t"
1211 "cmpb $0x08, -1(%%bp)\n\t"
1212 "jne 3f\n\t"
1213 "testb $0x80, %%dl\n\t"
1214 "movb %%cs:num_drives, %%dl\n\t"
1215 "jnz 3f\n\t"
1216 "movb %%cs:num_fdds, %%dl\n\t"
1217 /* Return */
1218 "\n3:\n\t"
1219 "movw %%bp, %%sp\n\t"
1220 "popw %%bp\n\t"
1221 "iret\n\t" ) : : );
1222
1223 hook_bios_interrupt ( 0x13, ( intptr_t ) int13_wrapper, &int13_vector );
1224 }
1225
1226
1227
1228 /**
1229 * Load and verify master boot record from INT 13 drive
1230 *
1231 * @v drive Drive number
1232 * @v address Boot code address to fill in
1233 * @ret rc Return status code
1234 */
1235 static int int13_load_mbr ( unsigned int drive, struct segoff *address ) {
1236 uint16_t status;
1237 int discard_b, discard_c, discard_d;
1238 uint16_t magic;
1239
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"
1244 "pushl %%ebx\n\t"
1245 "popw %%bx\n\t"
1246 "popw %%es\n\t"
1247 "stc\n\t"
1248 "sti\n\t"
1249 "int $0x13\n\t"
1250 "sti\n\t" /* BIOS bugs */
1251 "jc 1f\n\t"
1252 "xorw %%ax, %%ax\n\t"
1253 "\n1:\n\t"
1254 "popw %%es\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 ) );
1259 if ( status ) {
1260 DBG ( "INT13 drive %02x could not read MBR (status %04x)\n",
1261 drive, status );
1262 return -EIO;
1263 }
1264
1265 /* Check magic signature */
1266 get_real ( magic, address->segment,
1267 ( address->offset +
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",
1271 drive );
1272 return -ENOEXEC;
1273 }
1274
1275 return 0;
1276 }
1277
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 ),
1281 .count = 1,
1282 .buffer = 0x7c00,
1283 .start = 0,
1284 };
1285 #define eltorito_cmd __use_data16 ( eltorito_cmd )
1286
1287 /** El Torito disk address packet */
1288 static struct int13_disk_address __bss16 ( eltorito_address );
1289 #define eltorito_address __use_data16 ( eltorito_address )
1290
1291 /**
1292 * Load and verify El Torito boot record from INT 13 drive
1293 *
1294 * @v drive Drive number
1295 * @v address Boot code address to fill in
1296 * @ret rc Return status code
1297 */
1298 static int int13_load_eltorito ( unsigned int drive, struct segoff *address ) {
1299 struct {
1300 struct eltorito_validation_entry valid;
1301 struct eltorito_boot_entry boot;
1302 } __attribute__ (( packed )) catalog;
1303 uint16_t status;
1304
1305 if (g_sandev && g_sandev->drive == drive)
1306 {
1307 copy_to_user(phys_to_user ( eltorito_cmd.buffer ), 0, g_sandev->boot_catalog_sector, sizeof(g_sandev->boot_catalog_sector));
1308 }
1309 else
1310 {
1311 /* Use INT 13, 4d to read the boot catalog */
1312 __asm__ __volatile__ ( REAL_CODE ( "stc\n\t"
1313 "sti\n\t"
1314 "int $0x13\n\t"
1315 "sti\n\t" /* BIOS bugs */
1316 "jc 1f\n\t"
1317 "xorw %%ax, %%ax\n\t"
1318 "\n1:\n\t" )
1319 : "=a" ( status )
1320 : "a" ( 0x4d00 ), "d" ( drive ),
1321 "S" ( __from_data16 ( &eltorito_cmd ) ) );
1322 if ( status ) {
1323 DBG ( "INT13 drive %02x could not read El Torito boot catalog "
1324 "(status %04x)\n", drive, status );
1325 return -EIO;
1326 }
1327 }
1328
1329 copy_from_user ( &catalog, phys_to_user ( eltorito_cmd.buffer ), 0,
1330 sizeof ( catalog ) );
1331
1332 /* Sanity checks */
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 );
1336 return -ENOEXEC;
1337 }
1338 if ( catalog.boot.indicator != ELTORITO_BOOTABLE ) {
1339 DBG ( "INT13 drive %02x El Torito is not bootable\n", drive );
1340 return -ENOEXEC;
1341 }
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 );
1345 return -ENOTSUP;
1346 }
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 );
1354
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"
1362 "sti\n\t"
1363 "int $0x13\n\t"
1364 "sti\n\t" /* BIOS bugs */
1365 "jc 1f\n\t"
1366 "xorw %%ax, %%ax\n\t"
1367 "\n1:\n\t" )
1368 : "=a" ( status )
1369 : "a" ( 0x4200 ), "d" ( drive ),
1370 "S" ( __from_data16 ( &eltorito_address ) ) );
1371 if ( status ) {
1372 DBG ( "INT13 drive %02x could not read El Torito boot image "
1373 "(status %04x)\n", drive, status );
1374 return -EIO;
1375 }
1376
1377 return 0;
1378 }
1379
1380 /**
1381 * Hook INT 13 SAN device
1382 *
1383 * @v drive Drive number
1384 * @v uris List of URIs
1385 * @v count Number of URIs
1386 * @v flags Flags
1387 * @ret drive Drive number, or negative error
1388 *
1389 * Registers the drive with the INT 13 emulation subsystem, and hooks
1390 * the INT 13 interrupt vector (if not already hooked).
1391 */
1392 unsigned int ventoy_int13_hook (ventoy_chain_head *chain)
1393 {
1394 unsigned int blocks;
1395 unsigned int blocks_per_cyl;
1396 unsigned int natural_drive;
1397 struct int13_data *int13;
1398
1399 /* We simulate a cdrom, so no need to sync hd drive number */
1400 //int13_sync_num_drives();
1401
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);
1404
1405 //natural_drive = num_drives | 0x80;
1406 natural_drive = 0xE0; /* just set a cdrom drive number 224 */
1407
1408 if (chain->disk_drive >= 0x80 && chain->drive_map >= 0x80)
1409 {
1410 g_drive_map1 = chain->disk_drive;
1411 g_drive_map2 = chain->drive_map;
1412 }
1413
1414 /* a fake sandev */
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));
1425
1426
1427 /* Apply guesses if no geometry already specified */
1428 if ( ! int13->heads )
1429 int13->heads = 255;
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 );
1436
1437 int13->cylinders = ( blocks / blocks_per_cyl );
1438 if ( int13->cylinders > 1024 )
1439 int13->cylinders = 1024;
1440 }
1441
1442 /* Hook INT 13 vector if not already hooked */
1443 int13_hook_vector();
1444
1445 /* Update BIOS drive count */
1446 //int13_sync_num_drives();
1447
1448 return natural_drive;
1449 }
1450
1451 static uint8_t __bss16_array ( xbftab, [512 + 128])
1452 __attribute__ (( aligned ( 16 ) ));
1453 #define xbftab __use_data16 ( xbftab )
1454
1455 void * ventoy_get_runtime_addr(void)
1456 {
1457 return (void *)user_to_phys((userptr_t)(&xbftab), 0);
1458 }
1459
1460 /**
1461 * Attempt to boot from an INT 13 drive
1462 *
1463 * @v drive Drive number
1464 * @v filename Filename (or NULL to use default)
1465 * @ret rc Return status code
1466 *
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).
1471 *
1472 * Note that this function can never return success, by definition.
1473 */
1474 int ventoy_int13_boot ( unsigned int drive, void *imginfo, const char *cmdline) {
1475 //struct memory_map memmap;
1476 int rc;
1477 int headlen;
1478 struct segoff address;
1479 struct acpi_header *acpi = NULL;
1480 struct ibft_table *ibft = NULL;
1481
1482 /* Look for a usable boot sector */
1483 if ( ( ( rc = int13_load_eltorito ( drive, &address ) ) != 0 ) &&
1484 ( ( rc = int13_load_mbr ( drive, &address ) ) != 0 ))
1485 return rc;
1486
1487 if (imginfo)
1488 {
1489 if (strstr(cmdline, "ibft"))
1490 {
1491 headlen = 80;
1492 ibft = (struct ibft_table *)(&xbftab);
1493 acpi = &(ibft->acpi);
1494 memset(ibft, 0, headlen);
1495
1496 acpi->signature = IBFT_SIG;
1497 acpi->length = headlen + sizeof(ventoy_os_param);
1498 acpi->revision = 1;
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);
1503 }
1504 else
1505 {
1506 memcpy((&xbftab), imginfo, sizeof(ventoy_os_param));
1507 }
1508 }
1509
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
1513 * it's worth doing.
1514 */
1515 //get_memmap ( &memmap );
1516
1517 DBGC(g_sandev, "start to boot ...\n");
1518
1519 /* Jump to boot sector */
1520 if ( ( rc = call_bootsector ( address.segment, address.offset,
1521 drive ) ) != 0 ) {
1522 return rc;
1523 }
1524
1525 return -ECANCELED; /* -EIMPOSSIBLE */
1526 }
1527