summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/PC/BIOS/apm_pm.asm
blob: 42c0baa04eff8769d19ee0cf3e69e51a7746dc30 (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
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
; $Id:
;; @file
; Protected-mode APM implementation.
;

;
; Copyright (C) 2006-2023 Oracle and/or its affiliates.
;
; This file is part of VirtualBox base platform packages, as
; available from https://www.virtualbox.org.
;
; This program is free software; you can redistribute it and/or
; modify it under the terms of the GNU General Public License
; as published by the Free Software Foundation, in version 3 of the
; License.
;
; This program is distributed in the hope that it will be useful, but
; WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
; General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program; if not, see <https://www.gnu.org/licenses>.
;
; SPDX-License-Identifier: GPL-3.0-only
;


include commondefs.inc

;; 16-bit protected mode APM entry point

_TEXT		segment public 'CODE'

extern		_apm_function:near	; implemented in C code


public		apm_pm16_entry

SET_DEFAULT_CPU_286


; APM function dispatch table
apm_disp:
		dw	offset apmf_disconnect	; 04h
		dw	offset apmf_idle	; 05h
		dw	offset apmf_busy	; 06h
		dw	offset apmf_set_state	; 07h
		dw	offset apmf_enable	; 08h
		dw	offset apmf_restore	; 09h
		dw	offset apmf_get_status	; 0Ah
		dw	offset apmf_get_event	; 0Bh
		dw	offset apmf_pwr_state	; 0Ch
		dw	offset apmf_dev_pm	; 0Dh
		dw	offset apmf_version	; 0Eh
		dw	offset apmf_engage	; 0Fh
		dw	offset apmf_get_caps	; 10h
apm_disp_end:

;
; APM worker routine. Function code in AL; it is assumed that AL >= 4.
; Caller must preserve BP.
;
apm_worker	proc	near

		sti			; TODO ?? necessary ??

		push	ax		; check if function is supported...
		xor	ah, ah
		sub	al, 4
		mov	bp, ax
		shl	bp, 1
		cmp	al, (apm_disp_end - apm_disp) / 2
		pop	ax
		mov	ah, 53h		; put back APM function
		jae	apmw_bad_func	; validate function range

		jmp	apm_disp[bp]	; and dispatch

apmf_disconnect:			; function 04h
		jmp	apmw_success

apmf_idle:				; function 05h
                ;
                ; Windows 3.1 POWER.DRV in Standard mode calls into APM
                ; with CPL=3. If that happens, the HLT instruction will fault
                ; and Windows will crash. To prevent that, we check the CPL
                ; and do nothing (better than crashing).
                ;
                push    cs
                pop     ax
                test    ax, 3           ; CPL > 0?
                jnz     apmw_success
		sti
		hlt
		jmp	apmw_success

apmf_busy:				; function 06h
;		jmp	apmw_success

apmf_set_state:				; function 07h
;		jmp	apmw_success

apmf_enable:				; function 08h
		jmp	apmw_success

apmf_restore:				; function 09h
;		jmp	apmw_success

apmf_get_status:			; function 0Ah
		jmp	apmw_bad_func

apmf_get_event:				; function 0Bh
		mov	ah, 80h
		jmp	apmw_failure

apmf_pwr_state:				; function 0Ch

apmf_dev_pm:				; function 0Dh
		jmp	apmw_bad_func

apmf_version:				; function 0Eh
		mov	ax, 0102h
		jmp	apmw_success

apmf_engage:				; function 0Fh
		; TODO do something?
		jmp	apmw_success

apmf_get_caps:				; function 10h
		mov	bl, 0		; no batteries
		mov	cx, 0		; no special caps
		jmp	apmw_success

apmw_success:
		clc			; successful return
		ret

apmw_bad_func:
		mov	ah, 09h		; unrecognized device ID - generic

apmw_failure:
		stc			; error for unsupported functions
		ret

apm_worker	endp


;; 16-bit protected mode APM entry point

;; According to the APM spec, only CS (16-bit code selector) is defined.
;; The data selector can be derived from it.

apm_pm16_entry:

		mov	ah, 2		; mark as originating in 16-bit PM

					; fall through

apm_pm16_entry_from_32:

		push	ds		; save registers
		push	bp

		push	cs
		pop	bp
		add	bp, 8		; calculate data selector
		mov	ds, bp		; load data segment

		call	apm_worker	; call APM handler

		pop	bp
		pop	ds		; restore registers

		retf			; return to caller - 16-bit return
					; even to 32-bit thunk!

_TEXT		ends


if VBOX_BIOS_CPU ge 80386

.386

BIOS32		segment	public 'CODE' use32

public		apm_pm32_entry

;; 32-bit protected mode APM entry point and thunk

;; According to the APM spec, only CS (32-bit) is defined. 16-bit code
;; selector and the data selector can be derived from it.

;; WARNING: To simplify matters, we use 16-bit far return to go from 32-bit
;; code to 16-bit and back. As a consequence, the 32-bit APM code must lie
;; below 64K boundary in the 32-bit APM code segment.

apm_pm32_entry:

		push	ebp		; ebp is not used by APM

		mov	bp, cs		; return address for 16-bit code
		push	bp
		mov	ebp, apm_pm32_back
		push	bp		; Note: 16:16 address!

		push	cs
		pop	ebp
		add	ebp, 8		; calculate 16-bit code selector
		push	bp		; push 16-bit code selector

		mov	ebp, apm_pm16_entry_from_32
		push	bp		; push 16-bit offset

		mov	ah, 3		; mark as originating in 32-bit PM

		db	66h		; force a 16-bit return
		retf			; off to 16-bit code...

apm_pm32_back:				; return here from 16-bit code

		pop	ebp		; restore scratch register
		retf

BIOS32		ends

endif		; 32-bit code

		end