2edc1096813a6b67d894fed47369be3ea0b9f6da
[people/pcmattman/gpxe.git] / src / arch / i386 / include / librm.h
1 #ifndef LIBRM_H
2 #define LIBRM_H
3
4 /* Drag in protected-mode segment selector values */
5 #include "virtaddr.h"
6 #include "realmode.h"
7
8 #ifndef ASSEMBLY
9
10 #include "stddef.h"
11 #include "string.h"
12
13 /*
14  * Data structures and type definitions
15  *
16  */
17
18 /* Real-mode call parameter block, as passed to real_call */
19 struct real_call_params {
20         struct i386_seg_regs;
21         struct i386_regs;
22         segoff_t rm_code;
23         segoff_t reserved;
24 } PACKED;
25
26 /* Current location of librm in base memory */
27 extern char *installed_librm;
28
29 /* Start and size of our source copy of librm (i.e. the one that we
30  * can install by copying it to base memory and setting
31  * installed_librm)
32  */
33 extern char librm[];
34 extern size_t _librm_size[];
35
36 /* Linker symbols for offsets within librm.  Other symbols should
37  * almost certainly not be referred to from C code.
38  */
39 extern void (*_real_to_prot[]) ( void );
40 extern void (*_prot_to_real[]) ( void );
41 extern void (*_prot_call[]) ( void );
42 extern void (*_real_call[]) ( void );
43 extern uint32_t _librm_base[];
44 extern segoff_t _rm_stack[];
45 extern uint32_t _pm_stack[];
46 extern char _librm_ref_count[];
47
48 /* Symbols within current installation of librm */
49 #define LIBRM_VAR( sym ) \
50         ( * ( ( typeof ( * _ ## sym ) * ) \
51               & ( installed_librm [ (int) _ ## sym ] ) ) )
52 #define LIBRM_FN( sym ) \
53          ( ( typeof ( * _ ## sym ) ) \
54               & ( installed_librm [ (int) _ ## sym ] ) )
55 #define LIBRM_CONSTANT( sym ) \
56         ( ( typeof ( * _ ## sym ) ) ( _ ## sym ) )
57 #define inst_real_to_prot       LIBRM_FN ( real_to_prot )
58 #define inst_prot_to_real       LIBRM_FN ( prot_to_real )
59 #define inst_prot_call          LIBRM_FN ( prot_call )
60 #define inst_real_call          LIBRM_FN ( real_call )
61 #define inst_librm_base         LIBRM_VAR ( librm_base )
62 #define inst_rm_stack           LIBRM_VAR ( rm_stack )
63 #define inst_pm_stack           LIBRM_VAR ( pm_stack )
64 #define inst_librm_ref_count    LIBRM_VAR ( librm_ref_count )
65 #define librm_size              LIBRM_CONSTANT ( librm_size )
66
67 /* Symbols within local (uninstalled) copy of librm */
68 extern uint32_t librm_base;
69
70 /* Functions that librm expects to be able to link to.  Included here
71  * so that the compiler will catch prototype mismatches.
72  */
73 extern void _phys_to_virt ( void );
74 extern void _virt_to_phys ( void );
75 extern void gateA20_set ( void );
76
77 /*
78  * librm_mgmt: functions for manipulating base memory and executing
79  * real-mode code.
80  *
81  * Full API documentation for these functions is in realmode.h.
82  *
83  */
84
85 /* Macro for obtaining a physical address from a segment:offset pair. */
86 #define VIRTUAL(x,y) ( phys_to_virt ( ( ( x ) << 4 ) + ( y ) ) )
87
88 /* Copy to/from base memory */
89 static inline void copy_to_real_librm ( uint16_t dest_seg, uint16_t dest_off,
90                                         void *src, size_t n ) {
91         memcpy ( VIRTUAL ( dest_seg, dest_off ), src, n );
92 }
93 static inline void copy_from_real_librm ( void *dest,
94                                           uint16_t src_seg, uint16_t src_off,
95                                           size_t n ) {
96         memcpy ( dest, VIRTUAL ( src_seg, src_off ), n );
97 }
98 #define put_real_librm( var, dest_seg, dest_off )                             \
99         do {                                                                  \
100                 * ( ( typeof(var) * ) VIRTUAL ( dest_seg, dest_off ) ) = var; \
101         } while ( 0 )
102 #define get_real_librm( var, src_seg, src_off )                               \
103         do {                                                                  \
104                 var = * ( ( typeof(var) * ) VIRTUAL ( src_seg, src_off ) ); \
105         } while ( 0 )
106 #define copy_to_real copy_to_real_librm
107 #define copy_from_real copy_from_real_librm
108 #define put_real put_real_librm
109 #define get_real get_real_librm
110
111 /* Copy to/from real-mode stack */
112 extern uint16_t copy_to_rm_stack ( void *data, size_t size );
113 extern void remove_from_rm_stack ( void *data, size_t size );
114
115 /* Place/remove parameter on real-mode stack in a way that's
116  * compatible with libkir
117  */
118 #define BASEMEM_PARAMETER_INIT_LIBRM( param ) \
119         copy_to_rm_stack ( & ( param ), sizeof ( param ) )
120 #define BASEMEM_PARAMETER_DONE_LIBRM( param ) \
121         remove_from_rm_stack ( & ( param ), sizeof ( param ) )
122 #define BASEMEM_PARAMETER_INIT BASEMEM_PARAMETER_INIT_LIBRM
123 #define BASEMEM_PARAMETER_DONE BASEMEM_PARAMETER_DONE_LIBRM
124
125 /* REAL_FRAGMENT: Declare and define a real-mode code fragment in .text16 */
126 #define REAL_FRAGMENT( name, asm_code_str )                             \
127         extern void name ( void );                                      \
128         extern char name ## _size[];                                    \
129         __asm__ __volatile__ (                                          \
130                 ".section \".text16\"\n\t"                              \
131                 ".code16\n\t"                                           \
132                 ".arch i386\n\t"                                        \
133                 #name ":\n\t"                                           \
134                 asm_code_str "\n\t"                                     \
135                 "lret\n\t"                                              \
136                 #name "_end:\n\t"                                       \
137                 ".equ " #name "_size, " #name "_end - " #name "\n\t"    \
138                 ".code32\n\t"                                           \
139                 ".previous\n\t"                                         \
140                 : :                                                     \
141         )
142 #define FRAGMENT_SIZE( fragment ) ( (size_t) fragment ## _size )
143
144 /* REAL_CALL: call a real-mode routine via librm */
145 #define OUT_CONSTRAINTS(...) __VA_ARGS__
146 #define IN_CONSTRAINTS(...) "m" ( __routine ), ## __VA_ARGS__
147 #define CLOBBER(...) __VA_ARGS__
148 #define REAL_CALL( routine, num_out_constraints, out_constraints,            \
149                    in_constraints, clobber )                                 \
150         do {                                                                 \
151                 segoff_t __routine = routine;                                \
152                 __asm__ __volatile__ (                                       \
153                                       "pushl %" #num_out_constraints "\n\t"  \
154                                       "call 1f\n\t"                          \
155                                       "jmp 2f\n\t"                           \
156                                       "\n1:\n\t"                             \
157                                       "pushl installed_librm\n\t"            \
158                                       "addl $_real_call, 0(%%esp)\n\t"       \
159                                       "ret\n\t"                              \
160                                       "\n2:\n\t"                             \
161                                       "addl $4, %%esp\n\t"                   \
162                                       : out_constraints                      \
163                                       : in_constraints                       \
164                                       : clobber                              \
165                                       );                                     \
166         } while ( 0 )
167
168 /* REAL_EXEC: combine RM_FRAGMENT and REAL_CALL into one handy unit */
169 #define PASSTHRU(...) __VA_ARGS__
170 #define REAL_EXEC( name, asm_code_str, num_out_constraints, out_constraints, \
171                    in_constraints, clobber )                                 \
172         do {                                                                 \
173                 segoff_t fragment;                                           \
174                                                                              \
175                 REAL_FRAGMENT ( name, asm_code_str );                        \
176                                                                              \
177                 fragment.segment = inst_rm_stack.segment;                    \
178                 fragment.offset =                                            \
179                         copy_to_rm_stack ( name, FRAGMENT_SIZE ( name ) );   \
180                                                                              \
181                 REAL_CALL ( fragment, num_out_constraints,                   \
182                             PASSTHRU ( out_constraints ),                    \
183                             PASSTHRU ( in_constraints ),                     \
184                             PASSTHRU ( clobber ) );                          \
185                                                                              \
186                 remove_from_rm_stack ( NULL, FRAGMENT_SIZE ( name ) );       \
187         } while ( 0 )
188
189 #endif /* ASSEMBLY */
190
191 #endif /* LIBRM_H */