1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* -*- linux-c -*- ------------------------------------------------------- * |
3 | * |
4 | * Copyright (C) 1991, 1992 Linus Torvalds |
5 | * Copyright 2007 rPath, Inc. - All Rights Reserved |
6 | * Copyright 2009 Intel Corporation; author H. Peter Anvin |
7 | * |
8 | * Original APM BIOS checking by Stephen Rothwell, May 1994 |
9 | * (sfr@canb.auug.org.au) |
10 | * |
11 | * ----------------------------------------------------------------------- */ |
12 | |
13 | /* |
14 | * Get APM BIOS information |
15 | */ |
16 | |
17 | #include "boot.h" |
18 | |
19 | int query_apm_bios(void) |
20 | { |
21 | struct biosregs ireg, oreg; |
22 | |
23 | /* APM BIOS installation check */ |
24 | initregs(regs: &ireg); |
25 | ireg.ah = 0x53; |
26 | intcall(int_no: 0x15, ireg: &ireg, oreg: &oreg); |
27 | |
28 | if (oreg.flags & X86_EFLAGS_CF) |
29 | return -1; /* No APM BIOS */ |
30 | |
31 | if (oreg.bx != 0x504d) /* "PM" signature */ |
32 | return -1; |
33 | |
34 | if (!(oreg.cx & 0x02)) /* 32 bits supported? */ |
35 | return -1; |
36 | |
37 | /* Disconnect first, just in case */ |
38 | ireg.al = 0x04; |
39 | intcall(int_no: 0x15, ireg: &ireg, NULL); |
40 | |
41 | /* 32-bit connect */ |
42 | ireg.al = 0x03; |
43 | intcall(int_no: 0x15, ireg: &ireg, oreg: &oreg); |
44 | |
45 | boot_params.apm_bios_info.cseg = oreg.ax; |
46 | boot_params.apm_bios_info.offset = oreg.ebx; |
47 | boot_params.apm_bios_info.cseg_16 = oreg.cx; |
48 | boot_params.apm_bios_info.dseg = oreg.dx; |
49 | boot_params.apm_bios_info.cseg_len = oreg.si; |
50 | boot_params.apm_bios_info.cseg_16_len = oreg.hsi; |
51 | boot_params.apm_bios_info.dseg_len = oreg.di; |
52 | |
53 | if (oreg.flags & X86_EFLAGS_CF) |
54 | return -1; |
55 | |
56 | /* Redo the installation check as the 32-bit connect; |
57 | some BIOSes return different flags this way... */ |
58 | |
59 | ireg.al = 0x00; |
60 | intcall(int_no: 0x15, ireg: &ireg, oreg: &oreg); |
61 | |
62 | if ((oreg.eflags & X86_EFLAGS_CF) || oreg.bx != 0x504d) { |
63 | /* Failure with 32-bit connect, try to disconnect and ignore */ |
64 | ireg.al = 0x04; |
65 | intcall(int_no: 0x15, ireg: &ireg, NULL); |
66 | return -1; |
67 | } |
68 | |
69 | boot_params.apm_bios_info.version = oreg.ax; |
70 | boot_params.apm_bios_info.flags = oreg.cx; |
71 | return 0; |
72 | } |
73 | |
74 | |