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
31extern 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 */
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
91void pm_local_boot(com32sys_t *regs)
92{
93	local_boot(regs->eax.w[0]);
94}
95