17fcc78ba8547bc9d8b70c39daf29cc9c001f32c
[people/xl0/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 /* Access to variables in .data16 and .text16 */
19 extern char *data16;
20 extern char *text16;
21
22 #define __data16( variable )                                            \
23         _data16_ ## variable __asm__ ( #variable )                      \
24         __attribute__ (( section ( ".data16" ) ))
25
26 #define __text16( variable )                                            \
27         _text16_ ## variable __asm__ ( #variable )                      \
28         __attribute__ (( section ( ".text16.data" ) ))
29
30 #define __use_data16( variable )                                        \
31         ( * ( ( typeof ( _data16_ ## variable ) * )                     \
32               & ( data16 [ ( size_t ) & ( _data16_ ## variable ) ] ) ) )
33
34 #define __use_text16( variable )                                        \
35         ( * ( ( typeof ( _text16_ ## variable ) * )                     \
36               & ( text16 [ ( size_t ) & ( _text16_ ## variable ) ] ) ) )
37
38 #define __from_data16( variable )                                       \
39         ( * ( ( typeof ( variable ) * )                                 \
40               ( ( ( void * ) &(variable) ) - ( ( void * ) data16 ) ) ) )
41
42 #define __from_text16( variable )                                       \
43         ( * ( ( typeof ( variable ) * )                                 \
44               ( ( ( void * ) &(variable) ) - ( ( void * ) text16 ) ) ) )
45
46 /* Variables in librm.S, present in the normal data segment */
47 extern uint16_t rm_sp;
48 extern uint16_t rm_ss;
49 extern uint32_t pm_esp;
50 extern uint16_t __data16 ( rm_cs );
51 #define rm_cs __use_data16 ( rm_cs )
52 extern uint16_t __text16 ( rm_ds );
53 #define rm_ds __use_text16 ( rm_ds )
54
55 /* Functions that librm expects to be able to link to.  Included here
56  * so that the compiler will catch prototype mismatches.
57  */
58 extern void gateA20_set ( void );
59
60 /*
61  * librm_mgmt: functions for manipulating base memory and executing
62  * real-mode code.
63  *
64  * Full API documentation for these functions is in realmode.h.
65  *
66  */
67
68 /* Macro for obtaining a physical address from a segment:offset pair. */
69 #define VIRTUAL(x,y) ( phys_to_virt ( ( ( x ) << 4 ) + ( y ) ) )
70
71 /* Copy to/from base memory */
72 static inline __attribute__ (( always_inline )) void
73 copy_to_real_librm ( unsigned int dest_seg, unsigned int dest_off,
74                      void *src, size_t n ) {
75         memcpy ( VIRTUAL ( dest_seg, dest_off ), src, n );
76 }
77 static inline __attribute__ (( always_inline )) void
78 copy_from_real_librm ( void *dest, unsigned int src_seg,
79                        unsigned int src_off, size_t n ) {
80         memcpy ( dest, VIRTUAL ( src_seg, src_off ), n );
81 }
82 #define put_real_librm( var, dest_seg, dest_off )                             \
83         do {                                                                  \
84                 * ( ( typeof(var) * ) VIRTUAL ( dest_seg, dest_off ) ) = var; \
85         } while ( 0 )
86 #define get_real_librm( var, src_seg, src_off )                               \
87         do {                                                                  \
88                 var = * ( ( typeof(var) * ) VIRTUAL ( src_seg, src_off ) ); \
89         } while ( 0 )
90 #define copy_to_real copy_to_real_librm
91 #define copy_from_real copy_from_real_librm
92 #define put_real put_real_librm
93 #define get_real get_real_librm
94
95 /**
96  * A pointer to a user buffer
97  *
98  * Even though we could just use a void *, we use an intptr_t so that
99  * attempts to use normal pointers show up as compiler warnings.  Such
100  * code is actually valid for librm, but not for libkir (i.e. under
101  * KEEP_IT_REAL), so it's good to have the warnings even under librm.
102  */
103 typedef intptr_t userptr_t;
104
105 /**
106  * Copy data to user buffer
107  *
108  * @v buffer    User buffer
109  * @v offset    Offset within user buffer
110  * @v src       Source
111  * @v len       Length
112  */
113 static inline __attribute__ (( always_inline )) void
114 copy_to_user ( userptr_t buffer, off_t offset, const void *src, size_t len ) {
115         memcpy ( ( void * ) buffer + offset, src, len );
116 }
117
118 /**
119  * Copy data from user buffer
120  *
121  * @v dest      Destination
122  * @v buffer    User buffer
123  * @v offset    Offset within user buffer
124  * @v len       Length
125  */
126 static inline __attribute__ (( always_inline )) void
127 copy_from_user ( void *dest, userptr_t buffer, off_t offset, size_t len ) {
128         memcpy ( dest, ( void * ) buffer + offset, len );
129 }
130
131 /**
132  * Convert virtual address to user buffer
133  *
134  * @v virtual   Virtual address
135  * @ret buffer  User buffer
136  *
137  * This constructs a user buffer from an ordinary pointer.  Use it
138  * when you need to pass a pointer to an internal buffer to a function
139  * that expects a @c userptr_t.
140  */
141 static inline __attribute__ (( always_inline )) userptr_t
142 virt_to_user ( void * virtual ) {
143         return ( ( intptr_t ) virtual );
144 }
145
146 /**
147  * Convert segment:offset address to user buffer
148  *
149  * @v segment   Real-mode segment
150  * @v offset    Real-mode offset
151  * @ret buffer  User buffer
152  */
153 static inline __attribute__ (( always_inline )) userptr_t
154 real_to_user ( unsigned int segment, unsigned int offset ) {
155         return virt_to_user ( VIRTUAL ( segment, offset ) );
156 }
157
158 /* Copy to/from real-mode stack */
159 extern uint16_t copy_to_rm_stack ( void *data, size_t size );
160 extern void remove_from_rm_stack ( void *data, size_t size );
161
162 /* Place/remove parameter on real-mode stack in a way that's
163  * compatible with libkir
164  */
165 #define BASEMEM_PARAMETER_INIT_LIBRM( param ) \
166         copy_to_rm_stack ( & ( param ), sizeof ( param ) )
167 #define BASEMEM_PARAMETER_DONE_LIBRM( param ) \
168         remove_from_rm_stack ( & ( param ), sizeof ( param ) )
169 #define BASEMEM_PARAMETER_INIT BASEMEM_PARAMETER_INIT_LIBRM
170 #define BASEMEM_PARAMETER_DONE BASEMEM_PARAMETER_DONE_LIBRM
171
172 /* REAL_FRAGMENT: Declare and define a real-mode code fragment in .text16 */
173 #define REAL_FRAGMENT( name, asm_code_str )                             \
174         extern void name ( void );                                      \
175         __asm__ __volatile__ (                                          \
176                 ".section \".text16\", \"ax\", @progbits\n\t"           \
177                 ".code16\n\t"                                           \
178                 ".arch i386\n\t"                                        \
179                 #name ":\n\t"                                           \
180                 asm_code_str "\n\t"                                     \
181                 "ret\n\t"                                               \
182                 ".size " #name ", . - " #name "\n\t"                    \
183                 ".code32\n\t"                                           \
184                 ".previous\n\t"                                         \
185                 : :                                                     \
186         )
187 #define FRAGMENT_SIZE( fragment ) ( (size_t) fragment ## _size )
188
189 /* REAL_CALL: call a real-mode routine via librm */
190 #define OUT_CONSTRAINTS(...) __VA_ARGS__
191 #define IN_CONSTRAINTS(...) __VA_ARGS__
192 #define CLOBBER(...) __VA_ARGS__
193 #define REAL_CALL( routine, num_out_constraints, out_constraints,       \
194                    in_constraints, clobber )                            \
195         do {                                                            \
196                 __asm__ __volatile__ (                                  \
197                                       "pushl $" #routine "\n\t"         \
198                                       "call real_call\n\t"              \
199                                       "addl $4, %%esp\n\t"              \
200                                       : out_constraints                 \
201                                       : in_constraints                  \
202                                       : clobber                         \
203                                       );                                \
204         } while ( 0 )
205
206 /* REAL_EXEC: combine RM_FRAGMENT and REAL_CALL into one handy unit */
207 #define PASSTHRU(...) __VA_ARGS__
208 #define REAL_EXEC( name, asm_code_str, num_out_constraints, out_constraints, \
209                    in_constraints, clobber )                                 \
210         do {                                                                 \
211                 REAL_FRAGMENT ( name, asm_code_str );                        \
212                                                                              \
213                 REAL_CALL ( name, num_out_constraints,                       \
214                             PASSTHRU ( out_constraints ),                    \
215                             PASSTHRU ( in_constraints ),                     \
216                             PASSTHRU ( clobber ) );                          \
217         } while ( 0 )
218
219 #endif /* ASSEMBLY */
220
221 #endif /* LIBRM_H */