summaryrefslogtreecommitdiffstats
path: root/sys/i386/apm/apm_setup.s
blob: 0f7fb5ed1300333f8da6d9877e430e21e7c7f456 (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
/*
 * Copyright (C) 1994 by HOSOKAWA, Tatsumi <hosokawa@jp.FreeBSD.org>
 * Copyright (C) 1997 by Poul-Henning Kamp <phk@FreeBSD.org>
 *
 * This software may be used, modified, copied, distributed, and sold,
 * 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)
 *
 *	$Id: apm_setup.s,v 1.12 1997/11/04 18:12:45 nate Exp $
 */

#include "apm.h"
  
#if NAPM > 0

#define ASSEMBLER
#include "assym.s"                    /* system definitions */
#include <machine/asmacros.h>         /* miscellaneous asm macros */
#include <machine/apm_bios.h>
#include <machine/apm_segments.h>
#define PADDR(addr)        addr-KERNBASE
  
	.file	"apm_setup.s"

	.data
_apm_init_image:
	.globl	_apm_init_image

1:
#include "i386/apm/apm_init/apm_init.inc"
2:

_apm_init_image_size:
	.globl	_apm_init_image_size
	.long	2b - 1b

_apm_version:
	.globl	_apm_version
	.long	0

_apm_cs_entry:
	.globl	_apm_cs_entry
	.long	0

_apm_cs16_base:
	.globl	_apm_cs16_base
	.word	0

_apm_cs32_base:
	.globl	_apm_cs32_base
	.word	0

_apm_ds_base:
	.globl	_apm_ds_base
	.word	0

_apm_cs32_limit:
	.globl	_apm_cs32_limit
	.word	0

_apm_cs16_limit:
	.globl	_apm_cs16_limit
	.word	0

_apm_ds_limit:
	.globl	_apm_ds_limit
	.word	0

_apm_flags:
	.globl	_apm_flags
	.word	0
	.globl  _apm_current_gdt_pdesc          /* current GDT pseudo desc. */
_apm_current_gdt_pdesc:
	.word   0, 0, 0

	.globl  _bootstrap_gdt
_bootstrap_gdt:
	.space  SIZEOF_GDT*BOOTSTRAP_GDT_NUM 

	.text
_apm_setup:
	.globl	_apm_setup

	/*
	 * Setup APM BIOS:
	 *
	 * APM BIOS initialization should be done from real mode or V86 mode.
	 *
	 * (by HOSOKAWA, Tatsumi <hosokawa@jp.FreeBSD.org>)
	 */

	/*
	 * Don't trust the value of %fs and %gs (some AT-compatible BIOS 
	 * implementations leave junk values in these segment registers
	 * on bootstrap)
	 */
	xorl	%eax, %eax	/* null selector */
	movw	%ax, %fs
	movw	%ax, %gs

	/* 
         * Copy APM initializer under 1MB boundary:
	 *
	 * APM initializer program must switch the CPU to real mode.
	 * But FreeBSD kernel runs above 1MB boundary. So we must 
	 * copy the initializer code to conventional memory.
	 */
	movl	PADDR(_apm_init_image_size), %ecx	/* size */
	lea	PADDR(_apm_init_image), %esi		/* source */
	movl	$ APM_OURADDR, %edi			/* destination */
	cld
	rep
	movsb

	/* get GDT base */
	sgdt	PADDR(_apm_current_gdt_pdesc)

	/* copy GDT to _bootstrap_gdt */
	xorl	%ecx, %ecx
	movw	PADDR(_apm_current_gdt_pdesc), %cx
	movl	PADDR(_apm_current_gdt_pdesc + 2), %esi
	lea	PADDR(_bootstrap_gdt), %edi
	cld
	rep
	movsb

	/* setup GDT pseudo descriptor */
	movw	$(SIZEOF_GDT*BOOTSTRAP_GDT_NUM), %ax
	movw	%ax, PADDR(_apm_current_gdt_pdesc)
	leal	PADDR(_bootstrap_gdt), %eax
	movl	%eax, PADDR(_apm_current_gdt_pdesc + 2)

	/* load new GDTR */
	lgdt	PADDR(_apm_current_gdt_pdesc)

	/* setup GDT for APM initializer */
	lea	PADDR(_bootstrap_gdt), %ecx
	movl	$(APM_OURADDR), %eax	/* use %ax for 15..0 */
	movl	%eax, %ebx
	shrl	$16, %ebx		/* use %bl for 23..16 */
					/* use %bh for 31..24 */
#define APM_SETUP_GDT(index, attrib) \
	movl	$(index), %si ; \
	lea	0(%ecx,%esi,8), %edx ; \
	movw	$0xffff, (%edx) ; \
	movw	%ax, 2(%edx) ; \
	movb	%bl, 4(%edx) ; \
	movw	$(attrib), 5(%edx) ; \
	movb	%bh, 7(%edx)

	APM_SETUP_GDT(APM_INIT_CS_INDEX  , CS32_ATTRIB)
	APM_SETUP_GDT(APM_INIT_DS_INDEX  , DS32_ATTRIB)
	APM_SETUP_GDT(APM_INIT_CS16_INDEX, CS16_ATTRIB)
	APM_SETUP_GDT(APM_INIT_DS16_INDEX, DS16_ATTRIB)

	/*
	 * Call the initializer:
	 *
	 * direct intersegment call to conventional memory code
	 */
	.byte	0x9a		/* actually, lcall $APM_INIT_CS_SEL, $0 */
	.long	0
	.word	APM_INIT_CS_SEL

	movl	%eax, PADDR(_apm_version)
	movl	%ebx, PADDR(_apm_cs_entry)
	movw	%cx, PADDR(_apm_cs16_base)
	shrl	$16, %ecx
	movw	%cx, PADDR(_apm_cs32_base)
	movw	%dx, PADDR(_apm_ds_base)
	movw	%si, PADDR(_apm_cs32_limit)
	shrl	$16, %esi
	movw	%si, PADDR(_apm_ds_limit)
	movw	%di, PADDR(_apm_flags)

	ret

.text
	.align 2
	.globl	_apm_bios_call
_apm_bios_call:
	pushl	%ebp
	movl	8(%esp),%ebp
	pushl	%esi
	pushl	%edi
	pushl	%ebx
	movl	20(%ebp),%edi
	movl	16(%ebp),%esi
	movl	12(%ebp),%edx
	movl	8(%ebp),%ecx
	movl	4(%ebp),%ebx
	movl	0(%ebp),%eax
	pushl	%ebp
	lcall	_apm_addr
	popl	%ebp
	movl	%eax,0(%ebp)
	jc	1f
	xorl	%eax,%eax
	jz	2f
1:	movl	$1, %eax
2:	movl	%ebx,4(%ebp)
	movl	%ecx,8(%ebp)
	movl	%edx,12(%ebp)
	movl	%esi,16(%ebp)
	movl	%edi,20(%ebp)
	popl	%ebx
	popl	%edi
	popl	%esi
	popl	%ebp
	ret
#endif NAPM > 0
OpenPOWER on IntegriCloud