| 1 | ; $Id: d32CallGate.asm,v 1.3 2001-02-23 02:57:53 bird Exp $ | 
|---|
| 2 | ; | 
|---|
| 3 | ; 32-bit CallGate used to communitcate fast between Ring-3 and Ring-0. | 
|---|
| 4 | ; This module contains all assembly workers for this. | 
|---|
| 5 | ; | 
|---|
| 6 | ; Copyright (c) 2001 knut st. osmundsen (knut.stange.osmundsen@mynd.no) | 
|---|
| 7 | ; | 
|---|
| 8 | ; Project Odin Software License can be found in LICENSE.TXT | 
|---|
| 9 | ; | 
|---|
| 10 |  | 
|---|
| 11 | .386p | 
|---|
| 12 |  | 
|---|
| 13 | ; | 
|---|
| 14 | ;   Defined Constants And Macros | 
|---|
| 15 | ; | 
|---|
| 16 | INCL_ERRORS EQU 1 | 
|---|
| 17 |  | 
|---|
| 18 |  | 
|---|
| 19 | ; | 
|---|
| 20 | ;   Header Files | 
|---|
| 21 | ; | 
|---|
| 22 | include bseerr.inc | 
|---|
| 23 | include devsegdf.inc | 
|---|
| 24 | include devhlp.inc | 
|---|
| 25 | include win32k.inc | 
|---|
| 26 |  | 
|---|
| 27 |  | 
|---|
| 28 | ; | 
|---|
| 29 | ; Exported symbols | 
|---|
| 30 | ; | 
|---|
| 31 | public CallGateGDT | 
|---|
| 32 |  | 
|---|
| 33 | public InitCallGate | 
|---|
| 34 | public Win32kAPIRouter | 
|---|
| 35 |  | 
|---|
| 36 |  | 
|---|
| 37 | ; | 
|---|
| 38 | ; External symbols | 
|---|
| 39 | ; | 
|---|
| 40 | extrn  _Device_Help:dword | 
|---|
| 41 | extrn  pulTKSSBase32:dword | 
|---|
| 42 |  | 
|---|
| 43 | extrn  KMEnterKmodeSEF:near | 
|---|
| 44 | extrn  KMExitKmodeSEF8:near | 
|---|
| 45 | extrn  _TKFuBuff@16:near | 
|---|
| 46 |  | 
|---|
| 47 | extrn  k32AllocMemEx:near | 
|---|
| 48 | extrn  k32QueryOTEs:near | 
|---|
| 49 | extrn  k32QueryOptionsStatus:near | 
|---|
| 50 | extrn  k32SetOptions:near | 
|---|
| 51 | extrn  k32ProcessReadWrite:near | 
|---|
| 52 | extrn  k32HandleSystemEvent:near | 
|---|
| 53 | extrn  k32QuerySystemMemInfo:near | 
|---|
| 54 | extrn  k32QueryCallGate:near | 
|---|
| 55 |  | 
|---|
| 56 |  | 
|---|
| 57 | ; | 
|---|
| 58 | ;   Global Variables | 
|---|
| 59 | ; | 
|---|
| 60 | DATA16 segment | 
|---|
| 61 | CallGateGDT     dw  0                   ; GDT used for the 32-bit Ring-3 -> Ring-0 call gate. | 
|---|
| 62 | DATA16 ends | 
|---|
| 63 |  | 
|---|
| 64 | DATA32 segment | 
|---|
| 65 | GDTR_limit      dw ?                    ; The limit field of the GDTR. | 
|---|
| 66 | GDTR_base       dd ?                    ; The base field of the GDTR. (linear flat address) | 
|---|
| 67 |  | 
|---|
| 68 |  | 
|---|
| 69 | ; | 
|---|
| 70 | ; Structure containing the K32 API parameter packet size. | 
|---|
| 71 | ; | 
|---|
| 72 | ; Used for parameter packet validation, and for copying the parameter | 
|---|
| 73 | ; packet from user address space into system address space (the stack). | 
|---|
| 74 | ; | 
|---|
| 75 | acbK32Params: | 
|---|
| 76 | dd 0                                ; Not used - ie. invalid | 
|---|
| 77 | dd SIZE   K32ALLOCMEMEX             ; K32_ALLOCMEMEX          0x01 | 
|---|
| 78 | dd SIZE   K32QUERYOTES              ; K32_QUERYOTES           0x02 | 
|---|
| 79 | dd SIZE   K32QUERYOPTIONSSTATUS     ; K32_QUERYOPTIONSSTATUS  0x03 | 
|---|
| 80 | dd SIZE   K32SETOPTIONS             ; K32_SETOPTIONS          0x04 | 
|---|
| 81 | dd SIZE   K32PROCESSREADWRITE       ; K32_PROCESSREADWRITE    0x05 | 
|---|
| 82 | dd SIZE   K32HANDLESYSTEMEVENT      ; K32_HANDLESYSTEMEVENT   0x06 | 
|---|
| 83 | dd SIZE   K32QUERYSYSTEMMEMINFO     ; K32_QUERYSYSTEMMEMINFO  0x07 | 
|---|
| 84 | dd SIZE   K32QUERYCALLGATE          ; K32_QUERYCALLGATE       0x08 | 
|---|
| 85 |  | 
|---|
| 86 | ; | 
|---|
| 87 | ; Structure containing the offsets of K32 API worker routines. | 
|---|
| 88 | ; | 
|---|
| 89 | ; Used for calling the workers indirectly. | 
|---|
| 90 | ; | 
|---|
| 91 | apfnK32APIs: | 
|---|
| 92 | dd  FLAT:k32APIStub                 ; Not used - ie. invalid | 
|---|
| 93 | dd  FLAT:k32AllocMemEx              ; K32_ALLOCMEMEX          0x01 | 
|---|
| 94 | dd  FLAT:k32QueryOTEs               ; K32_QUERYOTES           0x02 | 
|---|
| 95 | dd  FLAT:k32QueryOptionsStatus      ; K32_QUERYOPTIONSSTATUS  0x03 | 
|---|
| 96 | dd  FLAT:k32SetOptions              ; K32_SETOPTIONS          0x04 | 
|---|
| 97 | dd  FLAT:k32ProcessReadWrite        ; K32_PROCESSREADWRITE    0x05 | 
|---|
| 98 | dd  FLAT:k32HandleSystemEvent       ; K32_HANDLESYSTEMEVENT   0x06 | 
|---|
| 99 | dd  FLAT:k32QuerySystemMemInfo      ; K32_QUERYSYSTEMMEMINFO  0x07 | 
|---|
| 100 | dd  FLAT:k32QueryCallGate           ; K32_QUERYCALLGATE       0x08 | 
|---|
| 101 | DATA32 ends | 
|---|
| 102 |  | 
|---|
| 103 |  | 
|---|
| 104 |  | 
|---|
| 105 | CODE32 segment | 
|---|
| 106 | assume cs:CODE32, ds:FLAT ;, es:nothing, ss:nothing | 
|---|
| 107 |  | 
|---|
| 108 | ;; | 
|---|
| 109 | ; This function initiates the callgate. | 
|---|
| 110 | ; @cproto   extern ULONG _Optlink InitCallGate(void); | 
|---|
| 111 | ; @returns  0 (NO_ERROR) on success. | 
|---|
| 112 | ;           appropriate error code on error. | 
|---|
| 113 | ; @uses     eax, ecx, edx | 
|---|
| 114 | ; @sketch | 
|---|
| 115 | ; @status | 
|---|
| 116 | ; @author   knut st. osmundsen (knut.stange.osmundsen@mynd.no) | 
|---|
| 117 | ; @remark | 
|---|
| 118 | InitCallGate proc near | 
|---|
| 119 | push    ebp | 
|---|
| 120 | mov     ebp, esp | 
|---|
| 121 | push    edi | 
|---|
| 122 | push    esi | 
|---|
| 123 | push    ebx | 
|---|
| 124 | push    ds | 
|---|
| 125 | push    es | 
|---|
| 126 |  | 
|---|
| 127 | ; | 
|---|
| 128 | ; Allocate GDT selector for the call gate. | 
|---|
| 129 | ; (URG! This call also allocates 68kb of virtual memory which i don't need!) | 
|---|
| 130 | ; | 
|---|
| 131 | mov     di, seg DATA16:CallGateGDT | 
|---|
| 132 | mov     es, di | 
|---|
| 133 | mov     di, offset DATA16:CallGateGDT | 
|---|
| 134 | mov     cx, 1 | 
|---|
| 135 | mov     dl, DevHlp_AllocGDTSelector | 
|---|
| 136 | jmp     far ptr CODE16:Thunk16_AllocGDTSelector | 
|---|
| 137 | Thunk32_AllocGDTSelector:: | 
|---|
| 138 | jnc     ICG_allocok | 
|---|
| 139 | movzx   eax, ax                     ; We failed, zero high word of eax to return proper return code. | 
|---|
| 140 | jmp     ICG_end                     ; bail out. | 
|---|
| 141 |  | 
|---|
| 142 | ; | 
|---|
| 143 | ; We successfully allocate the callgate GDT. | 
|---|
| 144 | ; How we'll find the descriptor entry for it. | 
|---|
| 145 | ; | 
|---|
| 146 | ICG_allocok: | 
|---|
| 147 | ASSUME  ds:FLAT | 
|---|
| 148 | sgdt    GDTR_limit                  ; Get the GDTR content. | 
|---|
| 149 | mov     ax, GDTR_limit | 
|---|
| 150 | mov     ebx, GDTR_base | 
|---|
| 151 | movzx   ecx, CallGateGDT | 
|---|
| 152 | and     cx, 0fff8h                  ; clear the dpl bits and descriptor type bit. (paranoia!) | 
|---|
| 153 | cmp     cx, ax                      ; check limit. (paranoia!!!) | 
|---|
| 154 | jl      ICG_limitok | 
|---|
| 155 | mov     eax, 0ffffffffh             ; return failure. | 
|---|
| 156 | jmp     ICG_end | 
|---|
| 157 | ICG_limitok: | 
|---|
| 158 | add     ebx, ecx                    ; GDTR_base + selector offset -> flat pointer to selector. | 
|---|
| 159 |  | 
|---|
| 160 | ; | 
|---|
| 161 | ; ebx is pointing to the descriptor table entry for my GDT selector. | 
|---|
| 162 | ; Now we'll have to change it into a callgate. | 
|---|
| 163 | ; This is the layout of a callgate descriptor: | 
|---|
| 164 | ;  bits | 
|---|
| 165 | ;  0-15  Segment offset low word | 
|---|
| 166 | ; 16-31  Segment selector | 
|---|
| 167 | ; -------second dword------- | 
|---|
| 168 | ;   0-4  Param Count | 
|---|
| 169 | ;   5-7  Reserved (zero) | 
|---|
| 170 | ;  8-11  Selector type - 1100b | 
|---|
| 171 | ;    12  Reserved (UVirt) zero | 
|---|
| 172 | ; 13-14  Descriptor Privelege Level (DPL) | 
|---|
| 173 | ;    15  Present flag / Gate valid. | 
|---|
| 174 | ; 16-31  Segment offset high word. | 
|---|
| 175 | ; | 
|---|
| 176 | mov     eax, offset FLAT:Win32kCallGate | 
|---|
| 177 | mov     word ptr [ebx], ax          ; set low segment offset word | 
|---|
| 178 | shr     eax, 10h | 
|---|
| 179 | mov     word ptr [ebx + 6], ax      ; set high segment offset word | 
|---|
| 180 |  | 
|---|
| 181 | mov     word ptr [ebx + 4], 1110110000000010b ; set flags and stuff. | 
|---|
| 182 | ; param count:  Two (2) - parameter struct and function number | 
|---|
| 183 | ; type:         32-bit call gate | 
|---|
| 184 | ; DPL:          Ring-3 | 
|---|
| 185 | ; Gate Valid:   Yes | 
|---|
| 186 | mov     word ptr [ebx + 2], seg FLAT:CODE32 ; Set the selector to FLAT Ring-0 code selector. | 
|---|
| 187 | xor     eax, eax                    ; return successfully. | 
|---|
| 188 |  | 
|---|
| 189 | ICG_end: | 
|---|
| 190 | pop     es | 
|---|
| 191 | pop     ds | 
|---|
| 192 | pop     ebx | 
|---|
| 193 | pop     esi | 
|---|
| 194 | pop     edi | 
|---|
| 195 | leave | 
|---|
| 196 | ret | 
|---|
| 197 | InitCallGate endp | 
|---|
| 198 |  | 
|---|
| 199 |  | 
|---|
| 200 |  | 
|---|
| 201 | ;; | 
|---|
| 202 | ; This is the callgate procedure. | 
|---|
| 203 | ; @cproto   none | 
|---|
| 204 | ; @returns  return value of the callgate router. | 
|---|
| 205 | ; @param    fill inn later.... | 
|---|
| 206 | ; @uses     eax, ecx, edx | 
|---|
| 207 | ; @sketch | 
|---|
| 208 | ; @status | 
|---|
| 209 | ; @author   knut st. osmundsen (knut.stange.osmundsen@mynd.no) | 
|---|
| 210 | ; @remark | 
|---|
| 211 | ;   stack frame - before KMEnterKmodeSEF: | 
|---|
| 212 | ;       --bottom of stack--- | 
|---|
| 213 | ;       calling ss                                                1ch | 
|---|
| 214 | ;       calling esp                                               18h | 
|---|
| 215 | ;       pParameter          (parameter 1)                         14h | 
|---|
| 216 | ;       ulFunctionCode      (parameter 0)                         10h | 
|---|
| 217 | ;       calling cs                                                0ch | 
|---|
| 218 | ;       calling eip         <-- esp points here upon entry.        8h | 
|---|
| 219 | ;       ---top of stack--- | 
|---|
| 220 | ;       flags               (pushf)                                4h | 
|---|
| 221 | ;       parameter size      (push 8h)                              0h | 
|---|
| 222 | ; | 
|---|
| 223 | ;  After the call to KMEnterKmodeSEF: | 
|---|
| 224 | ;       --bottom of stack--- | 
|---|
| 225 | ;       calling ss                                                50 | 
|---|
| 226 | ;       calling esp                                               4c | 
|---|
| 227 | ;       pParameter          (parameter 1)                         48 | 
|---|
| 228 | ;       ulFunctionCode      (parameter 0)                         44 | 
|---|
| 229 | ;       sef_cs                                                    40 | 
|---|
| 230 | ;       sef_eip                                                   3c | 
|---|
| 231 | ;       sef_eflag                                                 38 | 
|---|
| 232 | ;       sef_cbargs                                                34 | 
|---|
| 233 | ;       sef_retaddr                                               30 | 
|---|
| 234 | ;       sef_ds                                                    2c | 
|---|
| 235 | ;       sef_es                                                    28 | 
|---|
| 236 | ;       sef_fs                                                    24 | 
|---|
| 237 | ;       sef_gs                                                    20 | 
|---|
| 238 | ;       sef_eax                                                   1c | 
|---|
| 239 | ;       sef_ecx                                                   18 | 
|---|
| 240 | ;       sef_edx                                                   14 | 
|---|
| 241 | ;       sef_ebx                                                   10 | 
|---|
| 242 | ;       sef_padesp                                                 c | 
|---|
| 243 | ;       sef_ebp                                                    8 | 
|---|
| 244 | ;       sef_esi                                                    4h | 
|---|
| 245 | ;       sef_edi                                                    0h | 
|---|
| 246 | ; | 
|---|
| 247 | Win32kCallGate proc near | 
|---|
| 248 | ASSUME  ds:nothing, ss:nothing | 
|---|
| 249 | pushfd                              ; Push all flags (eflags) | 
|---|
| 250 | push    8h                          ; Size of parameters. | 
|---|
| 251 |  | 
|---|
| 252 | call    KMEnterKmodeSEF             ; This is an OS2 kernel function which does | 
|---|
| 253 | ; kernel entry housekeeping. | 
|---|
| 254 |  | 
|---|
| 255 | mov     edx, [esp + 48h]            ; pParameter (parameter 1) | 
|---|
| 256 | mov     eax, [esp + 44h]            ; ulFunctionCode (parameter 2) | 
|---|
| 257 | sub     esp, 8h                     ; (Even when using _Oplink we have to reserve space for parameters.) | 
|---|
| 258 | call    Win32kAPIRouter             ; This is my Ring-0 api router. | 
|---|
| 259 | add     esp, 8h | 
|---|
| 260 |  | 
|---|
| 261 | jmp     KMExitKmodeSEF8             ; This a an OS2 kernel function which does | 
|---|
| 262 | ; kernel exist housekeeping. | 
|---|
| 263 | Win32kCallGate endp | 
|---|
| 264 |  | 
|---|
| 265 |  | 
|---|
| 266 | ;; | 
|---|
| 267 | ; Internal function router which calls the correct function. | 
|---|
| 268 | ; Called from IOCtl worker in d32Win32kIOCtl.c and callgate. | 
|---|
| 269 | ; @cproto   APIRET _Optlink Win32kAPIRouter(ULONG ulFunction, PVOID pvParam); | 
|---|
| 270 | ; @returns  function return code. | 
|---|
| 271 | ;           0xdeadbeef if invalid function number. | 
|---|
| 272 | ; @param    eax - ulFunction    Function number to call. | 
|---|
| 273 | ; @param    edx - pvParam       Parameter packet for that function. | 
|---|
| 274 | ; @uses     eax, edx, ecx | 
|---|
| 275 | ; @sketch   Validate function number | 
|---|
| 276 | ;           Fetch the parameter pacted from user mode and place it on the stack. | 
|---|
| 277 | ;           Validate the size field of the parameter packet. | 
|---|
| 278 | ;           Remove the packet header from the stack => we have a callframe for the api. | 
|---|
| 279 | ;           Call the API worker. | 
|---|
| 280 | ;           Return. | 
|---|
| 281 | ; @status   Completely implemented. | 
|---|
| 282 | ; @author   knut st. osmundsen (knut.stange.osmundsen@mynd.no) | 
|---|
| 283 | Win32kAPIRouter proc near | 
|---|
| 284 | ASSUME  ds:FLAT, es:nothing, ss:nothing | 
|---|
| 285 | ; | 
|---|
| 286 | ; Validate function number. | 
|---|
| 287 | ; | 
|---|
| 288 | test    eax,eax | 
|---|
| 289 | jnz     APIR_notnull                ; This code should be faster (though it may look stupid to | 
|---|
| 290 | ; jump around like this). IIRC branch prediction allways | 
|---|
| 291 | ; takes a branch. And btw there are 4 NOPs after this jump! | 
|---|
| 292 | jmp     APIR_InvalidFunction | 
|---|
| 293 |  | 
|---|
| 294 | APIR_notnull: | 
|---|
| 295 | cmp     eax, K32_LASTIOCTLFUNCTION | 
|---|
| 296 | jle     APIR_ValidFunction | 
|---|
| 297 | APIR_InvalidFunction: | 
|---|
| 298 | mov     eax, 0deadbeefh | 
|---|
| 299 | ret | 
|---|
| 300 |  | 
|---|
| 301 | ; | 
|---|
| 302 | ; We have a valid function number now. | 
|---|
| 303 | ; Copy the parameter struct on to the stack. | 
|---|
| 304 | ; | 
|---|
| 305 | APIR_ValidFunction: | 
|---|
| 306 | push    ebp                         ; Make stack frame | 
|---|
| 307 | mov     ebp, esp | 
|---|
| 308 | mov     [ebp+8], eax                ; Save eax on the stack (reserved by caller according to _Optlink) | 
|---|
| 309 | mov     ecx, acbK32Params[eax*4]    ; ecx <- size of parameter packet. | 
|---|
| 310 | sub     esp, ecx                    ; Reserve stack space for the parameter packet. | 
|---|
| 311 | mov     eax, [pulTKSSBase32]        ; Calculate the FLAT address of esp. | 
|---|
| 312 | mov     eax, [eax] | 
|---|
| 313 | add     eax, esp                    ; eax <- flat address of ss:esp | 
|---|
| 314 | push    ecx                         ; Save the size. | 
|---|
| 315 | ; TKFuBuff(pv, pvParam, acbParams[ulFunction], TK_FUSU_NONFATAL); | 
|---|
| 316 | push    0                           ; TK_FUSU_NOFATAL | 
|---|
| 317 | push    ecx                         ; Size of parameter packet | 
|---|
| 318 | push    edx                         ; Pointer to user memory to fetch | 
|---|
| 319 | push    eax                         ; Pointer to target memory. | 
|---|
| 320 | call    _TKFuBuff@16                ; __stdcall (cleanup done by the called function) | 
|---|
| 321 | pop     ecx                         ; Restore size | 
|---|
| 322 | test    eax, eax | 
|---|
| 323 | jz      APIR_FetchOK | 
|---|
| 324 | jmp     APIR_end | 
|---|
| 325 |  | 
|---|
| 326 | ; | 
|---|
| 327 | ; Parameter packet is now read onto the stack. esp is pointing to it. | 
|---|
| 328 | ; Check the size of the struct as the caller sees it. | 
|---|
| 329 | ; | 
|---|
| 330 | APIR_FetchOK: | 
|---|
| 331 | cmp     ecx, [esp]                  ; (esp now point at the parameter struct) | 
|---|
| 332 | je      APIR_sizeok | 
|---|
| 333 | mov     eax, ERROR_BAD_ARGUMENTS    ; return code. | 
|---|
| 334 | jmp     APIR_end | 
|---|
| 335 |  | 
|---|
| 336 | ; | 
|---|
| 337 | ; The size is correct. | 
|---|
| 338 | ; Call the worker and return. | 
|---|
| 339 | ; | 
|---|
| 340 | APIR_sizeok: | 
|---|
| 341 | add     esp, SIZE K32HDR            ; Skip the parameter header. | 
|---|
| 342 | mov     eax, [ebp + 8]              ; Restore function number. | 
|---|
| 343 | mov     eax, apfnK32APIs[eax*4]     ; eax <- address of the K32 API worker. | 
|---|
| 344 | call    eax                         ; Call the worker. | 
|---|
| 345 | ; No cleanup needed as leave takes care of that | 
|---|
| 346 | ; We're ready for returning. | 
|---|
| 347 | APIR_end: | 
|---|
| 348 | leave | 
|---|
| 349 | ret | 
|---|
| 350 | Win32kAPIRouter endp | 
|---|
| 351 |  | 
|---|
| 352 |  | 
|---|
| 353 | ;; | 
|---|
| 354 | ; This is a stub function which does nothing but returning an error code. | 
|---|
| 355 | ; @return       ERROR_NOT_SUPPORTED | 
|---|
| 356 | k32APIStub proc near | 
|---|
| 357 | mov     eax, ERROR_NOT_SUPPORTED | 
|---|
| 358 | ret | 
|---|
| 359 | k32APIStub endp | 
|---|
| 360 |  | 
|---|
| 361 | CODE32 ends | 
|---|
| 362 |  | 
|---|
| 363 |  | 
|---|
| 364 |  | 
|---|
| 365 |  | 
|---|
| 366 |  | 
|---|
| 367 | CODE16 segment | 
|---|
| 368 | assume cs:CODE16, ds:FLAT | 
|---|
| 369 |  | 
|---|
| 370 | ; | 
|---|
| 371 | ; Thunker used by the InitCallGate procedure call the AllocGDTSelector devhelper. | 
|---|
| 372 | ; | 
|---|
| 373 | Thunk16_AllocGDTSelector: | 
|---|
| 374 | call [_Device_Help] | 
|---|
| 375 | jmp far ptr FLAT:Thunk32_AllocGDTSelector | 
|---|
| 376 |  | 
|---|
| 377 | CODE16 ends | 
|---|
| 378 |  | 
|---|
| 379 | end | 
|---|
| 380 |  | 
|---|