home *** CD-ROM | disk | FTP | other *** search
- /* swap.c - swap parent to disk, EMS, or XMS while executing child (MS-DOS)
- Copyright (C) 1990 by Thorsten Ohl, ohl@gnu.ai.mit.edu
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 1, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- IMPORTANT:
-
- This code is not an official part of the GNU project and the
- author is not affiliated to the Free Software Foundation.
- He just likes their code and spirit. */
-
- static char RCS_id[] =
- "$Header: e:/gnu/make/RCS/swap.c'v 0.11 90/07/23 18:34:29 tho Exp $";
-
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <ctype.h>
- #include <signal.h>
- #include <sys/types.h>
-
- #include <dos.h>
-
- /* Add OFF to PTR, taking care of segment overflow */
- #define FP_ADD(ptr,off) \
- (FP_SEG (ptr) += (off) >> 4, FP_OFF (ptr) += (off) & 0xff, ptr)
-
- /* Paragraph-align PTR. */
- #define FP_PARA_ALIGN(ptr) \
- { \
- FP_SEG (ptr) \
- += ((FP_OFF (ptr) + 15) >> 4) + 1; \
- FP_OFF (ptr) = 0x0000; \
- }
-
-
- /* generate inline code (usable in swapper!) */
- #pragma intrinsic (memcpy)
-
- /* don't call MS' stack checker (it will fail with the local stack!) */
- #pragma check_stack (off)
-
-
- #define FILE_IO_BLKSIZE 0x8000
- #define MAX_MSDOS_CMDLINE 126
- #define MAX_MSDOS_PATH 144
- #define MAX_MSDOS_MCBS 25
-
-
- /* Atributte to force storage in the code segment! */
- #define CODE _based (_segname ("_CODE"))
-
- static off_t CODE _swap_swapped_bytes;
- static unsigned int CODE _swap_handle;
- static unsigned int CODE _swap_psp;
- static unsigned int CODE _swap_resident_paras;
- static unsigned int CODE _swap_first_block_paras;
-
-
- /* Parameters for DOS for creating a child process */
- #pragma pack (1)
- static struct
- {
- _segment environment_segment;
- char _far *cmd_line_ptr;
- char _far *fcb_ptr_1;
- char _far *fcb_ptr_2;
-
- } CODE _swap_parameter_block;
- #pragma pack ()
-
- static char CODE _swap_path[MAX_MSDOS_PATH];
- static char CODE _swap_cmdline[MAX_MSDOS_CMDLINE + 2];
- static char CODE _swap_fcb_1[16]; /* FCBs for DOS. */
- static char CODE _swap_fcb_2[16];
- static unsigned int CODE _swap_environ_seg;
- static unsigned int CODE _swap_environment_size;
- static int CODE _swap_return_code;
-
- static struct
- {
- _segment loc;
- unsigned int len;
- } CODE _swap_orig_mcbs[MAX_MSDOS_MCBS];
-
- /* This is a kludge to store _far pointers in the code segment. */
-
- static struct
- {
- char _far *env;
- char _far *env_ptr;
- char _far *xms_fct;
- int (*swap_in_fct) (int handle, void _far * buffer, long bytes);
- int (*swap_out_fct) (int handle, void _far * buffer, long bytes);
-
- } CODE __swap_far_ptrs;
-
- #define _swap_environment (__swap_far_ptrs.env)
- #define _swap_environment_ptr (__swap_far_ptrs.env_ptr)
- #define _swap_xms_control (__swap_far_ptrs.xms_fct)
- #define _swap_in_function (__swap_far_ptrs.swap_in_fct)
- #define _swap_out_function (__swap_far_ptrs.swap_out_fct)
-
- #pragma pack (1)
- static struct
- {
- long length;
- int src_handle;
- long src_offset;
- int dest_handle;
- long dest_offset;
- } CODE _swap_xms_move_table;
- #pragma pack ()
-
-
- /* The local stack */
- #define STACK_SIZE 0x200
- static char CODE _swap_local_stack[STACK_SIZE];
- static unsigned int CODE _swap_stack_pointer;
- static _segment CODE _swap_stack_segment;
-
- /* This uses the first transient function to determine the end of the
- resident code. */
- #define FIRST_TO_SWAP (&install_parameters)
-
- /* MS-DOS interface */
-
- #pragma pack (1) /* won't fit, if we don't pack! */
- struct mcb_info
- {
- char id_byte; /* 'M': not, 'Z': last MCB */
- unsigned short owner; /* PSP of owner */
- unsigned short length; /* length (in paragraphs = 16b) */
- };
- #pragma pack ()
-
- static void _swap_fatal_error (char code, char CODE *msg, size_t len);
- static int _swap_free_block (_segment block);
- static int _swap_set_block (_segment block, unsigned int paras);
- static unsigned int _swap_allocate_block (unsigned int paras);
- static void _swap_free_upper_blocks (void);
- static void _swap_reclaim_upper_blocks (void);
- static int _swap_load_and_execute_program (void);
-
- /* Disk I/O */
-
- static unsigned int _swap_read (int handle, void _far * buffer, size_t bytes);
- static unsigned int _swap_write (int handle, void _far * buffer, size_t bytes);
- static int _swap_rewind (int handle);
- static int _swap_write_to_handle (int handle, void _far * buffer, long size);
- static int _swap_read_from_handle (int handle, void _far * buffer, long size);
-
-
- /* XMS */
-
- static int _swap_xms_move_out (int handle, void _far * buffer, long bytes);
- static int _swap_xms_move_in (int handle, void _far * buffer, long bytes);
- static int _swap_xms_move (void);
- static int xms_installed (void);
- static void xms_get_control_function (void);
- static unsigned int xms_allocate_memory (unsigned int kilobytes);
- static unsigned int xms_free_memory (unsigned int handle);
-
-
- /* EMS */
-
- static int _swap_ems_save_page_map (int handle);
- static int _swap_ems_restore_page_map (int handle);
- static int _swap_ems_map_logical_page (int handle, int logical_page);
- static int _swap_move_to_ems (int handle, void _far *buffer, long bytes);
- static int _swap_move_from_ems (int handle, void _far *buffer, long bytes);
- static int _swap_ems_present (void);
- static int _swap_ems_alloc_pages (int n);
- static int _swap_ems_free_pages (int handle);
- static void _far *_swap_ems_get_page_frame (void);
-
- /* Signal handling */
-
- static void (_interrupt _far *_swap_caller_int23) (void);
- static void _interrupt _far _swap_int23_handler (void);
-
- static int CODE _swap_user_interrupt = 0; /* record interrupts */
- static char CODE _swap_int23_handler_message[] =
- "\r\n\a\a\a*** User interrupt: waiting for child...\r\n\r\n";
-
- /* "Higher" level code. */
-
- static void _swap_setup_environment (void);
- static int _swap_spawn_child (void);
-
- static void install_parameters (char *path, char *cmdline, char *env,
- size_t size);
- static struct mcb_info far *last_mcb (void);
- static int alloc_swap_file (char *name, long size);
- static unsigned int cleanup_swap_file (unsigned handle, char *name);
-
-
- /* The ONE and ONLY entry point */
-
- enum swapping_mode { none, disk, ems, xms };
-
- int spawn_child (enum swapping_mode mode, char *path, char *cmdline,
- char *env, int len, char *swap_file);
-
- /* Very Fatal Error messages. */
-
- static char CODE _swap_err_msg_head[] = \
- "\r\nFatal error in memory management. Aborting.\r\nReason: ";
- static char CODE _swap_err_msg_0[] = "Can't reallocate core.";
- static char CODE _swap_err_msg_1[] = "Can't swap code back.";
- static char CODE _swap_err_msg_2[] = "Can't release core.";
- static char CODE _swap_err_msg_3[] = "Too many MCBs.";
-
- #define SWAP_FATAL_ERROR(num) \
- _swap_fatal_error (-1, _swap_err_msg_##num, sizeof (_swap_err_msg_##num))
-
-
- void
- _swap_setup_environment (void)
- {
- _swap_resident_paras = FP_SEG (_swap_environment) - _swap_psp;
-
- if (_swap_environment_size && *_swap_environment_ptr)
- {
- memcpy (_swap_environment, _swap_environment_ptr,
- _swap_environment_size);
- _swap_resident_paras += (_swap_environment_size + 15) >> 4;
- _swap_environ_seg = FP_SEG (_swap_environment);
- }
- else
- _swap_environ_seg = 0; /* pass our own environment */
- }
-
-
- /* Memory management.
-
- WARNING: this used undocumented MS-DOS features.
-
- This features seem to be very stable anyway (Microsoft obviously uses
- them in their own programs and since they won't want to break them,
- these feaatures shouldn't go away. */
-
- /* Does this MCB belong to us? */
- #define OUR_MCB(mcb) ((mcb)->owner == _swap_psp)
-
- /* Return a pointer to OUR first MCB */
- #define FIRST_MCB(mcb) \
- (FP_SEG (mcb) = _swap_psp - 1, FP_OFF (mcb) = 0, mcb)
-
- /* Return a pointer to the next MCB */
- #define NEXT_MCB(mcb) \
- (FP_SEG (mcb) = FP_SEG (mcb) + mcb->length + 1, mcb)
-
- int
- _swap_free_block (_segment block)
- {
- _asm
- {
- mov ax, block;
- mov es, ax;
- mov ah, 0x49 /* MS-DOS Free Allocated Memory */
- int 0x21
- jc failed
- xor ax, ax; /* success */
- failed:
- }
- }
-
- int
- _swap_set_block (_segment block, unsigned int paras)
- {
- _asm
- {
- mov ax, block
- mov es, ax
- mov bx, paras
- mov ah, 4ah /* MS-DOS Set Block */
- int 0x21
- jc failed
- xor ax, ax /* success */
- failed:
- }
- }
-
-
- static unsigned int
- _swap_allocate_block (unsigned int paras)
- {
- _asm
- {
- mov bx, paras
- mov ah, 0x48 /* MS-DOS Allocate Memory */
- int 0x21
- jnc done
- mov ax, 0x0000 /* failed */
- done:
- }
- }
-
-
- /* Free, one by one, the memoy blocks owned by us. This excluded the
- first block, which will be shrunk later. _swap_orig_mcbs will be
- zero-terminated. */
-
- void
- _swap_free_upper_blocks (void)
- {
- int i = 0;
- struct mcb_info far *mcb;
-
- FIRST_MCB (mcb);
-
- while (mcb->id_byte == 'M')
- {
- NEXT_MCB (mcb); /* leave the first block intact (for the moment) */
-
- if (OUR_MCB (mcb))
- {
- if (i >= MAX_MSDOS_MCBS)
- SWAP_FATAL_ERROR (3);
- if (_swap_free_block (FP_SEG (mcb) + 1))
- SWAP_FATAL_ERROR (2);
- _swap_orig_mcbs[i].loc = FP_SEG (mcb) + 1;
- _swap_orig_mcbs[i].len = mcb->length;
- i++;
- }
- }
- _swap_orig_mcbs[i].loc = 0x000;
- }
-
-
- /* Reclaim, one by one, the original memory blocks, as stored in
- _swap_orig_mcbs. From the MS-DOS point of view, this should be not
- necessary, since MS-DOS keeps (to my knowledge) no internal record of
- the memory allocation and the original MCBs are restored together with
- the image. But in this way we can catch the fatal condition when the
- child has (illegally) left a resident grandchild. Also we will be
- warned if our methos fails with future MS-DOS versions. */
-
- void
- _swap_reclaim_upper_blocks (void)
- {
- int i = 0;
-
- while (_swap_orig_mcbs[i].loc != 0x000)
- if (_swap_allocate_block (_swap_orig_mcbs[i].len)
- != _swap_orig_mcbs[i].loc)
- SWAP_FATAL_ERROR (0);
- else
- i++;
- }
-
-
- int
- _swap_load_and_execute_program (void)
- {
- _swap_parameter_block.environment_segment = _swap_environ_seg;
- _swap_parameter_block.cmd_line_ptr = (char _far *) &_swap_cmdline;
- _swap_parameter_block.fcb_ptr_1 = (char _far *) &_swap_fcb_1;
- _swap_parameter_block.fcb_ptr_2 = (char _far *) &_swap_fcb_2;
-
- /* The compiler saves si and di by himself. */
-
- _asm
- {
- push ds /* save ds */
-
- mov ax, cs /* let es and ds point into code segment */
- mov es, ax
- mov ds, ax
-
- mov si, offset _swap_cmdline /* parse commandline */
- mov di, offset _swap_fcb_1 /* create first FCB */
- mov ax, 0x2901 /* MS-DOS Parse File Name */
- int 0x21
- mov di, offset _swap_fcb_2 /* create second FCB */
- mov ax, 0x2901 /* MS-DOS Parse File Name */
- int 0x21
- mov bx, offset _swap_parameter_block /* es:bx */
- mov dx, offset _swap_path /* ds:dx */
-
- mov ax, 0x4b00 /* MS-DOS Load and Execute Program */
- int 21h
- mov ax, 0ffffh /* assume failure */
- jc failed
-
- mov ah, 0x4d /* MS-DOS Get Return Code of Child */
- int 21h
- mov _swap_return_code, ax /* store return code */
-
- failed:
- pop ds /* restore ds */
- }
- }
-
- int
- _swap_spawn_child (void) /* CAN'T TAKE PARAMETERS! */
- {
- /* void */ /* CAN'T HAVE LOCAL VARIABLES! */
-
- /* FROM HERE ON: DON'T REFER TO THE GLOBAL STACK! */
- _asm
- {
- mov cs:_swap_stack_pointer, sp /* save stack position */
- mov cs:_swap_stack_segment, ss
- cli /* Interrupts off */
- mov ax, seg _swap_local_stack /* Change stack */
- mov ss, ax /* Point to top of new stack */
- mov sp, offset _swap_local_stack + STACK_SIZE
- sti /* Interrupts on */
- }
-
- if ((*_swap_out_function) (_swap_handle, _swap_environment,
- _swap_swapped_bytes))
- return -1;
-
- _swap_setup_environment ();
- _swap_free_upper_blocks ();
- _swap_set_block (_swap_psp, _swap_resident_paras);
-
- _swap_load_and_execute_program (); /* !!! BIG DEAL !!! */
-
- if (_swap_set_block (_swap_psp, _swap_first_block_paras))
- SWAP_FATAL_ERROR (0);
- _swap_reclaim_upper_blocks ();
-
- if ((*_swap_in_function) (_swap_handle, _swap_environment,
- _swap_swapped_bytes))
- SWAP_FATAL_ERROR (1);
-
- _asm
- {
- mov ax, cs:_swap_stack_pointer /* get saved stack position */
- mov bx, cs:_swap_stack_segment
- cli /* Interrupts off */
- mov ss, bx /* Change stack */
- mov sp, ax
- sti /* Interrupts on */
- }
- /* THE GLOBAL STACK IS SAVE AGAIN! */
-
- return _swap_return_code;
-
- }
-
-
-
- /* Display LEN bytes from string MSG and *immediately* return to DOS,
- with CODE as return code. This is a panic exit, only to be used
- as a last resort. ~~~~~~~~~~ */
-
- void
- _swap_fatal_error (char code, char CODE *msg, size_t len)
- {
- _asm
- {
- mov ax, cs /* ds = cs */
- mov ds, ax
- mov bx, 0x02 /* /dev/stderr */
- mov dx, offset _swap_err_msg_head
- mov cx, length _swap_err_msg_head
- mov ah, 0x40 /* MS-DOS Write Handle */
- int 0x21
- mov dx, msg /* message */
- mov cx, len /* length */
- mov ah, 0x40
- int 0x21
- mov al, code /* bail out */
- mov ah, 0x4c /* MS-DOS End Process */
- int 0x21
- }
- }
-
-
- /* Lowest level disk I/0: */
-
- /* Write SIZE bytes from BUFFER to HANDLE. Returns 0 on success, -1 on
- failure. */
-
- int
- _swap_write_to_handle (int handle, void _far *buffer, off_t size)
- {
- while (size > 0L)
- {
- size_t bytes = (size_t) min (size, FILE_IO_BLKSIZE);
- size_t bytes_written = _swap_write (handle, buffer, bytes);
- if (bytes_written != bytes)
- return -1;
- FP_ADD (buffer, bytes);
- size -= bytes;
- }
-
- return 0;
- }
-
- size_t
- _swap_write (int handle, void _far *buffer, size_t bytes)
- {
- _asm
- {
- push ds
- mov dx, word ptr buffer /* offset */
- mov ax, word ptr buffer + 2 /* segment */
- mov ds, ax
- mov bx, handle
- mov cx, bytes
- mov ah, 0x40 /* MS-DOS Write Handle */
- int 0x21
- jnc done
- mov ax, 0xffff
- done:
- pop ds
- }
- }
-
-
- /* Read SIZE bytes from HANDLE to BUFFER. Returns 0 on success, -1 on
- failure. */
-
- int
- _swap_read_from_handle (int handle, void _far *buffer, off_t size)
- {
- _swap_rewind (handle);
-
- while (size > 0L)
- {
- size_t bytes = (size_t) min (size, FILE_IO_BLKSIZE);
- size_t bytes_read = _swap_read (handle, buffer, bytes);
- if (bytes_read != bytes)
- return -1;
- FP_ADD (buffer, bytes);
- size -= bytes;
- }
-
- return 0;
- }
-
- size_t
- _swap_read (int handle, void _far *buffer, size_t bytes)
- {
- _asm
- {
- push ds
- mov dx, word ptr buffer /* offset */
- mov ax, word ptr buffer + 2 /* segment */
- mov ds, ax
- mov bx, handle
- mov cx, bytes
- mov ah, 0x3f /* MS-DOS Read Handle */
- int 0x21
- jnc done
- mov ax, 0xffff
- done:
- pop ds
- }
- }
-
-
- /* Rewind the file pointer for HANDLE to the beginning of the file. */
-
- int
- _swap_rewind (int handle)
- {
- _asm
- {
- mov bx, handle
- mov cx, 0x0000 /* offset = 0 */
- mov dx, 0x0000
- mov ax, 0x4200 /* MS-DOS Move File Pointer, (beginning) */
- int 0x21
- jc failed
- mov ax, 0x0000
- failed:
- }
- }
-
- /* XMS interface */
-
- int
- _swap_xms_move_out (int handle, void _far *buffer, long bytes)
- {
- _swap_xms_move_table.length = bytes;
- _swap_xms_move_table.src_handle = 0x0000;
- _swap_xms_move_table.src_offset = (long) buffer;
- _swap_xms_move_table.dest_handle = handle;
- _swap_xms_move_table.dest_offset = 0L;
-
- _swap_xms_move ();
- }
-
- int
- _swap_xms_move_in (int handle, void _far *buffer, long bytes)
- {
- _swap_xms_move_table.length = bytes;
- _swap_xms_move_table.dest_handle = 0x0000;
- _swap_xms_move_table.dest_offset = (long) buffer;
- _swap_xms_move_table.src_handle = handle;
- _swap_xms_move_table.src_offset = 0L;
-
- _swap_xms_move ();
- }
-
- int
- _swap_xms_move (void)
- {
- _asm
- {
- push ds
- mov si, offset _swap_xms_move_table
- mov ax, seg _swap_xms_move_table
- mov ds, ax
- mov ah, 0x0b
- call far ptr cs:[_swap_xms_control]
- cmp ax, 0x0001
- jne failed
- mov ax, 0x0000
- jmp done
- failed:
- mov ax, 0xffff
- done:
- pop ds
- }
- }
-
-
- #if 0
-
- /* EMS interface */
-
- #define PHYSICAL_PAGE 0x00
-
- int
- _swap_move_to_ems (int handle, void _far *buffer, long bytes)
- {
- int logical_page = 0;
-
- while (paras > 0)
- {
- unsigned int bytes = min (paras, 0x0400) << 4;
- paras -= bytes >> 4;
- if (ems_map_logical_page (handle, logical_page++))
- return -1;
- memcpy (swappee.ems_page_frame, &msdos_child_environment, bytes);
- }
-
- return 0;
- }
-
-
- int
- _swap_move_from_ems (int handle, void _far *buffer, long bytes)
- {
- int logical_page = 0;
-
- while (paras > 0)
- {
- unsigned int bytes = min (paras, 0x0400) << 4;
- paras -= bytes >> 4;
- if (ems_map_logical_page (handle, logical_page++))
- return -1;
- memcpy (&msdos_child_environment, swappee.ems_page_frame, bytes);
- }
-
- return 0;
- }
-
-
- int
- _swap_ems_map_logical_page (int handle, int logical_page)
- {
- _asm
- {
- mov dx, handle
- mov bx, logical_page
- mov ax, 0x4400 + PHYSICAL_PAGE /* EMS Map Page */
- int 0x67
- mov cl, 8 /* "mov ax, ah" */
- shr ax, cl
- }
- }
-
- void
- _swap_ems_save_page_map (int handle)
- {
- _asm
- {
- mov dx, handle
- mov ah, 0x47 /* EMS Save Page Map */
- int 0x67
- mov cl, 8 /* "mov ax, ah" */
- shr ax, cl
- }
- }
-
- void
- _swap_ems_restore_page_map (int handle)
- {
- _asm
- {
- mov dx, handle
- mov ah, 0x48 /* EMS Restore Page Map */
- int 0x67
- mov cl, 8 /* "mov ax, ah" */
- shr ax, cl
- }
- }
-
- #endif /* NEVER */
-
- /* Signal handling */
-
- /* Simple ^C handler that displays a short message and waits for the child
- to return. Set a flag _swap_user_interrupt which can be used to
- determine, whether such an event occured.
- Note: resetting the C library signals is NOT enough, since even the
- default handlers use at least some library code. */
-
- void _interrupt _far
- _swap_int23_handler (void)
- {
- _swap_user_interrupt = 1;
-
- _asm
- {
- sti /* want to access DOS */
- mov ax, cs /* ds = cs */
- mov ds, ax
- mov bx, 0x02 /* /dev/stderr */
- mov dx, offset _swap_int23_handler_message
- mov cx, length _swap_int23_handler_message
- mov ah, 0x40 /* MS-DOS Write Handle */
- int 0x21
- }
- }
-
- /* The transient part starts here. */
- #pragma check_stack ()
-
- /* Install the global parameters. Execute this as the first function, since
- some macros need _swap_psp with the correct value. */
-
- void
- install_parameters (char *path, char *cmdline, char *env, size_t size)
- {
- size_t len = strlen (cmdline);
- struct mcb_info far *mcb;
-
- _fstrcpy ((char _far *) _swap_path, (char _far *) path);
-
- *_swap_cmdline = (char) len;
- _fstrcpy ((char _far *) _swap_cmdline + 1, (char _far *) cmdline);
- _swap_cmdline[len+1] = '\r';
-
- _swap_environment_ptr = env; /* this will be copied later */
- _swap_environment_size = size;
-
- _swap_psp = _psp; /* put them into a save place. */
- _swap_first_block_paras = FIRST_MCB (mcb)->length;
- }
-
-
- /* Allocate a swap file named NAME, making sure that at least SIZE bytes
- are available on the disk. Returns a MS-DOS handle (not to be
- confused with a C file-descriptor!). */
-
- int
- alloc_swap_file (char *name, off_t size)
- {
- struct diskfree_t disk_free;
- unsigned drive;
- off_t free;
- int handle;
-
- if (name == NULL || *name == '\0') /* could create filename ourselves. */
- return -1;
-
- if (name[1] == ':')
- drive = tolower (*name) - 'a' + 1;
- else
- /* Get current drive. */
- _dos_getdrive (&drive);
-
- _dos_getdiskfree (drive, &disk_free);
-
- free = (off_t) disk_free.avail_clusters *
- (off_t) disk_free.sectors_per_cluster * (off_t) disk_free.bytes_per_sector;
-
- if (free < size)
- return (-1);
-
- if (_dos_creat (name, _A_NORMAL, &handle))
- return (-1);
- else
- return handle;
- }
-
- /* Close and delete the temporary file. */
-
- unsigned int
- cleanup_swap_file (unsigned int handle, char *name)
- {
- return !_dos_close (handle) && !unlink (name);
- }
-
-
- /* More XMS */
- /* Microsoft's recommendation: */
-
- int
- xms_installed (void)
- {
- _asm
- {
- mov ax, 0x4300
- int 0x2f
- cmp al, 0x80
- jne failed
- mov ax, 0x0001
- jmp done
- failed:
- mov ax, 0x0000
- done:
- }
- }
-
- void
- xms_get_control_function (void)
- {
- _asm
- {
- mov ax, 0x4310
- int 0x2f
- mov word ptr cs:_swap_xms_control, bx
- mov bx, es
- mov word ptr cs:_swap_xms_control + 2, bx
- }
- }
-
- unsigned int
- xms_allocate_memory (unsigned int kilobytes)
- {
- _asm
- {
- mov dx, kilobytes
- mov ah, 0x09
- call far ptr cs:[_swap_xms_control]
- cmp ax, 0x0001
- jne failed
- mov ax, dx
- jmp done
- failed:
- mov ax, 0xffff
- done:
- }
- }
-
- unsigned int
- xms_free_memory (unsigned int handle)
- {
- _asm
- {
- mov dx, handle
- mov ah, 0x0a
- call far ptr cs:[_swap_xms_control]
- cmp ax, 0x0001
- je done
- mov ax, 0x0000
- done:
- }
- }
-
-
- #if 0
-
- /* More EMS */
-
- /* Test for presence of LIM EMS 4.0.
- (this procedure is taken from the LIM specification). */
-
- int
- _swap_ems_present (void)
- {
- static char _far ems_id[] = "EMMXXXX0"; /* LIM EMS 4.0 identification. */
- char _far *ems_device = (char _far *) _dos_getvect (0x67);
-
- FP_OFF (ems_device) = 0x000a;
-
- return !_fstrcmp (ems_id, ems_device);
- }
-
- /* Allocate pages from the EMS Manager. Returns handle or -1 no error. */
-
- int
- _swap_ems_alloc_pages (int n)
- {
- _asm
- {
- mov bx, n
- mov ah, 0x43 /* EMS Allocate Pages */
- int 0x67
- cmp ah, 0x00
- jz success
- mov ax, 0xffff /* failure */
- ret
- success:
- mov ax, dx /* return handle */
- }
- }
-
- /* Free pages allocated for HANDLE. Returns 0 if successful. */
-
- int
- _swap_ems_free_pages (int handle)
- {
- _asm
- {
- mov dx, handle
- mov ah, 0x45 /* EMS Free Pages */
- int 0x67
- mov cl, 8 /* "mov ax, ah" */
- shr ax, cl
- }
- }
-
- /* Return far pointer to EMS page frame. */
-
- void _far *
- _swap_ems_get_page_frame (void)
- {
- void _far *frame = (void _far *) 0;
-
- _asm
- {
- mov ah, 0x41 /* EMS Page Frame */
- int 0x67
- cmp ah, 0x00
- jz success
- ret /* failure */
- success:
- mov word ptr frame + 2, bx /* segment of page frame */
- }
-
- return frame;
- }
-
- #endif /* NEVER */
-
- /* Return the last MCB owned by us.
- WARNING: This assumes that _swap_psp has already been set to _PSP
- (e.g. by install_parameters()) */
-
- struct mcb_info far *
- last_mcb (void)
- {
- struct mcb_info far *mcb;
- struct mcb_info far *ret;
-
- FIRST_MCB (mcb);
-
- while (mcb->id_byte == 'M')
- {
- if (OUR_MCB (mcb))
- ret = NEXT_MCB (mcb);
- else
- NEXT_MCB (mcb);
- }
-
- if (mcb->id_byte == 'Z') /* found the end */
- return ret;
- else /* error */
- return NULL;
- }
-
-
- /* MODE is the preferred swapping mode, if XMS or EMS are requested but not
- available, it is mapped to DISK. PATH is the complete path of the program
- to be executed, it must not be longer than MAX_MSDOS_PATH (=144). CMDLINE
- is the commandline to be passed to the program, it must not be longer than
- MAX_MSDOS_CMDLINE (=126). ENV is a well formed MS-DOS environment of
- length LEN, including the terminating '\0's. FILE is a valid filename,
- which will be used for a possible disk swap file. */
-
- int
- spawn_child (enum swapping_mode mode, char *path, char *cmdline, char *env,
- int len, char *file)
- {
- int rc;
- unsigned int (*cleanup_function) (unsigned int handle,...);
-
- install_parameters (path, cmdline, env, len);
-
- _swap_environment = (char _far *) FIRST_TO_SWAP;
- FP_PARA_ALIGN (_swap_environment);
-
- _swap_swapped_bytes = (long) ((char _huge *) last_mcb ()
- - (char _huge *) _swap_environment);
-
- switch (mode)
- {
- case ems: /* not implemented yet */
- /* fall through */
-
- case xms:
- if (xms_installed ())
- {
- xms_get_control_function ();
- _swap_out_function = _swap_xms_move_out;
- _swap_in_function = _swap_xms_move_in;
- cleanup_function = xms_free_memory;
- _swap_handle = xms_allocate_memory (
- (unsigned int) ((_swap_swapped_bytes + 0x03ff) >> 10) + 1);
- if (_swap_handle != -1)
- break;
- }
- /* fall through */
-
- case disk:
- _swap_out_function = _swap_write_to_handle;
- _swap_in_function = _swap_read_from_handle;
- cleanup_function = cleanup_swap_file;
- _swap_handle = alloc_swap_file (file, _swap_swapped_bytes);
- if (_swap_handle == -1)
- {
- fprintf (stderr, "Out of swap space!\n");
- exit (0);
- }
- }
-
- _swap_user_interrupt = 0;
- _swap_caller_int23 = _dos_getvect (0x23); /* temporarily disable ^C */
- _dos_setvect (0x23, _swap_int23_handler);
-
- rc = _swap_spawn_child ();
-
- if (_swap_user_interrupt) /* did the user hit ^C ? */
- rc = 0xffff;
- _dos_setvect (0x23, _swap_caller_int23);
-
- cleanup_function (_swap_handle, file);
-
- return rc;
- }
-
-
- /*
- * Local Variables:
- * mode:C
- * minor-mode:auto-fill
- * ChangeLog:ChangeLog
- * compile-command:make
- * End:
- */
-