/*
 * The code in this package is released freely with only 1 restriction
 * on its usage.  It may not be copyrighted or patented.
 * Also this message must be packaged with any re-releases.
 *
 * No guarantees of merchantability or fitness for any
 * given application are implied or inferred, and the original author is not
 * responsible for any damages resulting from usage of this software,
 * either direct or indirect
 * and in fact no guarantee is even made that the software will actually
 * perform as specified.  It is supplied on an as-is basis, you use it 
 * totally at your own risk.
 *
 * This program was designed to run on a 'standard' pc.  It bypasses
 * the BIOS and directly manipulates hardware.
 *
 * Bug reports would be appreciated.  If you want me to feel appreciated
 *   send whatever you feel the software is worth to you to the 
 *   following address:
 *
 * Author: David Lindauer
 *	   1428 Hepburn Ln. APT #1
 *         Louisville, KY.
 *         40204
 * E-Mail: gclind01@ulkyvx.louisville.edu
 */

Note:
  Make sure you use the -d switch when you pkunzip all this.  It's just too
  confusing to try and keep everything in one directory, given all I'm
  giving.
  Also, There are two different kinds of EXE files included in this package;
  only one kind is formatted for DOS.  The other will run on my OS.

  Read the README files in some of the subdirs for more info.

What it is:

OS.EXE is the kernel for a primitive 32-bit operating system.
LINK32.EXE is a linker which will link object files and libraries generated
  by borland C++ and Borland TASM into images executeable by the operating
  system kernel.
OSLIB.LIB is a C library for interfacing with the kernel
C0OS.obj is a C header file for use with C programs and the linker
STARTUP.obj is the C startup code for use with C programs and the linker

This package will probably be less useful as a complete application than
as a guide to writing programs which deal with a wide variety of PC
hardware.  Although you could certainly use this to program a
complete application.  Sources included handle:
  386 paging/segments/ protected mode & real mode switching
  floppy disk control
  Time of day clock interrupt-driven handler
  Tick interrupt handler
  Serial port handler
  PIC handler
  An alternate file system.
  Task switching
  32-bit Debugger

To run sample programs:

You must have a 386 or better, with at least 2MB of extended memory.
You cannot run this if EMM386 is installed.

1) put os.exe on your path
2) switch to a sample program dir.
   OS\ASM\OS\OBJECT\TESTS	- miscellaneous program tests
   OS\C\UTILS			- file system utils
   OS\ASM\OS\OBJECT		- a couple more program tests
   OS\C\TESTS			- disk utils
   I suggest you switch to OS\ASM\OS\OBJECT\TESTS
3) Run a program.  I suggest kbtest1.exe:

   os kbtest1.exe

for this test program, hit any key and its hex value will be displayed,
along with elapsed time.  Do a CTRL-ALT-DEL to exit.

If you have a microsoft mouse you can also run mstest1.exe or mstest2.exe.
They will put a mouse up on the screen and you can move it around.

Other tests may or may not do anything obvious; they are designed more
as a guide to using the operating system than as meaningful user-level
programs.  The exception is the tests in OS\C\UTILS; they will format
a 1.44M floppy using the OS format, and copy between DOS and the floppy.
Refer to OS\C\UTILS\README.TXT for details.

To run the linker, put 32rtm.exe and dpmi32vm.ovl and link.exe on your
path; then type link.

Note on extended memory:  This system will report 1MB less extended
memory than you have.  It does this deliberately so that you can run it
with HIMEM.SYS installed.  Apparently COMMAND.COm swaps itself to
extended memory and if you overwrite it there is a problem, so I reserve
the lower MB of extended memory for it.  You can get more extended memory
by changing the constant PG_STARTOFEXTMEM in PAGE.ASI.

Needed for building this system:

OS.EXE:
  TASM 4.0, TLINK 5.0 ( NOT TLINK32)
    original code was prototyped under TASM 2.0, much of the development
    was done under TASM 3.0, finalized under version 4.0.  This code
    uses TASM's ideal mode, and will not be directly portable to MASM,
    although with some syntax changes it should assemble.

