Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

444 lines
14 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. vdmredir.h
  5. Abstract:
  6. Contains common defines, structures, macros, etc. for VdmRedir. This file
  7. contains macros to read and write the 3 basic data structures from/to VDM
  8. memory. We *must* use these macros because the MIPS processor does not like
  9. unaligned data: a DWORD must be read/written on a DWORD boundary (low two
  10. bits in address = 00), a WORD must be read/written on a WORD boundary (low
  11. two bits in address = X0) and a BYTE can be read/written to any address (low
  12. two bits in address = XX). It is illegal to access a WORD at an address
  13. whose LSB is not 0, and a DWORD at an address whose 2 least significant bits
  14. are not both 0. Dos programs don't care much about alignment (smart ones do
  15. because there is a performance penalty for unaligned data on x86, but it
  16. still works). So we have to assume the worst case for MIPS and break down
  17. the read/writes of WORDs and DWORDs in VDM memory into BYTE read/writes
  18. In order to improve efficiency of load/store to potentially unaligned
  19. addresses, the following data pointer types are made available from this
  20. include file:
  21. ULPBYTE - unaligned byte pointer (same as LPBYTE)
  22. ULPWORD - unaligned word pointer
  23. ULPDWORD - unaligned dword pointer
  24. NB. Dependent upon mvdm.h
  25. Author:
  26. Richard L Firth (rfirth) 16-Sep-1991
  27. Revision History:
  28. 16-Sep-1991 rfirth
  29. Created
  30. --*/
  31. #ifndef _VDMREDIR_
  32. #define _VDMREDIR_
  33. #include <softpc.h>
  34. //
  35. // PRIVATE - make a routine/data type inaccessible outside current module, but
  36. // only if not DEBUG version
  37. //
  38. #if DBG
  39. #define PRIVATE
  40. #else
  41. #define PRIVATE static
  42. #endif
  43. //
  44. // unaligned data pointer types. These produce exactly the same code as memory
  45. // accesses through 'aligned' pointers on x86, but generate code specific to
  46. // unaligned read/writes on MIPS (& other RISCs)
  47. //
  48. #ifdef UNALIGNED_VDM_POINTERS
  49. typedef BYTE UNALIGNED * ULPBYTE;
  50. typedef WORD UNALIGNED * ULPWORD;
  51. typedef DWORD UNALIGNED * ULPDWORD;
  52. #else
  53. typedef LPBYTE ULPBYTE;
  54. typedef LPWORD ULPWORD;
  55. typedef LPDWORD ULPDWORD;
  56. #endif
  57. //
  58. // misc. defines
  59. //
  60. #define BITS_IN_A_BYTE 8
  61. #define LOCAL_DEVICE_PREFIX "\\\\."
  62. //
  63. // Define network interrupt to be on Irql 14.
  64. // If NETWORK_ICA changes to ICA_MASTER then vrnetb.c should only execute 1 eoi
  65. // If either change then NETWORK_INTERRUPT in int5c.inc must also change.
  66. //
  67. #if defined(NEC_98)
  68. #define NETWORK_ICA ICA_MASTER
  69. #define NETWORK_LINE 5
  70. #else
  71. #define NETWORK_ICA ICA_SLAVE
  72. #define NETWORK_LINE 2
  73. #endif
  74. //
  75. // helper macros
  76. //
  77. //
  78. // MAKE_DWORD - converts 2 16-bit words into a 32-bit double word
  79. //
  80. #define MAKE_DWORD(h, l) ((DWORD)(((DWORD)((WORD)(h)) << 16) | (DWORD)((WORD)(l))))
  81. //
  82. // DWORD_FROM_WORDS - converts two 16-bit words into a 32-bit dword
  83. //
  84. #define DWORD_FROM_WORDS(h, l) MAKE_DWORD((h), (l))
  85. //
  86. // HANDLE_FROM_WORDS - converts a pair of 16-bit words into a 32-bit handle
  87. //
  88. #define HANDLE_FROM_WORDS(h, l) ((HANDLE)(MAKE_DWORD((h), (l))))
  89. //
  90. // POINTER_FROM_WORDS - returns a flat 32-bit VOID pointer (in the VDM) OR the
  91. // NULL macro, given the 16-bit real-mode segment & offset. On x86 this will
  92. // return 0 if we pass in 0:0 because all GetVDMAddr does is seg << 4 + off.
  93. // The MIPS version adds this to the start of the virtual DOS memory. The
  94. // problem arises when we have a NULL pointer, and want to keep it NULL - we
  95. // convert it to non-NULL on not x86
  96. //
  97. //#define POINTER_FROM_WORDS(seg, off) ((LPVOID)GetVDMAddr((seg), (off)))
  98. //#define POINTER_FROM_WORDS(seg, off) (((((DWORD)(seg)) << 16) | (off)) ? ((LPVOID)GetVDMAddr((seg), (off))) : ((LPVOID)0))
  99. #define POINTER_FROM_WORDS(seg, off) _inlinePointerFromWords((WORD)(seg), (WORD)(off))
  100. //
  101. // LPSTR_FROM_WORDS - returns a 32-bit pointer to an ASCIZ string given the
  102. // 16-bit real-mode segment & offset
  103. //
  104. #define LPSTR_FROM_WORDS(seg, off) ((LPSTR)POINTER_FROM_WORDS((seg), (off)))
  105. //
  106. // LPBYTE_FROM_WORDS - returns a 32-bit byte pointer given the 16-bit
  107. // real-mode segment & offset
  108. //
  109. #define LPBYTE_FROM_WORDS(seg, off) ((LPBYTE)POINTER_FROM_WORDS((seg), (off)))
  110. //
  111. // READ_FAR_POINTER - read the pair of words in VDM memory, currently pointed at
  112. // by a 32-bit flat pointer and convert them to a 32-bit flat pointer
  113. //
  114. #define READ_FAR_POINTER(addr) ((LPVOID)(POINTER_FROM_WORDS(GET_SELECTOR(addr), GET_OFFSET(addr))))
  115. //
  116. // READ_BYTE - retrieve a single byte from VDM memory. Both x86 and MIPS can
  117. // handle reading a single byte without pain
  118. //
  119. #define READ_BYTE(addr) (*((LPBYTE)(addr)))
  120. //
  121. // READ_WORD - read a single 16-bit little-endian word from VDM memory. x86 can
  122. // handle unaligned data, MIPS (&other RISCs) must be broken down into individual
  123. // BYTE reads & the WORD pieced together by shifting & oring. If we are using
  124. // UNALIGNED pointers then the RISC processor can handle non-aligned data
  125. //
  126. #ifdef i386
  127. #define READ_WORD(addr) (*((LPWORD)(addr)))
  128. #else
  129. #ifdef UNALIGNED_VDM_POINTERS
  130. #define READ_WORD(addr) (*((ULPWORD)(addr)))
  131. #else
  132. #define READ_WORD(addr) (((WORD)READ_BYTE(addr)) | (((WORD)READ_BYTE((LPBYTE)(addr)+1)) << 8))
  133. #endif // UNALIGNED_VDM_POINTERS
  134. #endif // i386
  135. //
  136. // READ_DWORD - read a 4-byte little-endian double word from VDM memory. x86 can
  137. // handle unaligned data, MIPS (&other RISCs) must be broken down into individual
  138. // BYTE reads & the DWORD pieced together by shifting & oring. If we are using
  139. // UNALIGNED pointers then the RISC processor can handle non-aligned data
  140. //
  141. #ifdef i386
  142. #define READ_DWORD(addr) (*((LPDWORD)(addr)))
  143. #else
  144. #ifdef UNALIGNED_VDM_POINTERS
  145. #define READ_DWORD(addr) (*((ULPDWORD)(addr)))
  146. #else
  147. #define READ_DWORD(addr) (((DWORD)READ_WORD(addr)) | (((DWORD)READ_WORD((LPWORD)(addr)+1)) << 16))
  148. #endif // UNALIGNED_VDM_POINTERS
  149. #endif // i386
  150. //
  151. // WRITE_BYTE - write a single byte in VDM memory. Both x86 and MIPS (RISC) can
  152. // write a single byte to a non-aligned address
  153. //
  154. #define WRITE_BYTE(addr, value) (*(LPBYTE)(addr) = (BYTE)(value))
  155. //
  156. // WRITE_WORD - write a 16-bit little-endian value into VDM memory. x86 can write
  157. // WORD data to non-word-aligned address; MIPS (& other RISCs) cannot, so we
  158. // break down the write into 2 byte writes. If we are using UNALIGNED pointers
  159. // then the MIPS (&other RISCs) can generate code to handle this situation
  160. //
  161. #ifdef i386
  162. #define WRITE_WORD(addr, value) (*((LPWORD)(addr)) = (WORD)(value))
  163. #else
  164. #ifdef UNALIGNED_VDM_POINTERS
  165. #define WRITE_WORD(addr, value) (*((ULPWORD)(addr)) = (WORD)(value))
  166. #else
  167. #define WRITE_WORD(addr, value) \
  168. {\
  169. ((LPBYTE)(addr))[0] = LOBYTE(value); \
  170. ((LPBYTE)(addr))[1] = HIBYTE(value); \
  171. }
  172. #endif // UNALIGNED_VDM_POINTERS
  173. #endif // i386
  174. //
  175. // WRITE_DWORD - write a 32-bit DWORD value into VDM memory. x86 can write
  176. // DWORD data to non-dword-aligned address; MIPS (& other RISCs) cannot, so we
  177. // break down the write into 4 byte writes. If we are using UNALIGNED pointers
  178. // then the MIPS (&other RISCs) can generate code to handle this situation
  179. //
  180. #ifdef i386
  181. #define WRITE_DWORD(addr, value) (*((LPDWORD)(addr)) = (DWORD)(value))
  182. #else
  183. #ifdef UNALIGNED_VDM_POINTERS
  184. #define WRITE_DWORD(addr, value) (*((ULPDWORD)(addr)) = (DWORD)(value))
  185. #else
  186. #define WRITE_DWORD(addr, value) \
  187. { \
  188. ((LPBYTE)(addr))[0] = LOBYTE(LOWORD((DWORD)(value))); \
  189. ((LPBYTE)(addr))[1] = HIBYTE(LOWORD((DWORD)(value))); \
  190. ((LPBYTE)(addr))[2] = LOBYTE(HIWORD((DWORD)(value))); \
  191. ((LPBYTE)(addr))[3] = HIBYTE(HIWORD((DWORD)(value))); \
  192. }
  193. #endif // UNALIGNED_VDM_POINTERS
  194. #endif // i386
  195. //
  196. // WRITE_FAR_POINTER - write a 16:16 pointer into VDM memory. This is the same
  197. // as writing a DWORD
  198. //
  199. #define WRITE_FAR_POINTER(addr, ptr) WRITE_DWORD((addr), (DWORD)(ptr))
  200. //
  201. // GET_SELECTOR - retrieves the selector word from the intel 32-bit far pointer
  202. // (DWORD) pointed at by <pointer> (remember: stored as offset, segment)
  203. //
  204. #define GET_SELECTOR(pointer) READ_WORD((LPWORD)(pointer)+1)
  205. //
  206. // GET_SEGMENT - same as GET_SELECTOR
  207. //
  208. #define GET_SEGMENT(pointer) GET_SELECTOR(pointer)
  209. //
  210. // GET_OFFSET - retrieves the offset word from an intel 32-bit far pointer
  211. // (DWORD) pointed at by <pointer> (remember: stored as offset, segment)
  212. //
  213. #define GET_OFFSET(pointer) READ_WORD((LPWORD)(pointer))
  214. //
  215. // SET_SELECTOR - writes a word into the segment word of a real-mode far pointer
  216. // (DWORD) pointed at by <pointer> (remember: stored as offset, segment)
  217. //
  218. #define SET_SELECTOR(pointer, word) WRITE_WORD(((LPWORD)(pointer)+1), (word))
  219. //
  220. // SET_SEGMENT - same as SET_SELECTOR
  221. //
  222. #define SET_SEGMENT(pointer, word) SET_SELECTOR(pointer, word)
  223. //
  224. // SET_OFFSET - writes a word into the offset word of a real-mode far pointer
  225. // (DWORD) pointed at by <pointer> (remember: stored as offset, segment)
  226. //
  227. #define SET_OFFSET(pointer, word) WRITE_WORD((LPWORD)(pointer), (word))
  228. //
  229. // POINTER_FROM_POINTER - read a segmented pointer in the VDM from an address
  230. // pointed at by a flat 32-bit pointer. Convert the segmented pointer to a
  231. // flat pointer. SAME AS READ_FAR_POINTER
  232. //
  233. #define POINTER_FROM_POINTER(pointer) POINTER_FROM_WORDS(GET_SELECTOR(pointer), GET_OFFSET(pointer))
  234. //
  235. // LPSTR_FROM_POINTER - perform a POINTER_FROM_POINTER, casting the result to
  236. // a string pointer. SAME AS READ_FAR_POINTER
  237. //
  238. #define LPSTR_FROM_POINTER(pointer) ((LPSTR)POINTER_FROM_POINTER(pointer))
  239. //
  240. // LPBYTE_FROM_POINTER - perform a POINTER_FROM_POINTER, casting the result to
  241. // a byte pointer. SAME AS READ_FAR_POINTER
  242. //
  243. #define LPBYTE_FROM_POINTER(pointer) ((LPBYTE)POINTER_FROM_POINTER(pointer))
  244. //
  245. // SET_ERROR - sets the caller's AX register in the VDM context descriptor to
  246. // the value given and sets the caller's VDM carry flag
  247. //
  248. #define SET_ERROR(err) {setAX(err); setCF(1);}
  249. //
  250. // SET_SUCCESS - sets the VDM caller's AX register to NERR_Success and clears
  251. // the carry flag
  252. //
  253. #define SET_SUCCESS() {setAX(NERR_Success); setCF(0);}
  254. //
  255. // SET_OK - an explicit version of SET_SUCCESS wherein NERR_Success would be
  256. // an inappropriate error, although the right value
  257. //
  258. #define SET_OK(value) {setAX(value); setCF(0);}
  259. //
  260. // Miscellaneous macros for working out sizes of things
  261. //
  262. //
  263. // ARRAY_ELEMENTS - gives the number of elements of a particular type in an
  264. // array
  265. //
  266. #define ARRAY_ELEMENTS(a) (sizeof(a)/sizeof((a)[0]))
  267. //
  268. // LAST_ELEMENT - returns the index of the last element in array
  269. //
  270. #define LAST_ELEMENT(a) (ARRAY_ELEMENTS(a)-1)
  271. //
  272. // BITSIN - returns the number of bits in a data type or structure. This is
  273. // predicated upon the number of bits in a byte being 8 and all data types
  274. // being composed of a collection of bytes (safe assumption?)
  275. //
  276. #define BITSIN(thing) (sizeof(thing) * BITS_IN_A_BYTE)
  277. //
  278. // Miscellaneous other macros
  279. //
  280. //
  281. // IS_ASCII_PATH_SEPARATOR - returns TRUE if ch is / or \. ch is a single
  282. // byte (ASCII) character
  283. //
  284. #define IS_ASCII_PATH_SEPARATOR(ch) (((ch) == '/') || ((ch) == '\\'))
  285. //
  286. // macros for setting CF and ZF flags for return from hardware interrupt
  287. // callback
  288. //
  289. #define SET_CALLBACK_NOTHING() {setZF(0); setCF(0);}
  290. #define SET_CALLBACK_NAMEPIPE() {setZF(0); setCF(1);}
  291. #define SET_CALLBACK_DLC() {setZF(1); setCF(0);}
  292. #define SET_CALLBACK_NETBIOS() {setZF(1); setCF(1);}
  293. //
  294. // DLC-specific macros etc.
  295. //
  296. extern LPVDM_REDIR_DOS_WINDOW lpVdmWindow;
  297. //
  298. // setPostRoutine - if dw is not 0 then we write the (DOS segmented) address of
  299. // the post routine into the dwPostRoutine field of the VDM_REDIR_DOS_WINDOW
  300. // structure passed to us at redir DLC initialization. We also set the flags
  301. // to indicate to the redir's hardware interrupt routine there is a DLC post
  302. // routine to run. If dw is 0 then we set the flags to indicate that there is
  303. // no post routine processing
  304. //
  305. #define setPostRoutine( dw ) if (dw) {\
  306. (lpVdmWindow->dwPostRoutine = (DWORD)(dw));\
  307. SET_CALLBACK_DLC();\
  308. } else {\
  309. SET_CALLBACK_NOTHING();\
  310. }
  311. //
  312. // VR_ASYNC_DISPOSITION - we maintain a serialized list of these structures.
  313. // Used to dispose of VDM redir asynchronous completions in the order in which
  314. // they occurred
  315. //
  316. typedef struct _VR_ASYNC_DISPOSITION {
  317. //
  318. // Next - maintains a singly-linked list of dispositions
  319. //
  320. struct _VR_ASYNC_DISPOSITION* Next;
  321. //
  322. // AsyncDispositionRoutine - pointer to VOID function taking no args which
  323. // will dispose of the next asynchronous completion - Netbios, named pipe
  324. // or DLC
  325. //
  326. VOID (*AsyncDispositionRoutine)(VOID);
  327. } VR_ASYNC_DISPOSITION, *PVR_ASYNC_DISPOSITION;
  328. //
  329. // _inlinePointerFromWords - the POINTER_FROM_WORDS macro is inefficient if the
  330. // arguments are calls to eg. getES(), getBX() - the calls are made twice if
  331. // the pointer turns out to be non-zero. Use an inline function to achieve the
  332. // same results, but only call function arguments once
  333. //
  334. #ifdef i386
  335. __inline LPVOID _inlinePointerFromWords(WORD seg, WORD off) {
  336. WORD _seg = seg;
  337. WORD _off = off;
  338. return (_seg + _off) ? (LPVOID)GetVDMAddr(_seg, _off) : 0;
  339. }
  340. #else
  341. LPVOID _inlinePointerFromWords(WORD seg, WORD off);
  342. #endif
  343. //
  344. // CONVERT_ADDRESS - convert a segmented (real or protect-mode) address to a
  345. // flat 32-bit address
  346. //
  347. //#define CONVERT_ADDRESS(seg, off, size, mode) !((WORD)(seg) | (WORD)(off)) ? 0 : Sim32GetVDMPointer((((DWORD)seg) << 16) + (DWORD)(off), (size), (mode))
  348. #define CONVERT_ADDRESS(seg, off, size, mode) _inlineConvertAddress((WORD)(seg), (WORD)(off), (WORD)(size), (BOOLEAN)(mode))
  349. #ifdef i386
  350. __inline LPVOID _inlineConvertAddress(WORD Seg, WORD Off, WORD Size, BOOLEAN Pm) {
  351. WORD _seg = Seg;
  352. WORD _off = Off;
  353. return (_seg | _off) ? Sim32GetVDMPointer(((DWORD)_seg << 16) + _off, Size, Pm) : 0;
  354. }
  355. #else
  356. extern LPVOID _inlineConvertAddress(WORD Seg, WORD Off, WORD Size, BOOLEAN Pm);
  357. #endif
  358. #endif // _VDMREDIR_