Add strlen_user() (will be needed for PXE API extensions)
[people/xl0/gpxe-arm.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         __attribute__ (( section ( ".data16" ) ))                       \
24         _data16_ ## variable __asm__ ( #variable )
25
26 #define __data16_array( variable, array )                               \
27         __attribute__ (( section ( ".data16" ) ))                       \
28         _data16_ ## variable array __asm__ ( #variable )
29
30 #define __text16( variable )                                            \
31         __attribute__ (( section ( ".text16.data" ) ))                  \
32         _text16_ ## variable __asm__ ( #variable )
33
34 #define __text16_array( variable, array )                               \
35         __attribute__ (( section ( ".text16.data" ) ))                  \
36         _text16_ ## variable array __asm__ ( #variable )
37
38 #define __use_data16( variable )                                        \
39         ( * ( ( typeof ( _data16_ ## variable ) * )                     \
40               & ( data16 [ ( size_t ) & ( _data16_ ## variable ) ] ) ) )
41
42 #define __use_text16( variable )                                        \
43         ( * ( ( typeof ( _text16_ ## variable ) * )                     \
44               & ( text16 [ ( size_t ) & ( _text16_ ## variable ) ] ) ) )
45
46 #define __from_data16( variable )                                       \
47         ( * ( ( typeof ( variable ) * )                                 \
48               ( ( ( void * ) &(variable) ) - ( ( void * ) data16 ) ) ) )
49
50 #define __from_text16( variable )                                       \
51         ( * ( ( typeof ( variable ) * )                                 \
52               ( ( ( void * ) &(variable) ) - ( ( void * ) text16 ) ) ) )
53
54 /* Variables in librm.S, present in the normal data segment */
55 extern uint16_t rm_sp;
56 extern uint16_t rm_ss;
57 extern uint32_t pm_esp;
58 extern uint16_t __data16 ( rm_cs );
59 #define rm_cs __use_data16 ( rm_cs )
60 extern uint16_t __text16 ( rm_ds );
61 #define rm_ds __use_text16 ( rm_ds )
62
63 /* Functions that librm expects to be able to link to.  Included here
64  * so that the compiler will catch prototype mismatches.
65  */
66 extern void gateA20_set ( void );
67
68 /*
69  * librm_mgmt: functions for manipulating base memory and executing
70  * real-mode code.
71  *
72  * Full API documentation for these functions is in realmode.h.
73  *
74  */
75
76 /* Macro for obtaining a physical address from a segment:offset pair. */
77 #define VIRTUAL(x,y) ( phys_to_virt ( ( ( x ) << 4 ) + ( y ) ) )
78
79 /* Copy to/from base memory */
80 static inline __attribute__ (( always_inline )) void
81 copy_to_real_librm ( unsigned int dest_seg, unsigned int dest_off,
82                      void *src, size_t n ) {
83         memcpy ( VIRTUAL ( dest_seg, dest_off ), src, n );
84 }
85 static inline __attribute__ (( always_inline )) void
86 copy_from_real_librm ( void *dest, unsigned int src_seg,
87                        unsigned int src_off, size_t n ) {
88         memcpy ( dest, VIRTUAL ( src_seg, src_off ), n );
89 }
90 #define put_real_librm( var, dest_seg, dest_off )                             \
91         do {                                                                  \
92                 * ( ( typeof(var) * ) VIRTUAL ( dest_seg, dest_off ) ) = var; \
93         } while ( 0 )
94 #define get_real_librm( var, src_seg, src_off )                               \
95         do {                                                                  \
96                 var = * ( ( typeof(var) * ) VIRTUAL ( src_seg, src_off ) ); \
97         } while ( 0 )
98 #define copy_to_real copy_to_real_librm
99 #define copy_from_real copy_from_real_librm
100 #define put_real put_real_librm
101 #define get_real get_real_librm
102
103 /**
104  * A pointer to a user buffer
105  *
106  * Even though we could just use a void *, we use an intptr_t so that
107  * attempts to use normal pointers show up as compiler warnings.  Such
108  * code is actually valid for librm, but not for libkir (i.e. under
109  * KEEP_IT_REAL), so it's good to have the warnings even under librm.
110  */
111 typedef intptr_t userptr_t;
112
113 /**
114  * Add offset to user pointer
115  *
116  * @v ptr               User pointer
117  * @v offset            Offset
118  * @ret new_ptr         New pointer value
119  */
120 static inline __attribute__ (( always_inline )) userptr_t
121 userptr_add ( userptr_t ptr, off_t offset ) {
122         return ( ptr + offset );
123 }
124
125 /**
126  * Copy data to user buffer
127  *
128  * @v buffer            User buffer
129  * @v offset            Offset within user buffer
130  * @v src               Source
131  * @v len               Length
132  */
133 static inline __attribute__ (( always_inline )) void
134 copy_to_user ( userptr_t buffer, off_t offset, const void *src, size_t len ) {
135         memcpy ( ( ( void * ) buffer + offset ), src, len );
136 }
137
138 /**
139  * Copy data from user buffer
140  *
141  * @v dest              Destination
142  * @v buffer            User buffer
143  * @v offset            Offset within user buffer
144  * @v len               Length
145  */
146 static inline __attribute__ (( always_inline )) void
147 copy_from_user ( void *dest, userptr_t buffer, off_t offset, size_t len ) {
148         memcpy ( dest, ( ( void * ) buffer + offset ), len );
149 }
150
151 /**
152  * Copy data between user buffers
153  *
154  * @v dest              Destination user buffer
155  * @v dest_off          Offset within destination buffer
156  * @v src               Source user buffer
157  * @v src_off           Offset within source buffer
158  * @v len               Length
159  */
160 static inline __attribute__ (( always_inline )) void
161 memcpy_user ( userptr_t dest, off_t dest_off, userptr_t src, off_t src_off,
162               size_t len ) {
163         memcpy ( ( ( void * ) dest + dest_off ), ( ( void * ) src + src_off ),
164                  len );
165 }
166
167 /**
168  * Copy data between user buffers, allowing for overlap
169  *
170  * @v dest              Destination user buffer
171  * @v dest_off          Offset within destination buffer
172  * @v src               Source user buffer
173  * @v src_off           Offset within source buffer
174  * @v len               Length
175  */
176 static inline __attribute__ (( always_inline )) void
177 memmove_user ( userptr_t dest, off_t dest_off, userptr_t src, off_t src_off,
178                size_t len ) {
179         memmove ( ( ( void * ) dest + dest_off ), ( ( void * ) src + src_off ),
180                   len );
181 }
182
183 /**
184  * Fill user buffer with a constant byte
185  *
186  * @v buffer            User buffer
187  * @v offset            Offset within buffer
188  * @v c                 Constant byte with which to fill
189  * @v len               Length
190  */
191 static inline __attribute__ (( always_inline )) void
192 memset_user ( userptr_t buffer, off_t offset, int c, size_t len ) {
193         memset ( ( ( void * ) buffer + offset ), c, len );
194 }
195
196 /**
197  * Find length of NUL-terminated string in user buffer
198  *
199  * @v buffer            User buffer
200  * @v offset            Offset within buffer
201  * @ret len             Length of string (excluding NUL)
202  */
203 static inline __attribute__ (( always_inline )) size_t
204 strlen_user ( userptr_t buffer, off_t offset ) {
205         return strlen ( ( void * ) buffer + offset );
206 }
207
208 /**
209  * Convert virtual address to user buffer
210  *
211  * @v virtual           Virtual address
212  * @ret buffer          User buffer
213  *
214  * This constructs a user buffer from an ordinary pointer.  Use it
215  * when you need to pass a pointer to an internal buffer to a function
216  * that expects a @c userptr_t.
217  */
218 static inline __attribute__ (( always_inline )) userptr_t
219 virt_to_user ( void * virtual ) {
220         return ( ( intptr_t ) virtual );
221 }
222
223 /**
224  * Convert segment:offset address to user buffer
225  *
226  * @v segment           Real-mode segment
227  * @v offset            Real-mode offset
228  * @ret buffer          User buffer
229  */
230 static inline __attribute__ (( always_inline )) userptr_t
231 real_to_user ( unsigned int segment, unsigned int offset ) {
232         return virt_to_user ( VIRTUAL ( segment, offset ) );
233 }
234
235 /**
236  * Convert physical address to user buffer
237  *
238  * @v physical          Physical address
239  * @ret buffer          User buffer
240  */
241 static inline __attribute__ (( always_inline )) userptr_t
242 phys_to_user ( physaddr_t physical ) {
243         return virt_to_user ( phys_to_virt ( physical ) );
244 }
245
246 /**
247  * Convert user buffer to physical address
248  *
249  * @v buffer            User buffer
250  * @v offset            Offset within user buffer
251  * @ret physical        Physical address
252  */
253 static inline __attribute__ (( always_inline )) physaddr_t
254 user_to_phys ( userptr_t buffer, off_t offset ) {
255         return virt_to_phys ( ( void * ) buffer + offset );
256 }
257
258 /* Copy to/from real-mode stack */
259 extern uint16_t copy_to_rm_stack ( void *data, size_t size );
260 extern void remove_from_rm_stack ( void *data, size_t size );
261
262 /* Place/remove parameter on real-mode stack in a way that's
263  * compatible with libkir
264  */
265 #define BASEMEM_PARAMETER_INIT_LIBRM( param ) \
266         copy_to_rm_stack ( & ( param ), sizeof ( param ) )
267 #define BASEMEM_PARAMETER_DONE_LIBRM( param ) \
268         remove_from_rm_stack ( & ( param ), sizeof ( param ) )
269 #define BASEMEM_PARAMETER_INIT BASEMEM_PARAMETER_INIT_LIBRM
270 #define BASEMEM_PARAMETER_DONE BASEMEM_PARAMETER_DONE_LIBRM
271
272 /* TEXT16_CODE: declare a fragment of code that resides in .text16 */
273 #define TEXT16_CODE( asm_code_str )                     \
274         ".section \".text16\", \"ax\", @progbits\n\t"   \
275         ".code16\n\t"                                   \
276         asm_code_str "\n\t"                             \
277         ".code32\n\t"                                   \
278         ".previous\n\t"
279
280 /* REAL_CODE: declare a fragment of code that executes in real mode */
281 #define REAL_CODE( asm_code_str )                       \
282         "pushl $1f\n\t"                                 \
283         "call real_call\n\t"                            \
284         "addl $4, %%esp\n\t"                            \
285         TEXT16_CODE ( "\n1:\n\t"                        \
286                       asm_code_str                      \
287                       "\n\t"                            \
288                       "ret\n\t" )
289
290 /* PHYS_CODE: declare a fragment of code that executes in flat physical mode */
291 #define PHYS_CODE( asm_code_str )                       \
292         "call _virt_to_phys\n\t"                        \
293         asm_code_str                                    \
294         "call _phys_to_virt\n\t"
295
296 #endif /* ASSEMBLY */
297
298 #endif /* LIBRM_H */