LINK32.EXE:
  Borland C++ 4.5
    LINK32 is itself a 32 bit program for DOS.  You might get by with BCC 4.0,
    I'm not sure when they started with 32 bit functionality.
  Borland PowerPack for DOS
    These products are required for running 32 bit programs under DOS.
    You can get by without powerpack if you want to do the work, essentially
    you borrow the DPMI loader stub from one of borlands compilers or linkers
    and either write a special program to install the new stub or name it
    32STUB.EXE,( put an appropriate EXE file header on it), and use TLINK32
    with the /Tpe/ax switches to create a DOS protected mode program.
    You only need LINK32 if you intend to run C programs on the os kernel.
    You do need C0X32.OBJ to build this program, I think I saw it on the
    BCC 4.5 distribution rather than in the power pack though.
  If you don't have borland C 4.5 change the constant USER_PROGRAM_OFFSET
    in TSS.ASI and rebuild the os with TASM.  This gives you a kernel
    where the task start address is linear 0 rather than linear 4096
    and so you can use TLINK to link the assembly test programs rather 
    than LINK.  This prevents you from using 32 Bit C programs with the OS,
    however.  Although I guess you could use the /B switch with LINK to get
    it to produce executable files.

OSLIB.LIB
  TASM 4.0
    you can't do without TASM 4.0 for the C library.  TASM 3.0 had a
    combination of bugs and unsupported features that made my implementation
    inoperable.  Basically, you can't get it to use the ARG statement
    in 32 bit mode.  I could have rewritten around that using symbolic
    constants, but I was getting the new assembler anyway so I didn't.

What you can expect:

