1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
|
/* $Id: smi-handler.S,v 1.21 2009-01-28 14:38:04 potyra Exp $
*
* SMI Handler for FAUmachine BIOS.
*
* Copyright (C) 2005-2009 FAUmachine Team <info@faumachine.org>.
* This program is free software. You can redistribute it and/or modify it
* under the terms of the GNU General Public License, either version 2 of
* the License, or (at your option) any later version. See COPYING.
*
* At the moment, everything is done in assembler. Somewhere in the future,
* this may be replaced by a "simple" wrapper that switches to PM, sets up
* a stack, calls some C functions from the BIOS rom mapped at the end of
* the 4 GB address space, and then calls RSM
*/
/* =================== REAL-MODE INIT ========================= */
#ifdef INIT_RM
#define APMC $0xb2
#define APMS $0xb3
#define DEBUGREG $0xffff
#define PMSTS $0x4000
#define PMEN $0x4002
#define PMCNTRL $0x4004
#define GLBSTS $0x4018
#define GLBCTL_H $0x402a
/*
* what we basically have to do is this:
* - check GLBSTS register for SMI causes:
* - handle APMC-caused SMIs:
* APMC=00: disable ACPI mode (reset SCI_EN bit in PMCNTRL register)
* APMC=01: enable ACPI mode (_set_ SCI_EN bit in PMCNTRL register)
* APMC=02: relocate SMBASE. set SMBASE cpu status to APMS << 16
* - handle hardware SMI reasons:
* if powerbutton is enabled pressed (PWRBTN bit in PMEN and PMSTS regs),
* power down system (write SUS_TYP 0 and SUS_EN set to PMCNTRL reg)
* - handle global lock:
* as this is unused, just clear the corresponding flag when someone sets
* it.
* - signal chipset that we're finished by setting EOS (End Of SMI) bit.
* if EOS can't be set, there happened something in the meantime, so
* start again.
* - quit SMI handling by using the "RSM" instruction
*/
.section .text.smi
.code16
asm_smi_handler:
/* check GLBSTS */
movw GLBSTS, %dx
inw %dx
testw $0x0020, %ax # APM_STS
jne handle_apmc
testw $0x0040, %ax # PM1_STS
jne handle_pmreg
testw $0x0001, %ax # BIOS_STS
jne handle_globallock
end_smi:
/* try setting EOS bit */
movw GLBCTL_H, %dx
inb %dx
andb $0xfe, %al # mask reserved bits
orb $0x01, %al # EOS is bit 16 => bit 0 of GLBCTL_H
outb %al, %dx
/* check if EOS could be set */
inb %dx
testb $0x01, %al
/* if EOS couldn't be set, start again... */
je asm_smi_handler
/* else end smi handling */
rsm
handle_apmc:
/* first, check APMC register */
movw APMC, %dx
inb %dx
testb %al, %al
je disable_acpi
cmpb $0x01, %al
je enable_acpi
/* unknown APMC: write '!' to stdout for debugging... */
movb $33, %al # 33 == '!'
movw DEBUGREG, %dx
handle_apmc_outb:
outb %al, %dx
/* reset APM_STS */
movw $0x0020, %ax # writing bits to GLBSTS clears them
movw GLBSTS, %dx
outw %ax, %dx
jmp asm_smi_handler
disable_acpi:
movw PMCNTRL, %dx
inb %dx
andb $0xfe, %al # reset SCI_EN (bit 0)
jmp handle_apmc_outb
enable_acpi:
movw PMCNTRL, %dx
inb %dx
orb $0x01, %al # set SCI_EN (bit 0)
jmp handle_apmc_outb
handle_globallock:
/* just clear BIOS_STS */
movw $0x0001, %ax # writing bits to GLBSTS clears the
movw GLBSTS, %dx
outw %ax, %dx
jmp asm_smi_handler
handle_pmreg:
/* check PMEN and PMSTS for PWRBTN bit */
movw PMEN, %dx
inw %dx
testb $0x01, %ah # PWRBTN_EN is bit 8 => bit 0 of %ah
je asm_smi_handler
movw PMSTS, %dx
inw %dx
testb $0x01, %ah # PWRBTN_STS is bit 8
je asm_smi_handler
/* at this point, we know that power button events were enabled
* and the power button has been pressed, so we clear the power
* button SMI reason and then shut down the system */
andw $0x0100, %ax # writing bits to PMSTS clears them
outw %ax, %dx # clear PWRBTN SMI reason
movw $0x2001, %ax # SUS_EN, SUS_TYP 0, SCI_EN
movw PMCNTRL, %dx
outw %ax, %dx
/* this point should never be reached */
endless_loop:
jmp endless_loop
#endif /* INIT_RM */
|