bioscall.s revision 60803
1/*-
2 * Copyright (c) 1997 Jonathan Lemon
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: head/sys/i386/i386/bioscall.s 60803 2000-05-22 17:02:53Z obrien $
27 */
28
29/*
30 * Functions for calling x86 BIOS functions from the BSD kernel
31 */
32
33#include <machine/asmacros.h>
34
35#include "assym.s"
36
37#define data16		.byte	0x66
38
39	.data
40	ALIGN_DATA
41bioscall_frame:		.long	0
42bioscall_stack:		.long	0
43
44	.text
45/*
46 * bios32(regs, offset, segment)
47 *	struct bios_regs *regs;
48 *	u_int offset;
49 * 	u_short segment;
50 */
51ENTRY(bios32)
52	pushl	%ebp
53	movl	16(%esp),%ebp
54	mov	%bp,_bioscall_vector+4
55	movl	12(%esp),%ebp
56	movl	%ebp,_bioscall_vector
57	movl	8(%esp),%ebp
58	pushl	%ebx
59	pushl	%esi
60	pushl	%edi
61	movl	0(%ebp),%eax
62	movl	4(%ebp),%ebx
63	movl	8(%ebp),%ecx
64	movl	12(%ebp),%edx
65	movl	16(%ebp),%esi
66	movl	20(%ebp),%edi
67	pushl	%ebp
68	lcall	*_bioscall_vector
69	popl	%ebp
70	movl	%eax,0(%ebp)
71	movl	%ebx,4(%ebp)
72	movl	%ecx,8(%ebp)
73	movl	%edx,12(%ebp)
74	movl	%esi,16(%ebp)
75	movl	%edi,20(%ebp)
76	movl	$0,%eax			/* presume success */
77	jnc	1f
78	movl	$1,%eax			/* nope */
791:
80	popl	%edi
81	popl	%esi
82	popl	%ebx
83	popl	%ebp
84	ret
85
86
87/*
88 * bios16_call(regs, stack)
89 *	struct bios_regs *regs;
90 *	char *stack;
91 */
92ENTRY(bios16_call)
93	pushl	%ebp
94	movl	%esp,%ebp
95	addl	$4,%ebp			/* frame pointer */
96	movl	%ebp,bioscall_frame	/* ... save it */
97	pushl	%ebx
98	pushl	%esi
99	pushl	%edi
100/*
101 * the problem with a full 32-bit stack segment is that 16-bit code
102 * tends to do a pushf, which only pushes %sp, not %esp.  This value
103 * is then popped off (into %esp) which causes a page fault because
104 * it is the wrong address.
105 *
106 * the reverse problem happens for 16-bit stack addresses; the kernel
107 * code attempts to get the address of something on the stack, and the
108 * value returned is the address relative to %ss, not %ds.
109 *
110 * we fix this by installing a temporary stack at page 0, so the
111 * addresses are always valid in both 32 bit and 16 bit modes.
112 */
113	movl	%esp,bioscall_stack	/* save current stack location */
114	movl	8(%ebp),%esp		/* switch to page 0 stack */
115
116	movl	4(%ebp),%ebp		/* regs */
117
118	movl	0(%ebp),%eax
119	movl	4(%ebp),%ebx
120	movl	8(%ebp),%ecx
121	movl	12(%ebp),%edx
122	movl	16(%ebp),%esi
123	movl	20(%ebp),%edi
124
125	pushl	$BC32SEL
126	leal	CNAME(bios16_jmp),%ebp
127	andl	$PAGE_MASK,%ebp
128	pushl	%ebp			/* reload %cs and */
129	lret				/* ...continue below */
130	.globl	CNAME(bios16_jmp)
131CNAME(bios16_jmp):
132	data16
133	lcall	*_bioscall_vector	/* 16-bit call */
134
135	jc	1f
136	pushl	$0			/* success */
137	jmp	2f
1381:
139	pushl	$1			/* failure */
1402:
141	movl	bioscall_frame,%ebp
142
143	movl	4(%ebp),%ebp		/* regs */
144
145	movl	%eax,0(%ebp)
146	movl	%ebx,4(%ebp)
147	movl	%ecx,8(%ebp)
148	movl	%edx,12(%ebp)
149	movl	%esi,16(%ebp)
150	movl	%edi,20(%ebp)
151
152	popl	%eax			/* recover return value */
153	movl	bioscall_stack,%esp	/* return to normal stack */
154
155	popl	%edi
156	popl	%esi
157	popl	%ebx
158	popl	%ebp
159
160	movl	(%esp),%ecx
161	pushl	%ecx			/* return address */
162	movl	$KCSEL,4(%esp)
163	lret				/* reload %cs on the way out */
164