]> pd.if.org Git - mmurtl/commitdiff
autocommit for file dated 1995-01-02 17:14:34
authorRichard Burgess <>
Mon, 2 Jan 1995 17:14:34 +0000 (17:14 +0000)
committerNathan Wagner <nw@hydaspes.if.org>
Mon, 17 Oct 2016 14:03:47 +0000 (14:03 +0000)
mscode16/mmloader/mmloader.c [new file with mode: 0644]

diff --git a/mscode16/mmloader/mmloader.c b/mscode16/mmloader/mmloader.c
new file mode 100644 (file)
index 0000000..d02c9c1
--- /dev/null
@@ -0,0 +1,564 @@
+/* MMLoader.c\r
+   This is the DOS loader for the MMURTL OS RUN file.\r
+\r
+   MMURTL is loaded into memory in two basic pieces.\r
+   The first piece is the DATA segment. It is loaded at linear\r
+   addrsss 0.  The default OS stacks are contained in this segment.\r
+   The second piece is the CODE. It is loaded at linear\r
+   address 10000h (The 64K boundry).  If you know anything about\r
+   MS-DOS, you that is doesn't consume this kind of memory.\r
+   This loader program will load somwhere between the 25K\r
+   and 64K linear boundry depending on whether DOS is loaded\r
+   "HIGH" or not, and also what TSRs you have installed.\r
+   We must allocate some dummy space to ensure that when we\r
+   load our two segments from disk and copy them down, we don't\r
+   overwrite this loader program (in which case\r
+   your system will lock up tighter than a drum!).\r
+\r
+   NOTE: This is the only program requiring a DOS programming\r
+   tool because "We don't do 16 bit real mode code..."\r
+   This must be compiled with Borland C        due to the inline assembler.\r
+\r
+       You MUST use the -B and -ml options. Example\r
+\r
+               BCC -B -ml MMLoader.c\r
+\r
+   The -B forces assebly language compilation and linkage.\r
+       -ml sets it to large model\r
+   You probably won't need to rebuild it all because it reads the\r
+   size of the segments for the MMURTL run file and adjusts the\r
+   buffers for them.  So modifying MMURTL (adding or taking away code or\r
+   data) shouldn't affect how the loader works (unless you exceed\r
+   128K for code or data, in which case you'll have to modify this\r
+   to handle it).\r
+\r
+   What actually happens here:\r
+       (This basically turns MS-DOS into a $79.00 loader)\r
+\r
+       1) Load the code and data into DOS memory (we don't own)\r
+          Gets the boot drive from OSName or MS-DOS id not\r
+          specified in OSName.\r
+       3) Clear interrupts\r
+       2) Turn on the A20 Address Line Gate\r
+       4) Move the data from the buffers into proper place for execution\r
+       5) Set the Interrupt and Global Descriptor table registers\r
+          in preparation for protect mode transition\r
+       6) Set Protected mode bit in CR0 (Control Register 0)\r
+       7) Jump to OS Code entry point at linear address 10000h\r
+       in the code segment/selector (which is 8h).\r
+       All OS segments are ZERO based.\r
+\r
+       NOTE: This the last the processor sees of 16 bit real mode code\r
+    (no great loss at all in my humble opinion)\r
+\r
+*/\r
+\r
+\r
+\r
+#define U32 unsigned long\r
+#define S32 long\r
+#define U16 unsigned int\r
+#define S16 int\r
+#define U8 unsigned char\r
+#define S8 char\r
+\r
+#define TRUE 1\r
+#define FALSE 1\r
+\r
+#include <ctype.h>\r
+#include <stdio.h>\r
+#include <string.h>\r
+#include <stdlib.h>\r
+#include <dos.h>\r
+#include <dir.h>\r
+#include "\OSSOURCE\runfile.h"\r
+\r
+U32 fEOF = 0;\r
+\r
+long CSegSize = 0;\r
+long DSegSize = 0;\r
+\r
+char *ptest;\r
+\r
+long   sStack = 0;\r
+long   sCode = 0;\r
+long   sData = 0;\r
+\r
+long   offCode = 0;\r
+long   offData = 0;\r
+long   pStart = 0;\r
+\r
+struct tagtype tag;\r
+\r
+char osname[50] = {"MMURTL.RUN"};      /* default OS name */\r
+\r
+FILE *run_fh = 0;\r
+FILE *out_fh = 0;\r
+\r
+unsigned char bootdrive;\r
+\r
+/**** Execute ************************************************\r
+   At this point:\r
+     Interrupts are disabled,\r
+     The code and data are waiting to be moved down to 0 linear\r
+        So we move it, then we tell the processor the size and\r
+        location of the IDT and GDT (with the SIDT and SGDT\r
+        insturctions), then set the protected mode bit and\r
+        jump to the OS code!\r
+     This code can't access any data segment variables.\r
+     It must all be self contained because we relocate it.\r
+**************************************************************/\r
+\r
+void Execute(void)\r
+{\r
+\r
+/* We're pulling some REAL cheating here in real mode\r
+to get this done.  We set DS up to where we moved the\r
+variables we need to use. We did this so we wouldn't\r
+overwrite them. Then we move the OS code & data DOWN\r
+and DO IT!  This code ends up at 9000:0\r
+*/\r
+\r
+asm {  .386P\r
+               CLI\r
+               NOP\r
+\r
+               MOV BX, 9800h\r
+               MOV DS, BX\r
+               MOV BX, 0\r
+               MOV WORD PTR DS:[BX], 07FFh\r
+               MOV BX, 2\r
+               MOV WORD PTR DS:[BX], 0h\r
+               MOV BX, 4\r
+               MOV WORD PTR DS:[BX], 0h\r
+\r
+               MOV BX, 6\r
+               MOV WORD PTR DS:[BX], 017FFh\r
+               MOV BX, 8\r
+               MOV WORD PTR DS:[BX], 0800h\r
+               MOV BX, 10\r
+               MOV WORD PTR DS:[BX], 0h\r
+\r
+\r
+               MOV BX, 0B800h\r
+               MOV ES, BX\r
+               MOV BX, 0\r
+               MOV WORD PTR ES:[BX], 4731h\r
+\r
+               /* Set up our new DS to where we moved the data */\r
+               /* We must do this before each 32K load cause we use DS */\r
+\r
+\r
+               /* Move first 32K data chunk */\r
+\r
+               MOV BX, 06000h\r
+               MOV DS, BX\r
+               XOR SI, SI\r
+               MOV AX,0000h\r
+               MOV ES,AX\r
+               XOR DI,DI\r
+               MOV CX,8000h\r
+               CLD                     ;\r
+               REP MOVSB                               ;\r
+\r
+               /* Move second 32K data chunk */\r
+\r
+               MOV BX, 06800h\r
+               MOV DS, BX\r
+               XOR SI, SI\r
+               MOV AX,0800h\r
+               MOV ES,AX\r
+               XOR DI,DI\r
+               MOV CX,8000h\r
+               CLD                     ;\r
+               REP MOVSB                               ;\r
+\r
+               /* Move first 32K code chunk */\r
+\r
+               MOV BX, 07000h\r
+               MOV DS, BX\r
+               XOR SI, SI\r
+               MOV AX,1000h\r
+               MOV ES,AX\r
+               XOR DI,DI\r
+               MOV CX,8000h\r
+               CLD                     ;\r
+               REP MOVSB                               ;\r
+\r
+               /* Move second 32K code chunk */\r
+\r
+               MOV BX, 07800h\r
+               MOV DS, BX\r
+               XOR SI, SI\r
+               MOV AX,1800h\r
+               MOV ES,AX\r
+               XOR DI,DI\r
+               MOV CX,8000h\r
+               CLD                     ;\r
+               REP MOVSB                               ;\r
+\r
+               /* Move third 32K code chunk */\r
+\r
+               MOV BX, 08000h\r
+               MOV DS, BX\r
+               XOR SI, SI\r
+               MOV AX,2000h\r
+               MOV ES,AX\r
+               XOR DI,DI\r
+               MOV CX,8000h\r
+               CLD                     ;\r
+               REP MOVSB                               ;\r
+\r
+\r
+               MOV BX, 0B800h\r
+               MOV ES, BX\r
+               MOV BX, 2\r
+               MOV WORD PTR ES:[BX], 4732h\r
+\r
+               MOV BX, 9800h\r
+               MOV DS, BX\r
+               MOV BX, 0\r
+\r
+               LIDT FWORD PTR DS:[BX+0]\r
+               LGDT FWORD PTR DS:[BX+6]\r
+               MOV EAX,CR0\r
+               OR AL,1\r
+               MOV CR0,EAX\r
+               JMP $+4\r
+               NOP\r
+               NOP\r
+               NOP\r
+               NOP\r
+\r
+        MOV BX, 10h\r
+               MOV DS,BX\r
+               MOV ES,BX\r
+               MOV FS,BX\r
+               MOV GS,BX\r
+               MOV SS,BX\r
+               DB 66h\r
+               DB 67h\r
+               DB 0EAh\r
+               DD 10000h\r
+               DW 8h\r
+               RETN\r
+} /* end of assembler */\r
+\r
+}\r
+\r
+\r
+/**** TurnOnA20 ****************************************************\r
+    This turns on the address line 20 Gate. This must be done before\r
+    we can physically address above 1 Meg.  If your machine only\r
+    shows one Meg of RAM and you know there's more, this isn't\r
+    working on your machine... (R&D time..)\r
+********************************************************************/\r
+\r
+void TurnOnA20(void)\r
+{\r
+\r
+asm {\r
+               CLI\r
+               XOR CX,CX\r
+       }\r
+\r
+IBEmm0:\r
+\r
+asm {\r
+               IN AL,64h\r
+               TEST AL,02h\r
+               LOOPNZ IBEmm0\r
+               MOV AL,0D1h\r
+               OUT 64h,AL\r
+               XOR CX,CX\r
+       }\r
+\r
+IBEmm1:\r
+\r
+asm {\r
+               IN AL,64h\r
+               TEST AL,02h\r
+               LOOPNZ IBEmm1\r
+               MOV AL,0DFh\r
+               OUT 60h,AL\r
+               XOR CX,CX\r
+       }\r
+\r
+IBEmm2:\r
+\r
+asm {\r
+               IN AL,64h\r
+               TEST AL,02h\r
+               LOOPNZ IBEmm2\r
+       }\r
+}\r
+\r
+/*** Relocate *********************************************\r
+This is a tricky little piece of code. We are going to\r
+manipulate DOS memory we don't even own.\r
+We are going to set up a temporary little environment\r
+up at A0000h linear (A000:0 segmented) for our\r
+data environment. And then at 90000h (9000:0) for\r
+the loader code itself. This will become CS.\r
+**********************************************************/\r
+\r
+void Relocate(void)\r
+{\r
+char *pdest, *psource, **pnewp;\r
+long *pnewl;\r
+unsigned int *pneww;\r
+int  i;\r
+\r
+/* First we move the code up */\r
+\r
+       psource = (void*) &Execute;\r
+\r
+       printf("SEG: %u OFF: %u\r\n", FP_SEG(psource), FP_OFF(psource));\r
+\r
+       pdest = MK_FP(0x9000,0);\r
+       i = 2000;       /* more than enough for the code */\r
+       while(i--)\r
+               *pdest++ = *psource++;\r
+\r
+}\r
+\r
+\r
+void CallExecute(void)\r
+\r
+{\r
+/* We push the new code address on the stack then RETF to it.\r
+   We PUSH CS then IP */\r
+\r
+asm {\r
+       MOV AX, 09000h\r
+       PUSH AX\r
+       MOV AX, 0\r
+       PUSH AX\r
+       RETF\r
+}\r
+\r
+}\r
+\r
+/* Borland calls procedures as near indirect\r
+to far data definitions. This means the\r
+bootdrive param will be at EBP+06\r
+*/\r
+\r
+void SetBootDrive(unsigned int bootdrive)\r
+\r
+{\r
+/* get boot drive off stack and place in DL */\r
+\r
+asm {\r
+       XOR EDX, EDX\r
+       MOV DX, WORD PTR [BP+06h]\r
+}\r
+\r
+}\r
+\r
+\r
+/*********************************************************\r
+  This reads and loads the two MMURTL segments into\r
+  six 32K buffers. Two for the data segment, and 4 for\r
+  the code segment. (192K Maximum).\r
+  The MMURTL OS is built as a standard MMURRL run file.\r
+  This is a tag/length/value file as described in the\r
+  DASM documentation (in great detail).\r
+*********************************************************/\r
+\r
+void LoadRunFile(void)\r
+{\r
+int ii;\r
+long i, dret, nobj, nread;\r
+char filetype, junk, *pin;\r
+\r
+       while (1) {\r
+               tag.id = 0;\r
+/*             fprintf(out_fh, "\r\nFile LFA: %ld\r\n", ftell(run_fh)); */\r
+               nobj = fread (&tag, 1, 5, run_fh);\r
+               if (nobj) {\r
+/*\r
+                       ii = tag.id;\r
+                       fprintf(out_fh, "Tag Value  (hex): %02X\r\n", ii);\r
+                       fprintf(out_fh, "Tag Length (dec): %ld\r\n", tag.len);\r
+*/\r
+               }\r
+               else {\r
+                       fprintf(out_fh, "Invalid OS Run file. No End Tag Found.\r\n");\r
+                       fclose(run_fh);\r
+                       exit(1);\r
+               }\r
+\r
+               switch (tag.id) {\r
+                       case IDTAG:\r
+                               nobj = fread (&filetype, 1, 1, run_fh);\r
+                               if (filetype == 1)\r
+                                       break;\r
+                               else {\r
+                                       fprintf(out_fh, "File MUST be a run file\r\n");\r
+                                       exit(1);\r
+                               }\r
+                               break;\r
+                       case SEGTAG:\r
+                               fprintf(out_fh, "Segment Sizes:\r\n");\r
+                               nobj = fread (&sStack, 1, 4, run_fh);\r
+                               if (nobj) nobj = fread (&sCode, 1, 4, run_fh);\r
+                               if (nobj) nobj = fread (&sData, 1, 4, run_fh);\r
+                               fprintf(out_fh, "  Stack   %ld\r\n", sStack);\r
+                               fprintf(out_fh, "  Code    %ld\r\n", sCode);\r
+                               fprintf(out_fh, "  Data    %ld\r\n", sData);\r
+                               break;\r
+                       case DOFFTAG:\r
+                               nobj = fread (&offData, 1, 4, run_fh);\r
+                               fprintf(out_fh, "Virtual Data Offset: %08lXh\r\n", offData);\r
+                               break;\r
+                       case COFFTAG:\r
+                               nobj = fread (&offCode, 1, 4, run_fh);\r
+                               fprintf(out_fh, "Virtual Code Offset: %08lXh\r\n", offCode);\r
+                               break;\r
+                       case STRTTAG:\r
+                               nobj = fread (&pStart, 1, 4, run_fh);\r
+                               fprintf(out_fh, "Start Address: %08lXh\r\n", pStart);\r
+                               break;\r
+                       case CODETAG:\r
+                               fprintf(out_fh, "Reading code:  %ld bytes\r\n", tag.len);\r
+                CSegSize = tag.len;\r
+\r
+                               if (tag.len >= 32768)\r
+                                       nread = 32768;\r
+                               else\r
+                                       nread = tag.len;\r
+                               tag.len -= nread;\r
+                               pin = MK_FP(0x7000,0);\r
+                               nobj = fread (pin, 1, nread, run_fh);\r
+\r
+                               if (tag.len >= 32768)\r
+                                       nread = 32768;\r
+                               else\r
+                                       nread = tag.len;\r
+                               tag.len -= nread;\r
+                               pin = MK_FP(0x7800,0);\r
+                               nobj = fread (pin, 1, nread, run_fh);\r
+\r
+                               if (tag.len >= 32768)\r
+                                       nread = 32768;\r
+                               else\r
+                                       nread = tag.len;\r
+                               tag.len -= nread;\r
+                               pin = MK_FP(0x8000,0);\r
+                               nobj = fread (pin, 1, nread, run_fh);\r
+                               break;\r
+                       case DATATAG:\r
+                               fprintf(out_fh, "Reading data:  %ld bytes\r\n", tag.len);\r
+                DSegSize = tag.len;\r
+                               if (tag.len >= 32768)\r
+                                       nread = 32768;\r
+                               else\r
+                                       nread = tag.len;\r
+                               tag.len -= nread;\r
+                               pin = MK_FP(0x6000, 0);\r
+                               nobj = fread (pin, 1, nread, run_fh);\r
+\r
+                               if (tag.len >= 32768)\r
+                                       nread = 32768;\r
+                               else\r
+                                       nread = tag.len;\r
+                               tag.len -= nread;\r
+                               pin = MK_FP(0x6800,0);\r
+                               nobj = fread (pin, 1, nread, run_fh);\r
+                               break;\r
+                       case CDFIXTAG:\r
+                       case CCFIXTAG:\r
+                       case DDFIXTAG:\r
+                       case DCFIXTAG:\r
+                               while ((tag.len) && (nobj)) {\r
+                                       nobj = fread (&i, 1, 4, run_fh);\r
+                                       tag.len-=4;\r
+                               }\r
+                               break;\r
+                       case ENDTAG:\r
+                               nobj = fread (&i, 1, 4, run_fh);        /* Eat the end tag */\r
+                               fclose(run_fh);\r
+                TurnOnA20();\r
+                               Relocate();                     /* Move the loader code & data */\r
+                               SetBootDrive((unsigned int) bootdrive);\r
+                               CallExecute();\r
+                               break;\r
+                       default:\r
+                               while ((tag.len--) && (nobj))\r
+                                       nobj = fread (&junk, 1, 1, run_fh);\r
+                               break;\r
+\r
+               } /* end of switch */\r
+       }\r
+}\r
+\r
+/***************************\r
+* Main program -- MMLoader\r
+****************************/\r
+\r
+void main(S16 argc, S8   *argv[])\r
+{\r
+S8   *ptr;\r
+S16  i;\r
+char fName;\r
+\r
+       out_fh = stdout;\r
+       fName = 0;\r
+\r
+       for(i=1; i < argc; ++i) {\r
+               ptr = argv[i];\r
+               if (*ptr == '/') {\r
+                 ptr++;\r
+                 switch(*ptr) {\r
+                       case 'U' :\r
+                       case 'u' :\r
+                               break;\r
+                       case 'D' :\r
+                       case 'd' :\r
+                               break;\r
+                       case 'O' :\r
+                       case 'o' :\r
+                               fName = 1;\r
+                               break;\r
+                       default:\r
+                               printf("Invalid option/swtich \n");\r
+                               if (run_fh)\r
+                                       fclose(run_fh);\r
+                               exit(1);\r
+                               break;\r
+                 }\r
+               }\r
+               else {\r
+                       if (fName)\r
+                               strncpy(osname, argv[i], 39);\r
+               }\r
+       }\r
+\r
+       printf("MMURTL DOS Loader Ver 1.0 \r\n");\r
+\r
+       printf("OS Filename specified: %s \r\n",  osname);\r
+\r
+       run_fh = fopen(osname, "rb");\r
+       if (!run_fh) {\r
+               printf("Can't open: %s \r\n",  osname);\r
+               exit(1);\r
+       }\r
+\r
+       if (osname[1] == ':')\r
+       {\r
+               bootdrive = osname[0] - 0x41;\r
+               if (bootdrive >= 0x20)\r
+                       bootdrive -= 0x20;      /* may be lower case */\r
+       }\r
+       else\r
+          bootdrive = getdisk();\r
+\r
+       ptest = malloc(100);    /*  32K */\r
+       printf("First MEM = SEG: %u OFF: %u\r\n", FP_SEG(ptest), FP_OFF(ptest));\r
+\r
+       LoadRunFile();\r
+\r
+}\r
+\r
+/*********************** End of Module *****************/\r