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 13FILE_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 */ 75static inline __always_inline void 76copy_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 */ 89static inline __always_inline void 90copy_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 */ 128