Browse Source

Add int13_boot(), to allow booting from INT 13 emulated drives.

tags/v0.9.3
Michael Brown 18 years ago
parent
commit
4435667a00
2 changed files with 89 additions and 0 deletions
  1. 1
    0
      src/arch/i386/include/int13.h
  2. 88
    0
      src/arch/i386/interface/pcbios/int13.c

+ 1
- 0
src/arch/i386/include/int13.h View File

@@ -153,5 +153,6 @@ struct int13_disk_parameters {
153 153
 
154 154
 extern void register_int13_drive ( struct int13_drive *drive );
155 155
 extern void unregister_int13_drive ( struct int13_drive *drive );
156
+extern int int13_boot ( unsigned int drive );
156 157
 
157 158
 #endif /* INT13_H */

+ 88
- 0
src/arch/i386/interface/pcbios/int13.c View File

@@ -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
+}

Loading…
Cancel
Save