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.

375 lines
12 KiB

  1. ;***************************************************************************
  2. ;* REBOOT.ASM
  3. ;*
  4. ;* Contains routines used to support a local reboot in the Sys
  5. ;* VM. To do this, we interact with USER and the Reboot VxD.
  6. ;*
  7. ;* This functionality is only present in the 386 KERNEL.
  8. ;*
  9. ;* The KRebootInit function is called just after USER is loaded.
  10. ;*
  11. ;* The Reboot VxD calls the local reboot proc to terminate an app.
  12. ;* The local reboot proc may fail and cause the VxD to trace until
  13. ;* it is able to kill the task. See comments in the local reboot
  14. ;* proc for more details.
  15. ;*
  16. ;* This code must be located in KERNEL due to the internal KERNEL
  17. ;* information it must access.
  18. ;*
  19. ;* Created by JonT starting 12 July 1991
  20. ;*
  21. ;***************************************************************************
  22. TITLE REBOOT - Local Reboot Routines
  23. .xlist
  24. include kernel.inc
  25. include tdb.inc
  26. include protect.inc
  27. include newexe.inc
  28. .list
  29. .386p
  30. MAX_TRACE EQU 5000h
  31. HookInt1 MACRO
  32. mov ax,0204h ;;Tell VxD to hook/unhook Int 1
  33. mov cx,cs ;;Point to ISR
  34. mov dx,codeOFFSET TraceOut
  35. movzx edx,dx
  36. call [lpReboot] ;;Call the VxD API
  37. ENDM
  38. UnhookInt1 MACRO
  39. mov ax,0204h ;;Tell VxD to hook/unhook Int 1
  40. xor cx,cx ;;Pass a zero in CX to unhook
  41. call [lpReboot] ;;Call the VxD API
  42. ENDM
  43. DataBegin
  44. externD lpReboot
  45. externW curTDB
  46. externW hExeHead
  47. externW hUser
  48. externB Kernel_Flags
  49. externB fTaskSwitchCalled
  50. externW wMyOpenFileReent
  51. externB OutBuf
  52. externW pGlobalHeap
  53. EVEN
  54. globalW wLastSeg, 0
  55. globalW wTraceCount, 0
  56. lpOldInt1 DD 0
  57. szUser DB 'USER'
  58. DataEnd
  59. externFP Int21Handler
  60. externFP GetPrivateProfileInt
  61. IFDEF FE_SB
  62. externFP FarMyIsDBCSLeadByte
  63. ENDIF
  64. ;** Note that this goes in the fixed code segment
  65. sBegin CODE
  66. assumes CS,CODE
  67. ; KRebootInit
  68. ; Initializes the KERNEL Local Reboot functionality and talks with
  69. ; the Reboot VxD.
  70. cProc KRebootInit, <FAR,PUBLIC>, <si,di,ds>
  71. cBegin
  72. SetKernelDS
  73. ;** Get the reboot device entry point if it exists
  74. xor di,di ;Get a NULL pointer
  75. mov es,di ; in case there's no reboot device
  76. mov bx,0009h
  77. mov ax,1684h ;Get device entry point
  78. int 2fh
  79. mov ax,es
  80. or ax,di
  81. jz SHORT RI_NoRebootDev
  82. mov WORD PTR lpReboot[0],di
  83. mov WORD PTR lpReboot[2],es
  84. ;** Set the reboot device call back
  85. mov ax, 0201h ;Reboot VxD #201: Set callback addr
  86. mov di,cs
  87. mov es,di
  88. lea di,KRebootProc
  89. lea si, fTaskSwitchCalled ;DS:SI points to task switch flag
  90. call [lpReboot]
  91. RI_NoRebootDev:
  92. cEnd
  93. ; LocalRebootProc
  94. ;
  95. ; Called by the Reboot VxD to cause the current Windows app to be
  96. ; terminated.
  97. cProc KRebootProc, <FAR,PUBLIC>
  98. cBegin nogen
  99. ;** Save all the registers so we can restart if necessary
  100. pusha ;16 bytes
  101. push ds ;2 bytes
  102. push es ;2 bytes
  103. SetKernelDS
  104. mov bp,sp ;Point with BP
  105. ;** If the KERNEL debugger is installed, DON'T trace!
  106. test Kernel_Flags[2],KF2_SYMDEB ;Debugger installed
  107. IF KDEBUG
  108. jz SHORT RP_CheckSeg ;No debugger, try to trace
  109. Trace_Out <'LocalReboot: Debugger installed, nuking app without tracing'>
  110. jmp SHORT RP_NukeIt ;Just try to nuke it here!
  111. ELSE
  112. jnz SHORT RP_NukeIt ;Just try to nuke it here!
  113. ENDIF
  114. ;** Get the code segment we were executing in
  115. RP_CheckSeg:
  116. mov ax,[bp + 22] ;Get CS from stack (IRET frame)
  117. ;** See if the owner of the code segment was loaded before USER
  118. cCall IsBootSeg ;Returns TRUE if owned by boot mod
  119. or ax,ax ;Ok to nuke?
  120. jnz RP_TraceOut ;No, must trace out
  121. RP_NukeIt:
  122. ;** First, we need to get the filename of the .EXE we're about to
  123. ;** nuke. We do this by getting the name out of the module
  124. ;** database. Module databases are not page locked and also
  125. ;** have the fully qualified pathname. So, we copy just the
  126. ;** module name into a buffer in our pagelocked data segment
  127. cld
  128. push ds
  129. pop es
  130. mov di, dataOFFSET OutBuf ;Point to start of buffer
  131. mov ds, curTDB ;Get the current TDB
  132. UnSetKernelDS
  133. mov ds, ds:[TDB_pModule] ;Point to the module database
  134. mov si, WORD PTR ds:[ne_crc + 2] ;Points to length byte of module EXE
  135. mov cl, [si] ;Get length byte
  136. xor ch, ch
  137. sub cl, 8 ;8 bytes of garbage
  138. add si, 8
  139. mov bx, si ;In case we don't find a slash (bad)
  140. RP_SlashLoop:
  141. lodsb ;Get this char
  142. IFDEF FE_SB
  143. call FarMyIsDBCSLeadByte
  144. jc SHORT RP_NoDBCSChar
  145. lodsb
  146. dec cx
  147. jmp SHORT RP_NoSlash ;It is, can't be a slash
  148. RP_NoDBCSChar:
  149. ENDIF
  150. cmp al, '\' ;Is this a slash?
  151. je SHORT RP_Slash ;Yes
  152. cmp al, '/'
  153. jne SHORT RP_NoSlash
  154. RP_Slash:
  155. mov bx, si ;BX points after last slash
  156. RP_NoSlash:
  157. loop RP_SlashLoop
  158. mov cx, si ;Compute count of characters in 8.3 name
  159. sub cx, bx
  160. mov si, bx ;Point to 8.3 name
  161. rep movsb ;Copy the string into OutBuf
  162. xor al, al ;Zero byte
  163. stosb
  164. ;** Call the VxD to put up the app name
  165. push es ;ES points to kernel DS
  166. pop ds
  167. ReSetKernelDS
  168. mov di, dataOFFSET OutBuf ;Point to module name with ES:DI
  169. mov ax, 203h ;Display message through VxD
  170. call [lpReboot]
  171. or ax, ax ;If non-zero, we nuke it
  172. jz SHORT RP_NoNuke
  173. IF KDEBUG
  174. krDebugOut DEB_WARN, <'LocalReboot: Trying to nuke @ES:DI'>
  175. ENDIF
  176. ;** Clean out some static info
  177. mov wMyOpenFileReent, 0 ;Clear reentrant flag for MyOpenFile
  178. ;** Call USER's signal proc for the task
  179. mov es,curTDB ;Get the current TDB
  180. cmp WORD PTR es:[TDB_USignalProc] + 2,0 ;USER signal proc?
  181. jz SHORT @F ;No
  182. mov bx,0666h ;Death knell
  183. mov di,-1
  184. cCall es:[TDB_USignalProc],<es,bx,di,es:[TDB_Module],es:[TDB_Queue]>
  185. @@:
  186. ;** Nuke the app. Does not return
  187. mov ax,4c00h
  188. DOSCALL
  189. ;** We're somewhere in a boot module. Try to trace out by telling
  190. ;** VxD to do another instruction
  191. RP_TraceOut:
  192. mov ax,[bp + 22] ;Get CS from stack (IRET frame)
  193. IF KDEBUG
  194. krDebugOut DEB_WARN, <'LocalReboot: Tracing out of boot module %AX2'>
  195. ENDIF
  196. mov wLastSeg,ax ;Save for next time
  197. mov wTraceCount,0 ;Clear the trace count
  198. HookInt1
  199. ;** Set the trace flag
  200. or WORD PTR [bp + 24],0100h
  201. jmp SHORT RP_SetFlag
  202. ;** Force the trap flag clear on the no nuke case
  203. RP_NoNuke:
  204. and WORD PTR [bp + 24],NOT 0100h
  205. RP_SetFlag:
  206. pop es
  207. pop ds
  208. popa
  209. STIRET ;VxD calls as an interrupt
  210. cEnd nogen
  211. ; TraceOut
  212. ;
  213. ; This routine continues to trace until it traces out of a boot module
  214. ; or until the trace count is up. If it needs to nuke the app,
  215. ; it jumps to RP_NukeIt which depends only on DS being set. This
  216. ; call returns via an IRET since it is called as an INT 1 handler.
  217. cProc TraceOut, <FAR,PUBLIC>
  218. cBegin nogen
  219. ;** Save all the registers so we can restart if necessary
  220. pusha ;16 bytes
  221. push ds ;2 bytes
  222. push es ;2 bytes
  223. SetKernelDS
  224. mov bp,sp ;Point with BP
  225. ;** We keep tracing forever if the heap is locked
  226. push es
  227. mov es, pGlobalHeap ;Point to GlobalInfo structure
  228. cmp es:[gi_lrulock], 0 ;Is the global heap busy
  229. pop es
  230. jne SHORT TO_10 ;Force the trace out
  231. ;** See if the CS is the same as last time
  232. inc wTraceCount ;Bump the count
  233. cmp wTraceCount,MAX_TRACE ;Too many instructions?
  234. IF KDEBUG
  235. jb SHORT TO_10 ;Count not exceeded
  236. mov cx,MAX_TRACE ;Get trace count
  237. Trace_Out <'LocalReboot: Trace count (#CXh instructions) exceeded'>
  238. jmp SHORT TO_Reboot
  239. ELSE
  240. jae SHORT TO_Reboot ;Yes, too many, nuke it
  241. ENDIF
  242. TO_10: mov ax,[bp + 22] ;Get the CS from the IRET frame
  243. cmp ax,wLastSeg ;Same as last time?
  244. je SHORT TO_StillBad ;Yes, don't bother looking up
  245. mov wLastSeg,ax ;Save as last executed segment
  246. mov bx,cs ;Get our CS
  247. cmp ax,bx ;Our segment?
  248. je SHORT TO_StillBad ;Yes, can't nuke here!
  249. cCall IsBootSeg ;Returns TRUE if owned by boot mod
  250. or ax,ax ;Ok to nuke?
  251. jnz SHORT TO_StillBad ;No, must continue tracing
  252. IF KDEBUG
  253. mov cx,wTraceCount ;Get trace count
  254. Trace_Out <'LocalReboot: Traced out after #CXh instructions'>
  255. ENDIF
  256. ;** Unhook the interrupt handler and kill the app now
  257. TO_Reboot:
  258. UnhookInt1
  259. jmp RP_NukeIt ;Try to nuke the app
  260. ;** Restore the registers and restart
  261. TO_StillBad:
  262. or WORD PTR [bp + 24],0100h ;Set the trace flag
  263. pop es
  264. pop ds
  265. popa
  266. iret ;VxD calls as an interrupt
  267. cEnd nogen
  268. ; IsBootSeg
  269. ;
  270. ; Tries to find a code segment somewhere in the initial segments
  271. ; loaded before USER. The CS value is passed in AX. Returns
  272. ; TRUE iff the CS was found in a boot module.
  273. cProc IsBootSeg, <NEAR,PUBLIC>
  274. cBegin nogen
  275. SetKernelDS
  276. mov dx,ax ;Put CS in DX for call
  277. mov es,hExeHead ;Get the first module on chain
  278. IBS_Loop:
  279. cCall IsModuleOwner ;See if we can find the owner
  280. or ax,ax ;Found?
  281. jnz SHORT IBS_End ;Yes, return TRUE
  282. mov ax,es ;Get the module handle
  283. cmp ax,hUser ;If we just tried USER, we're done
  284. je SHORT IBS_NotFound ;Not found
  285. mov es,es:[6] ;Nope, get next module to try
  286. jmp IBS_Loop
  287. IBS_NotFound:
  288. xor ax,ax ;Return FALSE
  289. IBS_End:
  290. cEnd
  291. ; IsModuleOwner
  292. ;
  293. ; Checks in the EXE header to see if the given segment is in this
  294. ; module.
  295. ; DX is the segment, ES points to the module database
  296. ; Returns TRUE/FALSE in AX. Doesn't trash DX.
  297. cProc IsModuleOwner, <NEAR,PUBLIC>
  298. cBegin nogen
  299. xor ax,ax ;Get a FALSE just in case
  300. mov cx,es:[ne_cseg] ;Get max number of segments
  301. jcxz SHORT IMO_End ;No segments
  302. mov di,es:[ne_segtab] ;Point to the segment table
  303. IMO_SegLoop:
  304. cmp dx,es:[di].ns_handle ;Is this the correct segment entry?
  305. jz SHORT IMO_FoundIt ;Yes, get out
  306. add di,SIZE new_seg1 ;Bump to next entry
  307. loop IMO_SegLoop ;Loop back to check next entry
  308. jmp SHORT IMO_End ;Didn't find it
  309. IMO_FoundIt:
  310. mov ax,1 ;Return that we found it here
  311. IMO_End:
  312. cEnd
  313. sEnd
  314. END