File: smi-handler.S

package info (click to toggle)
faumachine 20100527-2
  • links: PTS
  • area: main
  • in suites: squeeze
  • size: 53,836 kB
  • ctags: 20,552
  • sloc: ansic: 179,550; asm: 3,645; makefile: 3,611; perl: 2,103; sh: 1,529; python: 600; xml: 563; lex: 210; vhdl: 204
file content (149 lines) | stat: -rw-r--r-- 3,856 bytes parent folder | download | duplicates (2)
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 */