2 This is the DOS loader for the MMURTL OS RUN file.
\r
4 MMURTL is loaded into memory in two basic pieces.
\r
5 The first piece is the DATA segment. It is loaded at linear
\r
6 addrsss 0. The default OS stacks are contained in this segment.
\r
7 The second piece is the CODE. It is loaded at linear
\r
8 address 10000h (The 64K boundry). If you know anything about
\r
9 MS-DOS, you that is doesn't consume this kind of memory.
\r
10 This loader program will load somwhere between the 25K
\r
11 and 64K linear boundry depending on whether DOS is loaded
\r
12 "HIGH" or not, and also what TSRs you have installed.
\r
13 We must allocate some dummy space to ensure that when we
\r
14 load our two segments from disk and copy them down, we don't
\r
15 overwrite this loader program (in which case
\r
16 your system will lock up tighter than a drum!).
\r
18 NOTE: This is the only program requiring a DOS programming
\r
19 tool because "We don't do 16 bit real mode code..."
\r
20 This must be compiled with Borland C due to the inline assembler.
\r
22 You MUST use the -B and -ml options. Example
\r
24 BCC -B -ml MMLoader.c
\r
26 The -B forces assebly language compilation and linkage.
\r
27 -ml sets it to large model
\r
28 You probably won't need to rebuild it all because it reads the
\r
29 size of the segments for the MMURTL run file and adjusts the
\r
30 buffers for them. So modifying MMURTL (adding or taking away code or
\r
31 data) shouldn't affect how the loader works (unless you exceed
\r
32 128K for code or data, in which case you'll have to modify this
\r
35 What actually happens here:
\r
36 (This basically turns MS-DOS into a $79.00 loader)
\r
38 1) Load the code and data into DOS memory (we don't own)
\r
39 Gets the boot drive from OSName or MS-DOS id not
\r
40 specified in OSName.
\r
42 2) Turn on the A20 Address Line Gate
\r
43 4) Move the data from the buffers into proper place for execution
\r
44 5) Set the Interrupt and Global Descriptor table registers
\r
45 in preparation for protect mode transition
\r
46 6) Set Protected mode bit in CR0 (Control Register 0)
\r
47 7) Jump to OS Code entry point at linear address 10000h
\r
48 in the code segment/selector (which is 8h).
\r
49 All OS segments are ZERO based.
\r
51 NOTE: This the last the processor sees of 16 bit real mode code
\r
52 (no great loss at all in my humble opinion)
\r
58 #define U32 unsigned long
\r
60 #define U16 unsigned int
\r
62 #define U8 unsigned char
\r
74 #include "\OSSOURCE\runfile.h"
\r
93 char osname[50] = {"MMURTL.RUN"}; /* default OS name */
\r
98 unsigned char bootdrive;
\r
100 /**** Execute ************************************************
\r
102 Interrupts are disabled,
\r
103 The code and data are waiting to be moved down to 0 linear
\r
104 So we move it, then we tell the processor the size and
\r
105 location of the IDT and GDT (with the SIDT and SGDT
\r
106 insturctions), then set the protected mode bit and
\r
107 jump to the OS code!
\r
108 This code can't access any data segment variables.
\r
109 It must all be self contained because we relocate it.
\r
110 **************************************************************/
\r
115 /* We're pulling some REAL cheating here in real mode
\r
116 to get this done. We set DS up to where we moved the
\r
117 variables we need to use. We did this so we wouldn't
\r
118 overwrite them. Then we move the OS code & data DOWN
\r
119 and DO IT! This code ends up at 9000:0
\r
129 MOV WORD PTR DS:[BX], 07FFh
\r
131 MOV WORD PTR DS:[BX], 0h
\r
133 MOV WORD PTR DS:[BX], 0h
\r
136 MOV WORD PTR DS:[BX], 017FFh
\r
138 MOV WORD PTR DS:[BX], 0800h
\r
140 MOV WORD PTR DS:[BX], 0h
\r
146 MOV WORD PTR ES:[BX], 4731h
\r
148 /* Set up our new DS to where we moved the data */
\r
149 /* We must do this before each 32K load cause we use DS */
\r
152 /* Move first 32K data chunk */
\r
164 /* Move second 32K data chunk */
\r
176 /* Move first 32K code chunk */
\r
188 /* Move second 32K code chunk */
\r
200 /* Move third 32K code chunk */
\r
216 MOV WORD PTR ES:[BX], 4732h
\r
222 LIDT FWORD PTR DS:[BX+0]
\r
223 LGDT FWORD PTR DS:[BX+6]
\r
245 } /* end of assembler */
\r
250 /**** TurnOnA20 ****************************************************
\r
251 This turns on the address line 20 Gate. This must be done before
\r
252 we can physically address above 1 Meg. If your machine only
\r
253 shows one Meg of RAM and you know there's more, this isn't
\r
254 working on your machine... (R&D time..)
\r
255 ********************************************************************/
\r
257 void TurnOnA20(void)
\r
296 /*** Relocate *********************************************
\r
297 This is a tricky little piece of code. We are going to
\r
298 manipulate DOS memory we don't even own.
\r
299 We are going to set up a temporary little environment
\r
300 up at A0000h linear (A000:0 segmented) for our
\r
301 data environment. And then at 90000h (9000:0) for
\r
302 the loader code itself. This will become CS.
\r
303 **********************************************************/
\r
305 void Relocate(void)
\r
307 char *pdest, *psource, **pnewp;
\r
309 unsigned int *pneww;
\r
312 /* First we move the code up */
\r
314 psource = (void*) &Execute;
\r
316 printf("SEG: %u OFF: %u\r\n", FP_SEG(psource), FP_OFF(psource));
\r
318 pdest = MK_FP(0x9000,0);
\r
319 i = 2000; /* more than enough for the code */
\r
321 *pdest++ = *psource++;
\r
326 void CallExecute(void)
\r
329 /* We push the new code address on the stack then RETF to it.
\r
330 We PUSH CS then IP */
\r
342 /* Borland calls procedures as near indirect
\r
343 to far data definitions. This means the
\r
344 bootdrive param will be at EBP+06
\r
347 void SetBootDrive(unsigned int bootdrive)
\r
350 /* get boot drive off stack and place in DL */
\r
354 MOV DX, WORD PTR [BP+06h]
\r
360 /*********************************************************
\r
361 This reads and loads the two MMURTL segments into
\r
362 six 32K buffers. Two for the data segment, and 4 for
\r
363 the code segment. (192K Maximum).
\r
364 The MMURTL OS is built as a standard MMURRL run file.
\r
365 This is a tag/length/value file as described in the
\r
366 DASM documentation (in great detail).
\r
367 *********************************************************/
\r
369 void LoadRunFile(void)
\r
372 long i, dret, nobj, nread;
\r
373 char filetype, junk, *pin;
\r
377 /* fprintf(out_fh, "\r\nFile LFA: %ld\r\n", ftell(run_fh)); */
\r
378 nobj = fread (&tag, 1, 5, run_fh);
\r
382 fprintf(out_fh, "Tag Value (hex): %02X\r\n", ii);
\r
383 fprintf(out_fh, "Tag Length (dec): %ld\r\n", tag.len);
\r
387 fprintf(out_fh, "Invalid OS Run file. No End Tag Found.\r\n");
\r
394 nobj = fread (&filetype, 1, 1, run_fh);
\r
398 fprintf(out_fh, "File MUST be a run file\r\n");
\r
403 fprintf(out_fh, "Segment Sizes:\r\n");
\r
404 nobj = fread (&sStack, 1, 4, run_fh);
\r
405 if (nobj) nobj = fread (&sCode, 1, 4, run_fh);
\r
406 if (nobj) nobj = fread (&sData, 1, 4, run_fh);
\r
407 fprintf(out_fh, " Stack %ld\r\n", sStack);
\r
408 fprintf(out_fh, " Code %ld\r\n", sCode);
\r
409 fprintf(out_fh, " Data %ld\r\n", sData);
\r
412 nobj = fread (&offData, 1, 4, run_fh);
\r
413 fprintf(out_fh, "Virtual Data Offset: %08lXh\r\n", offData);
\r
416 nobj = fread (&offCode, 1, 4, run_fh);
\r
417 fprintf(out_fh, "Virtual Code Offset: %08lXh\r\n", offCode);
\r
420 nobj = fread (&pStart, 1, 4, run_fh);
\r
421 fprintf(out_fh, "Start Address: %08lXh\r\n", pStart);
\r
424 fprintf(out_fh, "Reading code: %ld bytes\r\n", tag.len);
\r
425 CSegSize = tag.len;
\r
427 if (tag.len >= 32768)
\r
432 pin = MK_FP(0x7000,0);
\r
433 nobj = fread (pin, 1, nread, run_fh);
\r
435 if (tag.len >= 32768)
\r
440 pin = MK_FP(0x7800,0);
\r
441 nobj = fread (pin, 1, nread, run_fh);
\r
443 if (tag.len >= 32768)
\r
448 pin = MK_FP(0x8000,0);
\r
449 nobj = fread (pin, 1, nread, run_fh);
\r
452 fprintf(out_fh, "Reading data: %ld bytes\r\n", tag.len);
\r
453 DSegSize = tag.len;
\r
454 if (tag.len >= 32768)
\r
459 pin = MK_FP(0x6000, 0);
\r
460 nobj = fread (pin, 1, nread, run_fh);
\r
462 if (tag.len >= 32768)
\r
467 pin = MK_FP(0x6800,0);
\r
468 nobj = fread (pin, 1, nread, run_fh);
\r
474 while ((tag.len) && (nobj)) {
\r
475 nobj = fread (&i, 1, 4, run_fh);
\r
480 nobj = fread (&i, 1, 4, run_fh); /* Eat the end tag */
\r
483 Relocate(); /* Move the loader code & data */
\r
484 SetBootDrive((unsigned int) bootdrive);
\r
488 while ((tag.len--) && (nobj))
\r
489 nobj = fread (&junk, 1, 1, run_fh);
\r
492 } /* end of switch */
\r
496 /***************************
\r
497 * Main program -- MMLoader
\r
498 ****************************/
\r
500 void main(S16 argc, S8 *argv[])
\r
509 for(i=1; i < argc; ++i) {
\r
525 printf("Invalid option/swtich \n");
\r
534 strncpy(osname, argv[i], 39);
\r
538 printf("MMURTL DOS Loader Ver 1.0 \r\n");
\r
540 printf("OS Filename specified: %s \r\n", osname);
\r
542 run_fh = fopen(osname, "rb");
\r
544 printf("Can't open: %s \r\n", osname);
\r
548 if (osname[1] == ':')
\r
550 bootdrive = osname[0] - 0x41;
\r
551 if (bootdrive >= 0x20)
\r
552 bootdrive -= 0x20; /* may be lower case */
\r
555 bootdrive = getdisk();
\r
557 ptest = malloc(100); /* 32K */
\r
558 printf("First MEM = SEG: %u OFF: %u\r\n", FP_SEG(ptest), FP_OFF(ptest));
\r
564 /*********************** End of Module *****************/
\r