xref: /openbmc/linux/arch/x86/boot/apm.c (revision 9e8238020c5beba64e7ffafbb7ea0fb02fe68270)
197873a3dSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
296ae6ea0SThomas Gleixner /* -*- linux-c -*- ------------------------------------------------------- *
396ae6ea0SThomas Gleixner  *
496ae6ea0SThomas Gleixner  *   Copyright (C) 1991, 1992 Linus Torvalds
596ae6ea0SThomas Gleixner  *   Copyright 2007 rPath, Inc. - All Rights Reserved
6d54ea252SH. Peter Anvin  *   Copyright 2009 Intel Corporation; author H. Peter Anvin
796ae6ea0SThomas Gleixner  *
896ae6ea0SThomas Gleixner  *   Original APM BIOS checking by Stephen Rothwell, May 1994
996ae6ea0SThomas Gleixner  *   (sfr@canb.auug.org.au)
1096ae6ea0SThomas Gleixner  *
1196ae6ea0SThomas Gleixner  * ----------------------------------------------------------------------- */
1296ae6ea0SThomas Gleixner 
1396ae6ea0SThomas Gleixner /*
1496ae6ea0SThomas Gleixner  * Get APM BIOS information
1596ae6ea0SThomas Gleixner  */
1696ae6ea0SThomas Gleixner 
1796ae6ea0SThomas Gleixner #include "boot.h"
1896ae6ea0SThomas Gleixner 
query_apm_bios(void)1996ae6ea0SThomas Gleixner int query_apm_bios(void)
2096ae6ea0SThomas Gleixner {
21d54ea252SH. Peter Anvin 	struct biosregs ireg, oreg;
2296ae6ea0SThomas Gleixner 
2396ae6ea0SThomas Gleixner 	/* APM BIOS installation check */
24d54ea252SH. Peter Anvin 	initregs(&ireg);
25d54ea252SH. Peter Anvin 	ireg.ah = 0x53;
26d54ea252SH. Peter Anvin 	intcall(0x15, &ireg, &oreg);
2796ae6ea0SThomas Gleixner 
28d54ea252SH. Peter Anvin 	if (oreg.flags & X86_EFLAGS_CF)
2996ae6ea0SThomas Gleixner 		return -1;		/* No APM BIOS */
3096ae6ea0SThomas Gleixner 
31d54ea252SH. Peter Anvin 	if (oreg.bx != 0x504d)		/* "PM" signature */
3296ae6ea0SThomas Gleixner 		return -1;
3396ae6ea0SThomas Gleixner 
34d54ea252SH. Peter Anvin 	if (!(oreg.cx & 0x02))		/* 32 bits supported? */
3596ae6ea0SThomas Gleixner 		return -1;
3696ae6ea0SThomas Gleixner 
3796ae6ea0SThomas Gleixner 	/* Disconnect first, just in case */
38d54ea252SH. Peter Anvin 	ireg.al = 0x04;
39d54ea252SH. Peter Anvin 	intcall(0x15, &ireg, NULL);
4096ae6ea0SThomas Gleixner 
4196ae6ea0SThomas Gleixner 	/* 32-bit connect */
42d54ea252SH. Peter Anvin 	ireg.al = 0x03;
43d54ea252SH. Peter Anvin 	intcall(0x15, &ireg, &oreg);
4496ae6ea0SThomas Gleixner 
45d54ea252SH. Peter Anvin 	boot_params.apm_bios_info.cseg        = oreg.ax;
46d54ea252SH. Peter Anvin 	boot_params.apm_bios_info.offset      = oreg.ebx;
47d54ea252SH. Peter Anvin 	boot_params.apm_bios_info.cseg_16     = oreg.cx;
48d54ea252SH. Peter Anvin 	boot_params.apm_bios_info.dseg        = oreg.dx;
49d54ea252SH. Peter Anvin 	boot_params.apm_bios_info.cseg_len    = oreg.si;
50d54ea252SH. Peter Anvin 	boot_params.apm_bios_info.cseg_16_len = oreg.hsi;
51d54ea252SH. Peter Anvin 	boot_params.apm_bios_info.dseg_len    = oreg.di;
5296ae6ea0SThomas Gleixner 
53d54ea252SH. Peter Anvin 	if (oreg.flags & X86_EFLAGS_CF)
5496ae6ea0SThomas Gleixner 		return -1;
5596ae6ea0SThomas Gleixner 
5696ae6ea0SThomas Gleixner 	/* Redo the installation check as the 32-bit connect;
5796ae6ea0SThomas Gleixner 	   some BIOSes return different flags this way... */
5896ae6ea0SThomas Gleixner 
59d54ea252SH. Peter Anvin 	ireg.al = 0x00;
60d54ea252SH. Peter Anvin 	intcall(0x15, &ireg, &oreg);
6196ae6ea0SThomas Gleixner 
62d54ea252SH. Peter Anvin 	if ((oreg.eflags & X86_EFLAGS_CF) || oreg.bx != 0x504d) {
63*023f270bSGeert Uytterhoeven 		/* Failure with 32-bit connect, try to disconnect and ignore */
64d54ea252SH. Peter Anvin 		ireg.al = 0x04;
65d54ea252SH. Peter Anvin 		intcall(0x15, &ireg, NULL);
6696ae6ea0SThomas Gleixner 		return -1;
6796ae6ea0SThomas Gleixner 	}
6896ae6ea0SThomas Gleixner 
69d54ea252SH. Peter Anvin 	boot_params.apm_bios_info.version = oreg.ax;
70d54ea252SH. Peter Anvin 	boot_params.apm_bios_info.flags   = oreg.cx;
7196ae6ea0SThomas Gleixner 	return 0;
7296ae6ea0SThomas Gleixner }
7396ae6ea0SThomas Gleixner 
74