|
@@ -16,7 +16,10 @@
|
16
|
16
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
17
|
17
|
*/
|
18
|
18
|
|
|
19
|
+#include <stdint.h>
|
19
|
20
|
#include <limits.h>
|
|
21
|
+#include <byteswap.h>
|
|
22
|
+#include <errno.h>
|
20
|
23
|
#include <assert.h>
|
21
|
24
|
#include <gpxe/list.h>
|
22
|
25
|
#include <gpxe/blockdev.h>
|
|
@@ -41,6 +44,16 @@ static struct segoff __text16 ( int13_vector );
|
41
|
44
|
/** Assembly wrapper */
|
42
|
45
|
extern void int13_wrapper ( void );
|
43
|
46
|
|
|
47
|
+/** Vector for storing original INT 18 handler
|
|
48
|
+ *
|
|
49
|
+ * We do not chain to this vector, so there is no need to place it in
|
|
50
|
+ * .text16.
|
|
51
|
+ */
|
|
52
|
+static struct segoff int18_vector;
|
|
53
|
+
|
|
54
|
+/** Restart point for INT 18 */
|
|
55
|
+extern void int13_exec_fail ( void );
|
|
56
|
+
|
44
|
57
|
/** List of registered emulated drives */
|
45
|
58
|
static LIST_HEAD ( drives );
|
46
|
59
|
|
|
@@ -473,3 +486,78 @@ void unregister_int13_drive ( struct int13_drive *drive ) {
|
473
|
486
|
if ( list_empty ( &drives ) )
|
474
|
487
|
unhook_int13();
|
475
|
488
|
}
|
|
489
|
+
|
|
490
|
+/**
|
|
491
|
+ * Attempt to boot from an INT 13 drive
|
|
492
|
+ *
|
|
493
|
+ * @v drive Drive number
|
|
494
|
+ * @ret rc Return status code
|
|
495
|
+ *
|
|
496
|
+ * This boots from the specified INT 13 drive by loading the Master
|
|
497
|
+ * Boot Record to 0000:7c00 and jumping to it. INT 18 is hooked to
|
|
498
|
+ * capture an attempt by the MBR to boot the next device. (This is
|
|
499
|
+ * the closest thing to a return path from an MBR).
|
|
500
|
+ *
|
|
501
|
+ * Note that this function can never return success, by definition.
|
|
502
|
+ */
|
|
503
|
+int int13_boot ( unsigned int drive ) {
|
|
504
|
+ int status, signature;
|
|
505
|
+ int d0, d1;
|
|
506
|
+
|
|
507
|
+ DBG ( "Booting from INT 13 drive %02x\n", drive );
|
|
508
|
+
|
|
509
|
+ /* Use INT 13 to read the boot sector */
|
|
510
|
+ REAL_EXEC ( rm_int13_boot,
|
|
511
|
+ "pushw $0\n\t"
|
|
512
|
+ "popw %%es\n\t"
|
|
513
|
+ "int $0x13\n\t"
|
|
514
|
+ "jc 1f\n\t"
|
|
515
|
+ "xorl %%eax, %%eax\n\t"
|
|
516
|
+ "\n1:\n\t"
|
|
517
|
+ "movzwl %%es:0x7dfe, %%ebx\n\t",
|
|
518
|
+ 4,
|
|
519
|
+ OUT_CONSTRAINTS ( "=a" ( status ), "=b" ( signature ),
|
|
520
|
+ "=c" ( d0 ), "=d" ( drive ) ),
|
|
521
|
+ IN_CONSTRAINTS ( "0" ( 0x0201 ), "1" ( 0x7c00 ),
|
|
522
|
+ "2" ( 0x0001 ), "3" ( drive ) ),
|
|
523
|
+ CLOBBER ( "ebp" ) );
|
|
524
|
+ if ( status )
|
|
525
|
+ return -EIO;
|
|
526
|
+
|
|
527
|
+ /* Check signature is correct */
|
|
528
|
+ if ( signature != be16_to_cpu ( 0x55aa ) ) {
|
|
529
|
+ DBG ( "Invalid disk signature %#04x (should be 0x55aa)\n",
|
|
530
|
+ cpu_to_be16 ( signature ) );
|
|
531
|
+ return -ENOEXEC;
|
|
532
|
+ }
|
|
533
|
+
|
|
534
|
+ /* Hook INT 18 to capture failure path */
|
|
535
|
+ hook_bios_interrupt ( 0x18, ( unsigned int ) int13_exec_fail,
|
|
536
|
+ &int18_vector );
|
|
537
|
+
|
|
538
|
+ /* Boot the loaded sector */
|
|
539
|
+ REAL_EXEC ( rm_int13_exec,
|
|
540
|
+ "movw %%ss, %%ax\n\t" /* Preserve stack pointer */
|
|
541
|
+ "movw %%ax, %%cs:int13_exec_saved_ss\n\t"
|
|
542
|
+ "movw %%sp, %%cs:int13_exec_saved_sp\n\t"
|
|
543
|
+ "ljmp $0, $0x7c00\n\t"
|
|
544
|
+ "\nint13_exec_saved_ss: .word 0\n\t"
|
|
545
|
+ "\nint13_exec_saved_sp: .word 0\n\t"
|
|
546
|
+ "\nint13_exec_fail:\n\t"
|
|
547
|
+ "movw %%cs:int13_exec_saved_ss, %%ax\n\t"
|
|
548
|
+ "movw %%ax, %%ss\n\t"
|
|
549
|
+ "movw %%cs:int13_exec_saved_sp, %%sp\n\t"
|
|
550
|
+ "\n99:\n\t",
|
|
551
|
+ 1,
|
|
552
|
+ OUT_CONSTRAINTS ( "=d" ( d1 ) ),
|
|
553
|
+ IN_CONSTRAINTS ( "d" ( drive ) ),
|
|
554
|
+ CLOBBER ( "eax", "ebx", "ecx", "esi", "edi", "ebp" ) );
|
|
555
|
+
|
|
556
|
+ DBG ( "Booted disk returned via INT 18\n" );
|
|
557
|
+
|
|
558
|
+ /* Unhook INT 18 */
|
|
559
|
+ unhook_bios_interrupt ( 0x18, ( unsigned int ) int13_exec_fail,
|
|
560
|
+ &int18_vector );
|
|
561
|
+
|
|
562
|
+ return -ECANCELED;
|
|
563
|
+}
|