Category : Alternate Operating Systems - Quarterdeck DesqView, CP/M, etc
Archive   : PCCAPP.ZIP
Filename : LOAD_MEM.C

 
Output of file : LOAD_MEM.C contained in archive : PCCAPP.ZIP
/*
* This file is part of the Choices Operating System
* Developed by: The TAPESTRY Parallel Computing Laboratory
* University of Illinois at Urbana-Champaign
* Department of Computer Science
* 1304 W. Springfield Ave.
* Urbana, IL 61801
*
* Copyright (c) 1987, 1988, 1989, 1990, 1991, 1992
* The University of Illinois Board of Trustees.
* All Rights Reserved.
* Distribution restricted under license agreement.
*
* Author: Dave Kohr ([email protected])
* Project Manager and Principal Investigator: Roy Campbell ([email protected])
*
* Funded by: NSF TAPESTRY Grant No. 1-5-30035, NASA ICLASS Grant
* No. 1-5-25469 and No. NSG1471 and AT&T Metronet Grant No. 1-5-37411.
*/
/**********************************************************************
$Id: load_mem.c,v 1.5 1992/06/07 17:07:10 lup Exp lup $

$Source: /home/guests/pcc/Loadcoff/RCS/load_mem.c,v $

$Log: load_mem.c,v $
* Revision 1.5 1992/06/07 17:07:10 lup
* *** empty log message ***
*
* Revision 1.3 1992/02/21 16:36:58 lup
* *** empty log message ***
*
* Revision 1.2 92/01/21 16:29:45 lup
* *** empty log message ***
*
Revision 1.1.1.5 91/12/06 11:02:17 drk
Minor fixups.

Revision 1.1.1.4 91/12/06 10:47:29 drk
Minor fixups; add zeroing out of .bss section.

Revision 1.1.1.3 91/12/06 10:06:07 drk
Minor fixes for Turbo-C

Revision 1.1.1.2 91/12/04 16:57:56 drk
Minor verbosity fix.

Revision 1.1.1.1 91/12/04 16:07:56 drk
First revision.

Revision 1.1 91/12/04 16:07:29 drk
First branch.


Routines to load Choices kernel into extended memory.
**********************************************************************/


#ifdef __MSDOS__
#include
#include
#endif

#include
#include
#include "loadcoff.h"
#include "minicoff.h"


/*
A COFF data section is copied out of the COFF file and into extended memory
by load_section(). load_section() in turn calls load_chunk() several times
to transfer CHUNK_SIZE-sized portions of the data. load_chunk() calls
move_chunk() to actually do the transfer. move_chunk() uses BIOS interrupt
0x15, function 0x87, to transfer the data. CHUNK_SIZE is limited by the
maximum transfer size of this BIOS function to be 0x8000 or less.

check_chunk() uses move_chunk() to read the data back from extended memory
and compare it with what was loaded.
*/

/*
Note that Turbo C puts both chunk and check into the same data segment
(since they're in the same file), which is at most 0xFFFF bytes long. This
means that if CHUNK_SIZE is defined to be 0x8000, a segment overflow will
occur during compilation.
*/

#define CHUNK_SIZE 0x4000 /* On the safe side. */

static unsigned char chunk[CHUNK_SIZE]; /* Chunk buffer. */

static unsigned char check[CHUNK_SIZE]; /* Buffer for checking last
chunk. */


#ifdef __MSDOS__
/* Input/output registers and segments for
BIOS interrupt. */
static union REGS inregs, outregs;
static struct SREGS sregs;

/*
Definition of the form of Global Descriptor Table used for BIOS intr. 0x15,
function 0x87. Adapted from Ralph Brown's Interrupt List.
*/

typedef struct global_desc_table {
unsigned char zero_1[16]; /* Zeroes. */
unsigned short src_seg_len; /* Source segment length. */
unsigned char src_addr[3]; /* 24-bit source address. */
unsigned char src_access; /* Src seg access rights: 0x93. */
unsigned short zero_2; /* Zero. */
unsigned short dest_seg_len; /* Destination seg length. */
unsigned char dest_addr[3]; /* 24-bit dest address. */
unsigned char dest_access; /* Dest seg access rights: 0x93. */
unsigned char zero_3[18]; /* Zeroes. */
} GLOBAL_DESC_TABLE;

static GLOBAL_DESC_TABLE gdt;

#endif /* #ifdef __MSDOS__ */


/*
Move data of length "size" bytes between real-mode buffer "chunk" and
extended memory buffer at address "phys_addr". Flag to_ext_mem is non-0 if
data is to be moved from "chunk" to "phys_addr", or 0 if to be moved from
"phys_addr" to "chunk". For MS-DOS, it is assumed that chunk is a "far"
pointer (so the program must be compiled with memory model "large").
*/

