summaryrefslogtreecommitdiffstats
path: root/sys/i386/bios/apm_init/apm_init.S
blob: 46196806968865e88b44b625ee0eac73219ca081 (plain)
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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
/*
 * APM (Advanced Power Management) BIOS Device Driver
 *
 * Copyright (c) 1994-1995 by HOSOKAWA, Tatsumi <hosokawa@jp.FreeBSD.org>
 *
 * This software may be used, modified, copied, and distributed, in
 * both source and binary form provided that the above copyright and
 * these terms are retained. Under no circumstances is the author 
 * responsible for the proper functioning of this software, nor does 
 * the author assume any responsibility for damages incurred with its 
 * use.
 *
 * Sep., 1994	Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD)
 *
 *	$FreeBSD$
 */

/*
 * If you want to know the specification of APM BIOS, see the following
 * documentations,
 *
 * [1] Intel Corporation and Microsoft Corporation, "Advanced Power 
 *     Management, The Next Generation, Version 1.0", Feb.,1992.
 *
 * [2] Intel Corporation and Microsoft Corporation, "Advanced Power
 *     Management (APM) BIOS Interface Specification Revision 1.1",
 *     Sep.,1993, Intel Order Number: 241704-001, Microsoft Part
 *     Number: 781-110-X01
 *
 * or contact
 *
 * APM Support Desk (Intel Corporation, US)
 *   TEL: (800)628-8686 
 *   FAX: (916)356-6100.
 */

	.file	"apm_init.S"

#define ASM

#include "real_prot.h"
#include "apm_bios.h"
#include "apm_segments.h"

/*
 * APM BIOS initializer
 *
 * Return value:
 *	%eax	0xffffffff	Can't find APM BIOS
 *		0xfffffffe	Don't support 32bit connection
 *		0xfffffffd	Connection error
 *		otherwise	APM version (16bit BCD format)
 *	%ebx			APM cs entry offset (32bit)
 *	%ecx	lower 16bit	APM 16bit cs base (real mode segment)
 *		upper 16bit	APM 32bit cs base (real mode segment)
 *	%edx	lower 16bit	APM ds limit (real mode segment)
 *		upper 16bit	[Reserved]
 *	%esi	lower 16bit	APM cs limit (APM 1.1 or later)
 *		upper 16bit	APM ds limit (APM 1.1 or later)
 *	%edi	bit0 = 1	16bit protected mode interface supported
 *		bit1 = 1	32bit protected mode interface supported
 *		bit2 = 1	"CPU idle" call slows processor clock speed
 *		bit3 = 1	APM BIOS Power Management disabled
 *		bit4 = 1	APM BIOS Power Management disengaged
 */

	.text
ENTRY(apm_init)
	cli				/* disable interrupt */
	pushl	%ebp			/* save original base pointer */
					/* ebp is used as a register variable */
	/* 
	 * save old data segments: We assume that %ds == %es && %ds == %ss
	 */
	pushl	%fs
	movw	%ds, %ax
	movw	%ax, %fs
	movw	$(APM_INIT_DS_SEL), %ax	/* initializer data segment */
	movw	%ax, %ds
	movw	%ax, %es
	movw	%ax, %ss
	movl	%esp, old_esp		/* save original stack pointer */
	movl	$0x10000, %esp		/* setup temporary stack */
					/* (note that it isn't 0x00000000) */

	sidt	EXT(Idtr_prot)		/* save current IDT */
	call	EXT(prot_to_real)	/* return to real mode */

	/*
	 * APM installation check
	 */
	movb	$(APM_BIOS), %ah
	movb	$(APM_INSTCHECK), %al
	data32
	movl	$(PMDV_APMBIOS), %ebx
	sti
	int	$(SYSTEM_BIOS)		/* call system BIOS */
	cli

	jnc	1f			/* if found, goto 1f */
	
	data32
	call	EXT(real_to_prot)	/* come back again to protected mode */
	movl	$(APMINI_CANTFIND), apm_version
					/* can't find APM BIOS */
	jmp	finish

1:
	movl	%eax, %edx		/* actually, movw %ax, %dx */
					/* save the value of %ax */
	data32
	call	EXT(real_to_prot)	/* come back again to protected mode */
	cmpw	$0x504d, %bx		/* "PM" signature? */
	jz	1f

	movl	$(APMINI_CANTFIND), apm_version
					/* can't find APM BIOS */
	jmp	finish

1:
	testl	$(APM_32BIT_SUPPORT), %ecx
					/* supports 32bit connection? */
	jnz	1f

	movl	$(APMINI_NOT32BIT), apm_version
					/* don't support 32bit connection */
	jmp	finish
1:
	andl	$0x0000ffff, %edx
	movl	%edx, apm_version
	andl	$0x0000ffff, %ecx
	movl	%ecx, apm_flags

	/*
	 * APM Protected Mode 32-bit Interface Connect
	 */
	call	EXT(prot_to_real)	/* return to real mode */

	/* Disconnect, just in case */
	movb	$(APM_BIOS), %ah
	movb	$(APM_DISCONNECT), %al
	data32
	movl	$(PMDV_APMBIOS), %ebx
	sti
	int	$(SYSTEM_BIOS)
	cli

	/* Ignore return code, but we can now connect safely */
	movb	$(APM_BIOS), %ah
	movb	$(APM_PROT32CONNECT), %al
	data32
	movl	$(PMDV_APMBIOS), %ebx
	sti
	int	$(SYSTEM_BIOS)
	cli
	jnc	1f			/* if successed, go to 1f */
	data32
	call	EXT(real_to_prot)
	movl	$(APMINI_CONNECTERR), apm_version
					/* connection error */
	jmp	finish
1:	
	/* save PM 32bit code segment into %bp */
	movl	%eax, %ebp		/* actually, movw %ax, %bp */
	data32
	call	EXT(real_to_prot)
	movl	$0x0000ffff, %eax
	andl	%eax, %ebp		/* 32bit cs base */
	andl	%eax, %ecx		/* 16bit cs base */
	andl	%eax, %edx		/* ds base */
	andl	%eax, %esi		/* cs length (APM 1.1 or later) */
	andl	%eax, %edi		/* ds length (APM 1.1 or later) */
					/* %ebx is code offset */
	/* pack 32bit cs and 16bit cs into %ecx */
	shll	$16, %ebp
	orl	%ebp, %ecx
	/* pack cs length and ds length into %esi */
	shll	$16, %edi
	orl	%edi, %esi
finish:
	cli
	lidt	EXT(Idtr_prot)		/* restore old IDTR */
	movl	old_esp, %esp		/* restore old stack pointer */
	movl	apm_version, %ebp	/* stored to %eax later */
	movl	apm_flags, %edi
	movw	%fs, %ax
	movw	%ax, %ss
	movw	%ax, %es
	movw	%ax, %ds
	movl	%ebp, %eax
	popl	%fs
	popl	%ebp			/* restore old base pointer */
	lret				/* restore old code segment */

	.data

	.globl	EXT(ouraddr)
LEXT(ouraddr)
	.long	APM_OURADDR

old_esp:
	.long	0
apm_version:
	.long	0
apm_flags:
	.long	0
old_ds:
	.word	0
old_es:
	.word	0
old_ss:
	.word	0
OpenPOWER on IntegriCloud