summaryrefslogtreecommitdiffstats
path: root/src/arch/i386/include/librm.h
blob: 1b82a982868db0ab414dc529924f97d049be4c22 (plain) (blame)
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
#ifndef LIBRM_H
#define LIBRM_H

/* Drag in protected-mode segment selector values */
#include "virtaddr.h"
#include "realmode.h"

#ifndef ASSEMBLY

#include "stddef.h"
#include "string.h"

/*
 * Data structures and type definitions
 *
 */

/* Real-mode call parameter block, as passed to real_call */
struct real_call_params {
	struct i386_seg_regs segs;
	struct i386_regs regs;
	segoff_t rm_code;
	segoff_t reserved;
} PACKED;

/* Current location of librm in base memory */
extern char *installed_librm;

/* Start and size of our source copy of librm (i.e. the one that we
 * can install by copying it to base memory and setting
 * installed_librm)
 */
extern char librm[];
extern size_t _librm_size[];

/* Linker symbols for offsets within librm.  Other symbols should
 * almost certainly not be referred to from C code.
 */
extern void (*_real_to_prot[]) ( void );
extern void (*_prot_to_real[]) ( void );
extern void (*_prot_call[]) ( void );
extern void (*_real_call[]) ( void );
extern uint32_t _librm_base[];
extern segoff_t _rm_stack[];
extern uint32_t _pm_stack[];
extern char _librm_ref_count[];

