doexec.asm
上传用户:xiaoan1112
上传日期:2013-04-11
资源大小:19621k
文件大小:19k
源码类别:

操作系统开发

开发平台:

Visual C++

  1. page ,132
  2. title doexec -- (xenix) exec a child process
  3. ;***
  4. ;doexec.asm - execute a child process
  5. ;
  6. ; Copyright (c) 1985-1988, Microsoft Corporation.  All rights reserved.
  7. ;
  8. ;Purpose:
  9. ; defines _doexec() - execute a child process (overlay existing process)
  10. ; This is complicated and involves some knowledge of DOS
  11. ; arena headers.
  12. ;
  13. ;*******************************************************************************
  14. ?DF = 1 ; tell cmacros.inc we want to define our own segments
  15. .xlist
  16. include version.inc
  17. include cmacros.inc
  18. include msdos.inc
  19. .list
  20. assumesdata macro seg ;;[1] Newer versions of CMACROS reject
  21. assumes seg,DGROUP ;;[1]
  22. endm ;;[1]
  23. createSeg _TEXT, code, word, public, CODE, <>
  24. createSeg _DATA, data, word, public, DATA, DGROUP
  25. createSeg EXEC, eseg, word, common, DATA, DGROUP
  26. defGrp DGROUP ; define DGROUP
  27. codeOFFSET equ offset _TEXT:
  28. dataOFFSET equ offset DGROUP:
  29. l macro nam ;;[1] Conditionally make label public
  30. nam: ;;[1]
  31. endm ;;[1]
  32. arena struc ; first 5 bytes of the arena header
  33. sig db 0 ; 'M' or 'Z' for last block
  34. own dw 0 ; PSP value of owner process or 0 if free
  35. asiz dw 0 ; size of block (not including header)
  36. arena ends
  37. extrn b$EX_MSG_BEG:FAR ;[1]
  38. extrn b$EX_MSG_END:FAR ;[1]
  39. sBegin data
  40. assumesdata ds ;[1]
  41. externW _psp ; psp segment
  42. externB _osmajor  ; dos major version number
  43. externW _sigintseg  ; SIGINT default signal handler (segment)
  44. externW _sigintoff  ; SIGINT default signal handler (offset)
  45. globalW _p_overlay,2  ; OLD_P_OVERLAY value
  46. staticW freepsp,0  ; arena of last free segment contiguous with PSP
  47. staticW emsg,<2+ OFFSET b$EX_MSG_BEG> ;[1] +2 to skip first msg number
  48. staticW emsgseg,<SEG b$EX_MSG_BEG>    ;[1]
  49. staticW emsgln,<OFFSET b$EX_MSG_END>;[1] must subtract emsg from it
  50. staticD target,0  ; for long jump to 'exec code'
  51. sEnd
  52. FCB1 = 5ch ; offset in psp
  53. FCB2 = 6ch
  54. DOS2CMD= 280h ; size of DOS 2.0 non-resident COMMAND.COM
  55. externP execve
  56. sBegin eseg
  57. dd execve ; force in execve() if called from spawnve
  58. sEnd
  59. sBegin code
  60. assumes cs,code
  61. assumesdata ds ;[1]
  62. page
  63. ;***
  64. ;_doexec - execute a child process (overlay existing)
  65. ;
  66. ;Purpose:
  67. ;
  68. ;Entry:
  69. ;
  70. ;Exit:
  71. ;
  72. ;Uses:
  73. ;
  74. ;Exceptions:
  75. ;
  76. ;*******************************************************************************
  77. cProc _doexec,<PUBLIC>,<si,di>
  78. parmw flag
  79. parmdp nam
  80. parmw nlength
  81. parmdp command
  82. parmdp envblock
  83. parmw elength
  84. parmw siz
  85. parmw initss
  86. parmw initsp
  87. parmw initcs
  88. parmw initip
  89. parmw fsiz
  90. cBegin
  91. ; exec overlays the current process using its PSP and all memory
  92. ; above it.
  93. push ds ; save DGROUP
  94. ; check for trashed arena before we go on - will assume OK from here on
  95. ; DGROUP is on the top of the stack
  96. assumes ds,nothing
  97. l checkmem
  98. pop ds ; restore DGROUP
  99. assumesdata ds ;[1]
  100. mov bx,-1 ; request max memory
  101. callos allocmem ; will always fail
  102. cmp al,E_arena
  103. je ov0 ;   arena is trashed
  104. ; find out how much contiguous memory there is that is either free
  105. ; or belongs to the current process
  106. mov bx,[_psp]
  107. mov dx,bx ; dx = current owner
  108. dec bx ; bx = current arena header
  109. xor cx,cx ; last free block in contiguous area
  110. push ds ; save DGROUP
  111. l maxloop
  112. assumes ds,nothing
  113. mov ds,bx ; ds = current arena
  114. mov ax,ds:[own]
  115. cmp ax,dx ; do we own it?
  116. je maxadd ;   yes - count it
  117. or ax,ax ; is it free?
  118. jne maxend ;   no - end of contiguous memory
  119. mov cx,bx ; last free block of memory
  120. l maxadd
  121. inc bx
  122. add bx,ds:[asiz]
  123. jc checkmem ;   carry - assuming arena is trashed
  124. mov al,ds:[sig] ; get arena signature
  125. cmp al,'M' ; are we at end of memory?
  126. je maxloop ;   no - have good next block
  127. cmp al,'Z' ;
  128. jne checkmem ;   unknown sig byte - assuming arena is trashed
  129. ; bx = top of contiguous area for current process
  130. ; cx = last free segment contiguous with PSP
  131. l maxend
  132. sub bx,dx ; bx = size
  133. pop ds ; restore DS
  134. assumesdata ds ;[1]
  135. mov [freepsp],cx ; save last free segment contiguous with PSP
  136. cmp [_osmajor],2 ; see if 2.x or above
  137. ja nohole ;   3.x or above, don't need hole for loader
  138. sub bx,DOS2CMD+1 ; leave 280h paras (10K) for the system's loader
  139. jnc nohole ;   enough space
  140. ;----- memory overflow or error before user memory is released
  141. l ov
  142. mov ax,E_nomem ; not enough memory
  143. l ov0
  144. mov AH,4CH ;[1]get code to terminate
  145. INT 21H ;[1]immediate termination
  146. ;-----
  147. l nohole
  148. ; see how big the exec code will be. it must sit in hi mem. it consists of
  149. ; code between a: and z: below (or b: and y: for .coms), the filename, (in the
  150. ; case of .exe files) a para of data (initial register values), and some room
  151. ; (160 bytes) for a local stack
  152. STKSIZ= 160
  153. exesz= z-a
  154. exeln= exesz + STKSIZ ; .exe loader size + stack
  155. comsz = y-b
  156. comln= comsz + STKSIZ ; .com loader size + stack
  157. push bx ; save max length possible
  158. sub [emsgln],offset b$EX_MSG_BEG ;[1] compute message length
  159. mov ax,[emsgln] ;[1] need emsgln in calculations
  160. add ax,BYTE PTR exeln ;[2] assume .exe
  161. cmp flag,0
  162. je join0 ;   was .exe
  163. ___tmp= comln-exeln
  164. add ax,BYTE PTR ___tmp ;[2] was .com
  165. l join0
  166. mov cl,4
  167. add ax,nlength ; plus filename
  168. add ax,0fh ; exec code rounded up to next para
  169. shr ax,cl ; (ax) = paras for exec code
  170. mov dx,elength ; new env length (in bytes)
  171. add dx,0fh ; env rounded up to next para
  172. shr dx,cl ; (dx) = paras for new env
  173. pop bx ; restore the maximum length to bx
  174. ; ax = exec code + data size
  175. ; dx = environment size
  176. ; bx = PSP contiguous size
  177. sub bx,dx ; reduce PSP by environment segment
  178. jbe ov
  179. sub bx,2 ; reduce by 2 (arena header + DOS 4.0 slop)
  180. jc ov
  181. ; bx = PSP contiguous size
  182. mov cx,siz ; cx = assumed .exe size
  183. cmp flag,0 ; .exe or .com?
  184. je join1 ;   was .exe
  185. mov cx,fsiz ; size of .com child in paras
  186. inc cx ; plus para for stack
  187. jz ov
  188. l join1
  189. add cx,10h ; child must have a PSP
  190. jc ov
  191. ; ax = exec code + data size
  192. ; cx = minimum size of child
  193. ; bx = PSP contiguous size
  194. cmp bx,cx ; enough for child?
  195. jb ov ;   no
  196. push ax ; save exec code size
  197. push dx ; save env size
  198. ; allocate and link all free memory in the system
  199. ; assume the arena is good here and all errors are not enough memory
  200. xor cx,cx ; cx = free link
  201. l allocloop
  202. mov bx,1 ; allocate 1 paragraph block
  203. callos allocmem
  204. jc allocall ;   all linked up
  205. mov es,ax ; es = segment to allocate
  206. mov bx,-1 ; bx = maximum request
  207. l allocretry
  208. callos setmem ; grow segment
  209. jc allocretry ;  force it to be allocated
  210. mov es:[0],cx ; save last free block
  211. mov cx,es ; cx = current free link
  212. mov dx,bx ; dx = size of last block
  213. jmp allocloop ; keep allocating
  214. l allocall
  215. mov bx,dx
  216. ; es = cx = free segment linked list
  217. ; bx = size of last free block
  218. cmp [_osmajor],2 ; check for DOS 2.0
  219. jne allocenv ;   no - just try allocing environment
  220. sub bx,DOS2CMD+1 ; size to cut back
  221. jnc shrinkdos2
  222. ;----- release all "free" blocks because of error
  223. l freefree  ; free all linked up "free" memory
  224. jcxz allfree
  225. mov es,cx
  226. mov cx,es:[0] ; next free block
  227. callos freemem
  228. jnc freefree ; keep freeing linked blocks
  229. l allfree ; if freemem error, just give up
  230. jmp ov ; fail with no memory error
  231. ;-----
  232. l shrinkdos2
  233. callos setmem
  234. jc freefree ; any error at this point is no memory
  235. ; es = cx = free segment linked list
  236. ; bx = size of last free block
  237. l allocenv
  238. pop dx ; dx = environment size
  239. push dx
  240. inc dx
  241. inc dx ; dx = envsize + 2 (for arena header + DOS 4.0)
  242. sub bx,dx
  243. jnc haveenv ; have space in this block for environment
  244. ; no space for environment in this block - try end of PSP contiguous area
  245. mov ax,[freepsp] ; ax = last free segment in PSP-contiguous area
  246. or ax,ax
  247. jz tryotherfree ;   none here - try other free blocks
  248. inc ax ; convert arena address to segment address
  249. mov es,ax
  250. mov bx,-1
  251. callos setmem ; find size of segment
  252. cmp al,E_nomem
  253. jne freefree ;   must be something like arena trashed
  254. sub bx,dx ; enough room?
  255. jnc haveenv ;   yes - do actual environment allocation
  256. ; else go try somewhere else
  257. ; try other free blocks if above attempts fail
  258. l tryotherfree
  259. jcxz allfree
  260. mov ax,cx
  261. ;
  262. ; dx = environment size in paragraphs + 2 (for arena hdr + DOS 4.0 slop)
  263. ; cx = pointer to beginning of "free" list (segment address)
  264. ; ax = pointer into "free" list (segment address)
  265. ;
  266. l tryotherloop
  267. dec ax ;[1] AX = header address (temporarily)
  268. mov es,ax ;    header of current free block
  269. mov bx,es:[asiz] ;    size of current free block (in header)
  270. inc ax ;[1] convert header addr back into seg addr
  271. mov es,ax ;[1] AX = ES = segment address
  272. sub bx,dx ; will environment fit?
  273. jnc haveenv ;   yes - do actual environment allocation
  274. mov ax,es:[0] ; else go on to next free block
  275. or ax,ax ; end of list?
  276. jz freefree ;   yes - not enough memory; clean up and fail
  277. jmp short tryotherloop ; keep trying
  278. ; es = segment to shrink for environment
  279. ; bx = size to which to shrink chosen "free" segment
  280. l haveenv
  281. callos setmem
  282. jc freefree ; any error at this point is no memory
  283. pop bx
  284. callos allocmem ; allocate environment segment
  285. jc freefree ; any error at this point is no memory
  286. ; ax = environment segment
  287. mov es,[_psp]
  288. mov bx,es
  289. mov es:[DOS_envp],ax ; new env segment
  290. mov es,ax
  291. xor di,di ; es:di points to new env
  292. if sizeD
  293. push ds ; save DGROUP
  294. lds si,envblock
  295. else
  296. mov si,envblock
  297. endif
  298. mov cx,elength
  299. rep movsb ; move env to new segment
  300. if sizeD
  301. pop ds ; restore DGROUP
  302. endif
  303. mov dx,es ; dx = environment segment
  304. ; bx = PSP
  305. ; dx = environment segment
  306. push dx ; save needed registers
  307. push bx
  308. cmp _sigintseg,0 ; has ^C been hooked ?
  309. je letsgo ; no, do the exec
  310. push ds
  311. mov dx,_sigintoff ; load system default address
  312. mov ds,_sigintseg ; load system default segment
  313. mov ax,DOS_setvector shl 8 + 23H ; reset ^C vector (INT 23H)
  314. callos
  315. pop ds ; restore registers
  316. l letsgo
  317. ;
  318. ; IMPORTANT NOTE:
  319. ;
  320. ; DOS 3.30 and later allow the user to increase the size of the
  321. ; file handle table.  If the file handle count > 20, then a far
  322. ; segment is allocated to store the table.  This segment must be
  323. ; freed up before the child program is exec-ed.  This code relies
  324. ; on the fact that DOS will free up that far segment if the handle
  325. ; count is set back to 20.  If DOS ever changes, this code will fail.
  326. ;
  327. mov ax,word ptr [_osmajor]
  328. xchg ah,al ; AH = _osmajor, AL = _osminor
  329. cmp ax,(3 shl 8) + 30
  330. jb pre_DOS330 ; _osmajor:_osminor < 3:30?
  331. mov bx,20 ; IF >= DOS 3.30 THEN
  332. mov ah,67h ; Set Handle Count on principle
  333. callos ; set number of handles to default value
  334. pre_DOS330:
  335. pop bx
  336. pop dx
  337. ; WARNING - any errors past this point - must go to execpanic
  338. ; now free all blocks of memory belonging to this process
  339. ; except the PSP and new environment block
  340. ; bx = PSP
  341. ; dx = environment segment
  342. l freemore
  343. push bx ; save PSP
  344. mov ah,52h ; magic DOS call
  345. int 21h
  346. mov ax,es:[bx-2] ; ax = first arena segment!!!
  347. pop bx ; restore PSP
  348. ; ax = current segment to check
  349. l findused
  350. mov es,ax
  351. inc ax
  352. cmp ax,bx ; is it PSP?
  353. je atend ;   yes - skip
  354. cmp ax,dx ; is it environment?
  355. je atend ;   yes - skip
  356. cmp es:[own],bx ; do we own it?
  357. jne atend ;   no -skip
  358. mov es,ax ; es = must be one past arena header
  359. callos freemem ; free up the segment
  360. jmp freemore ;   and start over - even if error
  361. l atend
  362. add ax,es:[asiz] ; add in segment size
  363. jc freemore ;   error - changed arena - retry
  364. cmp es:[sig],'Z' ; last segment?
  365. jne findused ;   no - check next segment
  366. ; increase size of PSP to maximum amount available
  367. ;
  368. ; bx = PSP
  369. mov es,bx ; es= PSP
  370. mov bx,-1
  371. callos setmem
  372. callos setmem ; allocates on second try
  373. jnc bigPSP
  374. l execpanic ; error in exec after memory freed
  375. mov dx,word ptr [emsg] ;[1] DS:DX = "Not enough memory"
  376. mov ax,word ptr [emsgseg] ;[1]
  377. mov ds,ax ;[1]
  378. callos message
  379. mov ax,DOS_terminate shl 8 + 255
  380. callos ; error code = 255
  381. l bigPSP
  382. mov ax,es
  383. add ax,bx ; bx = size of PSP block
  384. mov es:[DOS_maxpara],ax ; set new memory limit in PSP
  385. ; ax = top of PSP segment
  386. ; ((sp)) = (exec code size)
  387. pop cx ; cx = exec code size
  388. sub bx,cx ; reduce PSP size
  389. jc execpanic
  390. sub ax,cx
  391. mov word ptr [target+2],ax ; set up final jump address
  392. ; move the exec code and its data up to hi mem
  393. ;
  394. ; ax = exec code segment
  395. mov es,ax ; es = exec code segment
  396. push es ; save exec code segment
  397. push ds ; save DGROUP
  398. push cs
  399. pop ds ; ds points into code segment
  400. xor di,di
  401. mov cx,BYTE PTR exesz ;[1] assume exe file
  402. mov si,codeOFFSET a
  403. cmp flag,0 ; .exe or .com?
  404. je exe4 ;   .exe
  405. mov cx,BYTE PTR comsz ;[1]
  406. mov si,codeOFFSET b
  407. l exe4
  408. rep movsb ; move code to exec code segment
  409. pop ds ; restore DGROUP
  410. push ds ;[1] save DGROUP
  411. mov cx,[emsgln] ;[1] count of bytes to move
  412. mov si,word ptr [emsg] ;[1] DS:SI = start of 3 error messages
  413. mov ax,word ptr [emsgseg] ;[1]
  414. mov ds,ax ;[1]
  415. rep movsb ;[1] move 3 error messages
  416. pop ds ;[1] restore DGROUP
  417. mov bx,di ; (bx) = offset of data/name (save)
  418. cmp flag,0 ; .exe or .com?
  419. jne com5 ;   .com
  420. ; for .exe save initial register values
  421. mov ax,initss
  422. stosw
  423. mov ax,initsp
  424. stosw
  425. mov ax,initcs
  426. stosw
  427. mov ax,initip
  428. stosw
  429. l com5
  430. if sizeD
  431. push ds ; save DGROUP
  432. lds si,nam
  433. else
  434. mov si,nam
  435. endif
  436. mov cx,nlength
  437. rep movsb ; move name
  438. if sizeD
  439. pop ds ; restore DGROUP
  440. endif
  441. ; exec code and its data are in hi mem. set the dma and fix the psp (the
  442. ; command line at offset 80h, and the fcbs)
  443. mov es,[_psp] ; psp seg
  444. ; set the dma to psp:80h
  445. push ds ; save DGROUP
  446. push es
  447. pop ds ; psp segment
  448. mov dx,80h ; default dma=psp:80h
  449. callos setdma
  450. pop ds ; restore DGROUP
  451. ; set up the command line
  452. mov di,DOS_cmdline
  453. if sizeD
  454. push ds ; save DGROUP
  455. lds si,command
  456. else
  457. mov si,command
  458. endif
  459. mov cl,[si] ; length of command
  460. inc cx ; (ch) = 0 from last rep movsb (name)
  461. inc cx ; count byte & terminating <cr>
  462. rep movsb ; move the command line into psp:80h
  463. ; set up the fcbs
  464. mov dx,bx ; (dx) = data/name offset
  465. mov di,FCB1 ; fcb at offset 5ch
  466. xchg ax,cx ; null byte to store
  467. ; (cx) = 0 from last rep movsb (command line)
  468. mov cx,20h ; length of 2 fcbs
  469. rep stosb ; zero the fcbs
  470. mov di,FCB1 ; fcb at offset 5ch
  471. if sizeD
  472. lds si,command
  473. else
  474. mov si,command
  475. endif
  476. inc si ; si points to arg1 (or space before it)
  477. mov ax,DOS_fcbparse shl 8 + 1
  478. callos ; parse filename
  479. cmp al,0ffh ; see if invalid drive letter
  480. je bad1
  481. xor al,al
  482. l bad1
  483. mov bl,al ; first drive letter
  484. mov di,FCB2 ; second fcb in psp
  485. mov ax,DOS_fcbparse shl 8 + 1
  486. callos ; parse filename
  487. cmp al,0ffh ; see if invalid drive letter
  488. je bad2
  489. xor al,al
  490. l bad2
  491. mov bh,al ; bx = drive letter flags
  492. if sizeD
  493. pop ds ; restore DGROUP
  494. endif
  495. ; setup stack in exec code segment
  496. pop cx ; exec code segment
  497. mov si,dx ; data/name offset in exec code
  498. add si,STKSIZ ; push it up to produce a stack
  499. cmp flag,0 ; .exe or .com? (last frame reference)
  500. mov bp,bx ; initial ax
  501. cli ; disable interrupts until stack set up
  502. mov ss,cx
  503. mov sp,si
  504. sti ; temporary stack set up
  505. jne join6 ;   was .com
  506. push dx ; save data offset to init. register values
  507. add dx,8 ; name offset in hi mem
  508. l join6
  509. mov ax,es ; (ax) = paras from 0:0 to psp:0
  510. add ax,10h ; (ax) = paras from 0:0 to parameter block
  511. mov bx,100h ; psp:100h is parameter block for load/exec
  512. mov es:[bx],ax ; word segment address to load at
  513. mov es:[bx+2],ax ; word relocation factor to be applied
  514. push ax ; save relocation factor
  515. mov ax,DOS_exec shl 8 + 3
  516. ; (ax) = dos code for load/exec (4b03h)
  517. ; (dx) = name offset in exec segment
  518. ; (es:bx) = psp:100 (parameter block)
  519. ; (ds) = DGROUP seg
  520. ; (bp) = initial ax
  521. ;
  522. ; di and si are free
  523. jmp dword ptr [target] ; and away we go!
  524. ;-----------------------------------------------------------------------------
  525. NOMEM equ 5
  526. BADFORM equ 6
  527. BADENV equ 7
  528. execom macro lab,fil
  529. l lab
  530. push cs
  531. pop ds ; DS = exec code segment
  532. callos ; overlay parent with child
  533. jnc allok&lab
  534. mov bx,BADFORM - NOMEM
  535. cmp al,E_ifunc ; invalid format
  536. je die&lab
  537. mov bl,BADENV - NOMEM
  538. cmp al,E_badenv ; bad environment
  539. je die&lab
  540. mov bl,BADFORM - NOMEM
  541. cmp al,E_badfmt ; bad format
  542. je die&lab
  543. xor bx,bx ; NOMEM - NOMEM
  544. l die&lab
  545. push cs
  546. pop es ; es = exec code segment
  547. xor ax,ax
  548. mov cx,-1
  549. mov di,BYTE PTR fil&sz ;[2]
  550. or bx,bx
  551. jz outmsg&lab
  552. jmp short nmsg&lab
  553. ; Warning if you change this section above you must
  554. ; leave the following bytes for DOS 2.0 to walk all
  555. ; over without walking on data DOS walks on DS:2E to
  556. ; DS:31  extra slop just incase!
  557. org lab + 32h
  558. l nmsg&lab
  559. repne scasb
  560. inc di ; skip past message number
  561. inc di
  562. dec bx
  563. jnz nmsg&lab
  564. l outmsg&lab
  565. mov dx,di
  566. callos message
  567. mov ax,DOS_terminate shl 8 + 255
  568. callos ; terminate (255)
  569. l allok&lab
  570. endm
  571. ;-----------------------------------------------------------------------------
  572. ;
  573. ; .exe  exec code
  574. execom a,exe ; expand for .exe file
  575. pop di ; relocation factor
  576. pop si ; data offset of initial register values
  577. lodsw ; initss
  578. add ax,di ; relocation factor (paras) from 0:0
  579. xchg dx,ax
  580. lodsw ; initsp
  581. cli
  582. mov ss,dx ; reloc'd ss
  583. mov sp,ax
  584. sti
  585. lodsw ; initcs
  586. add di,ax
  587. lodsw
  588. push di ; save INIT CS
  589. push ax ; save INIT IP
  590. push es
  591. pop ds ; es = ds = PSP
  592. mov ax,bp ; ax = valid drive letter flags
  593. xglobal proc far
  594. ret ; force far return to dos int 21h handler
  595. xglobal endp
  596. z:
  597. ;-----------------------------------------------------------------------------
  598. ;
  599. ; .com  exec code
  600. execom b,com ; expand for .com file
  601. pop di ; burn relocation factor (not used)
  602. mov bx,cs ; get exec code segment
  603. mov ax,es ; get PSP segment
  604. sub bx,ax ; bx = size of program area (in paragraphs)
  605. mov cl,4
  606. test bx,0f000h ; will we lost precision when we shift?
  607. jz doit
  608. mov bx,1000h ;   yes, set ss:sp = psp:0000
  609. doit:
  610. shl bx,cl ; make byte offset from psp:0
  611. dec bx
  612. dec bx
  613. cli ; disable interrupts until stack's ok
  614. mov ss,ax
  615. mov sp,bx ; reserved para offset (stack grows down)
  616. sti ; enable interrupts; stack's ok now
  617. mov word ptr ss:[bx],0 ; put 0000 on top of stack for return
  618. push es
  619. mov ax,100h
  620. push ax ; INIT CS:IP = PSP:100h
  621. push es
  622. pop ds ; DS = ES = CS = PSP
  623. mov ax,bp ; ax = valid drive letter flags
  624. cglobal proc far
  625. ret ; force far return
  626. cglobal endp
  627. y:
  628. cEnd nogen
  629. sEnd
  630. end