home *** CD-ROM | disk | FTP | other *** search
/ PC Extra Super CD 1998 January / PCPLUS131.iso / DJGPP / V2MISC / PMODE12S.ZIP / SRC / PMODE / PMODSTUB.ASM < prev    next >
Encoding:
Assembly Source File  |  1997-02-22  |  33.8 KB  |  1,017 lines

  1. ; Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details
  2. ; -*- asm -*-
  3. ;
  4. ;-----------------------------------------------------------------------------
  5. ; PMODE/DJ - A stub with an inbuilt DPMI dos extender. (like PMODE/W)
  6. ;
  7. ; PMODE/DJ includes PMODE V3.07, which is (c) by Thomas Phytel
  8. ; PMODE/DJ was written by m.grimrath@tu-bs.de. Changes were made both to
  9. ; stub.asm and pmode.asm.
  10. ; stub.asm  - changed to compile with tasm and switches into PM via PMODE
  11. ; pmode.asm - added some features, like exceptionhandling and PIC
  12. ;               reprogramming, etc. See pmodedj.doc for details
  13. ;-----------------------------------------------------------------------------
  14. ;
  15. ; KLUDGE-WARNING!
  16. ;
  17. ; So you say you want to change this file, right?  Are you really sure
  18. ; that's a good idea?  Let me tell you a bit about the pitfalls here:
  19. ;
  20. ; * Some code runs in protected mode, some in real-mode, some in both.
  21. ; * Some code must run on a 8088 without crashing it.
  22. ; * Registers and flags may be expected to survive for a long time.
  23. ; * The code is optimized for size, not for speed or readability.
  24. ; * Some comments are parsed by other programs.
  25. ;
  26. ; You still want to change it?  Oh well, go ahead, but don't come
  27. ; crying back saying you weren't warned.
  28. ;
  29. ;-----------------------------------------------------------------------------
  30. ;  djgpp stub loader
  31. ;
  32. ;  (C) Copyright 1993-1995 DJ Delorie
  33. ;
  34. ;  Redistribution and use in source and binary forms are permitted
  35. ;  provided that: (1) source distributions retain this entire copyright
  36. ;  notice and comment, (2) distributions including binaries display
  37. ;  the following acknowledgement:  ``This product includes software
  38. ;  developed by DJ Delorie and contributors to the djgpp project''
  39. ;  in the documentation or other materials provided with the distribution
  40. ;  and in all advertising materials mentioning features or use of this
  41. ;  software, and (3) binary distributions include information sufficient
  42. ;  for the binary user to obtain the sources for the binary and utilities
  43. ;  required to built and use it. Neither the name of DJ Delorie nor the
  44. ;  names of djgpp's contributors may be used to endorse or promote
  45. ;  products derived from this software without specific prior written
  46. ;  permission.
  47. ;
  48. ;  THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  49. ;  IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  50. ;  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  51. ;
  52. ;  Revision history:
  53. ;
  54. ;  93/12/05 DJ Delorie  Initial version v2.00, requires DPMI 0.9
  55. ;  94/10/13 CW Sandmann v2.01, accumlated changes: 60K load bug, limits, cwsdpmi, optimization
  56. ;  94/10/29 CW Sandmann v2.03, M Welinder changes; cwsdpmi load anywhere, size decrease
  57. ;
  58.         ideal
  59.         p386
  60.         assume cs:_TEXT, ds:DGROUP, es:nothing, ss:nothing, fs:_TEXT
  61.         group DGROUP _DATA, _BSS
  62.  
  63.         SEGMENT _TEXT PUBLIC USE16 'CODE'
  64.  
  65. ;*****************************************************************************
  66. ;  structure definitions
  67. ;
  68.  
  69. coff_magic      = 0                     ; from coff header
  70.  
  71. aout_entry      = 16                    ; from aout header
  72.  
  73. s_paddr         = 8                     ; from section headers
  74. s_vaddr         = 12
  75. s_size          = 16
  76. s_scnptr        = 20
  77.  
  78. stack_sz        = 180h                  ; must be a multiple of 16!
  79.  
  80. SW_FLAGS        = 0002h                 ; switch flags for PMODE
  81. EXCEPTION_HANDLER = 0
  82.         EXTRN   pm_info:near, pm_init:near
  83.  
  84. ;-----------------------------------------------------------------------------
  85. ;  Interface to 32-bit executable:
  86. ;
  87. ;    cs:eip     according to COFF header
  88. ;    ds         32-bit data segment for COFF program
  89. ;    fs         selector for our data segment (fs:0 is stubinfo)
  90. ;    ss:sp      our stack (ss to be freed)
  91. ;    <others>   All unspecified registers have unspecified values in them.
  92. ;-----------------------------------------------------------------------------
  93. ;  This is the stubinfo structure.  The presence of this structure
  94. ;  indicates that the executable is a djgpp v2.00 executable.
  95. ;  Fields will never be deleted from this structure, only obsoleted.
  96. ;
  97. label stubinfo byte
  98. stubinfo_magic  \               ; char [16]
  99.         db "go32stub, v 2.00"   ; version may change, [0..7] won't
  100. stubinfo_size  \                ; unsigned long
  101.         dw      stubinfo_end,0  ; bytes in structure
  102. stubinfo_minstack  \            ; unsigned long
  103.         dd      40000h          ; minimum amount of DPMI stack space (256K)
  104. stubinfo_memory_handle  \       ; unsigned long
  105.         dd      0               ; DPMI memory handle
  106. stubinfo_initial_size  \        ; unsigned long
  107.         dd      0               ; size of initial segment
  108. stubinfo_minkeep  \             ; unsigned short
  109.         dw      16384           ; amount of automatic real-mode buffer
  110. stubinfo_ds_selector  \         ; unsigned short
  111.         dw      0               ; our DS selector (used for transfer buffer)
  112. stubinfo_ds_segment  \          ; unsigned short
  113.         dw      0               ; our DS segment (used for simulated calls)
  114. stubinfo_psp_selector  \        ; unsigned short
  115.         dw      0               ; PSP selector
  116. stubinfo_cs_selector  \         ; unsigned short
  117.         dw      0               ; to be freed
  118. stubinfo_env_size  \            ; unsigned short
  119.         dw      0               ; number of bytes of environment
  120. stubinfo_basename  \            ; char [8]
  121.         db      8 dup (0)       ; base name of executable to load (asciiz if < 8)
  122.         ;db "A",0,0,0,0,0,0,0
  123. stubinfo_argv0  \               ; char [16]
  124.         db      16 dup (0)      ; used ONLY by the application (asciiz if < 16)
  125. stubinfo_dpmi_server  \         ; char [16]
  126.         db      16 dup (0)      ; used by stub to load DPMI server if no DPMI
  127.                                 ; already present. Not used by PMODEDJ
  128.         align   4
  129. label stubinfo_end byte
  130.  
  131. ;*****************************************************************************
  132. ; CODE
  133.  
  134. ; THIS IS NOW IN PADSEC!
  135. ; db "The PMODEDJ.EXE stub loader is Copyright (C) 1993-1995 DJ Delorie. ",13,10
  136. ; db "Permission granted to use for any purpose provided this copyright ",13,10
  137. ; db "remains present and unmodified. ",13,10
  138. ; db "This only applies to the stub, and not neccessarily the whole program.",13,10
  139.  
  140. ;-----------------------------------------------------------------------------
  141. ;  First, set up our memory and stack environment
  142. start:                                  ; execution starts here
  143.         push    _DATA
  144.         pop     ds
  145.         cld
  146.  
  147.         mov     bp,_STACK + (stack_sz/16) ; end of needed memory
  148.         sub     bp,_TEXT                ; bp = # of paragraphs without psp
  149.         mov     [dos_block_seg],es      ; save psp
  150.  
  151. ;-----------------------------------------------------------------------------
  152. ;  Check that we have DOS 3.00 or later.  (We need this because earlier
  153. ;  versions don't supply argv[0] to us and will scrog registers on dpmi exec).
  154.         mov     ah, 030h
  155.         int     021h
  156.         mov     [dos_major],al
  157.         cmp     al, 3
  158.         jae     short dos3ok
  159.         mov     dx, offset msg_bad_dos
  160.         jmp     error
  161. dos3ok:
  162.  
  163. ;-----------------------------------------------------------------------------
  164. ;  Get DPMI information before doing anything 386-specific
  165.         mov     ax,SW_FLAGS
  166.         call    pm_info                 ; get protected mode info
  167.         jnc short @@ok
  168.         jmp     error_in_modesw
  169. @@ok:   mov     [modesw_mem], bx
  170.         push    cs
  171.         pop     fs
  172.         cmp     ch,3
  173.         jz short @@dpmi
  174.  
  175. ; PMODE/DJ is active - allocate a separate transferbuffer
  176.         mov     bx, bp
  177.         add     bx, 10h                 ; extra for psp
  178.         mov     es, [dos_block_seg]
  179.         mov     ah, 04ah
  180.         int     021h                    ; resize our memory block
  181.         jc      error_no_dos_memory
  182.  
  183.         call    include_umb
  184.         mov     ah,48h
  185.         mov     bx,[stubinfo_minkeep]
  186.         shr     bx,4
  187.         int     21h                     ; Allocate transbuffer
  188.         jnc short @@w1
  189.         call    restore_umb
  190.         jmp     error_no_dos_memory
  191. @@w1:   mov     [fs:stubinfo_ds_segment],ax
  192.         call    restore_umb
  193.         jmp short @@cont
  194.  
  195. ; A DPMI host is active - this loader can be overwritten
  196. @@dpmi: shl     bp, 4
  197.         cmp     bp, [stubinfo_minkeep]
  198.         ja short @@w2
  199.         mov     bp, [stubinfo_minkeep]
  200. @@w2:   mov     [fs:stubinfo_minkeep], bp
  201.         mov     bx, bp
  202.         inc     bh                      ; Add extra for psp
  203.         shr     bx, 4
  204.         mov     es, [dos_block_seg]
  205.         mov     ah, 04ah
  206.         int     021h                    ; resize our memory block
  207.         jc      error_no_dos_memory
  208.         mov     [fs:stubinfo_ds_segment], cs
  209.  
  210. @@cont:
  211. ;-----------------------------------------------------------------------------
  212. ;  Scan environment for the stub's full name after environment
  213.         mov     es, [dos_block_seg]
  214.         mov     es, [es:02ch]           ; get environment segment
  215.         xor     di, di                  ; begin search for NUL/NUL (di = 0)
  216.         mov     cx, 0ff04h              ; effectively `infinite' loop
  217.         xor     al, al
  218. scan_environment:
  219.         repne scasb                     ; search for NUL
  220.         scasb
  221.         jne short scan_environment      ; no, still environment
  222.         scasw                           ; adjust pointer to point to prog name
  223.  
  224. ;-----------------------------------------------------------------------------
  225. ; copy the filename to loadname
  226.         sub     al,al
  227.         push    di
  228.         mov     cx,-1
  229.         repne   scasb
  230.         not     cx
  231.         mov     [fs:stubinfo_env_size], di
  232.         pop     si
  233.         mov     di,offset loadname
  234.  
  235.         push    ds
  236.         push    es
  237.         push    ds
  238.         pop     es
  239.         pop     ds
  240.         rep     movsb
  241.         pop     ds
  242.  
  243.         mov     bx,di
  244. @@lp2:  dec     bx
  245.         cmp     [byte ptr bx],'\'       ; always succeeds, because filename
  246.         jne     short @@lp2             ; is qualified
  247.         inc     bx
  248.  
  249.         cmp     [byte ptr stubinfo_basename+0], 0
  250.         je      short no_symlink
  251.  
  252. ;-----------------------------------------------------------------------------
  253. ;  Replace the stub's file name with the link's name after the directory
  254.  
  255.         mov     cx, 8                   ; max length of basename
  256.         mov     di, offset stubinfo_basename ; pointer to new basename
  257. @@b11:
  258.         mov     al, [cs:di]             ; get next character
  259.         inc     di
  260.         or      al, al                  ; end of basename?
  261.         je      short @@f12
  262.         mov     [bx], al                ; store character
  263.         inc     bx
  264.         loop    @@b11                   ; eight characters?
  265. @@f12:
  266.         mov     [dword ptr bx+0], 04558452eh ; append ".EXE"
  267.         add     bx, 4
  268.         mov     [byte ptr bx], 0
  269.  
  270. no_symlink:
  271.  
  272. ;-----------------------------------------------------------------------------
  273. ;  Load the COFF information from the file
  274.  
  275.         mov     ax, 03d00h              ; open file for reading
  276.         mov     dx, offset loadname
  277.         int     021h
  278.         jc      error_no_progfile       ; do rest of error message
  279.  
  280.         mov     [program_file], ax      ; store for future reference
  281.  
  282.         mov     bx, ax
  283.         mov     cx, exe_header_length
  284.         mov     dx, offset exe_header
  285.         mov     ah, 03fh                ; read EXE header
  286.         int     021h
  287.  
  288.         xor     dx, dx                  ; dx = 0
  289.         xor     cx, cx                  ; offset of COFF header
  290.  
  291.         mov     ax, [exe_magic]
  292.         cmp     ax, 0014ch              ; COFF?
  293.         je      short file_is_just_coff
  294.         cmp     ax, 05a4dh              ; EXE magic value
  295.         jne     error_not_exe
  296.  
  297.         mov     dx, [exe_sectors]
  298.         shl     dx, 9                   ; 512 bytes per sector
  299.         mov     bx, [exe_bytes_last_page]
  300.         or      bx, bx                  ; is bx = 0 ?
  301.         je      short @@f13
  302.         sub     dh, 2                   ; dx -= 512
  303.         add     dx, bx
  304. @@f13:
  305.  
  306. file_is_just_coff:                      ; cx:dx is offset
  307.         mov     [word ptr coff_offset+0], dx
  308.         mov     [word ptr coff_offset+2], cx
  309.         mov     ax, 04200h              ; seek from beginning
  310.         mov     bx, [program_file]
  311.         int     021h
  312.  
  313.         mov     cx, coff_header_length
  314.         mov     dx, offset coff_header
  315.         mov     ah, 03fh                ; read file (bx = handle)
  316.         int     021h
  317.  
  318.         cmp     ax, coff_header_length
  319.         jne     short @@f21
  320.         cmp     [word ptr coff_header + coff_magic], 0014ch
  321. @@f21:
  322.         jne     error_not_coff
  323.  
  324.         mov     eax, [dword ptr aout_header + aout_entry]
  325.         mov     [start_eip], eax
  326.  
  327.         mov     ecx, [coff_offset]
  328.  
  329.         mov     eax, [dword ptr text_section + s_scnptr]
  330.         add     eax, ecx
  331.         mov     [text_foffset], eax
  332.  
  333.         mov     eax, [dword ptr data_section+ s_scnptr]
  334.         add     eax, ecx
  335.         mov     [data_foffset], eax
  336.  
  337.         mov     ebx, [dword ptr bss_section + s_vaddr]
  338.         mov     eax, [dword ptr bss_section + s_size]
  339.         add     ebx, eax
  340.         mov     eax, 00010001h
  341.         cmp     ebx, eax
  342.         jae     short @@f1
  343.         mov     ebx, eax                ; ensure 32-bit segment
  344. @@f1:
  345.         add     ebx, 0000ffffh          ; ensure 64K rounded
  346.         xor     bx, bx                  ; clear rounded bits
  347.         mov     [fs:stubinfo_initial_size], ebx
  348.  
  349. ;-----------------------------------------------------------------------------
  350. ;  Set up for the DPMI environment
  351.         call    include_umb
  352.         mov     bx, [modesw_mem]
  353.         or      bx, bx                  ; or clears carry
  354.         jz short @@noa
  355.         mov     ah, 048h                ; allocate memory for the DPMI host
  356.         int     021h
  357.         jnc short @@noa
  358.         call    restore_umb
  359.         jmp     error_no_dos_memory
  360. @@noa:  push    ax
  361.         call    restore_umb
  362.         pop     es
  363.         mov     ax,SW_FLAGS             ; switch flags
  364.         call    pm_init                 ; attempt to switch
  365.         jc      error_in_modesw
  366.  
  367. ;-----------------------------------------------------------------------------
  368. ; We're in protected mode at this point.
  369. IF EXCEPTION_HANDLER NE 0
  370.         push    es ds
  371.         mov     bx,cs
  372.         mov     ax,000Ah
  373.         int     31h                     ; create alias descriptor
  374.         jc      perror_no_selectors
  375.         mov     es,ax
  376.         mov     [es:offset exception_vector],ds
  377.  
  378.         mov     bx,0
  379.         sub     edx,edx
  380.         mov     dx,offset exception_code
  381.         mov     cx,cs
  382. @@ll:   mov     ax,203h
  383.         int     31h
  384.         add     dx,EXCEPTION_SIZE
  385.         inc     bx
  386.         cmp     bx,32
  387.         jne     @@ll
  388.         pop     ds es
  389. ENDIF
  390.         mov     bx,cs
  391.         mov     ax,000Ah
  392.         int     31h                     ; create alias descriptor
  393.         jc      perror_no_selectors
  394.         mov     fs,ax
  395.  
  396.         mov     [fs:stubinfo_psp_selector],es
  397.         mov     [fs:stubinfo_ds_selector],fs
  398.         mov     [fs:stubinfo_cs_selector],ds
  399.         push    ds
  400.         pop     es
  401.  
  402.         xor     ax, ax                  ; AX = 0x0000
  403.         mov     cx, 1
  404.         int     031h                    ; allocate LDT descriptor
  405.         jc      short @@f2
  406.         mov     [client_cs], ax
  407.  
  408.         xor     ax, ax                  ; AX = 0x0000
  409. ;       mov     cx, 1                   ; already set above
  410.         int     031h                    ; allocate LDT descriptor
  411. @@f2:
  412.         jc      perror_no_selectors
  413.         mov     [client_ds], ax
  414.  
  415. ; Try getting a DPMI 1.0 memory block first, then try DPMI 0.9
  416. ; Note:  This causes the Borland Windows VxD to puke, commented for now with ;*
  417. ;*      mov     ax, 0x0504
  418. ;*      xor     ebx, ebx                ; don't specify linear address
  419.         mov     ecx, [stubinfo_initial_size + 0]
  420. ;*      mov     edx, 1                  ; allocate committed pages
  421. ;*      int     0x31                    ; allocate memory block
  422. ;*      jc      try_old_dpmi_alloc
  423. ;*      mov     client_memory[0], ebx
  424. ;*      mov     fs:stubinfo_memory_handle[0], esi
  425. ;*      jmp     got_dpmi_memory
  426. try_old_dpmi_alloc:
  427.         mov     ax, 00501h
  428.         mov     bx, [word ptr stubinfo_initial_size + 2]
  429. ;       mov     cx, stubinfo_initial_size[0]             ;Set above
  430.         int     031h                    ; allocate memory block
  431.         jc      perror_no_dpmi_memory
  432.         mov     [word ptr client_memory + 2], bx
  433.         mov     [word ptr client_memory + 0], cx
  434.         mov     [word ptr fs:stubinfo_memory_handle + 2], si
  435.         mov     [word ptr fs:stubinfo_memory_handle + 0], di
  436. got_dpmi_memory:
  437.  
  438.         mov     ax, 00007h
  439.         mov     bx, [client_cs]         ; initialize client CS
  440.         mov     cx, [word ptr client_memory + 2]
  441.         mov     dx, [word ptr client_memory + 0]
  442.         int     031h                    ; set segment base address
  443.  
  444.         mov     ax, 00009h
  445. ;       mov     bx, [client_cs]         ; already set above
  446.         mov     cx, cs                  ; get CPL
  447.         and     cx, 00003h
  448.         shl     cx, 5
  449.         push    cx                      ; save shifted CPL for below
  450.         or      cx, 0c09bh              ; 32-bit, big, code, non-conforming, readable
  451.         int     031h                    ; set descriptor access rights
  452.  
  453.         mov     ax, 00008h
  454. ;       mov     bx, [client_cs]         ; already set above
  455.         mov     cx, [word ptr stubinfo_initial_size + 2]
  456.         dec     cx
  457.         mov     dx, 0ffffh
  458.         int     031h                    ; set segment limit
  459.  
  460.         mov     ax, 00007h
  461.         mov     bx, [client_ds]         ; initialize client DS
  462.         mov     cx, [word ptr client_memory + 2]
  463.         mov     dx, [word ptr client_memory + 0]
  464.         int     031h                    ; set segment base address
  465.  
  466.         mov     ax, 00009h
  467. ;       mov     bx, [client_ds]         ; already set above
  468.         pop     cx                      ; shifted CPL from above
  469.         or      cx, 0c093h              ; 32-bit, big, data, r/w, expand-up
  470.         int     031h                    ; set descriptor access rights
  471.  
  472.         mov     ax, 00008h
  473. ;       mov     bx, [client_ds]         ; already set above
  474.         mov     cx, [word ptr stubinfo_initial_size + 2]
  475.         dec     cx
  476.         mov     dx, 0ffffh
  477.         int     031h                    ; set segment limit
  478.  
  479. ;-----------------------------------------------------------------------------
  480. ;  Load the program data
  481.  
  482.         mov     ax, 00100h
  483.         mov     bx, 00f00h              ; 60K DOS block size
  484.         int     031h                    ; allocate DOS memory
  485.         jnc     short @@f1
  486.         cmp     ax, 00008h
  487.         jne     perror_no_dos_memory
  488.         mov     ax, 00100h              ; try again with new value in bx
  489.         int     031h                    ; allocate DOS memory
  490.         jc      perror_no_dos_memory
  491. @@f1:
  492.         mov     [dos_block_seg], ax
  493.         mov     [dos_block_sel], dx
  494.         shl     bx, 4                   ; paragraphs to bytes
  495.         mov     [dos_block_size], bx
  496.  
  497.         mov     esi, [text_foffset]     ; load text section
  498.         mov     edi, [dword ptr text_section + s_vaddr]
  499.         mov     ecx, [dword ptr text_section + s_size]
  500.         call    read_section
  501.  
  502.         mov     esi, [data_foffset]     ; load data section
  503.         mov     edi, [dword ptr data_section + s_vaddr]
  504.         mov     ecx, [dword ptr data_section + s_size]
  505.         call    read_section
  506.  
  507.         mov     es, [client_ds]         ; clear the BSS section
  508.         mov     edi, [dword ptr bss_section + s_vaddr]
  509.         mov     ecx, [dword ptr bss_section + s_size]
  510.         xor     eax,eax
  511.         shr     ecx,2
  512.         rep stos [dword ptr es:edi]
  513.  
  514.         mov     ah,03eh
  515.         mov     bx, [program_file]
  516.         int     021h                    ; close the file
  517.  
  518.         mov     ax, 00101h
  519.         mov     dx, [dos_block_sel]
  520.         int     031h                    ; free the DOS memory
  521.  
  522.         push    [dword ptr client_cs]
  523.         push    [dword ptr start_eip]   ; push entry address
  524.         push    [client_ds]
  525.  
  526.         mov     bx,fs
  527.         movzx   edx,[stubinfo_ds_segment]
  528.         shl     edx,4
  529.         shld    ecx,edx,16
  530.         mov     ax,007h
  531.         int     31h                     ; set fs to transferbuffer
  532.  
  533.         mov     bx,ds
  534.         mov     ax,007h
  535.         int     31h                     ; set ds to buffer also
  536.  
  537.         push    fs
  538.         pop     es
  539.         sub     si,si                   ; offset of stubinfo in codesegment
  540.         sub     di,di                   ;                       transferbuffer
  541.         mov     cx,(stubinfo_end - stubinfo)
  542.         rep movs [byte ptr es:di],[byte ptr cs:si] ; copy stubinfo structure
  543.         push    ds di                   ; little wrapper
  544.         mov     [dword ptr es:di], 0CD0001B8h
  545.         mov     [dword ptr es:di+4], 0CB661F31h
  546.  
  547.         mov     cx,cs                   ; set ds to 16 bit code
  548.         and     cx,3
  549.         shl     cx,5
  550.         or      cl,9Ah
  551.         mov     ax,009h
  552.         int     31h
  553.  
  554.         mov     bx,cs
  555.         retf                            ; jump to wrapper
  556.  
  557. ;-----------------------------------------------------------------------------
  558. ;  Read a section from the program file
  559.  
  560. read_section:
  561.         mov     eax, esi                ; sector alignment by default
  562.         and     eax, 01ffh
  563.         add     ecx, eax
  564.         sub     si, ax                  ; sector align disk offset (can't carry)
  565.         sub     edi, eax                ; memory maybe not aligned!
  566.  
  567.         mov     [read_size], ecx        ; store for later reference
  568.         mov     [read_soffset], edi
  569.  
  570.         call    zero_regs
  571.         mov     [word ptr dpmi_regs + dr_dx], si ; store file offset
  572.         shr     esi, 16
  573.         mov     [word ptr dpmi_regs + dr_cx], si
  574.         mov     bx, [program_file]
  575.         mov     [word ptr dpmi_regs + dr_bx], bx
  576.         mov     [word ptr dpmi_regs + dr_ax], 04200h
  577.         call    pm_dos                  ; seek to start of data
  578.  
  579. ; Note, handle set above
  580.         mov     ax, [dos_block_seg]
  581.         mov     [word ptr dpmi_regs + dr_ds], ax
  582.         mov     [word ptr dpmi_regs + dr_dx], 0  ; store file offset
  583. read_loop:
  584.         mov     [byte ptr dpmi_regs + dr_ah], 03fh
  585.         mov     ax, [word ptr read_size + 2]     ; see how many bytes to read
  586.         or      ax, ax
  587.         jnz     short read_too_big
  588.         mov     ax, [word ptr read_size + 0]
  589.         cmp     ax, [dos_block_size]
  590.         jna     short read_size_in_ax            ; jna shorter than jmp
  591. read_too_big:
  592.         mov     ax, [dos_block_size]
  593. read_size_in_ax:
  594.         mov     [word ptr dpmi_regs + dr_cx], ax
  595.         call    pm_dos                  ; read the next chunk of file data
  596.  
  597.         xor     ecx, ecx
  598.         mov     cx, [word ptr dpmi_regs + dr_ax] ; get byte count
  599.         mov     edi, [read_soffset]     ; adjust pointers
  600.         add     [read_soffset], ecx
  601.         sub     [read_size], ecx
  602.  
  603.         xor     esi, esi                ; esi=0 offset for copy data
  604.         shr     cx, 2                   ; ecx < 64K
  605.         push    ds
  606.         push    es
  607.         mov     es, [client_ds]
  608.         mov     ds, [dos_block_sel]
  609.         rep movs [dword ptr es:edi],[dword ptr ds:esi]
  610.         pop     es
  611.         pop     ds
  612.  
  613.         add     ecx, [read_size]        ; ecx zero from the rep movsd
  614.         jnz     read_loop
  615.  
  616.         ret
  617.  
  618. ;-----------------------------------------------------------------------------
  619. ;  Most errors come here, early ones jump direct (8088 instructions)
  620.  
  621. error_no_progfile:
  622.         mov     dx, offset msg_no_progfile
  623.         jmp     short error_fn
  624.  
  625. error_not_exe:
  626.         mov     dx, offset msg_not_exe
  627.         jmp     short error_fn
  628.  
  629. error_not_coff:
  630.         mov     dx, offset msg_not_coff
  631. ;       jmp     error_fn
  632.  
  633. error_fn:
  634.         push    dx
  635.         mov     bx, offset loadname
  636.         jmp     short error_in
  637.  
  638. error_no_dos_memory:
  639.         mov     dx, offset msg_no_dos_memory
  640.         jmp     short error
  641.  
  642. error_in_modesw:
  643.         mov     dx, offset msg_error_in_modesw
  644.         jmp     short error
  645.  
  646. perror_no_selectors:
  647.         mov     dx, offset msg_no_selectors
  648.         jmp     short error
  649.  
  650. perror_no_dpmi_memory:
  651.         mov     dx, offset msg_no_dpmi_memory
  652.         jmp     short error
  653.  
  654. perror_no_dos_memory:
  655.         mov     dx, offset msg_no_dos_memory
  656. ;       jmp     error
  657.  
  658. error:
  659.         push    dx
  660.         mov     bx, offset err_string
  661. error_in:
  662.         call    printstr
  663.         pop     bx
  664.         call    printstr
  665. exit:
  666.         mov     bx, offset crlfdollar
  667.         call    printstr
  668.         mov     ax, 04cffh              ; error exit
  669.         int     021h
  670.  
  671. printstr1:
  672.         inc     bx
  673.         mov     ah, 2
  674.         int     021h
  675. printstr:
  676.         mov     dl, [bx]
  677.         cmp     dl, 0
  678.         jne     printstr1
  679.         ret
  680.  
  681. ;-----------------------------------------------------------------------------
  682. ;  DPMI utility functions
  683.  
  684. zero_regs:
  685.         push    ax
  686.         push    cx
  687.         push    di
  688.         xor     ax, ax
  689.         mov     di, offset dpmi_regs
  690.         mov     cx, 019h
  691.         rep
  692.         stosw
  693.         pop     di
  694.         pop     cx
  695.         pop     ax
  696.         ret
  697.  
  698. pm_dos:
  699.         mov     ax, 00300h              ; simulate interrupt
  700.         mov     bx, 00021h              ; int 21, no flags
  701.         xor     cx, cx                  ; cx = 0x0000 (copy no args)
  702.         sub     edi,edi
  703.         mov     di, offset dpmi_regs
  704.         int     031h
  705.         ret
  706.  
  707. include_umb:
  708.         cmp     [dos_major], 5          ; Won't work before dos 5
  709.         jb short @f1
  710.         mov     ax, 05800h              ; get allocation strategy
  711.         int     021h
  712.         mov     [old_strategy],al
  713.         mov     ax, 05802h              ; Get UMB status.
  714.         int     021h
  715.         mov     [old_umb],al
  716.         mov     ax, 05801h
  717.         mov     bx, 00080h              ; first fit, first high then low
  718.         int     021h
  719.         mov     ax, 05803h
  720.         mov     bx, 00001h              ; include UMB in memory chain
  721.         int     021h
  722. @f1:    ret
  723.  
  724. restore_umb:
  725.         cmp     [dos_major], 5          ; Won't work before dos 5
  726.         jb short @f2
  727.         mov     ax, 05803h              ; restore UMB status.
  728.         mov     bl,[old_umb]
  729.         xor     bh, bh
  730.         int     021h
  731.         mov     ax, 05801h              ; restore allocation strategy
  732.         mov     bl,[old_strategy]
  733.         xor     bh, bh
  734.         int     021h
  735. @f2:    ret
  736.  
  737. IF EXCEPTION_HANDLER NE 0
  738.  
  739. STRUC tRegs
  740. edi     dd ?
  741. esi     dd ?
  742. ebp     dd ?
  743. res     dd ?
  744. ebx     dd ?
  745. edx     dd ?
  746. ecx     dd ?
  747. eax     dd ?
  748. flags   dw ?
  749. es      dw ?
  750. ds      dw ?
  751. fs      dw ?
  752. gs      dw ?
  753. ip      dw ?
  754. cs      dw ?
  755. sp      dw ?
  756. ss      dw ?
  757. esp     dd ?    ; My own extensions
  758. eip     dd ?
  759. eflags  dd ?
  760. cr2     dd ?
  761. ENDS
  762.  
  763. exception_code:
  764. count = 0
  765.         REPT    32
  766.         DB 68h
  767.         DW count                        ; push exception number
  768.         DB 0E9h
  769.         DW exception_handler - 2 - $    ; jmp exception_handler
  770. count = count +1
  771.         ENDM
  772. EXCEPTION_SIZE = ($ - exception_code) / 32
  773.  
  774. MACRO   CONVW dst,num
  775.         mov     cl,4
  776.         mov     dx,num
  777.         mov     bx,offset dst
  778.         call    conv_hex
  779. ENDM
  780.  
  781. MACRO   CONVD dst,num
  782.         mov     cl,8
  783.         mov     edx,num
  784.         mov     bx,offset dst
  785.         call    conv_hex
  786. ENDM
  787.  
  788.         public exception_vector, exception_handler
  789. exception_handler:
  790.         push    ds ebp
  791.  
  792.         mov     bp,0
  793. exception_vector = $-2
  794.         mov     ds,bp
  795.         mov     [exp_rg.eax],eax
  796.         mov     [exp_rg.ebx],ebx
  797.         mov     [exp_rg.ecx],ecx
  798.         mov     [exp_rg.edx],edx
  799.         mov     [exp_rg.esi],esi
  800.         mov     [exp_rg.edi],edi
  801.         mov     [exp_rg.es],es
  802.         mov     [exp_rg.fs],fs
  803.         mov     [exp_rg.gs],gs
  804.  
  805.         mov     ebp,esp
  806.         mov     eax,[ebp]
  807.         mov     [exp_rg.ebp],eax
  808.         mov     ax,[ebp+4]
  809.         mov     [exp_rg.ds],ax
  810.  
  811.         mov     eax,[ebp+8+3*4]                 ; Get cs:eip
  812.         mov     [exp_rg.eip],eax
  813.         mov     ax,[ebp+8+4*4]
  814.         mov     [exp_rg.cs],ax
  815.  
  816.         mov     eax,[ebp+8+5*4]
  817.         mov     [exp_rg.eflags],eax             ; Get eflags
  818.         mov     eax,[ebp+8+6*4]
  819.         mov     [exp_rg.esp],eax
  820.         mov     ax,[ebp+8+7*4]
  821.         mov     [exp_rg.ss],ax                  ; Get ss:esp
  822.  
  823.         mov     eax,cr2
  824.         mov     [exp_rg.cr2],eax
  825.  
  826.         push    ds
  827.         pop     es
  828.         CONVW   exctype,[ebp+6]
  829.         CONVW   excerr,[ebp+8+2*4]
  830.         CONVD   exceax,[exp_rg.eax]
  831.         CONVD   excebx,[exp_rg.ebx]
  832.         CONVD   excecx,[exp_rg.ecx]
  833.         CONVD   excedx,[exp_rg.edx]
  834.         CONVD   excesi,[exp_rg.esi]
  835.         CONVD   excedi,[exp_rg.edi]
  836.         CONVD   excebp,[exp_rg.ebp]
  837.         CONVW   excds,[exp_rg.ds]
  838.         CONVW   exces,[exp_rg.es]
  839.         CONVW   excfs,[exp_rg.fs]
  840.         CONVW   excgs,[exp_rg.gs]
  841.         CONVW   exccs,[exp_rg.cs]
  842.         CONVD   exceip,[exp_rg.eip]
  843.         CONVD   excflgs,[exp_rg.eflags]
  844.         CONVW   excss,[exp_rg.ss]
  845.         CONVD   excesp,[exp_rg.esp]
  846.         CONVD   exccr2,[exp_rg.cr2]
  847.  
  848.         mov     bx,offset excerror
  849.         call    printstr
  850.  
  851.         mov     ax,04CFFh
  852.         int     21h                             ; terminate
  853.  
  854. ; in: es:bx = stringbuffer, cl = # of digits, edx = number
  855. ; out: ax,bx,cl,edx = trashed
  856. conv_hex:
  857.         push    si
  858.         shl     cl,2
  859.         ror     edx,cl
  860.         shr     cl,2
  861. @@ll:   rol     edx,4           ; get digit
  862.         mov     si,15
  863.         and     si,dx           ; mask out
  864.         mov     al,[hexbuffer + si]
  865.         mov     [es:bx],al      ; store converted digit
  866.         inc     bx
  867.         dec     cl
  868.         jne     @@ll
  869.         pop     si
  870.         ret
  871.  
  872. ENDIF
  873.  
  874.         ENDS
  875.  
  876. ;*****************************************************************************
  877. ; Data
  878.         SEGMENT _DATA PUBLIC USE16 'DATA'
  879.  
  880. IF EXCEPTION_HANDLER NE 0
  881.         align   4                       ; Align ourselves to a paragraph
  882. exp_rg          tRegs ?
  883. hexbuffer       db '0123456789ABCDEF'
  884. label excerror byte
  885.         db 'exception #'
  886. exctype db 'xxxx occured with error code '
  887. excerr  db 'xxxx',13,10
  888.         db 'eax='
  889. exceax  db 'xxxxxxxx ebx='
  890. excebx  db 'xxxxxxxx ecx='
  891. excecx  db 'xxxxxxxx edx='
  892. excedx  db 'xxxxxxxx',13,10,'esi='
  893. excesi  db 'xxxxxxxx edi='
  894. excedi  db 'xxxxxxxx ebp='
  895. excebp  db 'xxxxxxxx',13,10
  896.         db 'ds='
  897. excds   db 'xxxx es='
  898. exces   db 'xxxx fs='
  899. excfs   db 'xxxx gs='
  900. excgs   db 'xxxx',13,10
  901.         db 'cs:eip='
  902. exccs   db 'xxxx:'
  903. exceip  db 'xxxxxxxx eflags='
  904. excflgs db 'xxxxxxxx ss:esp='
  905. excss   db 'xxxx:'
  906. excesp  db 'xxxxxxxx cr2='
  907. exccr2  db 'xxxxxxxx',13,10
  908.         db 0
  909.         align 4
  910. ENDIF
  911.  
  912. ;-----------------------------------------------------------------------------
  913. ;  Stored Data
  914. err_string      db      "Load error: ",0
  915. msg_no_progfile db      ": cannot open",0
  916. msg_not_exe     db      ": not EXE",0
  917. msg_not_coff    db      ": not COFF",0
  918. msg_no_dpmi     db      "no DPMI",0
  919. msg_no_dos_memory db    "no DOS memory",0
  920. msg_bad_dos     db      "need DOS 3",0
  921. msg_error_in_modesw db  "can't switch mode",0
  922. msg_no_selectors db     "no DPMI selectors",0
  923. msg_no_dpmi_memory  db  "no DPMI memory",0
  924. crlfdollar      db      13,10,0
  925.  
  926. label last_generated_byte byte          ; data after this isn't in file.
  927.         ENDS
  928.  
  929. ;-----------------------------------------------------------------------------
  930. ;  Unstored Data, available during and after mode switch
  931.         SEGMENT _BSS PUBLIC USE16 'BSS'
  932. modesw_mem      dw      ?               ; amount of memory DPMI needs
  933. program_file    dw      ?               ; file ID of program data
  934. text_foffset    dd      ?               ; offset in file
  935. data_foffset    dd      ?               ; offset in file
  936. start_eip       dd      ?               ; EIP value to start at
  937. client_cs       dw      ?               ; must follow start_eip
  938. client_ds       dw      ?
  939.  
  940. client_memory   dd      ?
  941.  
  942. dos_block_seg   dw      ?
  943. dos_block_sel   dw      ?
  944. dos_block_size  dw      ?
  945.  
  946. read_soffset    dd      ?
  947. read_size       dd      ?
  948.  
  949. dos_major       db      ?
  950. old_umb         db      ?
  951. old_strategy    db      ?
  952.  
  953.                 ALIGN 2
  954. dpmi_regs       db      32h dup (?)
  955. dr_edi = 000h
  956. dr_di  = 000h
  957. dr_esi = 004h
  958. dr_si  = 004h
  959. dr_ebp = 008h
  960. dr_bp  = 008h
  961. dr_ebx = 010h
  962. dr_bx  = 010h
  963. dr_bl  = 010h
  964. dr_bh  = 011h
  965. dr_edx = 014h
  966. dr_dx  = 014h
  967. dr_dl  = 014h
  968. dr_dh  = 015h
  969. dr_ecx = 018h
  970. dr_cx  = 018h
  971. dr_cl  = 018h
  972. dr_ch  = 019h
  973. dr_eax = 01ch
  974. dr_ax  = 01ch
  975. dr_al  = 01ch
  976. dr_ah  = 01dh
  977. dr_efl = 020h
  978. dr_es  = 022h
  979. dr_ds  = 024h
  980. dr_fs  = 026h
  981. dr_gs  = 028h
  982. dr_ip  = 02ah
  983. dr_cs  = 02ch
  984. dr_sp  = 02eh
  985. dr_ss  = 030h
  986.  
  987. ;-----------------------------------------------------------------------------
  988. ; At one time real mode only data.  Header stuff now used during image load.
  989.  
  990. loadname        db 81 dup (?)           ; name of program file to load, if it
  991.                                         ; gets really long ok to overwrite next
  992.  
  993. label exe_header byte                   ; loaded from front of loadfile
  994. exe_magic       dw      ?
  995. exe_bytes_last_page dw  ?
  996. exe_sectors     dw      ?
  997. exe_header_length = $ - exe_header
  998.  
  999. coff_offset     dd      ?               ; from start of file
  1000.  
  1001. coff_header     db      20 dup (?)      ; loaded from after stub
  1002.  
  1003. aout_header     db      28 dup (?)
  1004. text_section    db      40 dup (?)
  1005. data_section    db      40 dup (?)
  1006. bss_section     db      40 dup (?)
  1007. coff_header_length = $ - coff_header
  1008.  
  1009.         ENDS
  1010.  
  1011.         SEGMENT _STACK STACK 'STACK'
  1012.         db stack_sz dup (?)
  1013.         ENDS
  1014.  
  1015.         END start
  1016.  
  1017.