static void move_chunk(void *chunk, long size, long phys_addr,
int to_ext_mem)
{
int i;
/* Source and dest. buffer addresses. */
long src_addr, dest_addr;

#ifdef __MSDOS__
/*
Figure out in which direction to move data.
*/
if (to_ext_mem) {
src_addr = FP_OFF(chunk);
src_addr += ((long) FP_SEG(chunk)) << 4L;
dest_addr = phys_addr;
} else {
dest_addr = FP_OFF(chunk);
dest_addr += ((long) FP_SEG(chunk)) << 4L;
src_addr = phys_addr;
}

/*
Fill in gdt.
*/
for (i = 0; i < 15; i++)
gdt.zero_1[i] = 0;
gdt.zero_2 = 0;
for (i = 0; i < 18; i++)
gdt.zero_3[i] = 0;

gdt.src_seg_len = gdt.dest_seg_len = (unsigned short)
(2 * size - 1);
gdt.src_access= gdt.dest_access= 0x93;

gdt.src_addr[0] = (unsigned char) (src_addr & 0xFF);
gdt.src_addr[1] = (unsigned char) ((src_addr & 0xFF00L) >> 8);
gdt.src_addr[2] = (unsigned char) ((src_addr & 0xFF0000L) >> 16);

gdt.dest_addr[0] = (unsigned char) (dest_addr & 0xFF);
gdt.dest_addr[1] = (unsigned char) ((dest_addr & 0xFF00L) >> 8);
gdt.dest_addr[2] = (unsigned char) ((dest_addr & 0xFF0000L) >> 16);

/*
Set up BIOS function arguments.
*/
inregs.h.ah = 0x87;
inregs.x.cx = (unsigned short) size;
inregs.x.si = FP_OFF((void *) &gdt);
sregs.es = FP_SEG((void *) &gdt);

/*
Do BIOS call, check return status.
*/
int86x(0x15, &inregs, &outregs, &sregs);
// if (!outregs.x.cflag && !outregs.h.ah)
if (!outregs.x.cflag)
return; /* BIOS call succeeded. */
if (!outregs.h.ah) return;

sprintf(errmsg,
"BIOS interrupt 0x15, function 0x87\n\
(Copy Extended Memory) failed with error %#02X", outregs.h.ah);
io_error(errmsg);
#endif
}

/*
Load buffer "chunk" of length "size" into extended memory address
"phys_addr". For MS-DOS, it is assumed that chunk is a "far" pointer (so
the program must be compiled with memory model "large").
*/

static void load_chunk(void *chunk, long size, long phys_addr)
{
if (very_verbose)
printf(
"Copying chunk of size %ld to physical address %#04X.\n", size, phys_addr);
move_chunk(chunk, size, phys_addr, 1);
}

/*
Compare contents at extended memory address "phys_addr" with
previously-loaded buffer "chunk" of length "size", using buffer "check" as
a temporary for the comparison. Print error message and exit if
differences are found.
*/

static void check_chunk(void *chunk, void *check, long size,
long phys_addr)
{
int i;
unsigned char *chunkp = (unsigned char *) chunk,
*checkp = (unsigned char *) check;

/* Guarantee chunk and check have different
contents initially. */
for (i = 0; i < size; i++)
checkp[i] = ~chunkp[i];

move_chunk(check, size, phys_addr, 0);

/*
Compare check and chunk. Use for-loop instead of memcmp() so I can find
out exactly what byte is in error.
*/
for (i = 0; i < size; i++) {
if (checkp[i] == chunkp[i])

continue;
fprintf(stderr,
"Miscompare of memory loaded to extended address %#04lX:\n\
\tbyte was %#02X instead of %#02X\n", phys_addr + i, checkp[i], chunkp[i]);
exit(1);
}
if (very_verbose)
printf("Loaded chunk looks OK.\n");
}

/*
Load COFF section of length "size", starting at position "file_offset" in
file, to extended memory at location "phys_addr". If with_zeroes is
non-zero, the section loaded to extended memory will actually contain all
zero bytes, and no data will be read from the COFF file (this is for
handling the ".bss" segment).
*/

static void load_section(long file_offset, long size, long phys_addr,
int with_zeroes)
{
long transfer_size; /* Size of current chunk. */

/* Seek to start of data (if any). */
if (!with_zeroes &&
fseek(infile, file_offset, SEEK_SET) == -1)
io_error("fseek() failed");

while (size > 0) {
/* Get a single chunk. */
transfer_size = (size > CHUNK_SIZE) ? CHUNK_SIZE : size;
if (with_zeroes)
/* Use a chunk of zeroes. */
memset((void *) chunk, 0, transfer_size);
/* Read chunk from file. */
else if (fread((void *) chunk, 1, (int) transfer_size,
infile) != transfer_size) {
if (ferror(infile))
io_error("fread() of data failed");
else {
fprintf(stderr,
"loadcoff: hit EOF before expected while reading data\n");
exit(1);
}
}

/* Now load it. */
load_chunk((void *) chunk, transfer_size, phys_addr);
if (check_mem)
check_chunk((void *) chunk, (void *) check,
transfer_size, phys_addr);
phys_addr += transfer_size;
size -= transfer_size;
}
}


/*
Load PC's extended memory with COFF data. Assumes headers have been read
in.
*/

void load_mem(void)
{
if (verbose)
printf(
"Loading segment \"%s\" into extended memory.\n", TEXT_SCN_NAME);
load_section(text_hdr.s_scnptr, text_hdr.s_size, text_hdr.s_paddr,
0);
if (verbose)
printf(
"Loading segment \"%s\" into extended memory.\n", DATA_SCN_NAME);
load_section(data_hdr.s_scnptr, data_hdr.s_size, data_hdr.s_paddr,
0);
if (verbose)
printf(
"Loading zero bytes for segment \"%s\" into extended memory.\n",
BSS_SCN_NAME);
load_section(bss_hdr.s_scnptr, bss_hdr.s_size, bss_hdr.s_paddr, 1);
}


#ifndef __MSDOS__

/*
Stub for switching into protected mode and branching to start of Choices
kernel, for non-DOS compilation of this routine.

For DOS systems, the real routine for doing this is in an assembly file
written by Lup.
*/

void bootChoices(void)
{
printf("bootChoices() not implemented!\n");
}

#endif /* #ifndef __MSDOS__ */


  3 Responses to “Category : Alternate Operating Systems - Quarterdeck DesqView, CP/M, etc
Archive   : PCCAPP.ZIP
Filename : LOAD_MEM.C

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/