/* Symbols within current installation of librm */
#define LIBRM_VAR( sym ) \
	( * ( ( typeof ( * _ ## sym ) * ) \
	      & ( installed_librm [ (int) _ ## sym ] ) ) )
#define LIBRM_FN( sym ) \
	 ( ( typeof ( * _ ## sym ) ) \
	      & ( installed_librm [ (int) _ ## sym ] ) )
#define LIBRM_CONSTANT( sym ) \
	( ( typeof ( * _ ## sym ) ) ( _ ## sym ) )
#define inst_real_to_prot	LIBRM_FN ( real_to_prot )
#define inst_prot_to_real	LIBRM_FN ( prot_to_real )
#define inst_prot_call		LIBRM_FN ( prot_call )
#define inst_real_call		LIBRM_FN ( real_call )
#define inst_librm_base		LIBRM_VAR ( librm_base )
#define inst_rm_stack		LIBRM_VAR ( rm_stack )
#define inst_pm_stack		LIBRM_VAR ( pm_stack )
#define inst_librm_ref_count	LIBRM_VAR ( librm_ref_count )
#define librm_size		LIBRM_CONSTANT ( librm_size )

/* Symbols within local (uninstalled) copy of librm */
extern uint32_t librm_base;

/* Functions that librm expects to be able to link to.  Included here
 * so that the compiler will catch prototype mismatches.
 */
extern void _phys_to_virt ( void );
extern void _virt_to_phys ( void );
extern void gateA20_set ( void );

/*
 * librm_mgmt: functions for manipulating base memory and executing
 * real-mode code.
 *
 * Full API documentation for these functions is in realmode.h.
 *
 */

/* Macro for obtaining a physical address from a segment:offset pair. */
#define VIRTUAL(x,y) ( phys_to_virt ( ( ( x ) << 4 ) + ( y ) ) )

/* Copy to/from base memory */
static inline void copy_to_real_librm ( uint16_t dest_seg, uint16_t dest_off,
					void *src, size_t n ) {
	memcpy ( VIRTUAL ( dest_seg, dest_off ), src, n );
}
static inline void copy_from_real_librm ( void *dest,
					  uint16_t src_seg, uint16_t src_off,
					  size_t n ) {
	memcpy ( dest, VIRTUAL ( src_seg, src_off ), n );
}
#define put_real_librm( var, dest_seg, dest_off )			      \
	do {								      \
		* ( ( typeof(var) * ) VIRTUAL ( dest_seg, dest_off ) ) = var; \
	} while ( 0 )
#define get_real_librm( var, src_seg, src_off )				      \
	do {								      \
		var = * ( ( typeof(var) * ) VIRTUAL ( src_seg, src_off ) ); \
	} while ( 0 )
#define copy_to_real copy_to_real_librm
#define copy_from_real copy_from_real_librm
#define put_real put_real_librm
#define get_real get_real_librm

/* Copy to/from real-mode stack */
extern uint16_t copy_to_rm_stack ( void *data, size_t size );
extern void remove_from_rm_stack ( void *data, size_t size );

/* Place/remove parameter on real-mode stack in a way that's
 * compatible with libkir
 */
#define BASEMEM_PARAMETER_INIT_LIBRM( param ) \
	copy_to_rm_stack ( & ( param ), sizeof ( param ) )
#define BASEMEM_PARAMETER_DONE_LIBRM( param ) \
	remove_from_rm_stack ( & ( param ), sizeof ( param ) )
#define BASEMEM_PARAMETER_INIT BASEMEM_PARAMETER_INIT_LIBRM
#define BASEMEM_PARAMETER_DONE BASEMEM_PARAMETER_DONE_LIBRM

/* REAL_FRAGMENT: Declare and define a real-mode code fragment in .text16 */
#define	REAL_FRAGMENT( name, asm_code_str )				\
	extern void name ( void );					\
	extern char name ## _size[];					\
	__asm__ __volatile__ (						\
		".section \".text16\"\n\t"				\
		".code16\n\t"						\
		".arch i386\n\t"					\
		#name ":\n\t"						\
		asm_code_str "\n\t"					\
		"lret\n\t"						\
		#name "_end:\n\t"					\
		".equ " #name "_size, " #name "_end - " #name "\n\t"	\
		".code32\n\t"						\
		".previous\n\t"						\
		: :							\
	)
#define FRAGMENT_SIZE( fragment ) ( (size_t) fragment ## _size )

/* REAL_CALL: call a real-mode routine via librm */
#define OUT_CONSTRAINTS(...) __VA_ARGS__
#define IN_CONSTRAINTS(...) "m" ( __routine ), ## __VA_ARGS__
#define CLOBBER(...) __VA_ARGS__
#define REAL_CALL( routine, num_out_constraints, out_constraints,	     \
		   in_constraints, clobber )				     \
	do {								     \
		segoff_t __routine = routine;				     \
		__asm__ __volatile__ (					     \
				      "pushl %" #num_out_constraints "\n\t"  \
				      "call 1f\n\t"			     \
				      "jmp 2f\n\t"			     \
				      "\n1:\n\t"			     \
				      "pushl installed_librm\n\t"	     \
				      "addl $_real_call, 0(%%esp)\n\t"	     \
				      "ret\n\t"				     \
				      "\n2:\n\t"			     \
				      "addl $4, %%esp\n\t"		     \
				      : out_constraints			     \
				      : in_constraints			     \
				      : clobber				     \
				      );				     \
	} while ( 0 )

/* REAL_EXEC: combine RM_FRAGMENT and REAL_CALL into one handy unit */
#define PASSTHRU(...) __VA_ARGS__
#define REAL_EXEC( name, asm_code_str, num_out_constraints, out_constraints, \
		   in_constraints, clobber )				     \
	do {								     \
		segoff_t fragment;					     \
									     \
		REAL_FRAGMENT ( name, asm_code_str );			     \
									     \
		fragment.segment = inst_rm_stack.segment;		     \
		fragment.offset =					     \
			copy_to_rm_stack ( name, FRAGMENT_SIZE ( name ) );   \
									     \
		REAL_CALL ( fragment, num_out_constraints,		     \
			    PASSTHRU ( out_constraints ),		     \
			    PASSTHRU ( in_constraints ),		     \
			    PASSTHRU ( clobber ) );			     \
									     \
		remove_from_rm_stack ( NULL, FRAGMENT_SIZE ( name ) );	     \
	} while ( 0 )

#endif /* ASSEMBLY */

#endif /* LIBRM_H */