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$
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	.data
38	ALIGN_DATA
39bioscall_frame:		.long	0
40bioscall_stack:		.long	0
41
42	.text
43/*
44 * bios32(regs, offset, segment)
45 *	struct bios_regs *regs;
46 *	u_int offset;
47 * 	u_short segment;
48 */
49ENTRY(bios32)
50	pushl	%ebp
51	movl	16(%esp),%ebp
52	mov	%bp,bioscall_vector+4
53	movl	12(%esp),%ebp
54	movl	%ebp,bioscall_vector
55	movl	8(%esp),%ebp
56	pushl	%ebx
57	pushl	%esi
58	pushl	%edi
59	movl	0(%ebp),%eax
60	movl	4(%ebp),%ebx
61	movl	8(%ebp),%ecx
62	movl	12(%ebp),%edx
63	movl	16(%ebp),%esi
64	movl	20(%ebp),%edi
65	pushl	%ebp
66	lcall	*bioscall_vector
67	popl	%ebp
68	movl	%eax,0(%ebp)
69	movl	%ebx,4(%ebp)
70	movl	%ecx,8(%ebp)
71	movl	%edx,12(%ebp)
72	movl	%esi,16(%ebp)
73	movl	%edi,20(%ebp)
74	movl	$0,%eax			/* presume success */
75	jnc	1f
76	movl	$1,%eax			/* nope */
771:
78	popl	%edi
79	popl	%esi
80	popl	%ebx
81	popl	%ebp
82	ret
83
84
85/*
86 * bios16_call(regs, stack)
87 *	struct bios_regs *regs;
88 *	char *stack;
89 */
90ENTRY(bios16_call)
91	pushl	%ebp
92	movl	%esp,%ebp
93	addl	$4,%ebp			/* frame pointer */
94	movl	%ebp,bioscall_frame	/* ... save it */
95	pushl	%ebx
96	pushl	%esi
97	pushl	%edi
98/*
99 * the problem with a full 32-bit stack segment is that 16-bit code
100 * tends to do a pushf, which only pushes %sp, not %esp.  This value
101 * is then popped off (into %esp) which causes a page fault because
102 * it is the wrong address.
103 *
104 * the reverse problem happens for 16-bit stack addresses; the kernel
105 * code attempts to get the address of something on the stack, and the
106 * value returned is the address relative to %ss, not %ds.
107 *
108 * we fix this by installing a temporary stack at page 0, so the
109 * addresses are always valid in both 32 bit and 16 bit modes.
110 */
111	movl	%esp,bioscall_stack	/* save current stack location */
112	movl	8(%ebp),%esp		/* switch to page 0 stack */
113
114	movl	4(%ebp),%ebp		/* regs */
115
116	movl	0(%ebp),%eax
117	movl	4(%ebp),%ebx
118	movl	8(%ebp),%ecx
119	movl	12(%ebp),%edx
120	movl	16(%ebp),%esi
121	movl	20(%ebp),%edi
122
123	pushl	$BC32SEL
124	leal	CNAME(bios16_jmp),%ebp
125	andl	$PAGE_MASK,%ebp
126	pushl	%ebp			/* reload %cs and */
127	lret				/* ...continue below */
128	.globl	CNAME(bios16_jmp)
129CNAME(bios16_jmp):
130	lcallw	*bioscall_vector	/* 16-bit call */
131
132	jc	1f
133	pushl	$0			/* success */
134	jmp	2f
1351:
136	pushl	$1			/* failure */
1372:
138	movl	bioscall_frame,%ebp
139
140	movl	4(%ebp),%ebp		/* regs */
141
142	movl	%eax,0(%ebp)
143	movl	%ebx,4(%ebp)
144	movl	%ecx,8(%ebp)
145	movl	%edx,12(%ebp)
146	movl	%esi,16(%ebp)
147	movl	%edi,20(%ebp)
148
149	popl	%eax			/* recover return value */
150	movl	bioscall_stack,%esp	/* return to normal stack */
151
152	popl	%edi
153	popl	%esi
154	popl	%ebx
155	popl	%ebp
156
157	movl	(%esp),%ecx
158	pushl	%ecx			/* return address */
159	movl	$KCSEL,4(%esp)
160	lret				/* reload %cs on the way out */
161