]> pd.if.org Git - mmurtl/blob - mscode16/mmloader/mmloader.c
autocommit for file dated 1995-01-02 17:14:34
[mmurtl] / mscode16 / mmloader / mmloader.c
1 /* MMLoader.c\r
2    This is the DOS loader for the MMURTL OS RUN file.\r
3 \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
17 \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
21 \r
22         You MUST use the -B and -ml options. Example\r
23 \r
24                 BCC -B -ml MMLoader.c\r
25 \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
33    to handle it).\r
34 \r
35    What actually happens here:\r
36         (This basically turns MS-DOS into a $79.00 loader)\r
37 \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
41         3) Clear interrupts\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
50 \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
53 \r
54 */\r
55 \r
56 \r
57 \r
58 #define U32 unsigned long\r
59 #define S32 long\r
60 #define U16 unsigned int\r
61 #define S16 int\r
62 #define U8 unsigned char\r
63 #define S8 char\r
64 \r
65 #define TRUE 1\r
66 #define FALSE 1\r
67 \r
68 #include <ctype.h>\r
69 #include <stdio.h>\r
70 #include <string.h>\r
71 #include <stdlib.h>\r
72 #include <dos.h>\r
73 #include <dir.h>\r
74 #include "\OSSOURCE\runfile.h"\r
75 \r
76 U32 fEOF = 0;\r
77 \r
78 long CSegSize = 0;\r
79 long DSegSize = 0;\r
80 \r
81 char *ptest;\r
82 \r
83 long    sStack = 0;\r
84 long    sCode = 0;\r
85 long    sData = 0;\r
86 \r
87 long    offCode = 0;\r
88 long    offData = 0;\r
89 long    pStart = 0;\r
90 \r
91 struct tagtype tag;\r
92 \r
93 char osname[50] = {"MMURTL.RUN"};       /* default OS name */\r
94 \r
95 FILE *run_fh = 0;\r
96 FILE *out_fh = 0;\r
97 \r
98 unsigned char bootdrive;\r
99 \r
100 /**** Execute ************************************************\r
101    At this point:\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
111 \r
112 void Execute(void)\r
113 {\r
114 \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
120 */\r
121 \r
122 asm {   .386P\r
123                 CLI\r
124                 NOP\r
125 \r
126                 MOV BX, 9800h\r
127                 MOV DS, BX\r
128                 MOV BX, 0\r
129                 MOV WORD PTR DS:[BX], 07FFh\r
130                 MOV BX, 2\r
131                 MOV WORD PTR DS:[BX], 0h\r
132                 MOV BX, 4\r
133                 MOV WORD PTR DS:[BX], 0h\r
134 \r
135                 MOV BX, 6\r
136                 MOV WORD PTR DS:[BX], 017FFh\r
137                 MOV BX, 8\r
138                 MOV WORD PTR DS:[BX], 0800h\r
139                 MOV BX, 10\r
140                 MOV WORD PTR DS:[BX], 0h\r
141 \r
142 \r
143                 MOV BX, 0B800h\r
144                 MOV ES, BX\r
145                 MOV BX, 0\r
146                 MOV WORD PTR ES:[BX], 4731h\r
147 \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
150 \r
151 \r
152                 /* Move first 32K data chunk */\r
153 \r
154                 MOV BX, 06000h\r
155                 MOV DS, BX\r
156                 XOR SI, SI\r
157                 MOV AX,0000h\r
158                 MOV ES,AX\r
159                 XOR DI,DI\r
160                 MOV CX,8000h\r
161                 CLD                     ;\r
162                 REP MOVSB                               ;\r
163 \r
164                 /* Move second 32K data chunk */\r
165 \r
166                 MOV BX, 06800h\r
167                 MOV DS, BX\r
168                 XOR SI, SI\r
169                 MOV AX,0800h\r
170                 MOV ES,AX\r
171                 XOR DI,DI\r
172                 MOV CX,8000h\r
173                 CLD                     ;\r
174                 REP MOVSB                               ;\r
175 \r
176                 /* Move first 32K code chunk */\r
177 \r
178                 MOV BX, 07000h\r
179                 MOV DS, BX\r
180                 XOR SI, SI\r
181                 MOV AX,1000h\r
182                 MOV ES,AX\r
183                 XOR DI,DI\r
184                 MOV CX,8000h\r
185                 CLD                     ;\r
186                 REP MOVSB                               ;\r
187 \r
188                 /* Move second 32K code chunk */\r
189 \r
190                 MOV BX, 07800h\r
191                 MOV DS, BX\r
192                 XOR SI, SI\r
193                 MOV AX,1800h\r
194                 MOV ES,AX\r
195                 XOR DI,DI\r
196                 MOV CX,8000h\r
197                 CLD                     ;\r
198                 REP MOVSB                               ;\r
199 \r
200                 /* Move third 32K code chunk */\r
201 \r
202                 MOV BX, 08000h\r
203                 MOV DS, BX\r
204                 XOR SI, SI\r
205                 MOV AX,2000h\r
206                 MOV ES,AX\r
207                 XOR DI,DI\r
208                 MOV CX,8000h\r
209                 CLD                     ;\r
210                 REP MOVSB                               ;\r
211 \r
212 \r
213                 MOV BX, 0B800h\r
214                 MOV ES, BX\r
215                 MOV BX, 2\r
216                 MOV WORD PTR ES:[BX], 4732h\r
217 \r
218                 MOV BX, 9800h\r
219                 MOV DS, BX\r
220                 MOV BX, 0\r
221 \r
222                 LIDT FWORD PTR DS:[BX+0]\r
223                 LGDT FWORD PTR DS:[BX+6]\r
224                 MOV EAX,CR0\r
225                 OR AL,1\r
226                 MOV CR0,EAX\r
227                 JMP $+4\r
228                 NOP\r
229                 NOP\r
230                 NOP\r
231                 NOP\r
232 \r
233         MOV BX, 10h\r
234                 MOV DS,BX\r
235                 MOV ES,BX\r
236                 MOV FS,BX\r
237                 MOV GS,BX\r
238                 MOV SS,BX\r
239                 DB 66h\r
240                 DB 67h\r
241                 DB 0EAh\r
242                 DD 10000h\r
243                 DW 8h\r
244                 RETN\r
245 } /* end of assembler */\r
246 \r
247 }\r
248 \r
249 \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
256 \r
257 void TurnOnA20(void)\r
258 {\r
259 \r
260 asm {\r
261                 CLI\r
262                 XOR CX,CX\r
263         }\r
264 \r
265 IBEmm0:\r
266 \r
267 asm {\r
268                 IN AL,64h\r
269                 TEST AL,02h\r
270                 LOOPNZ IBEmm0\r
271                 MOV AL,0D1h\r
272                 OUT 64h,AL\r
273                 XOR CX,CX\r
274         }\r
275 \r
276 IBEmm1:\r
277 \r
278 asm {\r
279                 IN AL,64h\r
280                 TEST AL,02h\r
281                 LOOPNZ IBEmm1\r
282                 MOV AL,0DFh\r
283                 OUT 60h,AL\r
284                 XOR CX,CX\r
285         }\r
286 \r
287 IBEmm2:\r
288 \r
289 asm {\r
290                 IN AL,64h\r
291                 TEST AL,02h\r
292                 LOOPNZ IBEmm2\r
293         }\r
294 }\r
295 \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
304 \r
305 void Relocate(void)\r
306 {\r
307 char *pdest, *psource, **pnewp;\r
308 long *pnewl;\r
309 unsigned int *pneww;\r
310 int  i;\r
311 \r
312 /* First we move the code up */\r
313 \r
314         psource = (void*) &Execute;\r
315 \r
316         printf("SEG: %u OFF: %u\r\n", FP_SEG(psource), FP_OFF(psource));\r
317 \r
318         pdest = MK_FP(0x9000,0);\r
319         i = 2000;       /* more than enough for the code */\r
320         while(i--)\r
321                 *pdest++ = *psource++;\r
322 \r
323 }\r
324 \r
325 \r
326 void CallExecute(void)\r
327 \r
328 {\r
329 /* We push the new code address on the stack then RETF to it.\r
330    We PUSH CS then IP */\r
331 \r
332 asm {\r
333         MOV AX, 09000h\r
334         PUSH AX\r
335         MOV AX, 0\r
336         PUSH AX\r
337         RETF\r
338 }\r
339 \r
340 }\r
341 \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
345 */\r
346 \r
347 void SetBootDrive(unsigned int bootdrive)\r
348 \r
349 {\r
350 /* get boot drive off stack and place in DL */\r
351 \r
352 asm {\r
353         XOR EDX, EDX\r
354         MOV DX, WORD PTR [BP+06h]\r
355 }\r
356 \r
357 }\r
358 \r
359 \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
368 \r
369 void LoadRunFile(void)\r
370 {\r
371 int ii;\r
372 long i, dret, nobj, nread;\r
373 char filetype, junk, *pin;\r
374 \r
375         while (1) {\r
376                 tag.id = 0;\r
377 /*              fprintf(out_fh, "\r\nFile LFA: %ld\r\n", ftell(run_fh)); */\r
378                 nobj = fread (&tag, 1, 5, run_fh);\r
379                 if (nobj) {\r
380 /*\r
381                         ii = tag.id;\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
384 */\r
385                 }\r
386                 else {\r
387                         fprintf(out_fh, "Invalid OS Run file. No End Tag Found.\r\n");\r
388                         fclose(run_fh);\r
389                         exit(1);\r
390                 }\r
391 \r
392                 switch (tag.id) {\r
393                         case IDTAG:\r
394                                 nobj = fread (&filetype, 1, 1, run_fh);\r
395                                 if (filetype == 1)\r
396                                         break;\r
397                                 else {\r
398                                         fprintf(out_fh, "File MUST be a run file\r\n");\r
399                                         exit(1);\r
400                                 }\r
401                                 break;\r
402                         case SEGTAG:\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
410                                 break;\r
411                         case DOFFTAG:\r
412                                 nobj = fread (&offData, 1, 4, run_fh);\r
413                                 fprintf(out_fh, "Virtual Data Offset: %08lXh\r\n", offData);\r
414                                 break;\r
415                         case COFFTAG:\r
416                                 nobj = fread (&offCode, 1, 4, run_fh);\r
417                                 fprintf(out_fh, "Virtual Code Offset: %08lXh\r\n", offCode);\r
418                                 break;\r
419                         case STRTTAG:\r
420                                 nobj = fread (&pStart, 1, 4, run_fh);\r
421                                 fprintf(out_fh, "Start Address: %08lXh\r\n", pStart);\r
422                                 break;\r
423                         case CODETAG:\r
424                                 fprintf(out_fh, "Reading code:  %ld bytes\r\n", tag.len);\r
425                 CSegSize = tag.len;\r
426 \r
427                                 if (tag.len >= 32768)\r
428                                         nread = 32768;\r
429                                 else\r
430                                         nread = tag.len;\r
431                                 tag.len -= nread;\r
432                                 pin = MK_FP(0x7000,0);\r
433                                 nobj = fread (pin, 1, nread, run_fh);\r
434 \r
435                                 if (tag.len >= 32768)\r
436                                         nread = 32768;\r
437                                 else\r
438                                         nread = tag.len;\r
439                                 tag.len -= nread;\r
440                                 pin = MK_FP(0x7800,0);\r
441                                 nobj = fread (pin, 1, nread, run_fh);\r
442 \r
443                                 if (tag.len >= 32768)\r
444                                         nread = 32768;\r
445                                 else\r
446                                         nread = tag.len;\r
447                                 tag.len -= nread;\r
448                                 pin = MK_FP(0x8000,0);\r
449                                 nobj = fread (pin, 1, nread, run_fh);\r
450                                 break;\r
451                         case DATATAG:\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
455                                         nread = 32768;\r
456                                 else\r
457                                         nread = tag.len;\r
458                                 tag.len -= nread;\r
459                                 pin = MK_FP(0x6000, 0);\r
460                                 nobj = fread (pin, 1, nread, run_fh);\r
461 \r
462                                 if (tag.len >= 32768)\r
463                                         nread = 32768;\r
464                                 else\r
465                                         nread = tag.len;\r
466                                 tag.len -= nread;\r
467                                 pin = MK_FP(0x6800,0);\r
468                                 nobj = fread (pin, 1, nread, run_fh);\r
469                                 break;\r
470                         case CDFIXTAG:\r
471                         case CCFIXTAG:\r
472                         case DDFIXTAG:\r
473                         case DCFIXTAG:\r
474                                 while ((tag.len) && (nobj)) {\r
475                                         nobj = fread (&i, 1, 4, run_fh);\r
476                                         tag.len-=4;\r
477                                 }\r
478                                 break;\r
479                         case ENDTAG:\r
480                                 nobj = fread (&i, 1, 4, run_fh);        /* Eat the end tag */\r
481                                 fclose(run_fh);\r
482                 TurnOnA20();\r
483                                 Relocate();                     /* Move the loader code & data */\r
484                                 SetBootDrive((unsigned int) bootdrive);\r
485                                 CallExecute();\r
486                                 break;\r
487                         default:\r
488                                 while ((tag.len--) && (nobj))\r
489                                         nobj = fread (&junk, 1, 1, run_fh);\r
490                                 break;\r
491 \r
492                 } /* end of switch */\r
493         }\r
494 }\r
495 \r
496 /***************************\r
497 * Main program -- MMLoader\r
498 ****************************/\r
499 \r
500 void main(S16 argc, S8   *argv[])\r
501 {\r
502 S8   *ptr;\r
503 S16  i;\r
504 char fName;\r
505 \r
506         out_fh = stdout;\r
507         fName = 0;\r
508 \r
509         for(i=1; i < argc; ++i) {\r
510                 ptr = argv[i];\r
511                 if (*ptr == '/') {\r
512                   ptr++;\r
513                   switch(*ptr) {\r
514                         case 'U' :\r
515                         case 'u' :\r
516                                 break;\r
517                         case 'D' :\r
518                         case 'd' :\r
519                                 break;\r
520                         case 'O' :\r
521                         case 'o' :\r
522                                 fName = 1;\r
523                                 break;\r
524                         default:\r
525                                 printf("Invalid option/swtich \n");\r
526                                 if (run_fh)\r
527                                         fclose(run_fh);\r
528                                 exit(1);\r
529                                 break;\r
530                   }\r
531                 }\r
532                 else {\r
533                         if (fName)\r
534                                 strncpy(osname, argv[i], 39);\r
535                 }\r
536         }\r
537 \r
538         printf("MMURTL DOS Loader Ver 1.0 \r\n");\r
539 \r
540         printf("OS Filename specified: %s \r\n",  osname);\r
541 \r
542         run_fh = fopen(osname, "rb");\r
543         if (!run_fh) {\r
544                 printf("Can't open: %s \r\n",  osname);\r
545                 exit(1);\r
546         }\r
547 \r
548         if (osname[1] == ':')\r
549         {\r
550                 bootdrive = osname[0] - 0x41;\r
551                 if (bootdrive >= 0x20)\r
552                         bootdrive -= 0x20;      /* may be lower case */\r
553         }\r
554         else\r
555            bootdrive = getdisk();\r
556 \r
557         ptest = malloc(100);    /*  32K */\r
558         printf("First MEM = SEG: %u OFF: %u\r\n", FP_SEG(ptest), FP_OFF(ptest));\r
559 \r
560         LoadRunFile();\r
561 \r
562 }\r
563 \r
564 /*********************** End of Module *****************/\r