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.

1440 lines
33 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. ; Build Notes:
  43. ; ~~~~~~~~~~~~
  44. ; The microsoft C compiler will not produce "tiny" model programs. In the
  45. ; tiny model, the entire program consists of only one segment. The small
  46. ; model produced by our compilers consists of two segments: DGROUP and _TEXT.
  47. ; If you convert a small model program into a tiny model program, DS (which
  48. ; should point to DGROUP (bss,const,data) will always be wrong. For this reason
  49. ; we need an assembly module to do a simple run-time fixup on SS and DS. To
  50. ; guarantee that DS will point to DGROUP no matter where os2ldr is loaded,
  51. ; the paragraph (shifted right four bits) offset of DGROUP from _TEXT must
  52. ; be added to the value in CS to compute DS and SS.
  53. ;
  54. ; We get the linker to fixup the offset of the beginning of the dgroup segment
  55. ; relative to the beginning of the code segment and it's this value added
  56. ; to the value in CS that allows us to build a "tiny" model program in C
  57. ; without a lot of munging around in order to get the data reference offsets
  58. ; in the code correct.
  59. ;
  60. ; If the _TEXT:DGROUP fixup appears in other files (which it does), the linker
  61. ; will not compute the correct value unless the accumulated data pointer is
  62. ; zero when it gets there. Therefore, no data should be placed in the data segment
  63. ; until after all instances of _TEXT:DGROUP have been encountered by the linker.
  64. ; The linker processes files from right to left on the command line.
  65. ;
  66. ; A Note About Stacks
  67. ; Initially we run on our internal stack (SuStack) which is only 160 bytes deep
  68. ; but seems to do the trick. Then we have to have a separate double fault stack.
  69. ; This stack can be in the middle of the stack/data segment. It will step on
  70. ; the loader image, but that's ok since the fault was either caused by 16bit
  71. ; code (which won't be in the loader image) or, it was caused by the 32bit
  72. ; loader (which has already been relocated) so we won't be stepping on code
  73. ; that may have caused the fault. And finally, we have the "call back" stack
  74. ; which starts at the top of the stack/data segment. We use this during
  75. ; all call backs since the original loader source is no longer needed and
  76. ; this'll give us plenty of stack for bios calls etc.
  77. ;
  78. ;--
  79. DoubleWord struc
  80. lsw dw ?
  81. msw dw ?
  82. DoubleWord ends
  83. ;
  84. ; This is the structure used to pass all shared data between the boot sector
  85. ; and NTLDR.
  86. ;
  87. SHARED struc
  88. ReadClusters dd ? ; function pointer
  89. ReadSectors dd ? ; function pointer
  90. SectorBase dd ? ; starting sector
  91. ; for ReadSectors
  92. ; callback
  93. SHARED ends
  94. BPB struc
  95. BytesPerSector dw ?
  96. SectorsPerCluster db ?
  97. ReservedSectors dw ?
  98. Fats db ?
  99. DirectoryEntries dw ?
  100. Sectors dw ?
  101. Media db ?
  102. FatSectors dw ?
  103. SectorsPerTrack dw ?
  104. Heads dw ?
  105. HiddenSectors dd ?
  106. SectorsLong dd ?
  107. ;
  108. ; The following byte is NOT part of the BPB but is set by SYS and format
  109. ;
  110. BootDriveNumber db ?
  111. BPB ends
  112. SU_CODEMODULE equ 1 ; Identifies this module to "su.inc"
  113. include su.inc
  114. include macro.inc
  115. extrn _BootRecord:word
  116. extrn _puts:near
  117. extrn _MemoryDescriptorList:near
  118. extrn _InsertDescriptor:near
  119. MAXREAD EQU 10000h
  120. MAXSECTORS EQU MAXREAD/0200h
  121. _TEXT segment para use16 public 'CODE'
  122. ASSUME CS: _TEXT, DS: DGROUP, SS: DGROUP
  123. .386p
  124. ;
  125. ; Run-time fixups for stack and data segment
  126. ;
  127. public Start
  128. Start:
  129. ;
  130. ; The FAT boot sector only reads in the first 512 bytes of NTLDR. This is
  131. ; the module that contains those 512 bytes, so we are now responsible for
  132. ; loading the rest of the file. Other filesystems (i.e. HPFS, NTFS, RIPL)
  133. ; will load the whole file, so the default entrypoint branches around the
  134. ; FAT-specific code.
  135. ;
  136. jmp RealStart
  137. FatBegin:
  138. .386
  139. ;
  140. ; If we're here, we've booted off a FAT system and we must load the rest
  141. ; of NTLDR at 2000:0200 (right behind this sector) NTLDR passes us the
  142. ; following:
  143. ; BX = Starting Cluster Number of NTLDR
  144. ; DL = INT 13h drive number we've booted from
  145. ; DS:SI -> boot media's BPB
  146. ; DS:DI -> argument structure (see above struc definition)
  147. ;
  148. ;
  149. ; Save away the boot drive and the starting cluster number
  150. ;
  151. push dx
  152. push bx
  153. ;
  154. ; Blast the FAT into memory at 6000:0000 - 8000:0000
  155. ;
  156. .386
  157. push 06000h
  158. .8086
  159. pop es
  160. xor bx,bx ; (es:bx) = 6000:0000
  161. mov cx,ds:[si].ReservedSectors
  162. mov ds:[di].SectorBase.msw,0
  163. mov ds:[di].SectorBase.lsw,cx ; set up Sector Base
  164. mov ax,ds:[si].FatSectors ; (al) = # Sectors to read
  165. cmp ax,080h
  166. jbe FatLt64k
  167. ; The FAT is > 64k, so we read the first 64k chunk, then the rest.
  168. ; (A 16-bit FAT can't be bigger than 128k)
  169. push cx
  170. mov ax,080h ; (al) = # of sectors to read
  171. call ds:[di].ReadSectors
  172. pop cx ; (cx) = previous SectorBase
  173. .386
  174. push 07000h
  175. .8086
  176. pop es
  177. xor bx,bx ; (es:bx) = 7000:0000
  178. mov ax,ds:[si].FatSectors
  179. sub ax,080h ; (ax) = # Sectors left to read
  180. add cx,080h ; (cx) = SectorBase for next read
  181. mov ds:[di].SectorBase.lsw,cx
  182. adc ds:[di].SectorBase.msw,0 ; set up SectorBase
  183. ;
  184. ; (al) = # of sectors to read
  185. ;
  186. FatLt64k:
  187. call ds:[di].ReadSectors
  188. ;
  189. ; FAT is in memory, now we restore our starting cluster number
  190. ;
  191. pop dx ; (dx) = starting cluster number
  192. xor bx,bx
  193. ;
  194. ; set up FS and GS for reading the FAT
  195. ;
  196. .386
  197. mov ax,6000h
  198. mov fs,ax
  199. mov ax,7000h
  200. mov gs,ax
  201. .8086
  202. ;
  203. ; set up ES for reading in the rest of us
  204. ;
  205. push cs
  206. pop es
  207. mov ah,MAXSECTORS ; (ah) = number of sectors we can read
  208. ; until boundary
  209. FatLoop:
  210. ;
  211. ; (dx) = next cluster to load
  212. ;
  213. push dx
  214. mov al,ds:[si].SectorsPerCluster ; (al) = number of contiguous sectors
  215. ; found
  216. sub ah,ds:[si].SectorsPerCluster ; can read before 64k
  217. ;
  218. ; Check to see if we've reached the end of the file
  219. ;
  220. cmp dx,0ffffh
  221. jne Fat10
  222. ;
  223. ; The entire file has been loaded. Throw away the saved next cluster,
  224. ; restore the boot drive, and let NTLDR do its thing.
  225. ;
  226. pop dx
  227. pop dx
  228. jmp RealStart
  229. Fat10:
  230. mov cx,dx
  231. ;
  232. ; (dx) = (cx) = last contiguous cluster
  233. ; (al) = # of contiguous clusters found
  234. ;
  235. call NextFatEntry
  236. ;
  237. ; (dx) = cluster following last contiguous cluster
  238. ;
  239. ; Check to see if the next cluster is contiguous. If not, go load the
  240. ; contiguous block we've found.
  241. ;
  242. inc cx
  243. cmp dx,cx
  244. jne LncLoad
  245. ;
  246. ; Check to see if we've reached the 64k boundary. If so, go load the
  247. ; contiguous block so far. If not, increment the number of contiguous
  248. ; sectors and loop again.
  249. ;
  250. cmp ah,0
  251. jne Lnc20
  252. mov ah,MAXSECTORS ; (ah) = number of sectors until
  253. ; boundary reached again
  254. jmp short LncLoad
  255. Lnc20:
  256. add al,ds:[si].SectorsPerCluster
  257. sub ah,ds:[si].SectorsPerCluster
  258. jmp short Fat10
  259. LncLoad:
  260. ;
  261. ; (TOS) = first cluster to load
  262. ; (dx) = first cluster of next group to load
  263. ; (al) = number of contiguous sectors
  264. ;
  265. pop cx
  266. push dx
  267. mov dx,cx
  268. mov cx,10 ; (cx) = retry count
  269. ;
  270. ; N.B.
  271. ; This assumes that we will never have more than 255 contiguous clusters.
  272. ; Since that would get broken up into chunks that don't cross the 64k
  273. ; boundary, this is ok.
  274. ;
  275. ; (dx) = first cluster to load
  276. ; (al) = number of contiguous sectors
  277. ; (TOS) = first cluster of next group to load
  278. ; (es:bx) = address where clusters should be loaded
  279. ;
  280. FatRetry:
  281. push bx
  282. push ax
  283. push dx
  284. push cx
  285. if 0
  286. push dx
  287. call PrintDbg
  288. mov dx,ax
  289. call PrintDbg
  290. pop dx
  291. endif
  292. call [di].ReadClusters
  293. jnc ReadOk
  294. ;
  295. ; error in the read, reset the drive and try again
  296. ;
  297. if 0
  298. mov dx, ax
  299. call PrintDbg
  300. endif
  301. mov ax,01h
  302. mov al,ds:[si].BootDriveNumber
  303. int 13h
  304. if 0
  305. mov dx,ax
  306. call PrintDbg
  307. endif
  308. xor ax,ax
  309. mov al,ds:[si].BootDriveNumber
  310. int 13h
  311. ;
  312. ; pause for a while
  313. ;
  314. xor ax,ax
  315. FatPause:
  316. dec ax
  317. jnz FatPause
  318. pop cx
  319. pop dx
  320. pop ax
  321. pop bx
  322. dec cx
  323. jnz FatRetry
  324. ;
  325. ; we have re-tried ten times, it still doesn't work, so punt.
  326. ;
  327. push cs
  328. pop ds
  329. mov si,offset FAT_ERROR
  330. FatErrPrint:
  331. lodsb
  332. or al,al
  333. jz FatErrDone
  334. mov ah,14 ; write teletype
  335. mov bx,7 ; attribute
  336. int 10h ; print it
  337. jmp FatErrPrint
  338. FatErrDone:
  339. jmp $
  340. ; this should be replaced by a mechanism to get a pointer
  341. ; passed to us in the param block. since the boot sector msg itself
  342. ; is properly localized but this one isn't.
  343. FAT_ERROR db 13,10,"Disk I/O error",0dh,0ah,0
  344. ReadOk:
  345. pop cx
  346. pop dx
  347. pop ax
  348. pop bx
  349. pop dx ; (dx) = first cluster of next group
  350. ; to load.
  351. .386
  352. ;
  353. ; Convert # of sectors into # of bytes.
  354. ;
  355. mov cl,al
  356. xor ch,ch
  357. shl cx,9
  358. .8086
  359. add bx,cx
  360. jz FatLoopDone
  361. jmp FatLoop
  362. FatLoopDone:
  363. ;
  364. ; (bx) = 0
  365. ; This means we've just ended on a 64k boundary, so we have to
  366. ; increment ES to continue reading the file. We are guaranteed to
  367. ; always end on a 64k boundary and never cross it, because we
  368. ; will reduce the number of contiguous clusters to read
  369. ; to ensure that the last cluster read will end on the 64k boundary.
  370. ; Since we start reading at 0, and ClusterSize will always be a power
  371. ; of two, a cluster will never cross a 64k boundary.
  372. ;
  373. mov ax,es
  374. add ax,01000h
  375. mov es,ax
  376. mov ah,MAXSECTORS
  377. jmp FatLoop
  378. ;++
  379. ;
  380. ; NextFatEntry - This procedure returns the next cluster in the FAT chain.
  381. ; It will deal with both 12-bit and 16-bit FATs. It assumes
  382. ; that the entire FAT has been loaded into memory.
  383. ;
  384. ; Arguments:
  385. ; (dx) = current cluster number
  386. ; (fs:0) = start of FAT in memory
  387. ; (gs:0) = start of second 64k of FAT in memory
  388. ;
  389. ; Returns:
  390. ; (dx) = next cluster number in FAT chain
  391. ; (dx) = 0ffffh if there are no more clusters in the chain
  392. ;
  393. ;--
  394. NextFatEntry proc near
  395. push bx
  396. ;
  397. ; Check to see if this is a 12-bit or 16-bit FAT. The biggest FAT we can
  398. ; have for a 12-bit FAT is 4080 clusters. This is 6120 bytes, or just under
  399. ; 12 sectors.
  400. ;
  401. ; A 16-bit FAT that's 12 sectors long would only hold 3072 clusters. Thus,
  402. ; we compare the number of FAT sectors to 12. If it's greater than 12, we
  403. ; have a 16-bit FAT. If it's less than or equal to 12, we have a 12-bit FAT.
  404. ;
  405. call IsFat12
  406. jnc Next16Fat
  407. Next12Fat:
  408. mov bx,dx ; (fs:bx) => temporary index
  409. shr dx,1 ; (dx) = offset/2
  410. ; (CY) = 1 need to shift
  411. pushf ; = 0 don't need to shift
  412. add bx,dx ; (fs:bx) => next cluster number
  413. .386
  414. mov dx,fs:[bx] ; (dx) = next cluster number
  415. .8086
  416. popf
  417. jc shift ; carry flag tells us whether to
  418. and dx,0fffh ; mask
  419. jmp short N12Tail
  420. shift:
  421. .386
  422. shr dx,4 ; or shift
  423. .8086
  424. N12Tail:
  425. ;
  426. ; Check for end of file
  427. ;
  428. cmp dx,0ff8h ; If we're at the end of the file,
  429. jb NfeDone ; convert to canonical EOF.
  430. mov dx,0ffffh
  431. jmp short NfeDone
  432. Next16Fat:
  433. add dx,dx ; (dx) = offset
  434. jc N16high
  435. mov bx,dx ; (fs:bx) => next cluster number
  436. .386
  437. mov dx,fs:[bx] ; (dx) = next cluster number
  438. .8086
  439. jmp short N16Tail
  440. N16high:
  441. mov bx,dx
  442. .386
  443. mov dx,gs:[bx]
  444. .8086
  445. N16Tail:
  446. cmp dx,0fff8h
  447. jb NfeDone
  448. mov dx,0ffffh ; If we're at the end of the file
  449. ; convert to canonical EOF.
  450. NfeDone:
  451. pop bx
  452. ret
  453. NextFatEntry endp
  454. ;++
  455. ;
  456. ; IsFat12 - This function determines whether the BPB describes a 12-bit
  457. ; or 16-bit FAT.
  458. ;
  459. ; Arguments - ds:si supplies pointer to BPB
  460. ;
  461. ; Returns
  462. ; CY set - 12-bit FAT
  463. ; CY clear - 16-bit FAT
  464. ;
  465. ;--
  466. IsFat12 proc near
  467. .386
  468. push eax
  469. push ebx
  470. push ecx
  471. push edx
  472. movzx ecx, ds:[si].Sectors
  473. or cx,cx
  474. jnz if10
  475. mov ecx, ds:[si].SectorsLong
  476. if10:
  477. ;
  478. ; (ecx) = number of sectors
  479. ;
  480. movzx ebx, byte ptr ds:[si].Fats
  481. movzx eax, word ptr ds:[si].FatSectors
  482. mul ebx
  483. sub ecx,eax
  484. ;
  485. ; (ecx) = (#sectors)-(sectors in FATs)
  486. ;
  487. movzx eax, word ptr ds:[si].DirectoryEntries
  488. shl eax, 5
  489. ;
  490. ; (eax) = #bytes in root dir
  491. ;
  492. mov edx,eax
  493. and edx,0ffff0000h
  494. div word ptr ds:[si].BytesPerSector
  495. sub ecx,eax
  496. ;
  497. ; (ecx) = (#sectors) - (sectors in fat) - (sectors in root dir)
  498. ;
  499. movzx eax, word ptr ds:[si].ReservedSectors
  500. sub ecx, eax
  501. mov eax, ecx
  502. movzx ecx, byte ptr ds:[si].SectorsPerCluster
  503. xor edx,edx
  504. div ecx
  505. cmp eax, 4087
  506. jae if20
  507. stc
  508. jmp short if30
  509. if20:
  510. clc
  511. if30:
  512. pop edx
  513. pop ecx
  514. pop ebx
  515. pop eax
  516. ret
  517. .8086
  518. IsFat12 endp
  519. PrintDbg proc near
  520. push ax
  521. push bx
  522. push cx
  523. mov cx,4
  524. pd10:
  525. .386
  526. rol dx,4
  527. .8086
  528. mov ah,0eh
  529. mov bx,7
  530. mov al,dl
  531. and al,0fh
  532. add al,'0'
  533. cmp al,'9'
  534. jbe pd15
  535. add al,'A'-('9'+1)
  536. pd15:
  537. int 010h
  538. loop pd10
  539. mov ah,0eh
  540. mov al,' '
  541. mov bx,7
  542. int 010h
  543. pop cx
  544. pop bx
  545. pop ax
  546. ret
  547. PrintDbg endp
  548. Free EQU 512-($-Start)
  549. if Free lt 0
  550. %out FATAL PROBLEM: FAT-specific startup code is greater than
  551. %out 512 bytes. Fix it!
  552. .err
  553. endif
  554. RealStart:
  555. .386p
  556. ;
  557. ; Compute the paragraph needed for DS
  558. ;
  559. if 0
  560. mov ax,0
  561. int 16h
  562. endif
  563. mov bx,offset _TEXT:DGROUP ; first calculate offset to data
  564. shr bx,4 ; must be para aligned
  565. mov ax,cs ; get base of code
  566. add ax,bx ; add paragraph offset to data
  567. mov ss,ax ; ints disabled for next instruct
  568. mov sp,offset DGROUP:SuStack ; (sp) = top of internal stack
  569. ;
  570. ; Build C stack frame for _SuMain
  571. ;
  572. push dx ; pass bootdisk to main (high byte is ignored)
  573. ;
  574. ; Make DS point to the paragraph address of DGROUP
  575. ;
  576. mov ds,ax ; ds now points to beginning of DGROUP
  577. mov es,ax ; es now points to beginning of DGROUP
  578. ;
  579. ; Compute the physical address of the end of the data segment (which
  580. ; will be the beginning of the prepended loader file).
  581. ;
  582. movzx edx,ax
  583. shl edx,4
  584. add edx,offset DGROUP:_edata
  585. mov dword ptr _FileStart,edx
  586. ;
  587. ; Force the upper parts of
  588. ; of EBP and ESP to be zero in real mode.
  589. ;
  590. xor bp,bp
  591. movzx ebp,bp
  592. movzx esp,sp
  593. mov [saveDS],ds
  594. call _SuMain ; go to C code to do everything else.
  595. ;++
  596. ; _EnableProtectPaging
  597. ;
  598. ; Loads 386 protect mode registers.
  599. ; Enables 386 protection h/w
  600. ; Loads pagings registers
  601. ; Enables 386 paging h/w
  602. ;
  603. ;--
  604. public _EnableProtectPaging
  605. _EnableProtectPaging proc near
  606. ;
  607. ; Sanitize ES and GS and clean out any junk in the upper 16bits
  608. ; of the flags that may have been left by the bios, before we go protected
  609. ;
  610. push dword ptr 0
  611. popfd
  612. mov bx,sp
  613. mov dx,[bx+2] ; are we enabling prot/paging for the first time?
  614. xor ax,ax
  615. mov gs,ax
  616. mov es,ax
  617. ;
  618. ; FS must contain the selector of the PCR when we call the kernel
  619. ;
  620. push PCR_Selector
  621. pop fs
  622. ;
  623. ; Load the gdtr and idtr.
  624. ; We disable interrupts here since we can't handle interrups with the
  625. ; idt loaded while were in real mode and before we switch to protmode.
  626. cli
  627. lgdt fword ptr [_GDTregister]
  628. lidt fword ptr [_IDTregister]
  629. ;
  630. ; We have to stamp the segment portion of any real-mode far pointer with
  631. ; the corresponding selector values before we go protected.
  632. ;
  633. mov si,offset _ScreenStart
  634. mov word ptr [si+2],VideoSelector
  635. mov si,offset _vp
  636. mov word ptr [si+2],VideoSelector
  637. ;
  638. ; Enable protect and paging mode
  639. ;
  640. mov eax,cr0
  641. ; If we're enabling protect mode for the first time, don't turn on paging
  642. ; because the osloader does all that. However, if we're returning to
  643. ; protected mode, the page tables are already setup, therefore we do want
  644. ; to turn paging on.
  645. or dx,dx
  646. jz only_prot
  647. or eax,PROT_MODE + ENABLE_PAGING
  648. mov cr0,eax
  649. ;
  650. ; The following JMP must be DWORD-aligned in order to avoid an obscure i386
  651. ; hardware bug. If not, it is possible (albeit unlikely) that the prefetch
  652. ; queue can get trashed.
  653. ;
  654. ALIGN 4
  655. jmp flush
  656. only_prot:
  657. or eax,PROT_MODE
  658. mov cr0,eax
  659. ;
  660. ; Flush the prefetch queue
  661. ;
  662. ALIGN 4
  663. jmp flush
  664. flush:
  665. ;
  666. ; Load CS with the SU module's code selector
  667. ;
  668. push SuCodeSelector
  669. push offset cs:restart
  670. retf
  671. ;
  672. ; Now load DS and SS with the SU module's protect mode data selector.
  673. ;
  674. restart:
  675. mov ax,SuDataSelector
  676. mov ds,ax
  677. mov ss,ax
  678. ;
  679. ; Load LDT with zero since it will never be used.
  680. ;
  681. xor bx,bx
  682. lldt bx
  683. ;
  684. ; Load the Task Register and return to the boot SU module.
  685. ;
  686. or dx,dx
  687. jnz epp10
  688. mov bx,TSS_Selector
  689. ltr bx
  690. epp10:
  691. ret
  692. _EnableProtectPaging endp
  693. .286p
  694. ;** _biosint
  695. ;
  696. ; Rom bios interrupt dispatcher
  697. ;
  698. public _biosint
  699. _biosint proc near
  700. enter 0,0
  701. push di
  702. push si
  703. push ds
  704. push es
  705. ; Get pointer to register parameter frame
  706. les di,[bp+4]
  707. ; Get requested interrupt number
  708. mov ax,es:[di].intnum
  709. ; Check that requested bios interrupt is supported
  710. sub ax,10h ; sub lowest int number supported
  711. jnc short bios1
  712. mov es:[di].intnum,FUNCTION_ERROR
  713. jmp short biosx
  714. bios1:
  715. shl ax,1 ; shift if to make it a word offset
  716. cmp ax,bios_cnt ; offset beyond end of table?
  717. jb short bios2
  718. ; Error: requested interrupt not supported
  719. mov es:[di].sax,FUNCTION_ERROR
  720. jmp short biosx
  721. bios2: mov bx,ax
  722. mov ax,word ptr cs:bios_table[bx]
  723. push es ; save seg of address frame
  724. push di ; save stack register frame pointer
  725. push ax ; address of bios int
  726. mov ax,es:[di].sax
  727. mov bx,es:[di].sbx
  728. mov cx,es:[di].scx
  729. mov dx,es:[di].sdx
  730. mov si,es:[di].ssi
  731. mov es,es:[di].ses
  732. ret ; this sends us to the "int #" instruction
  733. ; We return here from the jmp instruction following the int
  734. bios_ret:
  735. pop di ; get address of register parameter frame
  736. pop es ; restore segment of parameter frame
  737. bios5: pushf
  738. pop es:[di].sfg
  739. mov es:[di].sax,ax
  740. mov es:[di].sbx,bx
  741. mov es:[di].scx,cx
  742. mov es:[di].sdx,dx
  743. mov es:[di].ssi,si
  744. mov es:[di].ses,es
  745. ; Restore original registers and return to caller
  746. biosx:
  747. pop es
  748. pop ds
  749. pop si
  750. pop di
  751. leave
  752. ret
  753. _biosint endp
  754. ;** Bios Interrupt Table
  755. ;
  756. bios10: int 10h
  757. jmp short bios_ret
  758. bios11: int 11h
  759. jmp short bios_ret
  760. bios12: int 12h
  761. jmp short bios_ret
  762. bios13: int 13h
  763. jmp short bios_ret
  764. bios14: int 14h
  765. jmp short bios_ret
  766. bios15: int 15h
  767. jmp short bios_ret
  768. bios16: int 16h
  769. jmp short bios_ret
  770. bios17: int 17h
  771. jmp short bios_ret
  772. bios18: int 18h
  773. jmp short bios_ret
  774. bios19: int 19h
  775. jmp short bios_ret
  776. bios_table dw bios10,bios11,bios12,bios13,bios14,bios15,bios16,bios17,bios18,bios19
  777. bios_cnt equ $ - bios_table
  778. .386p
  779. ;++
  780. ;
  781. ; _MoveMemory
  782. ;
  783. ; Routine Description
  784. ;
  785. ; Moves dwords in memory from source to destination.
  786. ;
  787. ; Arguments
  788. ;
  789. ; (TOS+4) = number of bytes to move
  790. ; (TOS+8) = linear address of destination
  791. ; (TOS+12) = linear address of source
  792. ;
  793. ; Notes
  794. ;
  795. ; 1) Valid page table entries must already exist for the
  796. ; source and destination memory.
  797. ;
  798. ; 2) ALL memory in the lower one megabyte is assumed to
  799. ; be identity mapped if used.
  800. ;
  801. ; USES ESI, EDI, ECX, FLAGS
  802. ;
  803. ;
  804. ;--
  805. public _MoveMemory
  806. _MoveMemory proc near
  807. enter 0,0
  808. push ds
  809. push es
  810. ;
  811. ; Get source, destination, and count arguments from the stack
  812. ; Make "count" the number of dwords to move.
  813. ;
  814. mov esi,dword ptr [bp+4]
  815. mov edi,dword ptr [bp+8]
  816. mov ecx,dword ptr [bp+12]
  817. shr ecx,2
  818. ;
  819. ; Load FLAT selectors into DS and ES
  820. ;
  821. mov ax,KeDataSelector
  822. mov ds,ax
  823. mov es,ax
  824. ;
  825. ; Move the block of data.
  826. ;
  827. assume es:FLAT, ds:FLAT
  828. ;
  829. ; move the dwords
  830. ;
  831. cld
  832. rep movs dword ptr [edi],dword ptr [esi]
  833. ;
  834. ; move the remaining tail
  835. ;
  836. mov ecx, dword ptr [bp+12]
  837. and ecx, 3
  838. rep movs byte ptr [edi],byte ptr [esi]
  839. assume es:nothing, ds:DGROUP
  840. pop es
  841. pop ds
  842. leave
  843. ret
  844. _MoveMemory endp
  845. ;++
  846. ;
  847. ; _ZeroMemory
  848. ;
  849. ; Routine Description
  850. ;
  851. ; Writes zeros into memory at the target address.
  852. ;
  853. ; Arguments
  854. ;
  855. ; (TOS+4) = linear address of target
  856. ; (TOS+8) = number of bytes to zero
  857. ;
  858. ; Notes
  859. ;
  860. ; 1) Valid page table entries must already exist for the
  861. ; source and destination memory.
  862. ;
  863. ; 2) ALL memory in the lower one megabyte is assumed to
  864. ; be identity mapped if used.
  865. ;
  866. ; USES ESI, EDI, ECX, FLAGS
  867. ;
  868. ;
  869. ;--
  870. public _ZeroMemory
  871. _ZeroMemory proc near
  872. enter 0,0
  873. push es
  874. ;
  875. ; Get source, destination, and count arguments from the stack
  876. ; Make "count" the number of dwords to move.
  877. ;
  878. mov edi,dword ptr [bp+4]
  879. mov ecx,dword ptr [bp+8]
  880. shr ecx,2
  881. ;
  882. ; Load FLAT selectors into DS and ES
  883. ;
  884. mov ax,KeDataSelector
  885. mov es,ax
  886. xor eax,eax
  887. ;
  888. ; Zero the the block of data.
  889. ;
  890. assume es:FLAT
  891. ;
  892. ; Zero the dwords
  893. ;
  894. cld
  895. rep stos dword ptr [edi]
  896. ;
  897. ; Zero the remaining bytes
  898. ;
  899. mov ecx, dword ptr [bp+8]
  900. and ecx, 3
  901. rep stos byte ptr [edi]
  902. assume es:nothing, ds:DGROUP
  903. pop es
  904. leave
  905. ret
  906. _ZeroMemory endp
  907. ;++
  908. ;
  909. ; Turn Floppy Drive Motor Off
  910. ;
  911. ;--
  912. public _TurnMotorOff
  913. DriveControlRegister equ 3f2h ; Floppy control register
  914. _TurnMotorOff proc near
  915. mov dx,DriveControlRegister
  916. mov ax,0CH
  917. out dx,al
  918. ret
  919. _TurnMotorOff endp
  920. ;
  921. ; Note: we do not save and restore the gdt and idt values because they
  922. ; cannot change while external services are being used by the OS loader.
  923. ; This is because they MUST remain identity mapped until all mode
  924. ; switching has ceased.
  925. ;
  926. public _RealMode
  927. _RealMode proc near
  928. ;
  929. ; Switch to real-mode
  930. ;
  931. sgdt fword ptr [_GDTregister]
  932. sidt fword ptr [_IDTregister]
  933. push [saveDS] ; push this so we can get to it later
  934. mov ax,SuDataSelector
  935. mov es,ax
  936. mov fs,ax
  937. mov gs,ax
  938. mov eax,cr0
  939. and eax, not (ENABLE_PAGING + PROT_MODE)
  940. mov cr0,eax
  941. ;
  942. ; flush the pipeline
  943. ;
  944. jmp far ptr here
  945. here:
  946. ;
  947. ; Flush TLB
  948. ;
  949. ; HACKHACK - We don't know where the page directory is, since it was
  950. ; allocated in the osloader. So we don't want to clear out cr3,
  951. ; but we DO want to flush the TLB....
  952. ;
  953. mov eax,cr3
  954. nop ; Fill - Ensure 13 non-page split
  955. nop ; accesses before CR3 load
  956. nop ; (P6 errata #11 stepping B0)
  957. nop
  958. mov cr3,eax
  959. ;
  960. ; switch to real mode addressing
  961. ;
  962. ; N. B. We need to do a far jump rather than a retf, because a retf will not
  963. ; reset the access rights to CS properly.
  964. ;
  965. db 0EAh ; JMP FAR PTR
  966. dw offset _TEXT:rmode ; 2000:rmode
  967. dw 02000h
  968. rmode:
  969. pop ax
  970. mov ds,ax
  971. mov ss,ax
  972. ;
  973. ; Stamp video pointers for real-mode use
  974. ;
  975. mov si,offset _ScreenStart
  976. mov word ptr [si+2],0b800h
  977. mov si,offset _vp
  978. mov word ptr [si+2],0b800h
  979. ;
  980. ; re-enable interrups
  981. ;
  982. lidt fword ptr [_IDTregisterZero]
  983. ;
  984. ; Re-enable interrupts
  985. ;
  986. sti
  987. ret
  988. _RealMode endp
  989. ;** _TransferToLoader - transfer control the the OS loader
  990. ;
  991. ;
  992. ; Arguments:
  993. ;
  994. ; None
  995. ;
  996. ; Returns:
  997. ;
  998. ; Does not return
  999. ;
  1000. ;**
  1001. public _TransferToLoader
  1002. _TransferToLoader proc near
  1003. ; generates a double fault for debug purposes
  1004. ; mov sp,0
  1005. ; push 0
  1006. mov ebx,dword ptr [esp+2] ; get entrypoint arg
  1007. xor eax,eax
  1008. mov ax,[saveDS]
  1009. ;
  1010. ; Setup OS loader's stack. Compute FLAT model esp to id map to
  1011. ; original stack.
  1012. ;
  1013. mov cx,KeDataSelector
  1014. mov ss,cx
  1015. mov esp,LOADER_STACK
  1016. ;
  1017. ; Load ds and es with kernel's data selectors
  1018. ;
  1019. mov ds,cx
  1020. mov es,cx
  1021. ;
  1022. ; Setup pointer to file system and boot context records
  1023. ;
  1024. ; Make a linear pointer to the Boot Context Record
  1025. shl eax,4
  1026. xor ecx,ecx
  1027. mov cx,offset _BootRecord
  1028. add eax,ecx
  1029. push eax
  1030. push 1010h ; dummy return address.
  1031. push 1010h ; dummy return address.
  1032. ;
  1033. ; Push 48bit address of loader entry-point
  1034. ;
  1035. db OVERRIDE
  1036. push KeCodeSelector
  1037. push ebx
  1038. ;
  1039. ; Pass control to the OS loader
  1040. ;
  1041. db OVERRIDE
  1042. retf
  1043. _TransferToLoader endp
  1044. ;++
  1045. ; Description:
  1046. ;
  1047. ; Gets memory block sizes for memory from zero to one meg and
  1048. ; from one meg to 64 meg. We do this by calling int 12h
  1049. ; (get conventional memory size) and int 15h function 88h (get
  1050. ; extended memory size).
  1051. ;
  1052. ; Arguments:
  1053. ;
  1054. ; None
  1055. ;
  1056. ; Returns:
  1057. ;
  1058. ; USHORT - Size of usable memory (in pages)
  1059. ;
  1060. ;--
  1061. public _IsaConstructMemoryDescriptors
  1062. BmlTotal equ [bp-4]
  1063. Func88Result equ [bp-6]
  1064. _IsaConstructMemoryDescriptors proc near
  1065. push bp ; save ebp
  1066. mov bp, sp
  1067. sub sp, 6
  1068. ;
  1069. ; Initialize the MemoryList to start with a zero entry. (end-of-list)
  1070. ;
  1071. les si, dword ptr _MemoryDescriptorList
  1072. xor eax,eax
  1073. mov es:[si].BlockSize,eax
  1074. mov es:[si].BlockBase,eax
  1075. ;
  1076. ; Get conventional (below one meg) memory size
  1077. ;
  1078. push es
  1079. push si
  1080. int 12h
  1081. movzx eax,ax
  1082. ;
  1083. ; EAX is the number of 1k blocks, which we need to convert to the
  1084. ; number of bytes.
  1085. ;
  1086. shl eax,10
  1087. push eax
  1088. shr eax, 12
  1089. mov BmlTotal, eax
  1090. xor eax,eax
  1091. push eax
  1092. call _InsertDescriptor
  1093. add sp,8
  1094. ;
  1095. ; Get extended memory size and fill-in the second descriptor
  1096. ;
  1097. mov ah,88h
  1098. int 15h
  1099. mov Func88Result,ax
  1100. and eax,0ffffh
  1101. ;
  1102. ; EAX is the number of 1k blocks, which we need to convert to the
  1103. ; number of bytes.
  1104. ;
  1105. shl eax,10
  1106. push eax
  1107. shr eax,12
  1108. add BmlTotal, ax
  1109. mov eax,0100000h
  1110. push eax
  1111. call _InsertDescriptor
  1112. add sp,8
  1113. ;
  1114. ; Try function E801, see if that is supported on this machine
  1115. ;
  1116. mov ax,0E801h
  1117. int 15h
  1118. jc short Isa50
  1119. cmp ax,Func88Result ; Is extended memory same as 88?
  1120. je short Isa40 ; Yes, go add the rest
  1121. cmp ax, (16-1) * 1024 ; Is extended memory exactly 16MB?
  1122. jne short Isa50 ; No, conflict between 88 & E801
  1123. Isa40:
  1124. ;
  1125. ; Function looks like it worked
  1126. ;
  1127. ; AX = extended memory < 16M in 1k blocks
  1128. ; BX = extended memory > 16M in 64k blocks
  1129. ;
  1130. and ebx,0ffffh
  1131. jz short Isa50
  1132. shl ebx,16 ; ebx = memory > 16M in bytes (via E801)
  1133. add ebx, 16*1024*1024 ; ebx = end of memory in bytes (via E801)
  1134. mov ax, Func88Result
  1135. and eax,0ffffh
  1136. shl eax, 10 ; eax = memory > 1M in bytes (via 88)
  1137. add eax, 1*1024*1024 ; eax = end of memory in bytes (via 88)
  1138. sub ebx, eax ; ebx = memory above eax
  1139. jbe short Isa50 ; if ebx <= eax, done
  1140. push ebx
  1141. shr ebx,12
  1142. add BmlTotal, bx
  1143. push eax
  1144. call _InsertDescriptor
  1145. add sp,8
  1146. and eax,0ffffh
  1147. Isa50:
  1148. pop si
  1149. pop es
  1150. mov eax, BmlTotal
  1151. mov sp, bp
  1152. pop bp
  1153. ret
  1154. _IsaConstructMemoryDescriptors endp
  1155. ;++
  1156. ;
  1157. ; BOOLEAN
  1158. ; Int15E820 (
  1159. ; E820Frame *Frame
  1160. ; );
  1161. ;
  1162. ;
  1163. ; Description:
  1164. ;
  1165. ; Gets address range descriptor by calling int 15 function E820h.
  1166. ;
  1167. ; Arguments:
  1168. ;
  1169. ; Returns:
  1170. ;
  1171. ; BOOLEAN - failed or succeed.
  1172. ;
  1173. ;--
  1174. cmdpFrame equ [bp + 6]
  1175. public _Int15E820
  1176. _Int15E820 proc near
  1177. push ebp
  1178. mov bp, sp
  1179. mov bp, cmdpFrame ; (bp) = Frame
  1180. push es
  1181. push edi
  1182. push esi
  1183. push ebx
  1184. push ss
  1185. pop es
  1186. mov ebx, [bp].Key
  1187. mov ecx, [bp].DescSize
  1188. lea di, [bp].BaseAddrLow
  1189. mov eax, 0E820h
  1190. mov edx, 'SMAP' ; (edx) = signature
  1191. INT 15h
  1192. mov [bp].Key, ebx ; update callers ebx
  1193. mov [bp].DescSize, ecx ; update callers size
  1194. sbb ecx, ecx ; ecx = -1 if carry, else 0
  1195. sub eax, 'SMAP' ; eax = 0 if signature matched
  1196. or ecx, eax
  1197. mov [bp].ErrorFlag, ecx ; return 0 or non-zero
  1198. pop ebx
  1199. pop esi
  1200. pop edi
  1201. pop es
  1202. pop ebp
  1203. ret
  1204. _Int15E820 endp
  1205. _TEXT ends
  1206. end Start