1 /* -----------------------------------------------------------------------
2  *
3  *   Copyright 1999-2008 H. Peter Anvin - All Rights Reserved
4  *
5  *   This program is free software; you can redistribute it and/or modify
6  *   it under the terms of the GNU General Public License as published by
7  *   the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
8  *   Boston MA 02110-1301, USA; either version 2 of the License, or
9  *   (at your option) any later version; incorporated herein by reference.
10  *
11  * -----------------------------------------------------------------------
12  */
13 #include <sys/cpu.h>
14 #include <sys/io.h>
15 #include <string.h>
16 #include <core.h>
17 #include <fs.h>
18 #include <bios.h>
19 #include <syslinux/video.h>
20 
21 /*
22  * localboot.c
23  *
24  * Boot from a local disk, or invoke INT 18h.
25  */
26 
27 #define LOCALBOOT_MSG	"Booting from local disk..."
28 
29 #define retry_count	16
30 
31 extern void local_boot16(void);
32 
33 /*
34  * Boot a specified local disk.  AX specifies the BIOS disk number; or
35  * -1 in case we should execute INT 18h ("next device.")
36  */
local_boot(int16_t ax)37 __export void local_boot(int16_t ax)
38 {
39 	com32sys_t ireg, oreg;
40 	int i;
41 
42         memset(&ireg, 0, sizeof(ireg));
43 	syslinux_force_text_mode();
44 
45 	writestr(LOCALBOOT_MSG);
46 	crlf();
47 	cleanup_hardware();
48 
49 	if (ax == -1) {
50 		/* Hope this does the right thing */
51 		__intcall(0x18, &zero_regs, NULL);
52 
53 		/* If we returned, oh boy... */
54 		kaboom();
55 	}
56 
57 	/*
58 	 * Load boot sector from the specified BIOS device and jump to
59 	 * it.
60 	 */
61 	memset(&ireg, 0, sizeof ireg);
62 	ireg.edx.b[0] = ax & 0xff;
63 	ireg.eax.w[0] = 0;	/* Reset drive */
64 	__intcall(0x13, &ireg, NULL);
65 
66 	memset(&ireg, 0, sizeof(ireg));
67 	ireg.eax.w[0] = 0x0201;	/* Read one sector */
68 	ireg.ecx.w[0] = 0x0001;	/* C/H/S = 0/0/1 (first sector) */
69 	ireg.ebx.w[0] = OFFS(trackbuf);
70 	ireg.es = SEG(trackbuf);
71 
72 	for (i = 0; i < retry_count; i++) {
73 		__intcall(0x13, &ireg, &oreg);
74 
75 		if (!(oreg.eflags.l & EFLAGS_CF))
76 			break;
77 	}
78 
79 	if (i == retry_count)
80 		kaboom();
81 
82 	cli();			/* Abandon hope, ye who enter here */
83 	memcpy((void *)0x07C00, trackbuf, 512);
84 
85 	ireg.esi.w[0] = OFFS(trackbuf);
86 	ireg.edi.w[0] = 0x07C00;
87 	ireg.edx.w[0] = ax;
88 	call16(local_boot16, &ireg, NULL);
89 }
90 
pm_local_boot(com32sys_t * regs)91 void pm_local_boot(com32sys_t *regs)
92 {
93 	local_boot(regs->eax.w[0]);
94 }
95