David Brazdil | 0f672f6 | 2019-12-10 10:32:29 +0000 | [diff] [blame^] | 1 | // SPDX-License-Identifier: GPL-2.0-only |
Andrew Scull | b4b6d4a | 2019-01-02 15:54:55 +0000 | [diff] [blame] | 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 | * |
Andrew Scull | b4b6d4a | 2019-01-02 15:54:55 +0000 | [diff] [blame] | 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(&ireg); |
| 25 | ireg.ah = 0x53; |
| 26 | intcall(0x15, &ireg, &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(0x15, &ireg, NULL); |
| 40 | |
| 41 | /* 32-bit connect */ |
| 42 | ireg.al = 0x03; |
| 43 | intcall(0x15, &ireg, &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(0x15, &ireg, &oreg); |
| 61 | |
| 62 | if ((oreg.eflags & X86_EFLAGS_CF) || oreg.bx != 0x504d) { |
| 63 | /* Failure with 32-bit connect, try to disconect and ignore */ |
| 64 | ireg.al = 0x04; |
| 65 | intcall(0x15, &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 | |