OS.EXE
  supports file handling, multitasking, miscellaneous bios tasks rewritten
  in 32 bit mode, and processor switching between protected mode and real mode,
  memory management, and perhaps other things I've forgotten.  Some of it
  resembles DOS in functionality, some of it was written explicitly so I could
  rewrite Borland's C++ library and use it with my kernel.  I've gotten
  creative with some of the algorithms used- for example my disk directory
  structure resembles that of the OBERON system in that it is formed as a
  balanced tree.  The file structure is modeled partly on OBERON's system
  and partly on what I saw many years ago when dissassembling Radio Shack's
  TRSDOS system.  It has a little bit of the POLYFORTH system of buffer handling
  thrown in for good measure.  On the other hand, my default memory management system
  is a clone of the DOS arena technique, or if you use the C support functions
  I added later you're actually doing something similar to what happens
  on a 386 windowed environment.  Allocating and deleting memory on a page
  by page basis.  Of course if you use the arena scheme there is no way to
  deallocate memory allocated to a task in the sense of letting another task
  get to it, at least not until the task runs down.
    I've rewritten key bios functions, such as a video handler, a keyboard
  handler, a floppy disk handler.  The video handler is capable of one
  vga graphics mode; I haven't tried it but I put in all the code I thought
  was necessary to do without the BIOS entirely.  So on video mode switches
  the system font (included in OS.EXE) is loaded into video memory and all
  necessary controller registers are modified as appropriate.  You may need to
  get into VGAINI.ASM and change some of the GCR registers for your computer,
  there's a program around somewhere in this mess for reading VGA registers
  into memory.  The only reason I say that is I'm running on an LCD computer
  and my values are non-standard.  You can try compiling without the 
  NOTEBOOK switch or just not use VGA mode switches in your code.  Or you can
  use BIOS interrupts in 386 mode; I've redirected the 386 interrupts to
  do a processer mode switch into real mode long enough to call DOS or the BIOS
    This is an excellent tutorial on PC hardware by the way, I've recoded
  most everything but the Hard Disk controller in 32 bit assembly on the
  assumption I just might want to replace the BIOS proms at some point.  The
  only thing I'm aware of that doesn't get initialized is DMA, but I think that
  is auto-initializing except that the extended bank will be disabled on
  power-up.  Oh I just realized, I never added code to get the 18.2 Hz timer
  appropriately enabled either.  Not a problem if you're just going to run
  the os under DOS.
    Since I have my own way of doing directories and such there is some
  code for DOS file system compatibility.  Basically the way it works right
  now ( I may change it ) is that you call special functions which do a
  transition to real mode and call MSDOS for the file I/O.  The need to
  be able to call the DOS and BIOS as required tempered early parts of the
  system design such as needing to locate stacks in the lower meg of memory,
  copying buffers around between dos-accessible memory, etc.  One current
  caveat is that I've redirected the 16-BIT floppy hardware interrupt to
  code which does a transition to 32 bit mode and calls the inbuilt floppy
  driver.  So you can't access DOS floppy drives from the OS kernel unless
  you change that.
    Task management is performed using 386 task switching.  Tasks are
  arranged as children and parents and siblings.  If a parent runs down
  all of its children are run down as well.  Task run down frees all memory
  allocated to the task either statically or dynamically.  One gotcha is
  that task rundown does not automatically free any opened file handles, and
  since the file handle scheme is currently modeled on the DOS scheme, i.e.
  there is a single file handle pool managed by the system this could pose
  a long-term problem.  Later I'm going to rewrite the handle scheme to put
  the handles in the task TSS since there is loads of extra space there, then
  rewrite the rundown routines to close all open handles.  Of course then I
  have to come up with a scheme for sharing file handles between parents and
  children.  Because the basic reason for having parents and children was to
  have a scheme whereby the entire program memory is shared between programs,
  so that shared memory functionality is more or less automatic.
    Programs are limited to 8MB; of this 4MB is reserved for code, static
  data, and the user and system stacks.  The other 4MB is allocated as needed
  dynamically.  These limitations come about because the 386 paging system
  which I've enabled maps 4MB chunks of memory for each allocated page of
  paging memory.  I don't plan on running behemoth programs so this seemed
  quite a reasonable compromise to me.
    User programs run in 386 ring 3; the operating system runs in 386 ring 0.
    A 32-bit debugger is included, it has a dissassembler but not an assembler.
  It is modeled on DOS DEBUG with a lot of missing functionality.  Most
  386 exceptions trap to the debugger, with the exception of number 12 which
  extends the user stack automatically if it occurs in user mode.  Stack is
  limited to 4096 Bytes in operaing system mode, because of limitations
  incurred by the fact that paging allows you to make non-contiguous bits
  of memory seem contiguous from one viewpoint but they are still non-contiguois
  from other viewpoints.  In particular, the operating system data segment
  used by the task switcher is unique in that physical pages are mapped
    For an idea of the arguments needed by system functions read the
  OSLIB.LIB sources and keep DOS in mind.  Most things are very similar.
  If an error occurs, the carry flag is set and AL has one of the error
  codes in ERRORS.ASI.  Bear in mind this is not a fully debugged system.
  I've gone to great lengths to test some things such as memory allocation,
  tasks, directory and file structures, and basic functionality of the
  various drivers built into the system but I ***DON'T*** guarantee anything
  whatsoever about fitness for any particular usage or that it will even
  actually perform as advertised.
    One problem you may have is in running it with extended memory managers
  in general.  I recommend you only run it with a 'bare' system- yes get
  out the DOS 6.21 manuals and configure the config.sys and autoexec.bat
  files so you can boot without any memory management whatsoever while
  you play with it.  I've used it with HIMEM.SYS though with no discernable
  problems.  Had to, ever since the latest versions of Borland's DPMI rely
  on it and the borland compilers and linkers all rely on DPMI.  
    One thing I'm unsure of is if all PCs use the same memory
  scheme for extended memory.  HIMEM.SYS toggles the A20 address line via
  the keyboard controller and I don't do this, instead I assume that extended
  memory starts at the 2MB mark physically.  Ironically the power-up code
  reports 4MB of memory on my system with or without HIMEM.SYS toggling the
  A20 line.  I'm not sure what goes on there!  By the way the OS limits itself
  to 16MB of memory.  I did that partly because I can't envision using this
  thing to the load limit and partly because DMA is limited to the lower 16MB
  of memory on an AT class machine.  (DMA for floppy controller)
    If you want to use the file system, you have to have 1.44MB floppy drive.
  To use it, you must first format the floppy disk via a FORMAT call and then
  make a file system with the make file system call.  See c\utils\format.c
  and c\utils\mfs.c for the general idea.  There may also be ASM versions
  in asm\os\object\tests, I'm not sure what all is there.  I won't guarantee
  the test programs as to having appropriate header includes; some were
  assembled in the tests directory and some were moved back tothe tests 
  directory for assembling.  Also, if you want you can link these with
  TLINK rather than LINK32, but you have to put in an ORG 4096 statement in.
  The linker knows that program origin is at 4096 ( the low page is unmapped
  so that C null pointers will result in a trap) and adjusts offsets
  accordingly.
    I put in some basic locks on things like the floppy handler, the file
  system, the memory manager, etc. so that multiple tasks can't access the
  same resources simultaneously.
    Oh and there is a mouse driver.  I've only tested it with an AGILER
  mouse but preliminary research indicates the agiler mouse uses the same
  protocol as the microsoft mouse.  This just in, I tested it with a 
  microsoft mouse and it works just fine!
    Read the various .TXT files for a little more of an idea of what is
  going on.  Use the makefiles to recreate the images.
    I know I'm a little low on documentation but then again I spent a lot of
  time doing this and don't have the time to spend documenting it.  You've
  got all the sources; I encourage you to read them to clarify anything
  that needs clarification.
    Be careful with the EXE files I've left lying around, except for OS.EXE
  and LINK32.EXE they are meant to be run on the OS.
    Using the OS, for example:

       os format.exe

  runs the format program (you have to be in c\utils and have os.exe on
  your path) and:

       os test.exe hi bye

  runs the test program with the command line "hi bye".
    That's about all I can think of to say by way of introduction to the
  kernel.

