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.

2005 lines
48 KiB

  1. ;++
  2. ;
  3. ; Module name
  4. ;
  5. ; su.asm
  6. ;
  7. ; Author
  8. ;
  9. ; Thomas Parslow (tomp) Jan-15-91
  10. ;
  11. ; Description
  12. ;
  13. ; Startup module for the 386 NT OS loader.
  14. ;
  15. ; Exported Procedures
  16. ;
  17. ; EnableProtectPaging
  18. ;
  19. ; Notes
  20. ; NT386 Boot Loader program. This assembly file is required in
  21. ; order to link C modules into a "/TINY" (single segment) memory
  22. ; model.
  23. ;
  24. ;
  25. ; This file does the following:
  26. ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  27. ; 1) Defines the entry point for the boot loader's startup program
  28. ; 2) Computes what values should actually be in the DS and SS registers.
  29. ; 3) Provides the int bios functionality
  30. ; 4) Provides 386/486 mode (protect/paging) switching code.
  31. ;
  32. ; The OS/2 bootstrap routine (boot sector) loads the boot loader program at
  33. ; real-mode address 2000:0000 with the following register values:
  34. ;
  35. ; CS = 2000
  36. ; IP = 0000
  37. ; DS = 07C0
  38. ; ES = 1000
  39. ; SS = 0000
  40. ; SP = 7C00
  41. ;
  42. ; The PXE boot PROM loads the boot loader program at real-mode address
  43. ; 0000:7C00 with the following register values:
  44. ;
  45. ; CS = 0000
  46. ; IP = 7C00
  47. ; DS = Data segment of PXE boot PROM
  48. ; SS = Stack segment of PXE boot PROM
  49. ; SP = Stack pointer of PXE boot PROM (at least 1K free)
  50. ; ES = 16-bit, real-mode, segment of PXENV Entry Point structure
  51. ; BX = 16-bit, real-mode, offset of PXENV Entry Point structure
  52. ; EDX = 32-bit, physical, address of PXENV Entry Point structure
  53. ;
  54. ; For a boot from an SDI image, startrom is loaded at real-mode address
  55. ; 0000:7C00 with the following register values:
  56. ;
  57. ; CS = 0000
  58. ; IP = 7C00
  59. ; DS = don't care
  60. ; SS = Caller-defined stack segment
  61. ; SP = Caller-defined stack pointer
  62. ; EDX = physical address of page-aligned SDI image ORed with 0x41
  63. ;
  64. ; This startup module relocates itself to 2000:0 and changes the CS and IP
  65. ; register values to:
  66. ;
  67. ; CS = 2000
  68. ; IP = 0000
  69. ;
  70. ; Build Notes:
  71. ; ~~~~~~~~~~~~
  72. ; The microsoft C compiler will not produce "tiny" model programs. In the
  73. ; tiny model, the entire program consists of only one segment. The small
  74. ; model produced by our compilers consists of two segments: DGROUP and _TEXT.
  75. ; If you convert a small model program into a tiny model program, DS (which
  76. ; should point to DGROUP (bss,const,data) will always be wrong. For this reason
  77. ; we need an assembly module to do a simple run-time fixup on SS and DS. To
  78. ; guarantee that DS will point to DGROUP no matter where os2ldr is loaded,
  79. ; the paragraph (shifted right four bits) offset of DGROUP from _TEXT must
  80. ; be added to the value in CS to compute DS and SS.
  81. ;
  82. ; We get the linker to fixup the offset of the beginning of the dgroup segment
  83. ; relative to the beginning of the code segment and it's this value added
  84. ; to the value in CS that allows us to build a "tiny" model program in C
  85. ; without a lot of munging around in order to get the data reference offsets
  86. ; in the code correct.
  87. ;
  88. ; If the _TEXT:DGROUP fixup appears in other files (which it does), the linker
  89. ; will not compute the correct value unless the accumulated data pointer is
  90. ; zero when it gets there. Therefore, no data should be placed in the data segment
  91. ; until after all instances of _TEXT:DGROUP have been encountered by the linker.
  92. ; The linker processes files from right to left on the command line.
  93. ;
  94. ; A Note About Stacks
  95. ; Initially we run on our internal stack (SuStack) which is only 160 bytes deep
  96. ; but seems to do the trick. Then we have to have a separate double fault stack.
  97. ; This stack can be in the middle of the stack/data segment. It will step on
  98. ; the loader image, but that's ok since the fault was either caused by 16bit
  99. ; code (which won't be in the loader image) or, it was caused by the 32bit
  100. ; loader (which has already been relocated) so we won't be stepping on code
  101. ; that may have caused the fault. And finally, we have the "call back" stack
  102. ; which starts at the top of the stack/data segment. We use this during
  103. ; all call backs since the original loader source is no longer needed and
  104. ; this'll give us plenty of stack for bios calls etc.
  105. ;
  106. ;--
  107. DoubleWord struc
  108. lsw dw ?
  109. msw dw ?
  110. DoubleWord ends
  111. ;
  112. ; This is the structure used to pass all shared data between the boot sector
  113. ; and NTLDR.
  114. ;
  115. SHARED struc
  116. ReadClusters dd ? ; function pointer
  117. ReadSectors dd ? ; function pointer
  118. SectorBase dd ? ; starting sector
  119. ; for ReadSectors
  120. ; callback
  121. SHARED ends
  122. BPB struc
  123. BytesPerSector dw ?
  124. SectorsPerCluster db ?
  125. ReservedSectors dw ?
  126. Fats db ?
  127. DirectoryEntries dw ?
  128. Sectors dw ?
  129. Media db ?
  130. FatSectors dw ?
  131. SectorsPerTrack dw ?
  132. Heads dw ?
  133. HiddenSectors dd ?
  134. SectorsLong dd ?
  135. ;
  136. ; The following byte is NOT part of the BPB but is set by SYS and format
  137. ;
  138. BootDriveNumber db ?
  139. BPB ends
  140. SU_CODEMODULE equ 1 ; Identifies this module to "su.inc"
  141. include su.inc
  142. include macro.inc
  143. extrn _BootRecord:word
  144. extrn _puts:near
  145. extrn _MemoryDescriptorList:near
  146. extrn _InsertDescriptor:near
  147. extrn _NetPcRomEntry:near
  148. extrn GetKeyEx:near
  149. extrn GetCounterReal:near
  150. include pxe_api.inc ; Included for PXENV Entry Point
  151. ; structure. Also includes
  152. ; pxe_cmn.inc file.
  153. MAXREAD EQU 10000h
  154. MAXSECTORS EQU MAXREAD/0200h
  155. _TEXT segment para use16 public 'CODE'
  156. ASSUME CS: _TEXT, DS: DGROUP, SS: DGROUP
  157. .386p
  158. ;
  159. ; Run-time fixups for stack and data segment
  160. ;
  161. public Start
  162. Start:
  163. ;
  164. ; The FAT boot sector only reads in the first 512 bytes of NTLDR. This is
  165. ; the module that contains those 512 bytes, so we are now responsible for
  166. ; loading the rest of the file. Other filesystems (i.e. HPFS, NTFS, RIPL)
  167. ; will load the whole file, so the default entrypoint branches around the
  168. ; FAT-specific code.
  169. ;
  170. jmp RealStart
  171. FatBegin:
  172. .386
  173. ;
  174. ; If we're here, we've booted off a FAT system and we must load the rest
  175. ; of NTLDR at 2000:0200 (right behind this sector) NTLDR passes us the
  176. ; following:
  177. ; BX = Starting Cluster Number of NTLDR
  178. ; DL = INT 13h drive number we've booted from
  179. ; DS:SI -> boot media's BPB
  180. ; DS:DI -> argument structure (see above struc definition)
  181. ;
  182. ;
  183. ; Save away the boot drive and the starting cluster number
  184. ;
  185. push dx
  186. push bx
  187. ;
  188. ; Blast the FAT into memory at 6000:0000 - 8000:0000
  189. ;
  190. .386
  191. push 06000h
  192. .8086
  193. pop es
  194. xor bx,bx ; (es:bx) = 6000:0000
  195. mov cx,ds:[si].ReservedSectors
  196. mov ds:[di].SectorBase.msw,0
  197. mov ds:[di].SectorBase.lsw,cx ; set up Sector Base
  198. mov ax,ds:[si].FatSectors ; (al) = # Sectors to read
  199. cmp ax,080h
  200. jbe FatLt64k
  201. ; The FAT is > 64k, so we read the first 64k chunk, then the rest.
  202. ; (A 16-bit FAT can't be bigger than 128k)
  203. push cx
  204. mov ax,080h ; (al) = # of sectors to read
  205. call ds:[di].ReadSectors
  206. pop cx ; (cx) = previous SectorBase
  207. .386
  208. push 07000h
  209. .8086
  210. pop es
  211. xor bx,bx ; (es:bx) = 7000:0000
  212. mov ax,ds:[si].FatSectors
  213. sub ax,080h ; (ax) = # Sectors left to read
  214. add cx,080h ; (cx) = SectorBase for next read
  215. mov ds:[di].SectorBase.lsw,cx
  216. adc ds:[di].SectorBase.msw,0 ; set up SectorBase
  217. ;
  218. ; (al) = # of sectors to read
  219. ;
  220. FatLt64k:
  221. call ds:[di].ReadSectors
  222. ;
  223. ; FAT is in memory, now we restore our starting cluster number
  224. ;
  225. pop dx ; (dx) = starting cluster number
  226. xor bx,bx
  227. ;
  228. ; set up FS and GS for reading the FAT
  229. ;
  230. .386
  231. mov ax,6000h
  232. mov fs,ax
  233. mov ax,7000h
  234. mov gs,ax
  235. .8086
  236. ;
  237. ; set up ES for reading in the rest of us
  238. ;
  239. push cs
  240. pop es
  241. mov ah,MAXSECTORS ; (ah) = number of sectors we can read
  242. ; until boundary
  243. FatLoop:
  244. ;
  245. ; (dx) = next cluster to load
  246. ;
  247. push dx
  248. mov al,ds:[si].SectorsPerCluster ; (al) = number of contiguous sectors
  249. ; found
  250. sub ah,ds:[si].SectorsPerCluster ; can read before 64k
  251. ;
  252. ; Check to see if we've reached the end of the file
  253. ;
  254. cmp dx,0ffffh
  255. jne Fat10
  256. ;
  257. ; The entire file has been loaded. Throw away the saved next cluster,
  258. ; restore the boot drive, and let NTLDR do its thing.
  259. ;
  260. pop dx
  261. pop dx
  262. jmp RealStart
  263. Fat10:
  264. mov cx,dx
  265. ;
  266. ; (dx) = (cx) = last contiguous cluster
  267. ; (al) = # of contiguous clusters found
  268. ;
  269. call NextFatEntry
  270. ;
  271. ; (dx) = cluster following last contiguous cluster
  272. ;
  273. ; Check to see if the next cluster is contiguous. If not, go load the
  274. ; contiguous block we've found.
  275. ;
  276. inc cx
  277. cmp dx,cx
  278. jne LncLoad
  279. ;
  280. ; Check to see if we've reached the 64k boundary. If so, go load the
  281. ; contiguous block so far. If not, increment the number of contiguous
  282. ; sectors and loop again.
  283. ;
  284. cmp ah,0
  285. jne Lnc20
  286. mov ah,MAXSECTORS ; (ah) = number of sectors until
  287. ; boundary reached again
  288. jmp short LncLoad
  289. Lnc20:
  290. add al,ds:[si].SectorsPerCluster
  291. sub ah,ds:[si].SectorsPerCluster
  292. jmp short Fat10
  293. LncLoad:
  294. ;
  295. ; (TOS) = first cluster to load
  296. ; (dx) = first cluster of next group to load
  297. ; (al) = number of contiguous sectors
  298. ;
  299. pop cx
  300. push dx
  301. mov dx,cx
  302. mov cx,10 ; (cx) = retry count
  303. ;
  304. ; N.B.
  305. ; This assumes that we will never have more than 255 contiguous clusters.
  306. ; Since that would get broken up into chunks that don't cross the 64k
  307. ; boundary, this is ok.
  308. ;
  309. ; (dx) = first cluster to load
  310. ; (al) = number of contiguous sectors
  311. ; (TOS) = first cluster of next group to load
  312. ; (es:bx) = address where clusters should be loaded
  313. ;
  314. FatRetry:
  315. push bx
  316. push ax
  317. push dx
  318. push cx
  319. if 0
  320. push dx
  321. call PrintDbg
  322. mov dx,ax
  323. call PrintDbg
  324. pop dx
  325. endif
  326. call [di].ReadClusters
  327. jnc ReadOk
  328. ;
  329. ; error in the read, reset the drive and try again
  330. ;
  331. if 0
  332. mov dx, ax
  333. call PrintDbg
  334. endif
  335. mov ax,01h
  336. mov al,ds:[si].BootDriveNumber
  337. int 13h
  338. if 0
  339. mov dx,ax
  340. call PrintDbg
  341. endif
  342. xor ax,ax
  343. mov al,ds:[si].BootDriveNumber
  344. int 13h
  345. ;
  346. ; pause for a while
  347. ;
  348. xor ax,ax
  349. FatPause:
  350. dec ax
  351. jnz FatPause
  352. pop cx
  353. pop dx
  354. pop ax
  355. pop bx
  356. dec cx
  357. jnz FatRetry
  358. ;
  359. ; we have re-tried ten times, it still doesn't work, so punt.
  360. ;
  361. push cs
  362. pop ds
  363. mov si,offset FAT_ERROR
  364. FatErrPrint:
  365. lodsb
  366. or al,al
  367. jz FatErrDone
  368. mov ah,14 ; write teletype
  369. mov bx,7 ; attribute
  370. int 10h ; print it
  371. jmp FatErrPrint
  372. FatErrDone:
  373. jmp $
  374. ; This should be replaced by a mechanism to get a pointer
  375. ; passed to us in the param block. since the boot sector msg itself
  376. ; is properly localized but this one isn't.
  377. FAT_ERROR db 13,10,"Disk I/O error",0dh,0ah,0
  378. ReadOk:
  379. pop cx
  380. pop dx
  381. pop ax
  382. pop bx
  383. pop dx ; (dx) = first cluster of next group
  384. ; to load.
  385. .386
  386. ;
  387. ; Convert # of sectors into # of bytes.
  388. ;
  389. mov cl,al
  390. xor ch,ch
  391. shl cx,9
  392. .8086
  393. add bx,cx
  394. jz FatLoopDone
  395. jmp FatLoop
  396. FatLoopDone:
  397. ;
  398. ; (bx) = 0
  399. ; This means we've just ended on a 64k boundary, so we have to
  400. ; increment ES to continue reading the file. We are guaranteed to
  401. ; always end on a 64k boundary and never cross it, because we
  402. ; will reduce the number of contiguous clusters to read
  403. ; to ensure that the last cluster read will end on the 64k boundary.
  404. ; Since we start reading at 0, and ClusterSize will always be a power
  405. ; of two, a cluster will never cross a 64k boundary.
  406. ;
  407. mov ax,es
  408. add ax,01000h
  409. mov es,ax
  410. mov ah,MAXSECTORS
  411. jmp FatLoop
  412. ;++
  413. ;
  414. ; NextFatEntry - This procedure returns the next cluster in the FAT chain.
  415. ; It will deal with both 12-bit and 16-bit FATs. It assumes
  416. ; that the entire FAT has been loaded into memory.
  417. ;
  418. ; Arguments:
  419. ; (dx) = current cluster number
  420. ; (fs:0) = start of FAT in memory
  421. ; (gs:0) = start of second 64k of FAT in memory
  422. ;
  423. ; Returns:
  424. ; (dx) = next cluster number in FAT chain
  425. ; (dx) = 0ffffh if there are no more clusters in the chain
  426. ;
  427. ;--
  428. NextFatEntry proc near
  429. push bx
  430. ;
  431. ; Check to see if this is a 12-bit or 16-bit FAT. The biggest FAT we can
  432. ; have for a 12-bit FAT is 4080 clusters. This is 6120 bytes, or just under
  433. ; 12 sectors.
  434. ;
  435. ; A 16-bit FAT that's 12 sectors long would only hold 3072 clusters. Thus,
  436. ; we compare the number of FAT sectors to 12. If it's greater than 12, we
  437. ; have a 16-bit FAT. If it's less than or equal to 12, we have a 12-bit FAT.
  438. ;
  439. call IsFat12
  440. jnc Next16Fat
  441. Next12Fat:
  442. mov bx,dx ; (fs:bx) => temporary index
  443. shr dx,1 ; (dx) = offset/2
  444. ; (CY) = 1 need to shift
  445. pushf ; = 0 don't need to shift
  446. add bx,dx ; (fs:bx) => next cluster number
  447. .386
  448. mov dx,fs:[bx] ; (dx) = next cluster number
  449. .8086
  450. popf
  451. jc shift ; carry flag tells us whether to
  452. and dx,0fffh ; mask
  453. jmp short N12Tail
  454. shift:
  455. .386
  456. shr dx,4 ; or shift
  457. .8086
  458. N12Tail:
  459. ;
  460. ; Check for end of file
  461. ;
  462. cmp dx,0ff8h ; If we're at the end of the file,
  463. jb NfeDone ; convert to canonical EOF.
  464. mov dx,0ffffh
  465. jmp short NfeDone
  466. Next16Fat:
  467. add dx,dx ; (dx) = offset
  468. jc N16high
  469. mov bx,dx ; (fs:bx) => next cluster number
  470. .386
  471. mov dx,fs:[bx] ; (dx) = next cluster number
  472. .8086
  473. jmp short N16Tail
  474. N16high:
  475. mov bx,dx
  476. .386
  477. mov dx,gs:[bx]
  478. .8086
  479. N16Tail:
  480. cmp dx,0fff8h
  481. jb NfeDone
  482. mov dx,0ffffh ; If we're at the end of the file
  483. ; convert to canonical EOF.
  484. NfeDone:
  485. pop bx
  486. ret
  487. NextFatEntry endp
  488. ;++
  489. ;
  490. ; IsFat12 - This function determines whether the BPB describes a 12-bit
  491. ; or 16-bit FAT.
  492. ;
  493. ; Arguments - ds:si supplies pointer to BPB
  494. ;
  495. ; Returns
  496. ; CY set - 12-bit FAT
  497. ; CY clear - 16-bit FAT
  498. ;
  499. ;--
  500. IsFat12 proc near
  501. .386
  502. push eax
  503. push ebx
  504. push ecx
  505. push edx
  506. movzx ecx, ds:[si].Sectors
  507. or cx,cx
  508. jnz if10
  509. mov ecx, ds:[si].SectorsLong
  510. if10:
  511. ;
  512. ; (ecx) = number of sectors
  513. ;
  514. movzx ebx, byte ptr ds:[si].Fats
  515. movzx eax, word ptr ds:[si].FatSectors
  516. mul ebx
  517. sub ecx,eax
  518. ;
  519. ; (ecx) = (#sectors)-(sectors in FATs)
  520. ;
  521. movzx eax, word ptr ds:[si].DirectoryEntries
  522. shl eax, 5
  523. ;
  524. ; (eax) = #bytes in root dir
  525. ;
  526. mov edx,eax
  527. and edx,0ffff0000h
  528. div word ptr ds:[si].BytesPerSector
  529. sub ecx,eax
  530. ;
  531. ; (ecx) = (#sectors) - (sectors in fat) - (sectors in root dir)
  532. ;
  533. movzx eax, word ptr ds:[si].ReservedSectors
  534. sub ecx, eax
  535. mov eax, ecx
  536. movzx ecx, byte ptr ds:[si].SectorsPerCluster
  537. xor edx,edx
  538. div ecx
  539. cmp eax, 4087
  540. jae if20
  541. stc
  542. jmp short if30
  543. if20:
  544. clc
  545. if30:
  546. pop edx
  547. pop ecx
  548. pop ebx
  549. pop eax
  550. ret
  551. .8086
  552. IsFat12 endp
  553. PrintDbg proc near
  554. push ax
  555. push bx
  556. push cx
  557. mov cx,4
  558. pd10:
  559. .386
  560. rol dx,4
  561. .8086
  562. mov ah,0eh
  563. mov bx,7
  564. mov al,dl
  565. and al,0fh
  566. add al,'0'
  567. cmp al,'9'
  568. jbe pd15
  569. add al,'A'-('9'+1)
  570. pd15:
  571. int 010h
  572. loop pd10
  573. mov ah,0eh
  574. mov al,' '
  575. mov bx,7
  576. int 010h
  577. pop cx
  578. pop bx
  579. pop ax
  580. ret
  581. PrintDbg endp
  582. IFDEF HEADLESS_SRV
  583. TerminalStatus dw 0
  584. endif
  585. Free EQU 512-($-Start)
  586. if Free lt 0
  587. %out FATAL PROBLEM: FAT-specific startup code is greater than
  588. %out 512 bytes. Fix it!
  589. .err
  590. endif
  591. RealStart:
  592. .386p
  593. ;
  594. ; Compute the paragraph needed for DS
  595. ;
  596. if 0
  597. mov ax,0
  598. int 16h
  599. endif
  600. ;
  601. ; If this is a network boot (known by CS == 0 and IP ~= 7C00), then
  602. ; move the startup module to 2000:0.
  603. ;
  604. call near ptr pxe_boot_check ; *(SP -= 2) = IP
  605. pxe_boot_check:
  606. pop ax ; AX := IP
  607. cmp ax, 7c00h + pxe_boot_check - Start
  608. jne not_pxe_boot
  609. mov ax, cs
  610. cmp ax, 0
  611. jne not_pxe_boot
  612. push ds
  613. push es
  614. xor ax,ax
  615. mov cx,7c0h ; move from 7C0:0
  616. mov ds,cx
  617. mov si,ax
  618. mov cx,2000h ; move to 2000:0
  619. mov es,cx
  620. mov di,ax
  621. mov ecx,offset _TEXT:DGROUP ; get length of text segment
  622. add ecx,offset DGROUP:_edata ; add length of data segment
  623. cld ; move forward
  624. rep movsb ; relocate to 2000:0
  625. pop es
  626. pop ds
  627. db 0EAh ; Far jump to 2000h:CS_IP_adjust
  628. dw offset CS_IP_adjust ; to change CS:IP and flush
  629. dw 2000h ; prefetch.
  630. CS_IP_adjust:
  631. IFDEF HEADLESS_SRV
  632. push edx
  633. mov ax, 00e3h ; Initialize, 9600 baud, no parity, 1 stop bit, 8 data bits
  634. mov dx, HEADLESS_COMPORT ; com port
  635. int 14h
  636. mov cs:TerminalStatus, ax ; Save the status for later
  637. pop edx
  638. endif
  639. ;
  640. ; Check DL as set by our caller. If it is 0x41, this implies that we're doing
  641. ; an SDI boot. Our caller is a different initial boot program that has loaded
  642. ; into memory an SDI image containing a ramdisk image, startrom.com and
  643. ; osloader.exe. The caller has copied startrom.com to 0:7c00 and jumped to it.
  644. ; We are to do the normal PXE bootstrap things here, except that we don't have
  645. ; to download the loader, because it's already here. We do have to move it into
  646. ; the right place from where it exists in the SDI image.
  647. ;
  648. ; If this is an SDI boot, the top three bytes of the page-aligned physical
  649. ; address of the SDI image are in the top three bytes of EDX. This address is
  650. ; passed to SuMain().
  651. ;
  652. cmp dl, 41h ; SDI boot?
  653. je sdi_boot ; Jump if yes (skip wait for F12,
  654. ; leave dl == 0x41 to indicate boot
  655. ; drive, and leave the SDI address in
  656. ; the upper part of edx.
  657. ;
  658. ; Give the user a chance to press F12 to request a network boot. If F12 is not
  659. ; pressed, then return from the boot code. This causes the BIOS to try the next
  660. ; boot device (usually the disk).
  661. ;
  662. ifndef ALWAYS_BOOT_FROM_NET
  663. call CheckForF12
  664. cmp ax,0
  665. jnz do_remote_boot
  666. retf
  667. do_remote_boot:
  668. endif
  669. mov dx, 0040h ; Default boot disk (0x40 == PXE boot)
  670. sdi_boot:
  671. not_pxe_boot:
  672. ;
  673. ; Compute the paragraph needed for DS
  674. ;
  675. mov bx,offset _TEXT:DGROUP ; first calculate offset to data
  676. shr bx,4 ; must be para aligned
  677. mov ax,cs ; get base of code
  678. add ax,bx ; add paragraph offset to data
  679. mov ss,ax ; ints disabled for next instruct
  680. mov sp,offset DGROUP:SuStack ; (sp) = top of internal stack
  681. ;
  682. ; Build C stack frame for _SuMain
  683. ;
  684. push edx ; pass bootdisk to main
  685. ;
  686. ; Make DS point to the paragraph address of DGROUP
  687. ;
  688. mov ds,ax ; ds now points to beginning of DGROUP
  689. mov es,ax ; es now points to beginning of DGROUP
  690. ;
  691. ; Compute the physical address of the end of the data segment (which
  692. ; will be the beginning of the prepended loader file).
  693. ;
  694. movzx edx,ax
  695. shl edx,4
  696. add edx,offset DGROUP:_edata
  697. mov dword ptr _FileStart,edx
  698. ;
  699. ; Force the upper parts of
  700. ; of EBP and ESP to be zero in real mode.
  701. ;
  702. xor bp,bp
  703. movzx ebp,bp
  704. movzx esp,sp
  705. mov [saveDS],ds
  706. call _SuMain ; go to C code to do everything else.
  707. ;++
  708. ; _EnableProtectPaging
  709. ;
  710. ; Loads 386 protect mode registers.
  711. ; Enables 386 protection h/w
  712. ; Loads pagings registers
  713. ; Enables 386 paging h/w
  714. ;
  715. ;--
  716. public _EnableProtectPaging
  717. _EnableProtectPaging proc near
  718. ;
  719. ; Sanitize ES and GS and clean out any junk in the upper 16bits
  720. ; of the flags that may have been left by the bios, before we go protected
  721. ;
  722. push dword ptr 0
  723. popfd
  724. mov bx,sp
  725. mov dx,[bx+2] ; are we enabling prot/paging for the first time?
  726. xor ax,ax
  727. mov gs,ax
  728. mov es,ax
  729. ;
  730. ; FS must contain the selector of the PCR when we call the kernel
  731. ;
  732. push PCR_Selector
  733. pop fs
  734. ;
  735. ; Load the gdtr and idtr.
  736. ; We disable interrupts here since we can't handle interrups with the
  737. ; idt loaded while were in real mode and before we switch to protmode.
  738. cli
  739. lgdt fword ptr [_GDTregister]
  740. lidt fword ptr [_IDTregister]
  741. ;
  742. ; We have to stamp the segment portion of any real-mode far pointer with
  743. ; the corresponding selector values before we go protected.
  744. ;
  745. mov si,offset _ScreenStart
  746. mov word ptr [si+2],VideoSelector
  747. mov si,offset _vp
  748. mov word ptr [si+2],VideoSelector
  749. mov si,offset _MemoryDescriptorList
  750. mov word ptr [si+2],MdlSelector
  751. ;
  752. ; Enable protect and paging mode
  753. ;
  754. mov eax,cr0
  755. ; If we're enabling protect mode for the first time, don't turn on paging
  756. ; because the osloader does all that. However, if we're returning to
  757. ; protected mode, the page tables are already setup, therefore we do want
  758. ; to turn paging on.
  759. cmp dx,1
  760. jnz only_prot
  761. or eax,PROT_MODE + ENABLE_PAGING
  762. mov cr0,eax
  763. ;
  764. ; The following JMP must be DWORD-aligned in order to avoid an obscure i386
  765. ; hardware bug. If not, it is possible (albeit unlikely) that the prefetch
  766. ; queue can get trashed.
  767. ;
  768. ALIGN 4
  769. jmp flush
  770. only_prot:
  771. or eax,PROT_MODE
  772. mov cr0,eax
  773. ;
  774. ; Flush the prefetch queue
  775. ;
  776. ALIGN 4
  777. jmp flush
  778. flush:
  779. ;
  780. ; Load CS with the SU module's code selector
  781. ;
  782. push SuCodeSelector
  783. push offset cs:restart
  784. retf
  785. ;
  786. ; Now load DS and SS with the SU module's protect mode data selector.
  787. ;
  788. restart:
  789. mov ax,SuDataSelector
  790. mov ds,ax
  791. mov ss,ax
  792. ;
  793. ; Load LDT with zero since it will never be used.
  794. ;
  795. xor bx,bx
  796. lldt bx
  797. ;
  798. ; Load the Task Register and return to the boot SU module.
  799. ;
  800. or dx,dx
  801. jnz epp10
  802. mov bx,TSS_Selector
  803. ltr bx
  804. epp10:
  805. ret
  806. _EnableProtectPaging endp
  807. .286p
  808. ;** _biosint
  809. ;
  810. ; Rom bios interrupt dispatcher
  811. ;
  812. public _biosint
  813. _biosint proc near
  814. enter 0,0
  815. push di
  816. push si
  817. push ds
  818. push es
  819. ; Get pointer to register parameter frame
  820. les di,[bp+4]
  821. ; Get requested interrupt number
  822. mov ax,es:[di].intnum
  823. ; Check that requested bios interrupt is supported
  824. sub ax,10h ; sub lowest int number supported
  825. jnc short bios1
  826. mov es:[di].intnum,FUNCTION_ERROR
  827. jmp short biosx
  828. bios1:
  829. shl ax,1 ; shift if to make it a word offset
  830. cmp ax,bios_cnt ; offset beyond end of table?
  831. jb short bios2
  832. ; Error: requested interrupt not supported
  833. mov es:[di].sax,FUNCTION_ERROR
  834. jmp short biosx
  835. bios2: mov bx,ax
  836. mov ax,word ptr cs:bios_table[bx]
  837. push es ; save seg of address frame
  838. push di ; save stack register frame pointer
  839. push ax ; address of bios int
  840. mov ax,es:[di].sax
  841. mov bx,es:[di].sbx
  842. mov cx,es:[di].scx
  843. mov dx,es:[di].sdx
  844. mov si,es:[di].ssi
  845. mov es,es:[di].ses
  846. ret ; this sends us to the "int #" instruction
  847. ; We return here from the jmp instruction following the int
  848. bios_ret:
  849. pop di ; get address of register parameter frame
  850. pop es ; restore segment of parameter frame
  851. bios5: pushf
  852. pop es:[di].sfg
  853. mov es:[di].sax,ax
  854. mov es:[di].sbx,bx
  855. mov es:[di].scx,cx
  856. mov es:[di].sdx,dx
  857. mov es:[di].ssi,si
  858. mov es:[di].ses,es
  859. ; Restore original registers and return to caller
  860. biosx:
  861. pop es
  862. pop ds
  863. pop si
  864. pop di
  865. leave
  866. ret
  867. _biosint endp
  868. ;** Bios Interrupt Table
  869. ;
  870. bios10: int 10h
  871. jmp short bios_ret
  872. bios11: int 11h
  873. jmp short bios_ret
  874. bios12: int 12h
  875. jmp short bios_ret
  876. bios13: int 13h
  877. jmp short bios_ret
  878. bios14: int 14h
  879. jmp short bios_ret
  880. bios15: int 15h
  881. jmp short bios_ret
  882. bios16: int 16h
  883. jmp short bios_ret
  884. bios17: int 17h
  885. jmp short bios_ret
  886. bios18: int 18h
  887. jmp short bios_ret
  888. bios19: int 19h
  889. jmp short bios_ret
  890. bios_table dw bios10,bios11,bios12,bios13,bios14,bios15,bios16,bios17,bios18,bios19
  891. bios_cnt equ $ - bios_table
  892. .386p
  893. ;++
  894. ;
  895. ; _MoveMemory
  896. ;
  897. ; Routine Description
  898. ;
  899. ; Moves dwords in memory from source to destination.
  900. ;
  901. ; Arguments
  902. ;
  903. ; (TOS+4) = number of bytes to move
  904. ; (TOS+8) = linear address of destination
  905. ; (TOS+12) = linear address of source
  906. ;
  907. ; Notes
  908. ;
  909. ; 1) Valid page table entries must already exist for the
  910. ; source and destination memory.
  911. ;
  912. ; 2) ALL memory in the lower one megabyte is assumed to
  913. ; be identity mapped if used.
  914. ;
  915. ; USES ESI, EDI, ECX, FLAGS
  916. ;
  917. ;
  918. ;--
  919. public _MoveMemory
  920. _MoveMemory proc near
  921. enter 0,0
  922. push ds
  923. push es
  924. ;
  925. ; Get source, destination, and count arguments from the stack
  926. ; Make "count" the number of dwords to move.
  927. ;
  928. mov esi,dword ptr [bp+4]
  929. mov edi,dword ptr [bp+8]
  930. mov ecx,dword ptr [bp+12]
  931. shr ecx,2
  932. ;
  933. ; Load FLAT selectors into DS and ES
  934. ;
  935. mov ax,KeDataSelector
  936. mov ds,ax
  937. mov es,ax
  938. ;
  939. ; Move the block of data.
  940. ;
  941. assume es:FLAT, ds:FLAT
  942. ;
  943. ; move the dwords
  944. ;
  945. cld
  946. rep movs dword ptr [edi],dword ptr [esi]
  947. ;
  948. ; move the remaining tail
  949. ;
  950. mov ecx, dword ptr [bp+12]
  951. and ecx, 3
  952. rep movs byte ptr [edi],byte ptr [esi]
  953. assume es:nothing, ds:DGROUP
  954. pop es
  955. pop ds
  956. leave
  957. ret
  958. _MoveMemory endp
  959. ;++
  960. ;
  961. ; _ZeroMemory
  962. ;
  963. ; Routine Description
  964. ;
  965. ; Writes zeros into memory at the target address.
  966. ;
  967. ; Arguments
  968. ;
  969. ; (TOS+4) = linear address of target
  970. ; (TOS+8) = number of bytes to zero
  971. ;
  972. ; Notes
  973. ;
  974. ; 1) Valid page table entries must already exist for the
  975. ; source and destination memory.
  976. ;
  977. ; 2) ALL memory in the lower one megabyte is assumed to
  978. ; be identity mapped if used.
  979. ;
  980. ; USES ESI, EDI, ECX, FLAGS
  981. ;
  982. ;
  983. ;--
  984. public _ZeroMemory
  985. _ZeroMemory proc near
  986. enter 0,0
  987. push es
  988. ;
  989. ; Get source, destination, and count arguments from the stack
  990. ; Make "count" the number of dwords to move.
  991. ;
  992. mov edi,dword ptr [bp+4]
  993. mov ecx,dword ptr [bp+8]
  994. shr ecx,2
  995. ;
  996. ; Load FLAT selectors into DS and ES
  997. ;
  998. mov ax,KeDataSelector
  999. mov es,ax
  1000. xor eax,eax
  1001. ;
  1002. ; Zero the the block of data.
  1003. ;
  1004. assume es:FLAT
  1005. ;
  1006. ; Zero the dwords
  1007. ;
  1008. cld
  1009. rep stos dword ptr [edi]
  1010. ;
  1011. ; Zero the remaining bytes
  1012. ;
  1013. mov ecx, dword ptr [bp+8]
  1014. and ecx, 3
  1015. rep stos byte ptr [edi]
  1016. assume es:nothing, ds:DGROUP
  1017. pop es
  1018. leave
  1019. ret
  1020. _ZeroMemory endp
  1021. public _SetMemory
  1022. _SetMemory proc near
  1023. enter 0,0
  1024. push es
  1025. ;
  1026. ; Get source, destination, and count arguments from the stack
  1027. ; Make "count" the number of dwords to move.
  1028. ;
  1029. mov edi,dword ptr [bp+4]
  1030. mov ecx,dword ptr [bp+8]
  1031. shr ecx,2
  1032. ;
  1033. ; Load FLAT selectors into DS and ES
  1034. ;
  1035. mov ax,KeDataSelector
  1036. mov es,ax
  1037. mov eax,dword ptr [bp+12]
  1038. ;
  1039. ; Set the the block of data.
  1040. ;
  1041. assume es:FLAT
  1042. ;
  1043. ; Set the dwords
  1044. ;
  1045. cld
  1046. rep stos dword ptr [edi]
  1047. ;
  1048. ; Set the remaining bytes
  1049. ;
  1050. mov ecx, dword ptr [bp+8]
  1051. and ecx, 3
  1052. rep stos byte ptr [edi]
  1053. assume es:nothing, ds:DGROUP
  1054. pop es
  1055. leave
  1056. ret
  1057. _SetMemory endp
  1058. ;++
  1059. ;
  1060. ; Turn Floppy Drive Motor Off
  1061. ;
  1062. ;--
  1063. public _TurnMotorOff
  1064. DriveControlRegister equ 3f2h ; Floppy control register
  1065. _TurnMotorOff proc near
  1066. mov dx,DriveControlRegister
  1067. mov ax,0CH
  1068. out dx,al
  1069. ret
  1070. _TurnMotorOff endp
  1071. ;
  1072. ; Note: we do not save and restore the gdt and idt values because they
  1073. ; cannot change while external services are being used by the OS loader.
  1074. ; This is because they MUST remain identity mapped until all mode
  1075. ; switching has ceased.
  1076. ;
  1077. public _RealMode
  1078. _RealMode proc near
  1079. ;
  1080. ; Switch to real-mode
  1081. ;
  1082. sgdt fword ptr [_GDTregister]
  1083. sidt fword ptr [_IDTregister]
  1084. push [saveDS] ; push this so we can get to it later
  1085. mov ax,SuDataSelector
  1086. mov es,ax
  1087. mov fs,ax
  1088. mov gs,ax
  1089. mov eax,cr0
  1090. and eax, not (ENABLE_PAGING + PROT_MODE)
  1091. mov cr0,eax
  1092. ;
  1093. ; flush the pipeline
  1094. ;
  1095. jmp far ptr here
  1096. here:
  1097. ;
  1098. ; Flush TLB
  1099. ;
  1100. ; HACKHACK - We don't know where the page directory is, since it was
  1101. ; allocated in the osloader. So we don't want to clear out cr3,
  1102. ; but we DO want to flush the TLB....
  1103. ;
  1104. mov eax,cr3
  1105. nop ; Fill - Ensure 13 non-page split
  1106. nop ; accesses before CR3 load
  1107. nop ; (P6 errata #11 stepping B0)
  1108. nop
  1109. mov cr3,eax
  1110. ;
  1111. ; switch to real mode addressing
  1112. ;
  1113. ; N. B. We need to do a far jump rather than a retf, because a retf will not
  1114. ; reset the access rights to CS properly.
  1115. ;
  1116. db 0EAh ; JMP FAR PTR
  1117. dw offset _TEXT:rmode ; 2000:rmode
  1118. dw 02000h
  1119. rmode:
  1120. pop ax
  1121. mov ds,ax
  1122. mov ss,ax
  1123. ;
  1124. ; Stamp video pointers for real-mode use
  1125. ;
  1126. mov si,offset _ScreenStart
  1127. mov word ptr [si+2],0b800h
  1128. mov si,offset _vp
  1129. mov word ptr [si+2],0b800h
  1130. ;
  1131. ; re-enable interrups
  1132. ;
  1133. lidt fword ptr [_IDTregisterZero]
  1134. ;
  1135. ; Re-enable interrupts
  1136. ;
  1137. sti
  1138. ret
  1139. _RealMode endp
  1140. ;** _TransferToLoader - transfer control the the OS loader
  1141. ;
  1142. ;
  1143. ; Arguments:
  1144. ;
  1145. ; None
  1146. ;
  1147. ; Returns:
  1148. ;
  1149. ; Does not return
  1150. ;
  1151. ;**
  1152. public _TransferToLoader
  1153. _TransferToLoader proc near
  1154. ; generates a double fault for debug purposes
  1155. ; mov sp,0
  1156. ; push 0
  1157. mov ebx,dword ptr [esp+2] ; get entrypoint arg
  1158. xor eax,eax
  1159. mov ax,[saveDS]
  1160. ;
  1161. ; Setup OS loader's stack. Compute FLAT model esp to id map to
  1162. ; original stack.
  1163. ;
  1164. mov cx,KeDataSelector
  1165. mov ss,cx
  1166. mov esp,LOADER_STACK
  1167. ;
  1168. ; Load ds and es with kernel's data selectors
  1169. ;
  1170. mov ds,cx
  1171. mov es,cx
  1172. ;
  1173. ; Setup pointer to file system and boot context records
  1174. ;
  1175. ; Make a linear pointer to the Boot Context Record
  1176. shl eax,4
  1177. xor ecx,ecx
  1178. mov cx,offset _BootRecord
  1179. add eax,ecx
  1180. push eax
  1181. push 1010h ; dummy return address.
  1182. push 1010h ; dummy return address.
  1183. ;
  1184. ; Push 48bit address of loader entry-point
  1185. ;
  1186. db OVERRIDE
  1187. push KeCodeSelector
  1188. push ebx
  1189. ;
  1190. ; Pass control to the OS loader
  1191. ;
  1192. db OVERRIDE
  1193. retf
  1194. _TransferToLoader endp
  1195. ;++
  1196. ; Description:
  1197. ;
  1198. ; Gets memory block sizes for memory from zero to one meg and
  1199. ; from one meg to 64 meg. We do this by calling int 12h
  1200. ; (get conventional memory size) and int 15h function 88h (get
  1201. ; extended memory size).
  1202. ;
  1203. ; Arguments:
  1204. ;
  1205. ; None
  1206. ;
  1207. ; Returns:
  1208. ;
  1209. ; USHORT - Size of usable memory (in pages)
  1210. ;
  1211. ;--
  1212. public _IsaConstructMemoryDescriptors
  1213. BmlTotal equ [bp-4]
  1214. Func88Result equ [bp-6]
  1215. _IsaConstructMemoryDescriptors proc near
  1216. push bp ; save ebp
  1217. mov bp, sp
  1218. sub sp, 6
  1219. ;
  1220. ; Initialize the MemoryList to start with a zero entry. (end-of-list)
  1221. ;
  1222. les si, dword ptr _MemoryDescriptorList
  1223. xor eax,eax
  1224. mov es:[si].BlockSize,eax
  1225. mov es:[si].BlockBase,eax
  1226. ;
  1227. ; Get conventional (below one meg) memory size
  1228. ;
  1229. push es
  1230. push si
  1231. int 12h
  1232. movzx eax,ax
  1233. ;
  1234. ; EAX is the number of 1k blocks, which we need to convert to the
  1235. ; number of bytes.
  1236. ;
  1237. shl eax,10
  1238. push eax
  1239. shr eax, 12
  1240. mov BmlTotal, eax
  1241. xor eax,eax
  1242. push eax
  1243. call _InsertDescriptor
  1244. add sp,8
  1245. ;
  1246. ; Get extended memory size and fill-in the second descriptor
  1247. ;
  1248. mov ah,88h
  1249. int 15h
  1250. mov Func88Result,ax
  1251. and eax,0ffffh
  1252. ;
  1253. ; EAX is the number of 1k blocks, which we need to convert to the
  1254. ; number of bytes.
  1255. ;
  1256. shl eax,10
  1257. push eax
  1258. shr eax,12
  1259. add BmlTotal, ax
  1260. mov eax,0100000h
  1261. push eax
  1262. call _InsertDescriptor
  1263. add sp,8
  1264. ;
  1265. ; Try function E801, see if that is supported on this machine
  1266. ;
  1267. mov ax,0E801h
  1268. int 15h
  1269. jc short Isa50
  1270. cmp ax,Func88Result ; Is extended memory same as 88?
  1271. je short Isa40 ; Yes, go add the rest
  1272. cmp ax, (16-1) * 1024 ; Is extended memory exactly 16MB?
  1273. jne short Isa50 ; No, conflict between 88 & E801
  1274. Isa40:
  1275. ;
  1276. ; Function looks like it worked
  1277. ;
  1278. ; AX = extended memory < 16M in 1k blocks
  1279. ; BX = extended memory > 16M in 64k blocks
  1280. ;
  1281. and ebx,0ffffh
  1282. jz short Isa50
  1283. shl ebx,16 ; ebx = memory > 16M in bytes (via E801)
  1284. add ebx, 16*1024*1024 ; ebx = end of memory in bytes (via E801)
  1285. mov ax, Func88Result
  1286. and eax,0ffffh
  1287. shl eax, 10 ; eax = memory > 1M in bytes (via 88)
  1288. add eax, 1*1024*1024 ; eax = end of memory in bytes (via 88)
  1289. sub ebx, eax ; ebx = memory above eax
  1290. jbe short Isa50 ; if ebx <= eax, done
  1291. push ebx
  1292. shr ebx,12
  1293. add BmlTotal, bx
  1294. push eax
  1295. call _InsertDescriptor
  1296. add sp,8
  1297. and eax,0ffffh
  1298. Isa50:
  1299. pop si
  1300. pop es
  1301. mov eax, BmlTotal
  1302. mov sp, bp
  1303. pop bp
  1304. ret
  1305. _IsaConstructMemoryDescriptors endp
  1306. ;++
  1307. ;
  1308. ; BOOLEAN
  1309. ; Int15E820 (
  1310. ; E820Frame *Frame
  1311. ; );
  1312. ;
  1313. ;
  1314. ; Description:
  1315. ;
  1316. ; Gets address range descriptor by calling int 15 function E820h.
  1317. ;
  1318. ; Arguments:
  1319. ;
  1320. ; Returns:
  1321. ;
  1322. ; BOOLEAN - failed or succeed.
  1323. ;
  1324. ;--
  1325. cmdpFrame equ [bp + 6]
  1326. public _Int15E820
  1327. _Int15E820 proc near
  1328. push ebp
  1329. mov bp, sp
  1330. mov bp, cmdpFrame ; (bp) = Frame
  1331. push es
  1332. push edi
  1333. push esi
  1334. push ebx
  1335. push ss
  1336. pop es
  1337. mov ebx, [bp].Key
  1338. mov ecx, [bp].DescSize
  1339. lea di, [bp].BaseAddrLow
  1340. mov eax, 0E820h
  1341. mov edx, 'SMAP' ; (edx) = signature
  1342. INT 15h
  1343. mov [bp].Key, ebx ; update callers ebx
  1344. mov [bp].DescSize, ecx ; update callers size
  1345. sbb ecx, ecx ; ecx = -1 if carry, else 0
  1346. sub eax, 'SMAP' ; eax = 0 if signature matched
  1347. or ecx, eax
  1348. mov [bp].ErrorFlag, ecx ; return 0 or non-zero
  1349. pop ebx
  1350. pop esi
  1351. pop edi
  1352. pop es
  1353. pop ebp
  1354. ret
  1355. _Int15E820 endp
  1356. ;++
  1357. ;
  1358. ; t_PXENV_ENTRY far *
  1359. ; PxenvGetEntry (
  1360. ; VOID
  1361. ; );
  1362. ;
  1363. ;
  1364. ; Description:
  1365. ; Get the address of the PXENV Entry Point structure using Int 1Ah.
  1366. ;
  1367. ; Arguments:
  1368. ; none
  1369. ;
  1370. ; Returns:
  1371. ; DX:AX := Far pointer to PXENV Entry Point structure.
  1372. ;
  1373. ;--
  1374. public _PxenvGetEntry
  1375. _PxenvGetEntry proc near
  1376. push ebp ; Save important C registers
  1377. push edi
  1378. push esi
  1379. push ds
  1380. push es
  1381. mov ax, 5650h ; Get address of PXENV Entry Point
  1382. int 1Ah ; structure.
  1383. jc no_pxenv_entry ; CF set if function not supported.
  1384. cmp ax, 564Eh ; Check for PXENV API signature.
  1385. jne no_pxenv_entry
  1386. mov dx, es ; Return far pointer to C in DX:AX.
  1387. mov ax, bx
  1388. jmp exit
  1389. no_pxenv_entry:
  1390. xor dx, dx ; Return NULL if PXENV Entry Point
  1391. xor ax, ax ; structure is not available.
  1392. exit:
  1393. pop es ; Restore C registers.
  1394. pop ds
  1395. pop esi
  1396. pop edi
  1397. pop ebp
  1398. ret
  1399. _PxenvGetEntry endp
  1400. ;++
  1401. ;
  1402. ; UINT16
  1403. ; PxenvApiCall(
  1404. ; UINT16 service,
  1405. ; void far *param
  1406. ; );
  1407. ;
  1408. ;
  1409. ; Description:
  1410. ; Make a service call into the PXENV API.
  1411. ;
  1412. ; Arguments:
  1413. ; ENTRY (TOS+6) := Far pointer to PXENV Entry Point structure
  1414. ; SERVICE (TOS+10) := PXENV API service number
  1415. ; PARAM (TOS+12) := Far pointer to PXENV API parameter structure
  1416. ;
  1417. ; Returns:
  1418. ; AX := Return value from PXENV API service
  1419. ; Contents of parameter structure will be modified as per API.
  1420. ;
  1421. ;--
  1422. SERVICE equ word ptr [bp + 6]
  1423. PARAM equ dword ptr [bp + 8]
  1424. public _PxenvApiCall
  1425. _PxenvApiCall proc near
  1426. push ebp ; Save caller's stack frame & use BP
  1427. mov bp, sp ; to reference stack parameters.
  1428. push ebx ; Save all general use registers.
  1429. push ecx
  1430. push edx
  1431. push edi
  1432. push esi
  1433. push ds
  1434. push es
  1435. mov bx, SERVICE ; Setup BX & ES:DI for call to
  1436. ifdef ALLOW_WAIT_FOR_F12_API
  1437. cmp bx,-1
  1438. jne xxxSkip
  1439. xxxLoop:
  1440. call GetKeyEx ; get keystroke, if any
  1441. mov ebx,eax ; copy it
  1442. cmp ebx,08600h ; check for F12
  1443. jz pxenv_api_ret ; jump out if F12 pressed
  1444. cmp ebx,0011Bh ; check for ESC
  1445. jz pxenv_api_ret ; jump out if ESC pressed
  1446. jmp xxxLoop ; loop
  1447. xxxSkip:
  1448. endif
  1449. les di, PARAM ; PXENV API service.
  1450. lds si, dword ptr _NetPcRomEntry
  1451. push cs ; Push far return address onto stack
  1452. lea ax, pxenv_api_ret ; (just as if we did a far call).
  1453. push ax
  1454. push ds
  1455. push si
  1456. retf ; Far return into API entry point.
  1457. pxenv_api_ret:
  1458. pop es ; Restore all general use registers.
  1459. pop ds
  1460. pop esi
  1461. pop edi
  1462. pop edx
  1463. pop ecx
  1464. pop ebx
  1465. pop ebp ; Restore caller's stack frame.
  1466. ret
  1467. _PxenvApiCall endp
  1468. ;++
  1469. ;
  1470. ; ULONG
  1471. ; CheckForF12(
  1472. ; VOID
  1473. ; );
  1474. ;
  1475. ;
  1476. ; Description:
  1477. ; This routine spins for three seconds monitoring the keyboard.
  1478. ; If the user presses F12, the routine returns immediately with
  1479. ; eax==1. If the user presses ESC, the routine returns immediately
  1480. ; with eax==0. All other keys are ignored. If neither F12 nor ESC
  1481. ; is pressed within three seconds, the routine returns with eax==0.
  1482. ;
  1483. ; If this is a restart invoked by a loader program (indicate by
  1484. ; a block of memory at a known location initialized correctly), the
  1485. ; return returns immediately with eax==1.
  1486. ;
  1487. ; Arguments:
  1488. ; None.
  1489. ;
  1490. ; Returns:
  1491. ; EAX - 1 if F12 pressed or if this is a restart; otherwise 0.
  1492. ;
  1493. ;--
  1494. CheckForF12 proc near
  1495. ;
  1496. ; Save DS and ES.
  1497. ;
  1498. push ds
  1499. push es
  1500. ;
  1501. ; Set DS and ES to 0.
  1502. ;
  1503. mov ax,0
  1504. mov ds,ax
  1505. mov es,ax
  1506. ;
  1507. ; Point ESI to the last DWORD of the restart block. Check to see if the
  1508. ; tag value is present. If not, jump to the wait loop.
  1509. ;
  1510. mov esi,07c00h + 08000h - 4 ; point to last DWORD of block
  1511. mov ebx,[esi] ; get the tag value
  1512. cmp ebx,'rtsR' ; is it right?
  1513. jnz DoF12Check ; if not, enter wait loop
  1514. ;
  1515. ; Calculate the checksum of the block. If it is 0, then this is a valid
  1516. ; restart block, so pretend that the user pressed F12.
  1517. ;
  1518. mov eax,0 ; accumulated checksum
  1519. mov ecx,128/4 ; length of block (last 128 bytes
  1520. ; of restart block)
  1521. F12csLoop:
  1522. mov ebx,[esi] ; get next DWORD
  1523. add eax,ebx ; add it to accumulated checksum
  1524. sub esi,4 ; point to previous DWORD
  1525. dec ecx ; check for end of block
  1526. jnz F12csLoop
  1527. cmp eax,0 ; is checksum correct?
  1528. mov eax,1 ; indicate F12 pressed
  1529. jz F12Done ; jump out if checksum is correct
  1530. DoF12Check:
  1531. ;
  1532. ; Write a prompt string. (Yes, this is not internationalizable.)
  1533. ;
  1534. push cs ; prompt string is in code segment
  1535. pop ds
  1536. mov si,offset F12Prompt ; ds:si points to prompt string
  1537. IFDEF HEADLESS_SRV
  1538. mov ax, cs:TerminalStatus ; If there is a terminal, initialize it
  1539. and al, 0b0h
  1540. cmp al, 0b0h
  1541. jne SkipTerminalInit
  1542. ;
  1543. ; Set color to black on white "\033[m\017"
  1544. ;
  1545. mov ah, 01h
  1546. mov al, 1bh
  1547. int 14h
  1548. mov ah, 01h
  1549. mov al, '['
  1550. int 14h
  1551. mov ah, 01h
  1552. mov al, 'm'
  1553. int 14h
  1554. mov ah, 01h
  1555. mov al, 11h
  1556. int 14h
  1557. ;
  1558. ; Clear the terminal screen "\033[H\033[J"
  1559. ;
  1560. mov ah, 01h
  1561. mov al, 1bh
  1562. int 14h
  1563. mov ah, 01h
  1564. mov al, '['
  1565. int 14h
  1566. mov ah, 01h
  1567. mov al, 'H'
  1568. int 14h
  1569. mov ah, 01h
  1570. mov al, 1bh
  1571. int 14h
  1572. mov ah, 01h
  1573. mov al, '['
  1574. int 14h
  1575. mov ah, 01h
  1576. mov al, 'J'
  1577. int 14h
  1578. SkipTerminalInit:
  1579. endif
  1580. PromptLoop:
  1581. lodsb ; get next byte of string
  1582. cmp al,0 ; end of string?
  1583. jz PromptDone ; jump out if yes
  1584. IFDEF HEADLESS_SRV
  1585. mov bx, cs:TerminalStatus ; if there is a terminal, write out to it as well
  1586. and bl, 0b0h
  1587. cmp bl, 0b0h
  1588. jne SkipTerminalPrompt
  1589. mov ah, 01h ; Write command
  1590. mov dx, HEADLESS_COMPORT ; Com port
  1591. int 14h ; Make com port call
  1592. SkipTerminalPrompt:
  1593. endif
  1594. mov ah,14
  1595. mov bx,7
  1596. int 10h ; print the byte
  1597. jmp PromptLoop
  1598. PromptDone:
  1599. push es ; restore ds
  1600. pop ds
  1601. ;
  1602. ; Capture the current RTC value.
  1603. ;
  1604. call GetCounterReal ; get starting RTC value
  1605. mov edi,eax ; calculate RTC value for now + 3 secs.
  1606. IFDEF HEADLESS_SRV
  1607. add edi,182 ; (if this is headless, make it 10 seconds)
  1608. ELSE
  1609. add edi,55 ; (RTC clicks 18.2 times per second)
  1610. ENDIF
  1611. F12Loop:
  1612. call GetKeyEx ; get keystroke, if any
  1613. mov ebx,eax ; copy it
  1614. cmp ebx,08600h ; check for F12
  1615. mov eax,1 ; indicate F12 pressed
  1616. jz F12Done ; jump out if F12 pressed
  1617. cmp ebx,0DA00h ; check for F12
  1618. mov eax,1 ; indicate F12 pressed
  1619. jz F12Done ; jump out if F12 pressed
  1620. cmp ebx,0011Bh ; check for ESC
  1621. mov eax,0 ; indicate F12 not pressed
  1622. jz F12Done ; jump out if ESC pressed
  1623. call GetCounterReal ; get current RTC value
  1624. cmp eax,edi ; is it higher than end value?
  1625. mov eax,0 ; indicate F12 not pressed
  1626. jb F12Loop ; loop if current < end
  1627. F12Done:
  1628. pop es
  1629. pop ds
  1630. ret
  1631. CheckForF12 endp
  1632. F12Prompt db 13,10,"Press F12 for network service boot",13,10,0
  1633. ;++
  1634. ;
  1635. ; ULONG
  1636. ; GetTickCount(
  1637. ; VOID
  1638. ; )
  1639. ;
  1640. ; Description:
  1641. ;
  1642. ; Reads the tick counter (incremented 18.2 times per second)
  1643. ;
  1644. ; Arguments:
  1645. ; None.
  1646. ;
  1647. ;--
  1648. public _GetTickCount
  1649. _GetTickCount proc near
  1650. push cx
  1651. mov ah,0
  1652. int 01ah
  1653. mov ax,dx ; low word of count
  1654. mov dx,cx ; high word of count
  1655. pop cx
  1656. ret
  1657. _GetTickCount endp
  1658. _TEXT ends
  1659. end Start