Subversion Repositories Kolibri OS

Rev

Rev 1941 | Rev 2014 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                              ;;
  3. ;; Copyright (C) KolibriOS team 2004-2010. All rights reserved. ;;
  4. ;; Copyright (C) MenuetOS 2000-2004 Ville Mikael Turjanmaa      ;;
  5. ;; Distributed under terms of the GNU General Public License    ;;
  6. ;;                                                              ;;
  7. ;;  BOOTCODE.INC                                                ;;
  8. ;;                                                              ;;
  9. ;;  KolibriOS 16-bit loader,                                    ;;
  10. ;;                        based on bootcode for MenuetOS        ;;
  11. ;;                                                              ;;
  12. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  13.  
  14. $Revision: 1952 $
  15.  
  16.  
  17. ;==========================================================================
  18. ;
  19. ;                           16 BIT FUNCTIONS
  20. ;
  21. ;==========================================================================
  22.  
  23. if 0
  24. putchar:
  25. ; in: al=character
  26.         mov     ah, 0Eh
  27.         mov     bh, 0
  28.         int     10h
  29.         ret
  30.  
  31. print:
  32. ; in: si->string
  33.         mov     al, 186
  34.         call    putchar
  35.         mov     al, ' '
  36.         call    putchar
  37.  
  38. printplain:
  39. ; in: si->string
  40.         pusha
  41.         lodsb
  42. @@:
  43.         call    putchar
  44.         lodsb
  45.         test    al,al
  46.         jnz     @b
  47.         popa
  48.         ret
  49.  
  50.  
  51. setcursor:
  52. ; in: dl=column, dh=row
  53.         mov     ah, 2
  54.         mov     bh, 0
  55.         int     10h
  56.         ret
  57.  
  58. macro _setcursor row,column
  59. {
  60.         mov     dx, row*256 + column
  61.         call    setcursor
  62. }
  63.  
  64. end if
  65.  
  66. boot_read_floppy:
  67.         push    si
  68.         xor     si, si
  69.         mov     ah, 2   ; read
  70. @@:
  71.         push    ax
  72.         int     0x13
  73.         pop     ax
  74.         jnc     @f
  75.         inc     si
  76.         cmp     si, 10
  77.         jnb     $
  78. @@:
  79.         pop     si
  80.         ret
  81.  
  82. sayerr_plain:
  83.         jmp     $
  84.  
  85. sayerr:
  86.         jmp     $
  87.  
  88.  
  89. ; convert abs. sector number (AX) to BIOS T:H:S
  90. ; sector number = (abs.sector%BPB_SecPerTrk)+1
  91. ; pre.track number = (abs.sector/BPB_SecPerTrk)
  92. ; head number = pre.track number%BPB_NumHeads
  93. ; track number = pre.track number/BPB_NumHeads
  94. ; Return: cl - sector number
  95. ;         ch - track number
  96. ;         dl - drive number (0 = a:)
  97. ;         dh - head number
  98. conv_abs_to_THS:
  99.         push    bx
  100.         mov     bx,word [BPB_SecPerTrk]
  101.         xor     dx,dx
  102.         div     bx
  103.         inc     dx
  104.         mov     cl, dl                          ; cl = sector number
  105.         mov     bx,word [BPB_NumHeads]
  106.         xor     dx,dx
  107.         div     bx
  108.         ; !!!!!!! ax = track number, dx = head number
  109.         mov     ch,al                           ; ch=track number
  110.         xchg    dh,dl                           ; dh=head number
  111.         mov     dl,0                            ; dl=0 (drive 0 (a:))
  112.         pop     bx
  113.         retn
  114. ; needed variables
  115. BPB_SecPerTrk   dw      0                       ; sectors per track
  116. BPB_NumHeads    dw      0                       ; number of heads
  117. BPB_FATSz16     dw      0                       ; size of FAT
  118. BPB_RootEntCnt  dw      0                       ; count of root dir. entries
  119. BPB_BytsPerSec  dw      0                       ; bytes per sector
  120. BPB_RsvdSecCnt  dw      0                       ; number of reserved sectors
  121. BPB_TotSec16    dw      0                       ; count of the sectors on the volume
  122. BPB_SecPerClus  db      0                       ; number of sectors per cluster
  123. BPB_NumFATs     db      0                       ; number of FAT tables
  124. abs_sector_adj  dw      0                       ; adjustment to make abs. sector number
  125. end_of_FAT      dw      0                       ; end of FAT table
  126. FirstDataSector dw      0                       ; begin of data
  127.  
  128. ;=========================================================================
  129. ;
  130. ;                           16 BIT CODE
  131. ;
  132. ;=========================================================================
  133.  
  134. include 'bootvesa.inc'                 ;Include source for boot vesa
  135.  
  136. start_of_code:
  137.         cld
  138. ; \begin{diamond}[02.12.2005]
  139. ; if bootloader sets ax = 'KL', then ds:si points to loader block
  140.         cmp     ax, 'KL'
  141.         jnz     @f
  142.         mov     word [cs:cfgmanager.loader_block], si
  143.         mov     word [cs:cfgmanager.loader_block+2], ds
  144. @@:
  145. ; \end{diamond}[02.12.2005]
  146.  
  147. ; if bootloader sets cx = 'HA' and dx = 'RD', then bx contains identifier of source hard disk
  148. ; (see comment to bx_from_load)
  149.         cmp     cx, 'HA'
  150.         jnz     no_hd_load
  151.         cmp     dx,'RD'
  152.         jnz     no_hd_load
  153.         mov     word [cs:bx_from_load], bx              ; {SPraid}[13.03.2007]
  154. no_hd_load:
  155.  
  156. ; set up stack
  157.         mov     ax, 3000h
  158.         mov     ss, ax
  159.         mov     sp, 0EC00h
  160. ; set up segment registers
  161.         push    cs
  162.         pop     ds
  163.         push    cs
  164.         pop     es
  165.  
  166. ; set videomode
  167.         mov     ax, 3
  168.         int     0x10
  169.  
  170. ; draw frames
  171.         push    0xb800
  172.         pop     es
  173.         xor     di, di
  174.         mov     ah, 1*16+15
  175.  
  176. cpugood:
  177.  
  178.         push    0
  179.         popf
  180.         sti
  181.  
  182. ; set up esp
  183.         movzx   esp, sp
  184.  
  185.         push    0
  186.         pop     es
  187.         and     word [es:0x9031], 0
  188. ; \begin{Mario79}
  189. ; find HDD IDE DMA PCI device
  190. ; check for PCI BIOS
  191.         mov     ax, 0xB101
  192.         int     0x1A
  193.         jc      .nopci
  194.         cmp     edx, 'PCI '
  195.         jnz     .nopci
  196. ; find PCI class code
  197. ; class 1 = mass storage
  198. ; subclass 1 = IDE controller
  199. ; a) class 1, subclass 1, programming interface 0x80
  200.         mov     ax, 0xB103
  201.         mov     ecx, 1*10000h + 1*100h + 0x80
  202.         xor     si, si  ; device index = 0
  203.         int     0x1A
  204.         jnc     .found
  205. ; b) class 1, subclass 1, programming interface 0x8A
  206.         mov     ax, 0xB103
  207.         mov     ecx, 1*10000h + 1*100h + 0x8A
  208.         xor     si, si  ; device index = 0
  209.         int     0x1A
  210.         jnc     .found
  211. ; c) class 1, subclass 1, programming interface 0x85
  212.         mov     ax, 0xB103
  213.         mov     ecx, 1*10000h + 1*100h + 0x85
  214.         xor     si, si
  215.         int     0x1A
  216.         jc      .nopci
  217. .found:
  218. ; get memory base
  219.         mov     ax, 0xB10A
  220.         mov     di, 0x20        ; memory base is config register at 0x20
  221.         int     0x1A
  222.         jc      .nopci
  223.         and     cx, 0xFFF0      ; clear address decode type
  224.         mov     [es:0x9031], cx
  225. .nopci:
  226. ; \end{Mario79}
  227.  
  228. ; --------------- APM ---------------------
  229.         and     word [es:0x9044], 0     ; ver = 0.0 (APM not found)
  230.         mov     ax, 0x5300
  231.         xor     bx, bx
  232.         int     0x15
  233.         jc      apm_end                 ; APM not found
  234.         test    cx, 2
  235.         jz      apm_end                 ; APM 32-bit protected-mode interface not supported
  236.         mov     [es:0x9044], ax         ; Save APM Version
  237.         mov     [es:0x9046], cx         ; Save APM flags
  238.  
  239.         mov     ax, 0x5304              ; Disconnect interface
  240.         xor     bx, bx
  241.         int     0x15
  242.         mov     ax, 0x5303              ; Connect 32 bit mode interface
  243.         xor     bx, bx
  244.         int     0x15
  245.  
  246.         mov     [es:0x9040], ebx
  247.         mov     [es:0x9050], ax
  248.         mov     [es:0x9052], cx
  249.         mov     [es:0x9054], dx
  250.  
  251. apm_end:
  252.  
  253. ;CHECK current of code
  254.         cmp     [cfgmanager.loader_block], -1
  255.         jz      noloaderblock
  256.         les     bx, [cfgmanager.loader_block]
  257.         cmp     byte [es:bx], 1
  258.         jnz     sayerr
  259.         push    0
  260.         pop     es
  261.  
  262. noloaderblock:
  263. ; DISPLAY VESA INFORMATION
  264.          call    print_vesa_info
  265.          call    calc_vmodes_table
  266.          call    check_first_parm  ;check and enable cursor_pos
  267.  
  268. ; \begin{diamond}[30.11.2005]
  269. cfgmanager:
  270. ; settings:
  271. ; a) preboot_graph = graphical mode
  272. ;    preboot_gprobe = probe this mode?
  273. ; b) preboot_dma  = use DMA access?
  274. ; c) preboot_vrrm = use VRR?
  275. ; d) preboot_device = from what boot?
  276.  
  277. ; determine default settings
  278. ;        mov     [.bSettingsChanged], 0
  279.  
  280. ;.preboot_gr_end:
  281.         mov     di, preboot_device
  282. ; if image in memory is present and [preboot_device] is uninitialized,
  283. ; set it to use this preloaded image
  284.         cmp     byte [di], 0
  285.         jnz     .preboot_device_inited
  286.         cmp     [.loader_block], -1
  287.         jz      @f
  288.         les     bx, [.loader_block]
  289.         test    byte [es:bx+1], 1
  290.         jz      @f
  291.         mov     byte [di], 3
  292.         jmp     .preboot_device_inited
  293. @@:
  294. ; otherwise, set [preboot_device] to 1 (default value - boot from floppy)
  295.         mov     byte [di], 1
  296. .preboot_device_inited:
  297. ; following 4 lines set variables to 1 if its current value is 0
  298.         cmp     byte [di+preboot_dma-preboot_device], 1
  299.         adc     byte [di+preboot_dma-preboot_device], 0
  300.         cmp     byte [di+preboot_biosdisk-preboot_device], 1
  301.         adc     byte [di+preboot_biosdisk-preboot_device], 0
  302.  
  303. ;        pop     ax              ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ??
  304.         jmp     .continue
  305. .loader_block dd -1
  306. .continue:
  307.         sti
  308.         jmp      .load
  309.  
  310. .loadc:
  311.         pop     eax
  312. .cont:
  313.         push    cs
  314.         pop     ds
  315. .load:
  316.  
  317. ; ASK GRAPHICS MODE
  318.  
  319.         call    set_vmode
  320.  
  321. ; GRAPHICS ACCELERATION
  322. ; force yes
  323.         mov     [es:0x901C], byte 1
  324.  
  325. ; DMA ACCESS TO HD
  326.  
  327.         mov     al, [preboot_dma]
  328.         mov     [es:0x901F], al
  329.  
  330. ; VRR_M USE
  331.  
  332.         mov     al,[preboot_vrrm]
  333.         mov     [es:0x9030], al
  334.         mov     [es:0x901E], byte 1
  335.  
  336. ; BOOT DEVICE
  337.  
  338.         mov     al, [preboot_device]
  339.         dec     al
  340.         mov     [boot_dev], al
  341.  
  342. ; GET MEMORY MAP
  343. include 'detect/biosmem.inc'
  344.  
  345. ; READ DISKETTE TO MEMORY
  346.  
  347. if 0
  348. ----
  349.         cmp     [boot_dev],0
  350.         jne     no_sys_on_floppy
  351.         xor     ax, ax            ; reset drive
  352.         xor     dx, dx
  353.         int     0x13
  354. ; do we boot from CD-ROM?
  355.         mov     ah, 41h
  356.         mov     bx, 55AAh
  357.         xor     dx, dx
  358.         int     0x13
  359.         jc      .nocd
  360.         cmp     bx, 0AA55h
  361.         jnz     .nocd
  362.         mov     ah, 48h
  363.         push    ds
  364.         push    es
  365.         pop     ds
  366.         mov     si, 0xa000
  367.         mov     word [si], 30
  368.         int     0x13
  369.         pop     ds
  370.         jc      .nocd
  371.         push    ds
  372.         lds     si, [es:si+26]
  373.         test    byte [ds:si+10], 40h
  374.         pop     ds
  375.         jz      .nocd
  376. ; yes - read all floppy by 18 sectors
  377.  
  378. ; TODO: !!!! read only first sector and set variables !!!!!
  379. ; ...
  380. ; TODO: !!! then read flippy image track by track
  381.  
  382.         mov     cx, 0x0001      ; startcyl,startsector
  383. .a1:
  384.         push    cx dx
  385.         mov     al, 18
  386.         mov     bx, 0xa000
  387.         call    boot_read_floppy
  388.         mov     si, movedesc
  389.         push    es
  390.         push    ds
  391.         pop     es
  392.         mov     cx, 256*18
  393.         mov     ah, 0x87
  394.         int     0x15
  395.         pop     es
  396.         pop     dx cx
  397.         test    ah, ah
  398.         jnz     sayerr_floppy
  399.         add     dword [si+8*3+2], 512*18
  400.         inc     dh
  401.         cmp     dh, 2
  402.         jnz     .a1
  403.         mov     dh, 0
  404.         inc     ch
  405.         cmp     ch, 80
  406.         jae     ok_sys_on_floppy
  407.         mov     al, ch
  408.         shr     ch, 2
  409.         jmp     .a1
  410. .nocd:
  411. ; no - read only used sectors from floppy
  412. ; now load floppy image to memory
  413. ; at first load boot sector and first FAT table
  414.  
  415. ; read only first sector and fill variables
  416.         mov     cx, 0x0001      ; first logical sector
  417.         xor     dx, dx          ; head = 0, drive = 0 (a:)
  418.         mov     al, 1           ; read one sector
  419.         mov     bx, 0xB000      ; es:bx -> data area
  420.         call    boot_read_floppy
  421. ; fill the necessary parameters to work with a floppy
  422.         mov     ax, word [es:bx+24]
  423.         mov     word [BPB_SecPerTrk], ax
  424.         mov     ax, word [es:bx+26]
  425.         mov     word [BPB_NumHeads], ax
  426.         mov     ax, word [es:bx+17]
  427.         mov     word [BPB_RootEntCnt], ax
  428.         mov     ax, word [es:bx+14]
  429.         mov     word [BPB_RsvdSecCnt], ax
  430.         mov     ax, word [es:bx+19]
  431.         mov     word [BPB_TotSec16], ax
  432.         mov     al, byte [es:bx+13]
  433.         mov     byte [BPB_SecPerClus], al
  434.         mov     al, byte [es:bx+16]
  435.         mov     byte [BPB_NumFATs], al
  436. ;<Lrz> 18.11.2008
  437.         mov     ax, word [es:bx+22]
  438.         mov     word [BPB_FATSz16], ax
  439.         mov     cx, word [es:bx+11]
  440.         mov     word [BPB_BytsPerSec], cx
  441.  
  442. ; count of clusters in FAT12 ((size_of_FAT*2)/3)
  443. ;        mov     ax, word [BPB_FATSz16]
  444. ;        mov     cx, word [BPB_BytsPerSec]
  445. ;end <Lrz> 18.11.2008
  446.         xor     dx, dx
  447.         mul     cx
  448.         shl     ax, 1
  449.         mov     cx, 3
  450.         div     cx              ; now ax - number of clusters in FAT12
  451.         mov     word [end_of_FAT], ax
  452.  
  453. ; load first FAT table
  454.         mov     cx, 0x0002      ; startcyl,startsector          ; TODO!!!!!
  455.         xor     dx, dx          ; starthead,drive
  456.         mov     al, byte [BPB_FATSz16]     ; no of sectors to read
  457.         add     bx, word [BPB_BytsPerSec]  ; es:bx -> data area
  458.         call    boot_read_floppy
  459.         mov     bx, 0xB000
  460.  
  461. ; and copy them to extended memory
  462.         mov     si, movedesc
  463.         mov     [si+8*2+3], bh          ; from
  464.  
  465.         mov     ax, word [BPB_BytsPerSec]
  466.         shr     ax, 1                   ; words per sector
  467.         mov     cx, word [BPB_RsvdSecCnt]
  468.         add     cx, word [BPB_FATSz16]
  469.         mul     cx
  470.         push    ax                      ; save to stack count of words in boot+FAT
  471.         xchg    ax, cx
  472.  
  473.         push    es
  474.         push    ds
  475.         pop     es
  476.         mov     ah, 0x87
  477.         int     0x15
  478.         pop     es
  479.         test    ah, ah
  480.         jz      @f
  481. sayerr_floppy:
  482.         mov     dx, 0x3f2
  483.         mov     al, 0
  484.         out     dx, al
  485. ;        mov     si, memmovefailed
  486.         jmp     $
  487. @@:
  488.         pop     ax                      ; restore from stack count of words in boot+FAT
  489.         shl     ax, 1                   ; make bytes count from count of words
  490.         and     eax, 0ffffh
  491.         add     dword [si+8*3+2], eax
  492.  
  493. ; copy first FAT to second copy
  494. ; TODO: BPB_NumFATs !!!!!
  495.         add     bx, word [BPB_BytsPerSec]       ; !!! TODO: may be need multiply by BPB_RsvdSecCnt !!!
  496.         mov     byte [si+8*2+3], bh     ; bx - begin of FAT
  497.  
  498.         mov     ax, word [BPB_BytsPerSec]
  499.         shr     ax, 1                   ; words per sector
  500.         mov     cx, word [BPB_FATSz16]
  501.         mul     cx
  502.         mov     cx, ax                  ; cx - count of words in FAT
  503.  
  504.         push    es
  505.         push    ds
  506.         pop     es
  507.         mov     ah, 0x87
  508.         int     0x15
  509.         pop     es
  510.         test    ah, ah
  511.         jnz     sayerr_floppy
  512.  
  513.         mov     ax, cx
  514.         shl     ax, 1
  515.         and     eax, 0ffffh             ; ax - count of bytes in FAT
  516.         add     dword [si+8*3+2], eax
  517.  
  518. ; reading RootDir
  519. ; TODO: BPB_NumFATs
  520.         add     bx, ax
  521.         add     bx, 100h
  522.         and     bx, 0ff00h                      ; bx - place in buffer to write RootDir
  523.         push    bx
  524.  
  525.         mov     bx, word [BPB_BytsPerSec]
  526.         shr     bx, 5                           ; divide bx by 32
  527.         mov     ax, word [BPB_RootEntCnt]
  528.         xor     dx, dx
  529.         div     bx
  530.         push    ax                              ; ax - count of RootDir sectors
  531.  
  532.         mov     ax, word [BPB_FATSz16]
  533.         xor     cx, cx
  534.         mov     cl, byte [BPB_NumFATs]
  535.         mul     cx
  536.         add     ax, word [BPB_RsvdSecCnt]       ; ax - first sector of RootDir
  537.  
  538.         mov     word [FirstDataSector], ax
  539.         pop     bx
  540.         push    bx
  541.         add     word [FirstDataSector], bx      ; Begin of data region of floppy
  542.  
  543. ; read RootDir
  544.         call    conv_abs_to_THS
  545.         pop     ax
  546.         pop     bx                              ; place in buffer to write
  547.         push    ax
  548.         call    boot_read_floppy                ; read RootDir into buffer
  549. ; copy RootDir
  550.         mov     byte [si+8*2+3], bh             ; from buffer
  551.         pop     ax                              ; ax = count of RootDir sectors
  552.         mov     cx, word [BPB_BytsPerSec]
  553.         mul     cx
  554.         shr     ax, 1
  555.         mov     cx, ax                          ; count of words to copy
  556.         push    es
  557.         push    ds
  558.         pop     es
  559.         mov     ah, 0x87
  560.         int     0x15
  561.         pop     es
  562.  
  563.         mov     ax, cx
  564.         shl     ax, 1
  565.         and     eax, 0ffffh             ; ax - count of bytes in RootDir
  566.         add     dword [si+8*3+2], eax   ; add count of bytes copied
  567.  
  568. ; Reading data clusters from floppy
  569.         mov     byte [si+8*2+3], bh
  570.         push    bx
  571.  
  572.         mov     di, 2                   ; First data cluster
  573. .read_loop:
  574.         mov     bx, di
  575.         shr     bx, 1                   ; bx+di = di*1.5
  576.         jnc     .even
  577.         test    word [es:bx+di+0xB200], 0xFFF0  ; TODO: may not be 0xB200 !!!
  578.         jmp     @f
  579. .even:
  580.         test    word [es:bx+di+0xB200], 0xFFF   ; TODO: may not be 0xB200 !!!
  581.  
  582. @@:
  583.         jz      .skip
  584. ; read cluster di
  585. ;.read:
  586.         ;conv cluster di to abs. sector ax
  587.         ; ax = (N-2) * BPB_SecPerClus + FirstDataSector
  588.         mov     ax, di
  589.         sub     ax, 2
  590.         xor     bx, bx
  591.         mov     bl, byte [BPB_SecPerClus]
  592.         mul     bx
  593.         add     ax, word [FirstDataSector]
  594.         call    conv_abs_to_THS
  595.         pop     bx
  596.         push    bx
  597.         mov     al, byte [BPB_SecPerClus]       ; number of sectors in cluster
  598.         call    boot_read_floppy
  599.         push    es
  600.         push    ds
  601.         pop     es
  602.         pusha
  603. ;
  604.         mov     ax, word [BPB_BytsPerSec]
  605.         xor     cx, cx
  606.         mov     cl, byte [BPB_SecPerClus]
  607.         mul     cx
  608.         shr     ax, 1                           ; ax = (BPB_BytsPerSec * BPB_SecPerClus)/2
  609.         mov     cx, ax                          ; number of words to copy (count words in cluster)
  610. ;
  611.         mov     ah, 0x87
  612.         int     0x15                            ; copy data
  613.         test    ah, ah
  614.         popa
  615.         pop     es
  616.         jnz     sayerr_floppy
  617. ; skip cluster di
  618. .skip:
  619.         mov     ax, word [BPB_BytsPerSec]
  620.         xor     cx, cx
  621.         mov     cl, byte [BPB_SecPerClus]
  622.         mul     cx
  623.         and     eax, 0ffffh             ; ax - count of bytes in cluster
  624.         add     dword [si+8*3+2], eax
  625.  
  626.         mov     ax, word [end_of_FAT]   ; max cluster number
  627.         pusha
  628. ; draw percentage
  629. ; total clusters: ax
  630. ; read clusters: di
  631.         xchg    ax, di
  632.         mov     cx, 100
  633.         mul     cx
  634.         div     di
  635.         aam
  636.         xchg    al, ah
  637.         add     ax, '00'
  638. @@:
  639.         popa
  640.         inc     di
  641.         cmp     di, word [end_of_FAT]   ; max number of cluster
  642.         jnz     .read_loop
  643.         pop     bx                      ; clear stack
  644.  
  645. ok_sys_on_floppy:
  646. no_sys_on_floppy:
  647.         xor     ax, ax          ; reset drive
  648.         xor     dx, dx
  649.         int     0x13
  650.         mov     dx, 0x3f2       ; floppy motor off
  651.         mov     al, 0
  652.         out     dx, al
  653. ---
  654. end if
  655.  
  656.  
  657. ; SET GRAPHICS
  658.  
  659.         xor     ax, ax
  660.         mov     es, ax
  661.  
  662.         mov     bx, [es:0x9008]         ; vga & 320x200
  663.         mov     ax, 0x4f02              ; Vesa
  664. setgr:
  665.         int     0x10
  666.         test    ah, ah
  667.         jnz     $
  668. gmok2:
  669.         push    ds
  670.         pop     es
  671.