|
@@ -20,10 +20,26 @@
|
20
|
20
|
#define __from_data16( variable ) variable
|
21
|
21
|
#define __from_text16( variable ) variable
|
22
|
22
|
|
|
23
|
+/* Real-mode data and code segments */
|
|
24
|
+static inline __attribute__ (( always_inline )) unsigned int _rm_cs ( void ) {
|
|
25
|
+ uint16_t cs;
|
|
26
|
+ __asm__ __volatile__ ( "movw %%cs, %w0" : "=r" ( cs ) );
|
|
27
|
+ return cs;
|
|
28
|
+}
|
|
29
|
+
|
|
30
|
+static inline __attribute__ (( always_inline )) unsigned int _rm_ds ( void ) {
|
|
31
|
+ uint16_t ds;
|
|
32
|
+ __asm__ __volatile__ ( "movw %%ds, %w0" : "=r" ( ds ) );
|
|
33
|
+ return ds;
|
|
34
|
+}
|
|
35
|
+
|
|
36
|
+#define rm_cs ( _rm_cs() )
|
|
37
|
+#define rm_ds ( _rm_ds() )
|
|
38
|
+
|
23
|
39
|
/* Copy to/from base memory */
|
24
|
40
|
|
25
|
41
|
static inline void copy_to_real_libkir ( uint16_t dest_seg, uint16_t dest_off,
|
26
|
|
- void *src, size_t n ) {
|
|
42
|
+ const void *src, size_t n ) {
|
27
|
43
|
__asm__ __volatile__ ( "movw %4, %%es\n\t"
|
28
|
44
|
"cld\n\t"
|
29
|
45
|
"rep movsb\n\t"
|
|
@@ -125,6 +141,69 @@ static inline void copy_from_real_libkir ( void *dest,
|
125
|
141
|
#define put_real put_real_kir
|
126
|
142
|
#define get_real get_real_kir
|
127
|
143
|
|
|
144
|
+/**
|
|
145
|
+ * A pointer to a user buffer
|
|
146
|
+ *
|
|
147
|
+ * This is actually a struct segoff, but encoded as a uint32_t to
|
|
148
|
+ * ensure that gcc passes it around efficiently.
|
|
149
|
+ */
|
|
150
|
+typedef uint32_t userptr_t;
|
|
151
|
+
|
|
152
|
+/**
|
|
153
|
+ * Copy data to user buffer
|
|
154
|
+ *
|
|
155
|
+ * @v buffer User buffer
|
|
156
|
+ * @v offset Offset within user buffer
|
|
157
|
+ * @v src Source
|
|
158
|
+ * @v len Length
|
|
159
|
+ */
|
|
160
|
+static inline __attribute__ (( always_inline )) void
|
|
161
|
+copy_to_user ( userptr_t buffer, off_t offset, const void *src, size_t len ) {
|
|
162
|
+ copy_to_real ( ( buffer >> 16 ), ( ( buffer & 0xffff ) + offset ),
|
|
163
|
+ src, len );
|
|
164
|
+}
|
|
165
|
+
|
|
166
|
+/**
|
|
167
|
+ * Copy data from user buffer
|
|
168
|
+ *
|
|
169
|
+ * @v dest Destination
|
|
170
|
+ * @v buffer User buffer
|
|
171
|
+ * @v offset Offset within user buffer
|
|
172
|
+ * @v len Length
|
|
173
|
+ */
|
|
174
|
+static inline __attribute__ (( always_inline )) void
|
|
175
|
+copy_from_user ( void *dest, userptr_t buffer, off_t offset, size_t len ) {
|
|
176
|
+ copy_from_real ( dest, ( buffer >> 16 ),
|
|
177
|
+ ( ( buffer & 0xffff ) + offset ), len );
|
|
178
|
+}
|
|
179
|
+
|
|
180
|
+/**
|
|
181
|
+ * Convert segment:offset address to user buffer
|
|
182
|
+ *
|
|
183
|
+ * @v segment Real-mode segment
|
|
184
|
+ * @v offset Real-mode offset
|
|
185
|
+ * @ret buffer User buffer
|
|
186
|
+ */
|
|
187
|
+static inline __attribute__ (( always_inline )) userptr_t
|
|
188
|
+real_to_user ( unsigned int segment, unsigned int offset ) {
|
|
189
|
+ return ( ( segment << 16 ) | offset );
|
|
190
|
+}
|
|
191
|
+
|
|
192
|
+/**
|
|
193
|
+ * Convert virtual address to user buffer
|
|
194
|
+ *
|
|
195
|
+ * @v virtual Virtual address
|
|
196
|
+ * @ret buffer User buffer
|
|
197
|
+ *
|
|
198
|
+ * This constructs a user buffer from an ordinary pointer. Use it
|
|
199
|
+ * when you need to pass a pointer to an internal buffer to a function
|
|
200
|
+ * that expects a @c userptr_t.
|
|
201
|
+ */
|
|
202
|
+static inline __attribute__ (( always_inline )) userptr_t
|
|
203
|
+virt_to_user ( void * virtual ) {
|
|
204
|
+ return real_to_user ( rm_ds, ( intptr_t ) virtual );
|
|
205
|
+}
|
|
206
|
+
|
128
|
207
|
/* Place/remove parameter on real-mode stack in a way that's
|
129
|
208
|
* compatible with libkir
|
130
|
209
|
*/
|
|
@@ -134,72 +213,12 @@ static inline void copy_from_real_libkir ( void *dest,
|
134
|
213
|
#define BASEMEM_PARAMETER_INIT BASEMEM_PARAMETER_INIT_LIBKIR
|
135
|
214
|
#define BASEMEM_PARAMETER_DONE BASEMEM_PARAMETER_DONE_LIBKIR
|
136
|
215
|
|
137
|
|
-/* REAL_FRAGMENT: Declare and define a real-mode code fragment in
|
138
|
|
- * .text16. We don't need this for REAL_EXEC, since we can just
|
139
|
|
- * execute our real-mode code inline, but it's handy in case someone
|
140
|
|
- * genuinely wants to create a block of code that can be copied to a
|
141
|
|
- * specific location and then executed.
|
142
|
|
- *
|
143
|
|
- * Note that we put the code in the data segment, since otherwise we
|
144
|
|
- * can't (easily) access it in order to copy it to its target
|
145
|
|
- * location. We should never be calling any REAL_FRAGMENT routines
|
146
|
|
- * directly anyway.
|
147
|
|
- */
|
148
|
|
-#define REAL_FRAGMENT( name, asm_code_str ) \
|
149
|
|
- extern void name ( void ); \
|
150
|
|
- extern char name ## _size[]; \
|
151
|
|
- __asm__ __volatile__ ( \
|
152
|
|
- ".section \".data.text16\"\n\t" \
|
153
|
|
- ".code16\n\t" \
|
154
|
|
- ".arch i386\n\t" \
|
155
|
|
- #name ":\n\t" \
|
156
|
|
- asm_code_str "\n\t" \
|
157
|
|
- "lret\n\t" \
|
158
|
|
- #name "_end:\n\t" \
|
159
|
|
- ".equ " #name "_size, " #name "_end - " #name "\n\t" \
|
160
|
|
- ".code16gcc\n\t" \
|
161
|
|
- ".previous\n\t" \
|
162
|
|
- : : \
|
163
|
|
- )
|
164
|
|
-#define FRAGMENT_SIZE( fragment ) ( (size_t) fragment ## _size )
|
165
|
|
-
|
166
|
|
-/* REAL_CALL: call an external real-mode routine */
|
167
|
|
-#define OUT_CONSTRAINTS(...) __VA_ARGS__
|
168
|
|
-#define IN_CONSTRAINTS(...) "m" ( __routine ), ## __VA_ARGS__
|
169
|
|
-#define CLOBBER(...) __VA_ARGS__
|
170
|
|
-#define REAL_CALL( routine, num_out_constraints, out_constraints, \
|
171
|
|
- in_constraints, clobber ) \
|
172
|
|
- do { \
|
173
|
|
- segoff_t __routine = routine; \
|
174
|
|
- __asm__ __volatile__ ( \
|
175
|
|
- "pushl %" #num_out_constraints "\n\t" \
|
176
|
|
- ".code16\n\t" \
|
177
|
|
- "pushw %%gs\n\t" /* preserve segs */ \
|
178
|
|
- "pushw %%fs\n\t" \
|
179
|
|
- "pushw %%es\n\t" \
|
180
|
|
- "pushw %%ds\n\t" \
|
181
|
|
- "pushw %%cs\n\t" /* lcall to routine */ \
|
182
|
|
- "call 1f\n\t" \
|
183
|
|
- "jmp 2f\n\t" \
|
184
|
|
- "\n1:\n\t" \
|
185
|
|
- "addr32 pushl 12(%%esp)\n\t" \
|
186
|
|
- "lret\n\t" \
|
187
|
|
- "\n2:\n\t" \
|
188
|
|
- "popw %%ds\n\t" /* restore segs */ \
|
189
|
|
- "popw %%es\n\t" \
|
190
|
|
- "popw %%fs\n\t" \
|
191
|
|
- "popw %%gs\n\t" \
|
192
|
|
- "addw $4, %%sp\n\t" \
|
193
|
|
- ".code16gcc\n\t" \
|
194
|
|
- : out_constraints : in_constraints : clobber \
|
195
|
|
- ); \
|
196
|
|
- } while ( 0 )
|
197
|
|
-
|
198
|
216
|
/* REAL_EXEC: execute some inline assembly code in a way that matches
|
199
|
217
|
* the interface of librm
|
200
|
218
|
*/
|
201
|
|
-
|
202
|
|
-#define IN_CONSTRAINTS_NO_ROUTINE( routine, ... ) __VA_ARGS__
|
|
219
|
+#define OUT_CONSTRAINTS(...) __VA_ARGS__
|
|
220
|
+#define IN_CONSTRAINTS(...) __VA_ARGS__
|
|
221
|
+#define CLOBBER(...) __VA_ARGS__
|
203
|
222
|
#define REAL_EXEC( name, asm_code_str, num_out_constraints, out_constraints, \
|
204
|
223
|
in_constraints, clobber ) \
|
205
|
224
|
__asm__ __volatile__ ( \
|
|
@@ -216,7 +235,7 @@ static inline void copy_from_real_libkir ( void *dest,
|
216
|
235
|
"popw %%gs\n\t" \
|
217
|
236
|
".code16gcc\n\t" \
|
218
|
237
|
: out_constraints \
|
219
|
|
- : IN_CONSTRAINTS_NO_ROUTINE ( in_constraints ) \
|
|
238
|
+ : in_constraints \
|
220
|
239
|
: clobber \
|
221
|
240
|
);
|
222
|
241
|
|