10a28b2372d6d36a29d2257d79956b0c8b4a8d33
[people/xl0/gpxe.git] / src / arch / i386 / include / realmode.h
1 #ifndef REALMODE_H
2 #define REALMODE_H
3
4 #ifndef ASSEMBLY
5
6 #include "stdint.h"
7 #include "registers.h"
8 #include "io.h"
9
10 /*
11  * Data structures and type definitions
12  *
13  */
14
15 /* Segment:offset structure.  Note that the order within the structure
16  * is offset:segment.
17  */
18 struct segoff {
19         uint16_t offset;
20         uint16_t segment;
21 } __attribute__ (( packed ));
22
23 typedef struct segoff segoff_t;
24
25 /* Macro hackery needed to stringify bits of inline assembly */
26 #define RM_XSTR(x) #x
27 #define RM_STR(x) RM_XSTR(x)
28
29 /* Drag in the selected real-mode transition library header */
30 #ifdef KEEP_IT_REAL
31 #include "libkir.h"
32 #else
33 #include "librm.h"
34 #endif
35
36 /*
37  * The API to some functions is identical between librm and libkir, so
38  * they are documented here, even though the prototypes are in librm.h
39  * and libkir.h.
40  *
41  */
42
43 /*
44  * Declaration of variables in .data16
45  *
46  * To place a variable in the .data16 segment, declare it using the
47  * pattern:
48  *
49  *   int __data16 ( foo );
50  *   #define foo __use_data16 ( foo );
51  *
52  *   extern uint32_t __data16 ( bar );
53  *   #define bar __use_data16 ( bar );
54  *
55  *   static long __data16 ( baz ) = 0xff000000UL;
56  *   #define baz __use_data16 ( baz );
57  *
58  * i.e. take a normal declaration, add __data16() around the variable
59  * name, and add a line saying "#define <name> __use_data16 ( <name> )
60  *
61  * You can then access them just like any other variable, for example
62  *
63  *   int x = foo + bar;
64  *
65  * This magic is achieved at a cost of only around 7 extra bytes per
66  * group of accesses to .data16 variables.  When using KEEP_IT_REAL,
67  * there is no extra cost.
68  *
69  * You should place variables in .data16 when they need to be accessed
70  * by real-mode code.  Real-mode assembly (e.g. as created by
71  * REAL_EXEC()) can access these variables via the usual data segment.
72  * You can therefore write something like
73  *
74  *   static uint16_t __data16 ( foo );
75  *   #define foo __use_data16 ( foo )
76  *
77  *   int bar ( void ) {
78  *     REAL_EXEC ( baz,
79  *                 "int $0xff\n\t"
80  *                 "movw %ax, foo",
81  *                 ... );
82  *     return foo;
83  *   }
84  *
85  * Variables may also be placed in .text16 using __text16 and
86  * __use_text16.  Some variables (e.g. chained interrupt vectors) fit
87  * most naturally in .text16; most should be in .data16.
88  *
89  * If you have only a pointer to a magic symbol within .data16 or
90  * .text16, rather than the symbol itself, you can attempt to extract
91  * the underlying symbol name using __from_data16() or
92  * __from_text16().  This is not for the faint-hearted; check the
93  * assembler output to make sure that it's doing the right thing.
94  */
95
96 /*
97  * void copy_to_real ( uint16_t dest_seg, uint16_t dest_off,
98  *                     void *src, size_t n )
99  * void copy_from_real ( void *dest, uint16_t src_seg, uint16_t src_off,
100  *                       size_t n )
101  *
102  * These functions can be used to copy data to and from arbitrary
103  * locations in base memory.
104  */
105
106 /*
107  * put_real ( variable, uint16_t dest_seg, uint16_t dest_off )
108  * get_real ( variable, uint16_t src_seg, uint16_t src_off )
109  *
110  * These macros can be used to read or write single variables to and
111  * from arbitrary locations in base memory.  "variable" must be a
112  * variable of either 1, 2 or 4 bytes in length.
113  */
114
115 /*
116  * REAL_CALL ( routine, num_out_constraints, out_constraints,
117  *             in_constraints, clobber )
118  * REAL_EXEC ( name, asm_code_str, num_out_constraints, out_constraints,
119  *             in_constraints, clobber )
120  *
121  * If you have a pre-existing real-mode routine that you want to make
122  * a far call to, use REAL_CALL.  If you have a code fragment that you
123  * want to copy down to base memory, execute, and then remove, use
124  * REAL_EXEC.
125  *
126  * out_constraints must be of the form OUT_CONSTRAINTS(constraints),
127  * and in_constraints must be of the form IN_CONSTRAINTS(constraints),
128  * where "constraints" is a constraints list as would be used in an
129  * inline __asm__()
130  *
131  * clobber must be of the form CLOBBER ( clobber_list ), where
132  * "clobber_list" is a clobber list as would be used in an inline
133  * __asm__().
134  *
135  * These are best illustrated by example.  To write a character to the
136  * console using INT 10, you would do something like:
137  *
138  *      REAL_EXEC ( rm_test_librm,
139  *                  "int $0x10",
140  *                  1,
141  *                  OUT_CONSTRAINTS ( "=a" ( discard ) ),
142  *                  IN_CONSTRAINTS ( "a" ( 0x0e00 + character ),
143  *                                   "b" ( 1 ) ),
144  *                  CLOBBER ( "ebx", "ecx", "edx", "ebp", "esi", "edi" ) );
145  *
146  * IMPORTANT: gcc does not automatically assume that input operands
147  * get clobbered.  The only way to specify that an input operand may
148  * be modified is to also specify it as an output operand; hence the
149  * "(discard)" in the above code.
150  */
151
152 #endif /* ASSEMBLY */
153
154 #endif /* REALMODE_H */