1 | #ifndef REALMODE_H |
---|
2 | #define REALMODE_H |
---|
3 | |
---|
4 | #include <stdint.h> |
---|
5 | #include <registers.h> |
---|
6 | #include <gpxe/uaccess.h> |
---|
7 | |
---|
8 | /* |
---|
9 | * Data structures and type definitions |
---|
10 | * |
---|
11 | */ |
---|
12 | |
---|
13 | FILE_LICENCE ( GPL2_OR_LATER ); |
---|
14 | |
---|
15 | /* |
---|
16 | * Declaration of variables in .data16 |
---|
17 | * |
---|
18 | * To place a variable in the .data16 segment, declare it using the |
---|
19 | * pattern: |
---|
20 | * |
---|
21 | * int __data16 ( foo ); |
---|
22 | * #define foo __use_data16 ( foo ); |
---|
23 | * |
---|
24 | * extern uint32_t __data16 ( bar ); |
---|
25 | * #define bar __use_data16 ( bar ); |
---|
26 | * |
---|
27 | * static long __data16 ( baz ) = 0xff000000UL; |
---|
28 | * #define baz __use_data16 ( baz ); |
---|
29 | * |
---|
30 | * i.e. take a normal declaration, add __data16() around the variable |
---|
31 | * name, and add a line saying "#define <name> __use_data16 ( <name> ) |
---|
32 | * |
---|
33 | * You can then access them just like any other variable, for example |
---|
34 | * |
---|
35 | * int x = foo + bar; |
---|
36 | * |
---|
37 | * This magic is achieved at a cost of only around 7 extra bytes per |
---|
38 | * group of accesses to .data16 variables. When using KEEP_IT_REAL, |
---|
39 | * there is no extra cost. |
---|
40 | * |
---|
41 | * You should place variables in .data16 when they need to be accessed |
---|
42 | * by real-mode code. Real-mode assembly (e.g. as created by |
---|
43 | * REAL_CODE()) can access these variables via the usual data segment. |
---|
44 | * You can therefore write something like |
---|
45 | * |
---|
46 | * static uint16_t __data16 ( foo ); |
---|
47 | * #define foo __use_data16 ( foo ) |
---|
48 | * |
---|
49 | * int bar ( void ) { |
---|
50 | * __asm__ __volatile__ ( REAL_CODE ( "int $0xff\n\t" |
---|
51 | * "movw %ax, foo" ) |
---|
52 | * : : ); |
---|
53 | * return foo; |
---|
54 | * } |
---|
55 | * |
---|
56 | * Variables may also be placed in .text16 using __text16 and |
---|
57 | * __use_text16. Some variables (e.g. chained interrupt vectors) fit |
---|
58 | * most naturally in .text16; most should be in .data16. |
---|
59 | * |
---|
60 | * If you have only a pointer to a magic symbol within .data16 or |
---|
61 | * .text16, rather than the symbol itself, you can attempt to extract |
---|
62 | * the underlying symbol name using __from_data16() or |
---|
63 | * __from_text16(). This is not for the faint-hearted; check the |
---|
64 | * assembler output to make sure that it's doing the right thing. |
---|
65 | */ |
---|
66 | |
---|
67 | /** |
---|
68 | * Copy data to base memory |
---|
69 | * |
---|
70 | * @v dest_seg Destination segment |
---|
71 | * @v dest_off Destination offset |
---|
72 | * @v src Source |
---|
73 | * @v len Length |
---|
74 | */ |
---|
75 | static inline __always_inline void |
---|
76 | copy_to_real ( unsigned int dest_seg, unsigned int dest_off, |
---|
77 | void *src, size_t n ) { |
---|
78 | copy_to_user ( real_to_user ( dest_seg, dest_off ), 0, src, n ); |
---|
79 | } |
---|
80 | |
---|
81 | /** |
---|
82 | * Copy data to base memory |
---|
83 | * |
---|
84 | * @v dest Destination |
---|
85 | * @v src_seg Source segment |
---|
86 | * @v src_off Source offset |
---|
87 | * @v len Length |
---|
88 | */ |
---|
89 | static inline __always_inline void |
---|
90 | copy_from_real ( void *dest, unsigned int src_seg, |
---|
91 | unsigned int src_off, size_t n ) { |
---|
92 | copy_from_user ( dest, real_to_user ( src_seg, src_off ), 0, n ); |
---|
93 | } |
---|
94 | |
---|
95 | /** |
---|
96 | * Write a single variable to base memory |
---|
97 | * |
---|
98 | * @v var Variable to write |
---|
99 | * @v dest_seg Destination segment |
---|
100 | * @v dest_off Destination offset |
---|
101 | */ |
---|
102 | #define put_real( var, dest_seg, dest_off ) \ |
---|
103 | copy_to_real ( (dest_seg), (dest_off), &(var), sizeof (var) ) |
---|
104 | |
---|
105 | /** |
---|
106 | * Read a single variable from base memory |
---|
107 | * |
---|
108 | * @v var Variable to read |
---|
109 | * @v src_seg Source segment |
---|
110 | * @v src_off Source offset |
---|
111 | */ |
---|
112 | #define get_real( var, src_seg, src_off ) \ |
---|
113 | copy_from_real ( &(var), (src_seg), (src_off), sizeof (var) ) |
---|
114 | |
---|
115 | /* |
---|
116 | * REAL_CODE ( asm_code_str ) |
---|
117 | * |
---|
118 | * This can be used in inline assembly to create a fragment of code |
---|
119 | * that will execute in real mode. For example: to write a character |
---|
120 | * to the BIOS console using INT 10, you would do something like: |
---|
121 | * |
---|
122 | * __asm__ __volatile__ ( REAL_CODE ( "int $0x16" ) |
---|
123 | * : "=a" ( character ) : "a" ( 0x0000 ) ); |
---|
124 | * |
---|
125 | */ |
---|
126 | |
---|
127 | #endif /* REALMODE_H */ |
---|