home *** CD-ROM | disk | FTP | other *** search
/ ProfitPress Mega CDROM2 …eeware (MSDOS)(1992)(Eng) / ProfitPress-MegaCDROM2.B6I / MISC / GNU / MAK358AS.ZIP / SWAP.C < prev    next >
Encoding:
C/C++ Source or Header  |  1992-02-22  |  26.0 KB  |  1,066 lines

  1. /*  swap.c - swap parent to disk, EMS, or XMS while executing child (MS-DOS)
  2.     Copyright (C) 1990 by Thorsten Ohl, ohl@gnu.ai.mit.edu
  3.  
  4.     This program is free software; you can redistribute it and/or modify
  5.     it under the terms of the GNU General Public License as published by
  6.     the Free Software Foundation; either version 1, or (at your option)
  7.     any later version.
  8.  
  9.     This program is distributed in the hope that it will be useful,
  10.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.     GNU General Public License for more details.
  13.  
  14.     You should have received a copy of the GNU General Public License
  15.     along with this program; if not, write to the Free Software
  16.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  
  18.     IMPORTANT:
  19.  
  20.     This code is not an official part of the GNU project and the
  21.     author is not affiliated to the Free Software Foundation.
  22.     He just likes their code and spirit.  */
  23.  
  24. static char RCS_id[] =
  25. "$Header: e:/gnu/make/RCS/swap.c'v 0.11 90/07/23 18:34:29 tho Exp $";
  26.  
  27.  
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <string.h>
  31. #include <ctype.h>
  32. #include <signal.h>
  33. #include <sys/types.h>
  34.  
  35. #include <dos.h>
  36.  
  37. /* Add OFF to PTR, taking care of segment overflow  */
  38. #define FP_ADD(ptr,off) \
  39.   (FP_SEG (ptr) += (off) >> 4, FP_OFF (ptr) += (off) & 0xff, ptr)
  40.  
  41. /* Paragraph-align PTR.  */
  42. #define FP_PARA_ALIGN(ptr)            \
  43.   {                        \
  44.     FP_SEG (ptr)                \
  45.       += ((FP_OFF (ptr) + 15) >> 4) + 1;    \
  46.     FP_OFF (ptr) = 0x0000;            \
  47.   }
  48.  
  49.  
  50. /* generate inline code (usable in swapper!) */
  51. #pragma intrinsic (memcpy)
  52.  
  53. /* don't call MS' stack checker (it will fail with the local stack!)  */
  54. #pragma check_stack (off)
  55.  
  56.  
  57. #define FILE_IO_BLKSIZE        0x8000
  58. #define MAX_MSDOS_CMDLINE    126
  59. #define MAX_MSDOS_PATH        144
  60. #define MAX_MSDOS_MCBS        25
  61.  
  62.  
  63. /* Atributte to force storage in the code segment! */
  64. #define CODE _based (_segname ("_CODE"))
  65.  
  66. static off_t        CODE _swap_swapped_bytes;
  67. static unsigned int    CODE _swap_handle;
  68. static unsigned int    CODE _swap_psp;
  69. static unsigned int    CODE _swap_resident_paras;
  70. static unsigned int    CODE _swap_first_block_paras;
  71.  
  72.  
  73. /* Parameters for DOS for creating a child process */
  74. #pragma pack (1)
  75. static struct
  76. {
  77.   _segment    environment_segment;
  78.   char _far    *cmd_line_ptr;
  79.   char _far    *fcb_ptr_1;
  80.   char _far    *fcb_ptr_2;
  81.  
  82. }            CODE _swap_parameter_block;
  83. #pragma pack ()
  84.  
  85. static char        CODE _swap_path[MAX_MSDOS_PATH];
  86. static char        CODE _swap_cmdline[MAX_MSDOS_CMDLINE + 2];
  87. static char        CODE _swap_fcb_1[16];    /* FCBs for DOS.  */
  88. static char        CODE _swap_fcb_2[16];
  89. static unsigned int    CODE _swap_environ_seg;
  90. static unsigned int    CODE _swap_environment_size;
  91. static int        CODE _swap_return_code;
  92.  
  93. static struct
  94. {
  95.   _segment    loc;
  96.   unsigned int    len;
  97. }            CODE _swap_orig_mcbs[MAX_MSDOS_MCBS];
  98.  
  99. /* This is a kludge to store _far pointers in the code segment.  */
  100.  
  101. static struct
  102. {
  103.   char _far *env;
  104.   char _far *env_ptr;
  105.   char _far *xms_fct;
  106.   int (*swap_in_fct) (int handle, void _far * buffer, long bytes);
  107.   int (*swap_out_fct) (int handle, void _far * buffer, long bytes);
  108.  
  109. }             CODE __swap_far_ptrs;
  110.  
  111. #define _swap_environment    (__swap_far_ptrs.env)
  112. #define _swap_environment_ptr    (__swap_far_ptrs.env_ptr)
  113. #define _swap_xms_control    (__swap_far_ptrs.xms_fct)
  114. #define _swap_in_function    (__swap_far_ptrs.swap_in_fct)
  115. #define _swap_out_function    (__swap_far_ptrs.swap_out_fct)
  116.  
  117. #pragma pack (1)
  118. static struct
  119. {
  120.   long    length;
  121.   int    src_handle;
  122.   long    src_offset;
  123.   int    dest_handle;
  124.   long    dest_offset;
  125. }            CODE  _swap_xms_move_table;
  126. #pragma pack ()
  127.  
  128.  
  129. /* The local stack */
  130. #define STACK_SIZE    0x200
  131. static char        CODE _swap_local_stack[STACK_SIZE];
  132. static unsigned int    CODE _swap_stack_pointer;
  133. static _segment        CODE _swap_stack_segment;
  134.  
  135. /* This uses the first transient function to determine the end of the
  136.    resident code.  */
  137. #define FIRST_TO_SWAP    (&install_parameters)
  138.  
  139. /* MS-DOS interface */
  140.  
  141. #pragma pack (1)        /* won't fit, if we don't pack! */
  142. struct mcb_info
  143. {
  144.   char         id_byte;    /* 'M': not, 'Z': last MCB    */
  145.   unsigned short owner;        /* PSP of owner            */
  146.   unsigned short length;    /* length (in paragraphs = 16b)    */
  147. };
  148. #pragma pack ()
  149.  
  150. static void _swap_fatal_error (char code, char CODE *msg, size_t len);
  151. static int  _swap_free_block (_segment block);
  152. static int  _swap_set_block (_segment block, unsigned int paras);
  153. static unsigned int  _swap_allocate_block (unsigned int paras);
  154. static void _swap_free_upper_blocks (void);
  155. static void _swap_reclaim_upper_blocks (void);
  156. static int  _swap_load_and_execute_program (void);
  157.  
  158. /* Disk I/O */
  159.  
  160. static unsigned int _swap_read (int handle, void _far * buffer, size_t bytes);
  161. static unsigned int _swap_write (int handle, void _far * buffer, size_t bytes);
  162. static int  _swap_rewind (int handle);
  163. static int  _swap_write_to_handle (int handle, void _far * buffer, long size);
  164. static int  _swap_read_from_handle (int handle, void _far * buffer, long size);
  165.  
  166.  
  167. /* XMS */
  168.  
  169. static int _swap_xms_move_out (int handle, void _far * buffer, long bytes);
  170. static int _swap_xms_move_in (int handle, void _far * buffer, long bytes);
  171. static int _swap_xms_move (void);
  172. static int xms_installed (void);
  173. static void xms_get_control_function (void);
  174. static unsigned int xms_allocate_memory (unsigned int kilobytes);
  175. static unsigned int xms_free_memory (unsigned int handle);
  176.  
  177.  
  178. /* EMS */
  179.  
  180. static int _swap_ems_save_page_map (int handle);
  181. static int _swap_ems_restore_page_map (int handle);
  182. static int _swap_ems_map_logical_page (int handle, int logical_page);
  183. static int _swap_move_to_ems (int handle, void _far *buffer, long bytes);
  184. static int _swap_move_from_ems (int handle, void _far *buffer, long bytes);
  185. static int _swap_ems_present (void);
  186. static int _swap_ems_alloc_pages (int n);
  187. static int _swap_ems_free_pages (int handle);
  188. static void _far *_swap_ems_get_page_frame (void);
  189.  
  190. /* Signal handling */
  191.  
  192. static void (_interrupt _far *_swap_caller_int23) (void);
  193. static void _interrupt _far _swap_int23_handler (void);
  194.  
  195. static int    CODE _swap_user_interrupt = 0;    /* record interrupts  */
  196. static char    CODE _swap_int23_handler_message[] =
  197.   "\r\n\a\a\a*** User interrupt: waiting for child...\r\n\r\n";
  198.  
  199. /* "Higher" level code.  */
  200.  
  201. static void _swap_setup_environment (void);
  202. static int  _swap_spawn_child (void);
  203.  
  204. static void install_parameters (char *path, char *cmdline, char *env,
  205.                 size_t size);
  206. static struct mcb_info far *last_mcb (void);
  207. static int  alloc_swap_file (char *name, long size);
  208. static unsigned int cleanup_swap_file (unsigned handle, char *name);
  209.  
  210.  
  211. /* The ONE and ONLY entry point */
  212.  
  213. enum swapping_mode { none, disk, ems, xms };
  214.  
  215. int spawn_child (enum swapping_mode mode, char *path, char *cmdline,
  216.          char *env, int len, char *swap_file);
  217.  
  218. /* Very Fatal Error messages.  */
  219.  
  220. static char CODE _swap_err_msg_head[] = \
  221.   "\r\nFatal error in memory management. Aborting.\r\nReason: ";
  222. static char CODE _swap_err_msg_0[] = "Can't reallocate core.";
  223. static char CODE _swap_err_msg_1[] = "Can't swap code back.";
  224. static char CODE _swap_err_msg_2[] = "Can't release core.";
  225. static char CODE _swap_err_msg_3[] = "Too many MCBs.";
  226.  
  227. #define SWAP_FATAL_ERROR(num) \
  228.   _swap_fatal_error (-1, _swap_err_msg_##num, sizeof (_swap_err_msg_##num))
  229.  
  230.  
  231. void
  232. _swap_setup_environment (void)
  233. {
  234.   _swap_resident_paras = FP_SEG (_swap_environment) - _swap_psp;
  235.  
  236.   if (_swap_environment_size && *_swap_environment_ptr)
  237.     {
  238.       memcpy (_swap_environment, _swap_environment_ptr,
  239.           _swap_environment_size);
  240.       _swap_resident_paras += (_swap_environment_size + 15) >> 4;
  241.       _swap_environ_seg = FP_SEG (_swap_environment);
  242.     }
  243.   else
  244.     _swap_environ_seg = 0;    /* pass our own environment */
  245. }
  246.  
  247.  
  248. /* Memory management.
  249.  
  250.    WARNING:  this used undocumented MS-DOS features.
  251.  
  252.    This features seem to be very stable anyway (Microsoft obviously uses
  253.    them in their own programs and since they won't want to break them,
  254.    these feaatures shouldn't go away.  */
  255.  
  256. /* Does this MCB belong to us?  */
  257. #define OUR_MCB(mcb) ((mcb)->owner == _swap_psp)
  258.  
  259. /* Return a pointer to OUR first MCB */
  260. #define FIRST_MCB(mcb) \
  261.   (FP_SEG (mcb) = _swap_psp - 1, FP_OFF (mcb) = 0, mcb)
  262.  
  263. /* Return a pointer to the next MCB */
  264. #define NEXT_MCB(mcb) \
  265.   (FP_SEG (mcb) = FP_SEG (mcb) + mcb->length + 1, mcb)
  266.  
  267. int
  268. _swap_free_block (_segment block)
  269. {
  270.   _asm
  271.     {
  272.       mov    ax, block;
  273.       mov    es, ax;
  274.       mov    ah, 0x49        /* MS-DOS Free Allocated Memory */
  275.       int    0x21
  276.       jc    failed
  277.       xor    ax, ax;            /* success */
  278.     failed:
  279.     }
  280. }
  281.  
  282. int
  283. _swap_set_block (_segment block, unsigned int paras)
  284. {
  285.   _asm
  286.     {
  287.       mov    ax, block
  288.       mov    es, ax
  289.       mov    bx, paras
  290.       mov    ah, 4ah            /* MS-DOS Set Block */
  291.       int    0x21
  292.       jc    failed
  293.       xor    ax, ax            /* success */
  294.     failed:
  295.     }
  296. }
  297.  
  298.  
  299. static unsigned int
  300.  _swap_allocate_block (unsigned int paras)
  301. {
  302.   _asm
  303.     {
  304.       mov    bx, paras
  305.       mov    ah, 0x48    /* MS-DOS Allocate Memory */
  306.       int    0x21
  307.       jnc    done
  308.       mov    ax, 0x0000    /* failed */
  309.     done:
  310.     }
  311. }
  312.  
  313.  
  314. /* Free, one by one, the memoy blocks owned by us.  This excluded the
  315.    first block, which will be shrunk later.  _swap_orig_mcbs will be
  316.    zero-terminated. */
  317.  
  318. void
  319. _swap_free_upper_blocks (void)
  320. {
  321.   int i = 0;
  322.   struct mcb_info far *mcb;
  323.  
  324.   FIRST_MCB (mcb);
  325.  
  326.   while (mcb->id_byte == 'M')
  327.     {
  328.       NEXT_MCB (mcb);    /* leave the first block intact (for the moment)  */
  329.  
  330.       if (OUR_MCB (mcb))
  331.     {
  332.       if (i >= MAX_MSDOS_MCBS)
  333.         SWAP_FATAL_ERROR (3);
  334.       if (_swap_free_block (FP_SEG (mcb) + 1))
  335.         SWAP_FATAL_ERROR (2);
  336.       _swap_orig_mcbs[i].loc = FP_SEG (mcb) + 1;
  337.       _swap_orig_mcbs[i].len = mcb->length;
  338.       i++;
  339.     }
  340.     }
  341.   _swap_orig_mcbs[i].loc = 0x000;
  342. }
  343.  
  344.  
  345. /* Reclaim, one by one, the original memory blocks, as stored in
  346.    _swap_orig_mcbs.  From the MS-DOS point of view, this should be not
  347.    necessary, since MS-DOS keeps (to my knowledge) no internal record of
  348.    the memory allocation and the original MCBs are restored together with
  349.    the image.  But in this way we can catch the fatal condition when the
  350.    child has (illegally) left a resident grandchild.  Also we will be
  351.    warned if our methos fails with future MS-DOS versions.  */
  352.  
  353. void
  354. _swap_reclaim_upper_blocks (void)
  355. {
  356.   int i = 0;
  357.  
  358.   while (_swap_orig_mcbs[i].loc != 0x000)
  359.     if (_swap_allocate_block (_swap_orig_mcbs[i].len)
  360.     != _swap_orig_mcbs[i].loc)
  361.       SWAP_FATAL_ERROR (0);
  362.     else
  363.       i++;
  364. }
  365.  
  366.  
  367. int
  368. _swap_load_and_execute_program (void)
  369. {
  370.   _swap_parameter_block.environment_segment = _swap_environ_seg;
  371.   _swap_parameter_block.cmd_line_ptr = (char _far *) &_swap_cmdline;
  372.   _swap_parameter_block.fcb_ptr_1 = (char _far *) &_swap_fcb_1;
  373.   _swap_parameter_block.fcb_ptr_2 = (char _far *) &_swap_fcb_2;
  374.  
  375.   /* The compiler saves si and di by himself.  */
  376.  
  377.   _asm
  378.     {
  379.       push    ds        /* save ds */
  380.  
  381.       mov    ax, cs        /* let es and ds point into code segment */
  382.       mov    es, ax
  383.       mov    ds, ax
  384.  
  385.       mov    si, offset _swap_cmdline    /* parse commandline */
  386.       mov    di, offset _swap_fcb_1        /* create first FCB */
  387.       mov    ax, 0x2901         /* MS-DOS Parse File Name */
  388.       int    0x21
  389.       mov    di, offset _swap_fcb_2        /* create second FCB */
  390.       mov    ax, 0x2901          /* MS-DOS Parse File Name */
  391.       int    0x21
  392.       mov    bx, offset _swap_parameter_block /* es:bx */
  393.       mov    dx, offset _swap_path         /* ds:dx */
  394.  
  395.       mov    ax, 0x4b00        /* MS-DOS Load and Execute Program */
  396.       int    21h
  397.       mov    ax, 0ffffh        /* assume failure */
  398.       jc    failed
  399.  
  400.       mov    ah, 0x4d        /* MS-DOS Get Return Code of Child */
  401.       int    21h
  402.       mov    _swap_return_code, ax    /* store return code */
  403.  
  404.     failed:
  405.       pop    ds        /* restore ds */
  406.     }
  407. }
  408.  
  409. int
  410. _swap_spawn_child (void)    /* CAN'T TAKE PARAMETERS! */
  411. {
  412.   /* void */            /* CAN'T HAVE LOCAL VARIABLES!  */
  413.  
  414.     /* FROM HERE ON: DON'T REFER TO THE GLOBAL STACK! */
  415.   _asm
  416.     {
  417.       mov    cs:_swap_stack_pointer, sp    /* save stack position */
  418.       mov    cs:_swap_stack_segment, ss
  419.       cli                    /* Interrupts off */
  420.       mov    ax, seg _swap_local_stack    /* Change stack */
  421.       mov    ss, ax                /* Point to top of new stack */
  422.       mov    sp, offset _swap_local_stack + STACK_SIZE
  423.       sti                    /* Interrupts on */
  424.     }
  425.  
  426.   if ((*_swap_out_function) (_swap_handle, _swap_environment,
  427.                  _swap_swapped_bytes))
  428.     return -1;
  429.  
  430.   _swap_setup_environment ();
  431.   _swap_free_upper_blocks ();
  432.   _swap_set_block (_swap_psp, _swap_resident_paras);
  433.  
  434.   _swap_load_and_execute_program ();        /* !!! BIG DEAL !!! */
  435.  
  436.   if (_swap_set_block (_swap_psp, _swap_first_block_paras))
  437.     SWAP_FATAL_ERROR (0);
  438.   _swap_reclaim_upper_blocks ();
  439.  
  440.   if ((*_swap_in_function) (_swap_handle, _swap_environment,
  441.                  _swap_swapped_bytes))
  442.     SWAP_FATAL_ERROR (1);
  443.  
  444.   _asm
  445.     {
  446.       mov    ax, cs:_swap_stack_pointer    /* get saved stack position */
  447.       mov    bx, cs:_swap_stack_segment
  448.       cli                    /* Interrupts off */
  449.       mov    ss, bx                /* Change stack */
  450.       mov    sp, ax
  451.       sti                    /* Interrupts on */
  452.     }
  453.     /* THE GLOBAL STACK IS SAVE AGAIN! */
  454.  
  455.   return _swap_return_code;
  456.  
  457. }
  458.  
  459.  
  460.  
  461. /* Display LEN bytes from string MSG and *immediately* return to DOS,
  462.    with CODE as return code.  This is a panic exit, only to be used
  463.    as a last resort.            ~~~~~~~~~~            */
  464.  
  465. void
  466. _swap_fatal_error (char code, char CODE *msg, size_t len)
  467. {
  468.   _asm
  469.     {
  470.       mov    ax, cs        /* ds = cs */
  471.       mov    ds, ax
  472.       mov    bx, 0x02    /* /dev/stderr */
  473.       mov    dx, offset _swap_err_msg_head
  474.       mov    cx, length _swap_err_msg_head
  475.       mov    ah, 0x40    /* MS-DOS Write Handle */
  476.       int    0x21
  477.       mov    dx, msg        /* message */
  478.       mov    cx, len        /* length */
  479.       mov    ah, 0x40
  480.       int    0x21
  481.       mov    al, code    /* bail out */
  482.       mov    ah, 0x4c    /* MS-DOS End Process */
  483.       int    0x21
  484.     }
  485. }
  486.  
  487.  
  488. /* Lowest level disk I/0:  */
  489.  
  490. /* Write SIZE bytes from BUFFER to HANDLE.  Returns 0 on success, -1 on
  491.    failure.  */
  492.  
  493. int
  494. _swap_write_to_handle (int handle, void _far *buffer, off_t size)
  495. {
  496.   while (size > 0L)
  497.     {
  498.       size_t bytes = (size_t) min (size, FILE_IO_BLKSIZE);
  499.       size_t bytes_written = _swap_write (handle, buffer, bytes);
  500.       if (bytes_written != bytes)
  501.     return -1;
  502.       FP_ADD (buffer, bytes);
  503.       size -= bytes;
  504.     }
  505.  
  506.   return 0;
  507. }
  508.  
  509. size_t
  510. _swap_write (int handle, void _far *buffer, size_t bytes)
  511. {
  512.   _asm
  513.     {
  514.       push    ds
  515.       mov    dx, word ptr buffer    /* offset */
  516.       mov    ax, word ptr buffer + 2    /* segment */
  517.       mov    ds, ax
  518.       mov    bx, handle
  519.       mov    cx, bytes
  520.       mov    ah, 0x40        /* MS-DOS Write Handle */
  521.       int    0x21
  522.       jnc    done
  523.       mov    ax, 0xffff
  524.     done:
  525.       pop    ds
  526.     }
  527. }
  528.  
  529.  
  530. /* Read SIZE bytes from HANDLE to BUFFER.  Returns 0 on success, -1 on
  531.    failure.  */
  532.  
  533. int
  534. _swap_read_from_handle (int handle, void _far *buffer, off_t size)
  535. {
  536.   _swap_rewind (handle);
  537.  
  538.   while (size > 0L)
  539.     {
  540.       size_t bytes = (size_t) min (size, FILE_IO_BLKSIZE);
  541.       size_t bytes_read = _swap_read (handle, buffer, bytes);
  542.       if (bytes_read != bytes)
  543.     return -1;
  544.       FP_ADD (buffer, bytes);
  545.       size -= bytes;
  546.     }
  547.  
  548.   return 0;
  549. }
  550.  
  551. size_t
  552. _swap_read (int handle, void _far *buffer, size_t bytes)
  553. {
  554.   _asm
  555.     {
  556.       push    ds
  557.       mov    dx, word ptr buffer    /* offset */
  558.       mov    ax, word ptr buffer + 2 /* segment */
  559.       mov    ds, ax
  560.       mov    bx, handle
  561.       mov    cx, bytes
  562.       mov    ah, 0x3f        /* MS-DOS Read Handle */
  563.       int    0x21
  564.       jnc    done
  565.       mov    ax, 0xffff
  566.     done:
  567.       pop    ds
  568.     }
  569. }
  570.  
  571.  
  572. /* Rewind the file pointer for HANDLE to the beginning of the file.  */
  573.  
  574. int
  575. _swap_rewind (int handle)
  576. {
  577.   _asm
  578.     {
  579.       mov    bx, handle
  580.       mov    cx, 0x0000    /* offset = 0 */
  581.       mov    dx, 0x0000
  582.       mov    ax, 0x4200    /* MS-DOS Move File Pointer, (beginning) */
  583.       int    0x21
  584.       jc    failed
  585.       mov    ax, 0x0000
  586.     failed:
  587.     }
  588. }
  589.  
  590. /* XMS interface */
  591.  
  592. int
  593. _swap_xms_move_out (int handle, void _far *buffer, long bytes)
  594. {
  595.   _swap_xms_move_table.length = bytes;
  596.   _swap_xms_move_table.src_handle = 0x0000;
  597.   _swap_xms_move_table.src_offset = (long) buffer;
  598.   _swap_xms_move_table.dest_handle = handle;
  599.   _swap_xms_move_table.dest_offset = 0L;
  600.  
  601.   _swap_xms_move ();
  602. }
  603.  
  604. int
  605. _swap_xms_move_in (int handle, void _far *buffer, long bytes)
  606. {
  607.   _swap_xms_move_table.length = bytes;
  608.   _swap_xms_move_table.dest_handle = 0x0000;
  609.   _swap_xms_move_table.dest_offset = (long) buffer;
  610.   _swap_xms_move_table.src_handle = handle;
  611.   _swap_xms_move_table.src_offset = 0L;
  612.  
  613.   _swap_xms_move ();
  614. }
  615.  
  616. int
  617. _swap_xms_move (void)
  618. {
  619.   _asm
  620.     {
  621.       push    ds
  622.       mov    si, offset _swap_xms_move_table
  623.       mov    ax, seg _swap_xms_move_table
  624.       mov    ds, ax
  625.       mov    ah, 0x0b
  626.       call    far ptr cs:[_swap_xms_control]
  627.       cmp    ax, 0x0001
  628.       jne    failed
  629.       mov    ax, 0x0000
  630.       jmp    done
  631.     failed:
  632.       mov    ax, 0xffff
  633.     done:
  634.       pop    ds
  635.     }
  636. }
  637.  
  638.  
  639. #if 0
  640.  
  641. /* EMS interface */
  642.  
  643. #define PHYSICAL_PAGE    0x00
  644.  
  645. int
  646. _swap_move_to_ems (int handle, void _far *buffer, long bytes)
  647. {
  648.   int logical_page = 0;
  649.  
  650.   while (paras > 0)
  651.     {
  652.       unsigned int bytes = min (paras, 0x0400) << 4;
  653.       paras -= bytes >> 4;
  654.       if (ems_map_logical_page (handle, logical_page++))
  655.     return -1;
  656.       memcpy (swappee.ems_page_frame, &msdos_child_environment, bytes);
  657.     }
  658.  
  659.   return 0;
  660. }
  661.  
  662.  
  663. int
  664. _swap_move_from_ems (int handle, void _far *buffer, long bytes)
  665. {
  666.   int logical_page = 0;
  667.  
  668.   while (paras > 0)
  669.     {
  670.       unsigned int bytes = min (paras, 0x0400) << 4;
  671.       paras -= bytes >> 4;
  672.       if (ems_map_logical_page (handle, logical_page++))
  673.     return -1;
  674.       memcpy (&msdos_child_environment, swappee.ems_page_frame, bytes);
  675.     }
  676.  
  677.   return 0;
  678. }
  679.  
  680.  
  681. int
  682. _swap_ems_map_logical_page (int handle, int logical_page)
  683. {
  684.   _asm
  685.     {
  686.       mov    dx, handle
  687.       mov    bx, logical_page
  688.       mov    ax, 0x4400 + PHYSICAL_PAGE    /* EMS Map Page */
  689.       int    0x67
  690.       mov    cl,  8                /* "mov ax, ah" */
  691.       shr    ax, cl
  692.     }
  693. }
  694.  
  695. void
  696. _swap_ems_save_page_map (int handle)
  697. {
  698.   _asm
  699.     {
  700.       mov    dx, handle
  701.       mov    ah, 0x47            /* EMS Save Page Map */
  702.       int    0x67
  703.       mov    cl,  8                /* "mov ax, ah" */
  704.       shr    ax, cl
  705.     }
  706. }
  707.  
  708. void
  709. _swap_ems_restore_page_map (int handle)
  710. {
  711.   _asm
  712.     {
  713.       mov    dx, handle
  714.       mov    ah, 0x48            /* EMS Restore Page Map */
  715.       int    0x67
  716.       mov    cl,  8                /* "mov ax, ah" */
  717.       shr    ax, cl
  718.     }
  719. }
  720.  
  721. #endif /* NEVER */
  722.  
  723. /* Signal handling */
  724.  
  725. /* Simple ^C handler that displays a short message and waits for the child
  726.    to return.  Set a flag _swap_user_interrupt which can be used to
  727.    determine, whether such an event occured.
  728.    Note:  resetting the C library signals is NOT enough, since even the
  729.    default handlers use at least some library code.  */
  730.  
  731. void _interrupt _far
  732. _swap_int23_handler (void)
  733. {
  734.   _swap_user_interrupt = 1;
  735.  
  736.   _asm
  737.     {
  738.       sti            /* want to access DOS */
  739.       mov    ax, cs        /* ds = cs */
  740.       mov    ds, ax
  741.       mov    bx, 0x02    /* /dev/stderr */
  742.       mov    dx, offset _swap_int23_handler_message
  743.       mov    cx, length _swap_int23_handler_message
  744.       mov    ah, 0x40    /* MS-DOS Write Handle */
  745.       int    0x21
  746.     }
  747. }
  748.  
  749. /* The transient part starts here. */
  750. #pragma check_stack ()
  751.  
  752. /* Install the global parameters.  Execute this as the first function, since
  753.    some macros need _swap_psp with the correct value.  */
  754.  
  755. void
  756. install_parameters (char *path, char *cmdline, char *env, size_t size)
  757. {
  758.   size_t len = strlen (cmdline);
  759.   struct mcb_info far *mcb;
  760.  
  761.   _fstrcpy ((char _far *) _swap_path, (char _far *) path);
  762.  
  763.   *_swap_cmdline = (char) len;
  764.   _fstrcpy ((char _far *) _swap_cmdline + 1, (char _far *) cmdline);
  765.   _swap_cmdline[len+1] = '\r';
  766.  
  767.   _swap_environment_ptr = env;    /* this will be copied later */
  768.   _swap_environment_size = size;
  769.  
  770.   _swap_psp = _psp;    /* put them into a save place. */
  771.   _swap_first_block_paras = FIRST_MCB (mcb)->length;
  772. }
  773.  
  774.  
  775. /* Allocate a swap file named NAME, making sure that at least SIZE bytes
  776.    are available on the disk.  Returns a MS-DOS handle (not to be
  777.    confused with a C file-descriptor!).  */
  778.  
  779. int
  780. alloc_swap_file (char *name, off_t size)
  781. {
  782.   struct diskfree_t disk_free;
  783.   unsigned drive;
  784.   off_t free;
  785.   int handle;
  786.  
  787.   if (name == NULL || *name == '\0')    /* could create filename ourselves. */
  788.     return -1;
  789.  
  790.   if (name[1] == ':')
  791.     drive = tolower (*name) - 'a' + 1;
  792.   else
  793.     /* Get current drive. */
  794.     _dos_getdrive (&drive);
  795.  
  796.   _dos_getdiskfree (drive, &disk_free);
  797.  
  798.   free = (off_t) disk_free.avail_clusters *
  799.     (off_t) disk_free.sectors_per_cluster * (off_t) disk_free.bytes_per_sector;
  800.  
  801.   if (free < size)
  802.     return (-1);
  803.  
  804.   if (_dos_creat (name, _A_NORMAL, &handle))
  805.     return (-1);
  806.   else
  807.     return handle;
  808. }
  809.  
  810. /* Close and delete the temporary file.  */
  811.  
  812. unsigned int
  813. cleanup_swap_file (unsigned int handle, char *name)
  814. {
  815.   return !_dos_close (handle) && !unlink (name);
  816. }
  817.  
  818.  
  819. /* More XMS */
  820. /* Microsoft's recommendation:  */
  821.  
  822. int
  823. xms_installed (void)
  824. {
  825.   _asm
  826.     {
  827.       mov    ax, 0x4300
  828.       int    0x2f
  829.       cmp    al, 0x80
  830.       jne    failed
  831.       mov    ax, 0x0001
  832.       jmp    done
  833.     failed:
  834.       mov    ax, 0x0000
  835.     done:
  836.     }
  837. }
  838.  
  839. void
  840. xms_get_control_function (void)
  841. {
  842.   _asm
  843.     {
  844.       mov    ax, 0x4310
  845.       int    0x2f
  846.       mov    word ptr cs:_swap_xms_control, bx
  847.       mov    bx, es
  848.       mov    word ptr cs:_swap_xms_control + 2, bx
  849.     }
  850. }
  851.  
  852. unsigned int
  853. xms_allocate_memory (unsigned int kilobytes)
  854. {
  855.   _asm
  856.     {
  857.       mov    dx, kilobytes
  858.       mov    ah, 0x09
  859.       call    far ptr cs:[_swap_xms_control]
  860.       cmp    ax, 0x0001
  861.       jne    failed
  862.       mov    ax, dx
  863.       jmp    done
  864.     failed:
  865.       mov    ax, 0xffff
  866.     done:
  867.     }
  868. }
  869.  
  870. unsigned int
  871. xms_free_memory (unsigned int handle)
  872. {
  873.   _asm
  874.     {
  875.       mov    dx, handle
  876.       mov    ah, 0x0a
  877.       call    far ptr cs:[_swap_xms_control]
  878.       cmp    ax, 0x0001
  879.       je    done
  880.       mov    ax, 0x0000
  881.     done:
  882.     }
  883. }
  884.  
  885.  
  886. #if 0
  887.  
  888. /* More EMS */
  889.  
  890. /* Test for presence of LIM EMS 4.0.
  891.    (this procedure is taken from the LIM specification).  */
  892.  
  893. int
  894. _swap_ems_present (void)
  895. {
  896.   static char _far ems_id[] = "EMMXXXX0"; /* LIM EMS 4.0 identification. */
  897.   char _far *ems_device = (char _far *) _dos_getvect (0x67);
  898.  
  899.   FP_OFF (ems_device) = 0x000a;
  900.  
  901.   return !_fstrcmp (ems_id, ems_device);
  902. }
  903.  
  904. /* Allocate pages from the EMS Manager.  Returns handle or -1 no error.  */
  905.  
  906. int
  907. _swap_ems_alloc_pages (int n)
  908. {
  909.   _asm
  910.     {
  911.       mov    bx, n
  912.       mov    ah, 0x43    /* EMS Allocate Pages */
  913.       int    0x67
  914.       cmp    ah, 0x00
  915.       jz    success
  916.       mov    ax, 0xffff    /* failure */
  917.       ret
  918.     success:
  919.       mov    ax, dx        /* return handle */
  920.     }
  921. }
  922.  
  923. /* Free pages allocated for HANDLE.  Returns 0 if successful.  */
  924.  
  925. int
  926. _swap_ems_free_pages (int handle)
  927. {
  928.   _asm
  929.     {
  930.       mov    dx, handle
  931.       mov    ah, 0x45    /* EMS Free Pages */
  932.       int    0x67
  933.       mov    cl, 8        /* "mov ax, ah" */
  934.       shr    ax, cl
  935.     }
  936. }
  937.  
  938. /* Return far pointer to EMS page frame.  */
  939.  
  940. void _far *
  941. _swap_ems_get_page_frame (void)
  942. {
  943.   void _far *frame = (void _far *) 0;
  944.  
  945.   _asm
  946.     {
  947.       mov    ah, 0x41        /* EMS Page Frame */
  948.       int    0x67
  949.       cmp    ah, 0x00
  950.       jz    success
  951.       ret                /* failure */
  952.     success:
  953.       mov    word ptr frame + 2, bx    /* segment of page frame */
  954.     }
  955.  
  956.   return frame;
  957. }
  958.  
  959. #endif /* NEVER */
  960.  
  961. /* Return the last MCB owned by us.
  962.    WARNING:  This assumes that _swap_psp has already been set to _PSP
  963.          (e.g. by install_parameters())   */
  964.  
  965. struct mcb_info far *
  966. last_mcb (void)
  967. {
  968.   struct mcb_info far *mcb;
  969.   struct mcb_info far *ret;
  970.  
  971.   FIRST_MCB (mcb);
  972.  
  973.   while (mcb->id_byte == 'M')
  974.     {
  975.       if (OUR_MCB (mcb))
  976.     ret = NEXT_MCB (mcb);
  977.       else
  978.     NEXT_MCB (mcb);
  979.     }
  980.  
  981.   if (mcb->id_byte == 'Z')    /* found the end */
  982.     return ret;
  983.   else                /* error */
  984.     return NULL;
  985. }
  986.  
  987.  
  988. /* MODE is the preferred swapping mode, if XMS or EMS are requested but not
  989.    available, it is mapped to DISK.  PATH is the complete path of the program
  990.    to be executed, it must not be longer than MAX_MSDOS_PATH (=144).  CMDLINE
  991.    is the commandline to be passed to the program, it must not be longer than
  992.    MAX_MSDOS_CMDLINE (=126).  ENV is a well formed MS-DOS environment of
  993.    length LEN, including the terminating '\0's.  FILE is a valid filename,
  994.    which will be used for a possible disk swap file.  */
  995.  
  996. int
  997. spawn_child (enum swapping_mode mode, char *path, char *cmdline, char *env,
  998.          int len, char *file)
  999. {
  1000.   int rc;
  1001.   unsigned int (*cleanup_function) (unsigned int handle,...);
  1002.  
  1003.   install_parameters (path, cmdline, env, len);
  1004.  
  1005.   _swap_environment = (char _far *) FIRST_TO_SWAP;
  1006.   FP_PARA_ALIGN (_swap_environment);
  1007.  
  1008.   _swap_swapped_bytes = (long) ((char _huge *) last_mcb ()
  1009.             - (char _huge *) _swap_environment);
  1010.  
  1011.   switch (mode)
  1012.     {
  1013.     case ems:            /* not implemented yet */
  1014.       /* fall through */
  1015.  
  1016.     case xms:
  1017.       if (xms_installed ())
  1018.     {
  1019.       xms_get_control_function ();
  1020.       _swap_out_function = _swap_xms_move_out;
  1021.       _swap_in_function = _swap_xms_move_in;
  1022.       cleanup_function = xms_free_memory;
  1023.       _swap_handle = xms_allocate_memory (
  1024.         (unsigned int) ((_swap_swapped_bytes + 0x03ff) >> 10) + 1);
  1025.       if (_swap_handle != -1)
  1026.         break;
  1027.     }
  1028.       /* fall through */
  1029.  
  1030.     case disk:
  1031.       _swap_out_function = _swap_write_to_handle;
  1032.       _swap_in_function = _swap_read_from_handle;
  1033.       cleanup_function = cleanup_swap_file;
  1034.       _swap_handle = alloc_swap_file (file, _swap_swapped_bytes);
  1035.       if (_swap_handle == -1)
  1036.     {
  1037.       fprintf (stderr, "Out of swap space!\n");
  1038.       exit (0);
  1039.     }
  1040.     }
  1041.  
  1042.   _swap_user_interrupt = 0;
  1043.   _swap_caller_int23 = _dos_getvect (0x23);    /* temporarily disable ^C  */
  1044.   _dos_setvect (0x23, _swap_int23_handler);
  1045.  
  1046.   rc = _swap_spawn_child ();
  1047.  
  1048.   if (_swap_user_interrupt)            /* did the user hit ^C ? */
  1049.     rc = 0xffff;
  1050.   _dos_setvect (0x23, _swap_caller_int23);
  1051.  
  1052.   cleanup_function (_swap_handle, file);
  1053.  
  1054.   return rc;
  1055. }
  1056.  
  1057.  
  1058. /* 
  1059.  * Local Variables:
  1060.  * mode:C
  1061.  * minor-mode:auto-fill
  1062.  * ChangeLog:ChangeLog
  1063.  * compile-command:make
  1064.  * End:
  1065.  */
  1066.