LINK32.EXE
  was meant to take the output of Borland's C compilers and set it up
  to run on my kernel.  It is essentially an OMF-compliant linker except
  for quirks Borland C shows.  It doesn't handle a variety of things which
  should never happen though, especially doesn't handle imports/exports.
  Doesn't handle 16 bit segments, doesn't handle
  I recommend the OMF standards manual which is in the public domain 
  (intel node of the world-wide-web) if you want to know the data formats. 
     I've made a variety of 
  simplifications though; for one thing names are always presumed
  to come before they are referenced ( not strictly a requirement 
  according to the standards but something borland seems to adhere to).
  For another, I don't do group processing at all
  beyond recognizing a few standard group names that I can depend on seeing
  from the borland compilers.  Other group names will generate an error.
  I order groups in a strictly predetermined order.
  Also, object modules are relocated on a first-come first-serve basis.
  Libraries are assumed to be in the TLIB 4.0 format, which differs from
  the OMF standard on the point of determining where a library module is
  located once it is known to be needed.  This seems to be something DOS
  librarians do in general though.
     LINK32 parameters are very similar to TLINK32 command line parameters.
  With some less functionality, and
  of course no debugging records.  Arguments are more or less the same, 
  except that Code packing is off by default and you have to turn it on
  manually if you want it.  Response files have a totally different format,
  however.  See c\utils\makefile for the general idea.
     I do have a rewritten version of the BORLAND C runtime library which
  makes use of operating system calls; this is how the C programs in the C
  directory were able to do file I/O to my kernel.  BC4.5 comes with sources;
  this is how I came by that.  I can't give it to you though because all
  that stuff is copyrighted by BORLAND.  I've included new versions of the
  startup code in object file format because I mostly rewrote that from
  scratch, but if you want C libraries you'll just have to get into converting
  Windows calls to calls to the OSLIB for yourself.  It's mostly pretty
  straightforward, except that the basic memory handling provided by
  windows is more complicated that what I provide in my kernel.  Basically
  you rewrite the functions that allocate memory without commiting it to
  return with no error only once, then rewrite the memory commit code to
  just do a kernel call.  A hint: write a program, do a LINK32 with the program,
  C0OS.obj and startup.obj and CW32.LIB (from bc45\lib) and this will tell 
  you what function calls need to be modified and what files they are in.
  Then whereis might come in handy for actually locating the files.  As I
  say, it's pretty much straightforward.  Oh do be sure though to get into
  the SETENVP program and check to see if the environment is a null pointer
  and quit if so.  C0OS.OBJ sets the environment to be a null pointer since
  I don't support environments at this point

OSLIB.LIB
  This is a C-compatible library of all known OS calls.  You use a call
  gate to call the OS, this is handled by the OS macro in OS.ASI.  
  Essentially the only thing functions in this library do is move 
  data from the stack to registers and call the OS, returning a result 
  to a stack parameter or in EAX.

C0OS.OBJ
  This is a rewrite of c0x32.obj which does little besides create a module
  definition table for STARTUP.C and push the command line ptr and
  module def table ptr on the stack for startup.c

STARTUP.OBJ
  This is a rewrite of STARTUP.OBJ which entirely ignores DLLs.  IT does little
  besides what Borland's startup.C file does in the way of calling startup
  and exit procedures.  OS/2 shared memory was wiped out in entirety. As was
  exception handling; the kernel doesn't have any provision for handling either
  386 exceptions or software initiated exceptions.  If you make a C library
  ( I called mine COS.LIB) replace the startup module in the library with
  STARTUP.OBJ or rewrite the startup files for yourself.  