]> pd.if.org Git - mmurtl/blob - ossource/monitor.c
autocommit for file dated 2003-12-29 17:36:54
[mmurtl] / ossource / monitor.c
1 /*\r
2   MMURTL Operating System Source Code\r
3   Copyright 1991,1992,1993,1994 Richard A. Burgess\r
4   ALL RIGHTS RESERVED\r
5   Version 1.0\r
6 */\r
7 \r
8 \r
9 /* This is the MMURTL Monitor program.\r
10    It provides the user with statistics and control of the\r
11    environment, and a few basic functions such as starting a CLI.\r
12 \r
13    The monitor has three main functions:\r
14    1) Sets up internal device drivers and services.\r
15    2) Checks config files and loads any system services specified\r
16       in the config file,\r
17    3) Loads a CLI and assigns the video and keyboard to it.\r
18 \r
19    Because the Monitor is part of the OS we do not declare a main\r
20    function.  The entry point to the monitor is called Monitor and\r
21    it has no parameters.  After the OS gets done with its low level\r
22    initialization, the monitor procedure is "Jumped" to.\r
23 \r
24 */\r
25 \r
26 #define U32 unsigned long\r
27 #define S32 long\r
28 #define U16 unsigned int\r
29 #define S16 int\r
30 #define U8 unsigned char\r
31 #define S8 char\r
32 \r
33 #include "MKernel.h"\r
34 #include "MMemory.h"\r
35 #include "MData.h"\r
36 #include "MTimer.h"\r
37 #include "MVid.h"\r
38 #include "MKbd.h"\r
39 #include "MJob.h"\r
40 #include "MFiles.h"\r
41 #include "MDevDrv.h"\r
42 \r
43 \r
44 #define ok 0\r
45 #define ErcNoDevice 504\r
46 \r
47 static char rgStatLine[] =\r
48 "mm/dd/yy  00:00:00              MMURTL Monitor                   Tick:0         ";\r
49 \r
50 static char rgMonMenu1[] = "LdCLI\xb3Jobs  \xb3Stats \xb3      ";\r
51 static char rgMonMenu2[] = "     \xb3      \xb3      \xb3Reboot";\r
52 static char rgMonMenu3[] = "     \xb3Debug \xb3      \xb3     ";\r
53 \r
54 static char rgCPR1[] ="MMURTL (tm) - Message based, MUltitasking, Real-Time kerneL";\r
55 static char rgCPR2[] ="Copyright (c) R.A. Burgess, 1990-1993, All Rights Reserved";\r
56 \r
57 static char *CRLF = "\r\n\r\n";\r
58 \r
59 static unsigned long Color = WHITE|BGBLACK;             /* Color test for xprintf */\r
60 \r
61 static long time, date, tick;\r
62 \r
63 unsigned long KillExch;         /* Messaging for stat task KILL proc */\r
64 \r
65 static unsigned long KillMsg[2];        /* First DWORD = TSSExch, second is ERROR */\r
66 static unsigned long KillError;\r
67 static unsigned long KillJobNum;\r
68 static unsigned char fKilled;\r
69 \r
70 static unsigned long MngrExch;          /* Messaging for stat task */\r
71 static unsigned long MngrMsg[2];\r
72 static unsigned long MngrHndl;\r
73 static unsigned long gcode;\r
74 \r
75 static unsigned long GPExch;            /* Messaging for main */\r
76 static unsigned long GPMsg[2];\r
77 static unsigned long GPHndl;\r
78 \r
79 static unsigned long GP1Exch;           /* Extra Messaging for main */\r
80 static unsigned long GP1Msg[2];\r
81 static unsigned long GP1Hndl;\r
82 \r
83 /* Structure for disk device driver status and setup */\r
84 \r
85 static struct diskstattype {\r
86   U32 erc;\r
87   U32 blocks_done;\r
88   U32 BlocksMax;\r
89   U8 fNewMedia;\r
90   U8 type_now;          /* current disk type for drive selected */\r
91   U8 resvd1[2];         /* padding for DWord align  */\r
92   U32 nCyl;                     /* total physical cylinders */\r
93   U32 nHead;            /* total heads on device    */\r
94   U32 nSectors;         /* Sectors per track        */\r
95   U32 nBPS;                     /* Number of bytes per sect */\r
96 \r
97   U32 LastRecalErc0;\r
98   U32 LastSeekErc0;\r
99   U8  LastStatByte0;\r
100   U8  LastErcByte0;\r
101   U8  fIntOnReset;      /* Interrupt was received on HDC_RESET */\r
102   U8  filler0;\r
103   U32 LastRecalErc1;\r
104   U32 LastSeekErc1;\r
105   U8  LastStatByte1;\r
106   U8  LastErcByte1;\r
107   U8  ResetStatByte;    /* Status Byte immediately after RESET */\r
108   U8  filler1;\r
109   U32 resvd1[2];        /* out to 64 bytes */\r
110   };\r
111 \r
112 static struct diskstattype DiskStatus;\r
113 \r
114 #define nMaxJCBs 34             /* 32 dynamic plus 2 static */\r
115 static struct JCBRec *pJCB;\r
116 \r
117 static long StatStack[256];     /* 1024 byte stack for Stat task */\r
118 \r
119 static long MngrStack[256];     /* 1024 byte stack for Mngr task */\r
120 \r
121 static unsigned char Buffer[512];\r
122 static unsigned long nMemPages;\r
123 \r
124 extern unsigned long oMemMax;\r
125 extern unsigned long nSwitches;\r
126 extern unsigned long nSlices;\r
127 extern unsigned long nHalts;\r
128 extern unsigned long nReady;\r
129 extern unsigned long nRQBLeft;\r
130 extern unsigned long nJCBLeft;\r
131 extern unsigned long nTSSLeft;\r
132 extern unsigned long nLBLeft;\r
133 extern unsigned long nEXCHLeft;\r
134 extern unsigned long BootDrive;\r
135 \r
136 /*============ protos (NEAR MMURTL support calls) =================*/\r
137 \r
138 extern long InitKBDService(void);       /* From Keyboard.asm */\r
139 extern long fdisk_setup(void);          /* From Floppy.c */\r
140 extern long hdisk_setup(void);          /* From HardIDE.c */\r
141 extern long coms_setup(void);           /* From RS232.c */\r
142 extern long lpt_setup(void);            /* From Parallel.c */\r
143 extern long InitFS(void);                       /* From Fsys.c */\r
144 \r
145 extern long GetExchOwner(long Exch, char *pJCBRet);\r
146 extern long DeAllocJCB(long *pdJobNumRet, char *ppJCBRet);\r
147 \r
148 /*=================== START OF CODE ====================*/\r
149 \r
150 /**************************************************************\r
151  Formatted output routines for montitor program\r
152  xprintf, xsprintf.\r
153 ***************************************************************/\r
154 \r
155 #include <stdarg.h>\r
156 \r
157 #define S_SIZE  100\r
158 \r
159 /*********************************************\r
160 * Determine if a character is a numeric digit\r
161 **********************************************/\r
162 \r
163 static long isdigit(long chr)\r
164 {\r
165 ;\r
166 #asm\r
167         MOV EAX,[EBP+8]\r
168         CMP AL, 30h             ;0\r
169         JL isdigit0             ;No\r
170         CMP AL, 39h             ;\r
171         JLE isdigit1    ;Yes\r
172 isdigit0:\r
173         XOR EAX,EAX             ;No\r
174         JMP SHORT isdigit2\r
175 isdigit1:\r
176         MOV EAX, -1\r
177 isdigit2:\r
178 \r
179 #endasm\r
180 }\r
181 \r
182 static long strlen(char *cs)\r
183 {\r
184 ;\r
185 #asm\r
186         XOR EAX, EAX\r
187         MOV ESI,[EBP+8]\r
188 _strlen0:\r
189         CMP BYTE PTR [ESI],0\r
190         JE _strlen1\r
191         INC ESI\r
192         INC EAX\r
193         JMP SHORT _strlen0\r
194 _strlen1:\r
195 #endasm\r
196 }\r
197 \r
198 /*************************************************************\r
199  This does the actual parsing of the format and also moves to\r
200  the next arg(s) in the list from the passed in arg pointer.\r
201  The number of chars written is returned (not incl \0).\r
202 **************************************************************/\r
203 static long _ffmt(char *outptr, char *fmt, long *argptr)\r
204 {\r
205 char numstk[33], *ptr, justify, zero, minus, chr;\r
206 unsigned long width, value, i, total;\r
207 \r
208         total = 0;\r
209         while(chr = *fmt++) \r
210         {\r
211                 if(chr == '%') \r
212                 {                                       /* format code */\r
213                         chr = *fmt++;\r
214             ptr = &numstk[32];\r
215                         *ptr = justify = minus = 0;\r
216                         width = value = i = 0;\r
217                         zero = ' ';\r
218                         if(chr == '-')\r
219                         {                               /* left justify */\r
220                                 --justify;\r
221                                 chr = *fmt++;\r
222                         }\r
223                         if(chr == '0')                                  /* leading zeros */\r
224                                 zero = '0';\r
225                         while(isdigit(chr))\r
226                         {                       /* field width specifier */\r
227                                 width = (width * 10) + (chr - '0');\r
228                                 chr = *fmt++;\r
229                         }\r
230 \r
231                         value = *--argptr;                              /* get parameter value */\r
232 \r
233                         switch(chr)\r
234                         {\r
235                                 case 'd' :                                      /* decimal number */\r
236                                         if(value & 0x80000000)\r
237                                         {\r
238                                                 value = -value;\r
239                                                 ++minus;\r
240                                         }\r
241                                 case 'u' :                                      /* unsigned number */\r
242                                         i = 10;\r
243                                         break;\r
244                                 case 'x' :                                      /* hexidecimal number */\r
245                                 case 'X' :\r
246                                         i = 16;\r
247                                         break;\r
248                                 case 'o' :                                      /* octal number */\r
249                                         i = 8;\r
250                                         break;\r
251                                 case 'b' :                                      /* binary number */\r
252                                         i = 2;\r
253                                         break;\r
254                                 case 'c' :                                      /* character data */\r
255                                         *--ptr = value;\r
256                                         break;\r
257                                 case 's' :                                      /* string */\r
258                                         ptr = value;                    /* value is ptr to string */\r
259                                         break;\r
260                                 default:                                        /* all others */\r
261                                         *--ptr = chr;\r
262                                         ++argptr;                               /* backup to last arg */\r
263                         }\r
264 \r
265                         if(i)           /* for all numbers, generate the ASCII string */\r
266                                 do \r
267                                 {\r
268                                         if((chr = (value % i) + '0') > '9')\r
269                                                 chr += 7;\r
270                                         *--ptr = chr; \r
271                                 }\r
272                                 while(value /= i);\r
273 \r
274                         /* output sign if any */\r
275 \r
276                         if(minus) \r
277                         {\r
278                                 *outptr++ = '-';\r
279                                 ++total;\r
280                                 if(width)\r
281                                         --width;\r
282                         }\r
283 \r
284                         /* pad with 'zero' value if right justify enabled  */\r
285 \r
286                         if(width && !justify) \r
287                         {\r
288                                 for(i = strlen(ptr); i < width; ++i)\r
289                                         *outptr++ = zero;\r
290                                         ++total;\r
291                         }\r
292 \r
293                         /* move in data */\r
294 \r
295                         i = 0;\r
296                         value = width - 1;\r
297 \r
298                         while((*ptr) && (i <= value)) \r
299                         {\r
300                                 *outptr++ = *ptr++;\r
301                                 ++total;\r
302                                 ++i;\r
303                         }\r
304 \r
305                         /* pad with 'zero' value if left justify enabled */\r
306 \r
307                         if(width && justify) \r
308                         {\r
309                                 while(i < width) \r
310                                 {\r
311                                         *outptr++ = zero;\r
312                                         ++total;\r
313                                         ++i;\r
314                                 }\r
315                         }\r
316                 }\r
317                 else \r
318                 {\r
319                         /* not format char, just move into string  */\r
320                         *outptr++ = chr;\r
321                         ++total;\r
322                 }\r
323         }\r
324 \r
325         *outptr = 0;\r
326         return total;\r
327 }\r
328 \r
329 /************************************\r
330     Formatted print to screen\r
331 *************************************/\r
332 \r
333 long xprintf(char *fmt, ...)\r
334 {\r
335         va_list ap;\r
336         long total;\r
337         char buffer[S_SIZE];\r
338 \r
339         va_start(ap, fmt);              /* set up ap pointer */\r
340         total = _ffmt(buffer, fmt, ap);\r
341         TTYOut(buffer, strlen(buffer), Color);\r
342         va_end(ap, fmt);\r
343         return total;\r
344 }\r
345 \r
346 /************************************\r
347     Formatted print to string s\r
348 *************************************/\r
349 \r
350 long xsprintf(char *s, char *fmt, ...)\r
351 {\r
352         va_list ap;\r
353         long total;\r
354 \r
355         va_start(ap, fmt);                      /* set up ap pointer */\r
356         total = _ffmt(s, fmt, ap);\r
357         va_end(ap, fmt);\r
358         return total;\r
359 }\r
360 \r
361 /**********************************************\r
362  Checks to ensure we don't scroll the function\r
363  keys off the screen.\r
364 **********************************************/\r
365 \r
366 void CheckScreen()\r
367 {\r
368 long iCol, iLine;\r
369 \r
370         GetXY(&iCol, &iLine);\r
371         if (iLine >= 23)\r
372         {\r
373                 ScrollVid(0,1,80,23,1);\r
374                 SetXY(0,22);\r
375         }\r
376 }\r
377 \r
378 /*********************************************************\r
379     This is called to initialize the sacreen.\r
380 *********************************************************/\r
381 \r
382 static void InitScreen(void)\r
383 {\r
384         ClrScr();\r
385     xsprintf(&rgStatLine[70], "%d", tick);\r
386     PutVidChars(0,0, rgStatLine, 80, WHITE|BGBLUE);\r
387         PutVidChars(0,  24, rgMonMenu1, 26, BLUE|BGWHITE);\r
388         PutVidChars(27, 24, rgMonMenu2, 26, BLUE|BGWHITE);\r
389         PutVidChars(54, 24, rgMonMenu3, 25, BLUE|BGWHITE);\r
390         SetXY(0,1);\r
391         return;\r
392 }\r
393 \r
394 /*********************************************************\r
395     This is the status task for the Monitor.\r
396     Besides displaying the top status line for\r
397     the montitor, it has the job of looking for\r
398     messages from the job code that indicate\r
399     a job has terminated. When it gets one,\r
400     it recovers the last of the resources and\r
401     then notifies the user on the screen.\r
402 *********************************************************/\r
403 \r
404 static void StatTask(void)\r
405 {\r
406 unsigned long erc, i, Exch, Msg[2];\r
407 U8 *pPD, *pVid;\r
408 \r
409 for(;;)\r
410 {\r
411         GetCMOSTime(&time);\r
412         rgStatLine[10] = '0' + ((time >> 20) & 0x0f);\r
413         rgStatLine[11] = '0' + ((time >> 16) & 0x0f);\r
414         rgStatLine[13] = '0' + ((time >> 12) & 0x0f);\r
415         rgStatLine[14] = '0' + ((time >> 8) & 0x0f);\r
416         rgStatLine[16] = '0' + ((time >> 4) & 0x0f);    /* seconds */\r
417         rgStatLine[17] = '0' + (time & 0x0f);\r
418 \r
419         GetCMOSDate(&date);\r
420         rgStatLine[0] = '0' + ((date >> 20) & 0x0f); /* month */\r
421         rgStatLine[1] = '0' + ((date >> 16) & 0x0f);\r
422         rgStatLine[3] = '0' + ((date >> 12) & 0x0f); /* Day */\r
423         rgStatLine[4] = '0' + ((date >> 8)  & 0x0f);\r
424         rgStatLine[6] = '0' + ((date >> 28) & 0x0f); /* year */\r
425         rgStatLine[7] = '0' + ((date >> 24) & 0x0f);\r
426 \r
427         GetTimerTick(&tick);\r
428         xsprintf(&rgStatLine[70], "%d", tick);\r
429         PutVidChars(0,0, rgStatLine, 80, WHITE|BGBLUE);\r
430 \r
431         Sleep(50);      /* sleep 0.5 second */\r
432 \r
433         GetTimerTick(&tick);\r
434         xsprintf(&rgStatLine[70], "%d", tick);\r
435         PutVidChars(0,0, rgStatLine, 80, WHITE|BGBLUE);\r
436 \r
437         Sleep(50);      /* sleep 0.5 second */\r
438 \r
439         /* Now we check for tasks that are Jobs that are killing\r
440         themselves (either due to fatal errors or no exitjob).\r
441         The message has Error, TSSExch in it.\r
442         */\r
443 \r
444         erc =  CheckMsg(KillExch, KillMsg);\r
445         if (!erc)\r
446         {        /* someones there wanting to terminate...*/\r
447 \r
448                 /* Get and save the error (KillMsg[0]) */\r
449                 KillError = KillMsg[0];\r
450 \r
451                 /* Call GetExchOwner which gives us pJCB */\r
452 \r
453                 erc = GetExchOwner(KillMsg[1], &pJCB);\r
454                 if (!erc)\r
455                 {\r
456 \r
457                         KillJobNum = pJCB->JobNum;\r
458                         Tone(440,50);\r
459                         xprintf("Job number %d terminated. Error: %d\r\n",\r
460                                         KillJobNum, KillError);\r
461                         CheckScreen();\r
462 \r
463                         pPD  = pJCB->pJcbPD;\r
464                         pVid = pJCB->pVirtVid;\r
465 \r
466                         /* Must change video to monitor if this guy owned it */\r
467 \r
468                         GetVidOwner(&i);\r
469                         if (i == KillJobNum)\r
470                         {\r
471                                 GetTSSExch(&Exch);      /* Use our TSS exchange for Request */\r
472                                 SetVidOwner(1);\r
473                                 erc = Request("KEYBOARD", 4, Exch, &i, 0,\r
474                                         0, 0,   0, 0,   1, 0, 0);\r
475                                 erc = WaitMsg(Exch, Msg);\r
476                         }\r
477 \r
478                         /* Now we deallocate the JCB and the TSSExch\r
479                         which will free the TSS automatically!\r
480                         */\r
481 \r
482                         DeAllocExch(KillMsg[1]);\r
483                         DeAllocJCB(pJCB);       /* No error returned */\r
484 \r
485                         /* When the JCB was created, the PD and it's 1st\r
486                         PDE (PT) were allocated as two pages next to each other\r
487                         in linear memory.  So we can just deallocate both\r
488                         pages in one shot. Then we deallocate the single\r
489                         page for virtual video.\r
490                         */\r
491 \r
492                         DeAllocPage(pPD, 2);\r
493                         DeAllocPage(pVid, 1);\r
494 \r
495                         fKilled = 1;\r
496                         /* We're done (and so is he...) */\r
497                 }\r
498         }\r
499 \r
500 } /* for EVER */\r
501 }\r
502 \r
503 /*********************************************************\r
504     This is the Manager task for the Monitor.\r
505     It allows us to switch jobs with the\r
506     CTRL-ALT-PageDown key.\r
507     We don't actually switch jobs, we just\r
508     ressign video and keyboard to the next\r
509     active job (except the Debugger).\r
510     Also, if the debugger has the video...\r
511     we don't do it at all!\r
512     This also looks for CTRL-ALT-DELETE which kills\r
513     the job that owns the keyboard/Video so long as it's\r
514     not the Monitor or the Debugger.\r
515 *********************************************************/\r
516 \r
517 static void MngrTask(void)\r
518 {\r
519 long erc, i, j, fDone;\r
520 char *pJCB;\r
521 \r
522 /* Leave a Global Key Request outstanding with KBD service\r
523    for the status task\r
524 */\r
525 \r
526 erc = Request("KEYBOARD", 2, MngrExch, &MngrHndl, 0, &gcode,\r
527                           4, 0, 0, 0, 0, 0);\r
528 \r
529 for(;;) \r
530 {\r
531         erc = WaitMsg(MngrExch, MngrMsg);\r
532 \r
533         if (!erc)\r
534         {\r
535                 if ((gcode & 0xff) == 0x0C)\r
536                 {\r
537                         /*  Find next valid Job that is NOT the\r
538                         debugger and assign Vid and Keyboard to\r
539                                 it.\r
540                         */\r
541 \r
542                         erc = GetVidOwner(&j);\r
543                         fDone = 0;\r
544                         i = j;\r
545                         while (!fDone)\r
546                         {\r
547                                 i++;\r
548                                 if (i==2) i = 3;\r
549                                 else if (i>34) i = 1;\r
550                                 erc = GetpJCB(i, &pJCB);                /* erc = 0 if valid JCB */\r
551                                 if ((!erc) || (i==j))\r
552                                         fDone = 1;\r
553                         }\r
554                         if (i != j)\r
555                         {\r
556                                 SetVidOwner(i);\r
557                                 erc = Request("KEYBOARD", 4, MngrExch, &MngrHndl, 0,\r
558                                         0, 0,   0, 0,   i, 0, 0);\r
559                                 erc = WaitMsg(MngrExch, MngrMsg);\r
560 \r
561                         }\r
562                 }\r
563                 else if ((gcode & 0xff) == 0x7F)        /* CTRL-ALT-DEL (Kill)*/\r
564                 {\r
565                         erc = GetVidOwner(&j);\r
566                         erc = KillJob(j);\r
567                 }\r
568 \r
569                 /* leave another global key request */\r
570                 erc = Request("KEYBOARD", 2, MngrExch, &MngrHndl, 0, &gcode,\r
571                                   4, 0, 0, 0, 0, 0);\r
572         }\r
573 \r
574 } /* for EVER */\r
575 }\r
576 \r
577 /*********************************************************\r
578   This simply does a software interrupt 03 (Debugger).\r
579 *********************************************************/\r
580 \r
581 static void GoDebug(void)\r
582 {\r
583 ;\r
584 #asm\r
585         INT 03\r
586 #endasm\r
587 return;\r
588 }\r
589 \r
590 /*********************************************************\r
591   This strobes keyboard data port 60h with 00 after\r
592   sending 0D1 command to Command port.  We have to loop\r
593   reading the status bit of the command port to make\r
594   sure it's OK to send the command. This resets the\r
595   processor which then executes the boot ROM.\r
596 *********************************************************/\r
597 \r
598 static void Reboot(void)\r
599 {\r
600 ;\r
601 #asm\r
602                 CLI                     ;first we clear interrupts\r
603                 MOV ECX, 0FFFFh         ;check port up to 64K times\r
604 Reboot0:\r
605                 IN AL,64h                       ;Read Status Byte into AL\r
606                 TEST AL,02h                             ;Test The Input Buffer Full Bit\r
607                 LOOPNZ Reboot0\r
608                 MOV AL,0FEh                             ;Strobe bit 0 of keyboard crtlr output\r
609                 OUT 64h,AL\r
610                 STI\r
611 #endasm\r
612 return;\r
613 }\r
614 \r
615 /*********************************************************\r
616   This reads a file called Initial.Job from the system\r
617   directory and loads all jobs specified in the file.\r
618   Video and keyboard are not assigned to any of these\r
619   jobs unless it is cli.run and the last job loaded.\r
620 *********************************************************/\r
621 \r
622 void LoadJobFile(void)\r
623 {\r
624 long erc, fh, sjobfile, cbrunfile, i, j, job;\r
625 unsigned char sdisk;\r
626 char ajobfile[50];\r
627 char arunfile[80];\r
628 char fdone, fcli;\r
629 \r
630         GetSystemDisk(&sdisk);\r
631         sdisk &= 0x7F;\r
632         sdisk += 0x41;          /* 0=A, 1=B, 2=C etc. */\r
633         ajobfile[0] = sdisk;\r
634         CopyData(":\\MMSYS\\INITIAL.JOB\0", &ajobfile[1], 20);\r
635         sjobfile = strlen(ajobfile);\r
636 \r
637         erc =  OpenFile(ajobfile, sjobfile, 0, 1, &fh);\r
638         if (!erc)\r
639         {\r
640                 fdone = 0;\r
641                 job = 0;\r
642                 fcli = 0;\r
643                 while (!fdone)\r
644                 {\r
645                         i = 0;\r
646                         do\r
647                         {\r
648                                 erc = ReadBytes(fh, &arunfile[i++], 1, &j);\r
649 \r
650                         } while ((!erc) && (arunfile[i-1] != 0x0A) && (i < 80));\r
651 \r
652                         if ((!erc) && (i > 1))\r
653                         {\r
654                                 if (arunfile[0] == ';')  /* a comment line */\r
655                                         continue;\r
656 \r
657                                 cbrunfile = 0;\r
658                                 while ((arunfile[cbrunfile] != 0x0A) &&\r
659                        (arunfile[cbrunfile] != 0x0D) &&\r
660                        (arunfile[cbrunfile] != 0x20) &&\r
661                        (arunfile[cbrunfile] != 0x09) &&\r
662                        (arunfile[cbrunfile]))\r
663                                         cbrunfile++;\r
664 \r
665                                 if (cbrunfile > 2)\r
666                                 {\r
667                                         arunfile[cbrunfile] = 0; /* null terminte for display */\r
668 \r
669                                         if ((cbrunfile > 8) &&\r
670                                                 (CompareNCS(&arunfile[cbrunfile-7],\r
671                                                                         "cli.run", 7) == -1))\r
672                                                 fcli = 1;\r
673                                         else\r
674                                                 fcli = 0;\r
675 \r
676                                         xprintf("Loading: %s...\r\n", arunfile);\r
677                                         CheckScreen();\r
678                                         erc =  LoadNewJob(arunfile, cbrunfile, &job);\r
679                                         if (!erc)\r
680                                         {\r
681                                                 xprintf("Successfully loaded as job %d\r\n", job);\r
682                                                 CheckScreen();\r
683                                                 Sleep(50);\r
684                                         }\r
685                                         else\r
686                                         {\r
687                                                 xprintf("ERROR %d Loading job\r\n", erc);\r
688                                                 CheckScreen();\r
689                                                 Sleep(50);\r
690                                                 job = 0;\r
691                                                 erc = 0;\r
692                                         }\r
693                                 }\r
694                         }\r
695                         else fdone = 1;\r
696                 }\r
697                 CloseFile(fh);\r
698 \r
699                 /* if the last succesfully loaded job was a cli,\r
700                    assign the keybaord and video to it.\r
701                 */\r
702 \r
703                 if ((job > 2) && (fcli))\r
704                 {\r
705                         SetVidOwner(job);\r
706                         erc = Request("KEYBOARD", 4, GP1Exch, &GP1Hndl, 0,\r
707                                 0, 0,   0, 0,   job, 0, 0);\r
708                         if (!erc)\r
709                                 erc = WaitMsg(GP1Exch, GP1Msg);\r
710                 }\r
711         }\r
712         else\r
713         {\r
714                 xprintf("INITIAL.JOB file not found in system directory.\r\n");\r
715                 CheckScreen();\r
716         }\r
717 }\r
718 \r
719 \r
720 /*********************************************************\r
721   This Loads the MMURTL Command Line Interpreter\r
722   and switches video and keyboard to give the\r
723   user access to it.\r
724 *********************************************************/\r
725 \r
726 static long LoadCLI(void)\r
727 {\r
728 long erc, job;\r
729 unsigned char sdisk, acli[40];\r
730 \r
731         GetSystemDisk(&sdisk);\r
732         sdisk &= 0x7F;\r
733         sdisk += 0x41;          /* 0=A, 1=B, 2=C etc. */\r
734         acli[0] = sdisk;\r
735         CopyData(":\\MMSYS\\CLI.RUN\0", &acli[1], 16);\r
736         xprintf("Loading: %s...", acli);\r
737 \r
738         erc =  LoadNewJob(acli, strlen(acli), &job);\r
739         if (!erc)\r
740         {\r
741                 xprintf("New CLI Job Number is: %d\r\n", job);\r
742                 CheckScreen();\r
743                 Sleep(50);\r
744                 SetVidOwner(job);\r
745                 erc = Request("KEYBOARD", 4, GP1Exch, &GP1Hndl, 0,\r
746                         0, 0,   0, 0,   job, 0, 0);\r
747                 if (!erc)\r
748                         erc = WaitMsg(GP1Exch, GP1Msg);\r
749         }\r
750 return erc;\r
751 }\r
752 \r
753 /*********************************************************\r
754     This is the main procedure called from the OS after\r
755     all OS structures and memory are initialized.\r
756 *********************************************************/\r
757 \r
758 void Monitor(void)\r
759 {\r
760 long erc, i, j, k, iCol, iLine;\r
761 unsigned long ccode, ccode1;\r
762 unsigned char c;\r
763 char text[70];\r
764 \r
765 InitScreen();\r
766 \r
767 Tone(250,15);           /* 250 Hz for 150ms */\r
768 Tone(1000,33);          /* 250 Hz for 330ms */\r
769 \r
770 /* Allocate an exchange for the Manager task global keycode */\r
771 \r
772 erc = AllocExch(&MngrExch);\r
773 if (erc)\r
774   xprintf("AllocExch (Mngr Exch) Error: %d\r\n", erc);\r
775 \r
776 erc = SpawnTask( &StatTask, 24, 0, &StatStack[255], 1 );        /* Task 4 */\r
777 if (erc)\r
778   xprintf("SpawnTask (StatTask) Error: %d\r\n", erc);\r
779 \r
780 erc = AllocExch(&KillExch);\r
781 if (erc)\r
782   xprintf("AllocExch (Kill Exch) Error: %d\r\n", erc);\r
783 \r
784 Color = YELLOW|BGBLACK;\r
785 xprintf("MMURTL (tm) - Message based, MUltitasking, Real-Time kerneL\r\n");\r
786 xprintf("Copyright (c) R.A.Burgess, 1991-1995  ALL RIGHTS RESERVED\r\n\r\n");\r
787 \r
788 Color = WHITE|BGBLACK;\r
789 \r
790 c = ((BootDrive & 0x7f) + 0x41);\r
791 xprintf("BootDrive: %c\r\n", c);\r
792 \r
793 i = (oMemMax+1)/1024;\r
794 xprintf("Total memory (Kb): %d\r\n", i);\r
795 \r
796 erc = QueryPages(&nMemPages);\r
797 i = (nMemPages*4096)/1024;\r
798 xprintf("Free memory  (Kb): %d\r\n", i);\r
799 \r
800 erc = InitKBDService();\r
801 xprintf("Init KBD Service Error: %d\r\n", erc);\r
802 \r
803 erc = coms_setup();\r
804 xprintf("Init Serial Comms Device Driver Error: %d\r\n", erc);\r
805 \r
806 erc = lpt_setup();\r
807 xprintf("Init Parallel LPT Device Driver Error: %d\r\n", erc);\r
808 \r
809 /* Allocate general purpose exchanges to use in the monitor */\r
810 \r
811 erc = AllocExch(&GPExch);\r
812 if (erc)\r
813   xprintf("AllocExch Error: %d\r\n", erc);\r
814 \r
815 erc = AllocExch(&GP1Exch);\r
816 if (erc)\r
817   xprintf("AllocExch GP1 Error: %d\r\n", erc);\r
818 \r
819 xprintf("Init floppy device driver... Error: ");\r
820 erc = fdisk_setup();\r
821 xprintf("%d\r\n", erc);\r
822 \r
823 xprintf("Init hard disk device driver... Error: ");\r
824 erc = hdisk_setup();\r
825 xprintf("%d\r\n", erc);\r
826 \r
827 xprintf("Initializing file system...\r\n");\r
828 erc = InitFS();\r
829 xprintf("File System... Error: %d\r\n", erc);\r
830 \r
831 /* Spawn manager task */\r
832 \r
833 SpawnTask( &MngrTask, 10, 0, &MngrStack[255], 1 );\r
834 \r
835 /*\r
836    Call LoadJobFile to read job file from system directory \r
837    and execute and jobs listed there.\r
838 */\r
839 \r
840 LoadJobFile();\r
841 \r
842 for (;;)  /* Loop forEVER looking for user desires */\r
843 {\r
844 \r
845         /* Make a ReadKbd Key Request with KBD service. Tell it\r
846         to wait for a key.\r
847         */\r
848 \r
849         erc = Request("KEYBOARD", 1, GPExch, &GPHndl, 0, &ccode,\r
850                                           4, 0, 0, 1, 0, 0);\r
851         if (erc)\r
852             xprintf("Kbd Svc Request KERNEL ERROR: %d\r\n", erc);\r
853 \r
854         /* wait for the keycode to come back */\r
855 \r
856         erc = WaitMsg(GPExch, GPMsg);\r
857         if (erc)\r
858          xprintf("KERNEL Error from Wait msg:  %d\r\n", erc);\r
859 \r
860         c = ccode & 0xff; /* lop off everything but the key value */\r
861 \r
862         switch (c)\r
863         {\r
864         case 0x0F:              /* F1 Run */\r
865                         erc = LoadCLI();\r
866                         if (erc)\r
867                                 xprintf("Error from LoadCLI:  %d\r\n", erc);\r
868                         break;\r
869         case 0x10:              /* F2 Jobs */\r
870                         InitScreen();\r
871                         j = 2; /* Line */\r
872                         k = 0; /* Col offset */\r
873                         for     (i=1; i<nMaxJCBs; i++)\r
874                         {\r
875                                 if (j > 20)\r
876                                         k = 40;\r
877                                 erc = GetpJCB(i, &pJCB);                /* erc = 0 if valid JCB */\r
878                                 if (!erc)\r
879                                 {\r
880                                         SetXY(k,j);\r
881                                         xprintf("Job: %d\r\n", pJCB->JobNum);\r
882                                         SetXY(k+10,j);\r
883                                         CopyData(&pJCB->sbJobName[1], text, 13);\r
884                                         text[pJCB->sbJobName[0]] = 0;\r
885                                         xprintf("Name: %s\r\n", text);\r
886                                         j++;\r
887                                 }\r
888                         }\r
889                         break;\r
890         case 0x11:              /* F3 Stats - loops displaying status till key is hit */\r
891                         InitScreen();\r
892                         while (erc = ReadKbd(&ccode1, 0))\r
893                         { /* ReadKbd no wait until no error */\r
894                                 SetXY(0,1);\r
895                                 erc = QueryPages(&nMemPages);\r
896                 xprintf("Any key to dismiss status... \r\n");\r
897                 xprintf("Free 4K memory pages:      %d\r\n", nMemPages);\r
898                 xprintf("Task switches total:       %d\r\n", nSwitches);\r
899                 xprintf("Preemptive task switches:  %d\r\n", nSlices);\r
900                 xprintf("CPU idle ticks (no work):  %d\r\n", nHalts);\r
901                 xprintf("Tasks Ready to Run:        %d\r\n", nReady);\r
902                 xprintf("Free Task State Segments:  %d\r\n", nTSSLeft);\r
903                 xprintf("Free Job Control Blocks:   %d\r\n", nJCBLeft);\r
904                 xprintf("Free Request Blocks:       %d\r\n", nRQBLeft);\r
905                 xprintf("Free Link Blocks:          %d\r\n", nLBLeft);\r
906                 xprintf("Free Exchanges:            %d\r\n", nEXCHLeft);\r
907                                 SetXY(0,1);\r
908                                 PutVidChars(29, 1, "|",  1, GREEN|BGBLACK); Sleep(9);\r
909                                 PutVidChars(29, 1, "/",  1, GREEN|BGBLACK); Sleep(9);\r
910                                 PutVidChars(29, 1, "-",  1, GREEN|BGBLACK); Sleep(12);\r
911                                 PutVidChars(29, 1, "\\", 1, GREEN|BGBLACK); Sleep(9);\r
912                                 PutVidChars(29, 1, "|",  1, GREEN|BGBLACK); Sleep(9);\r
913                                 PutVidChars(29, 1, "/",  1, GREEN|BGBLACK); Sleep(9);\r
914                                 PutVidChars(29, 1, "-",  1, GREEN|BGBLACK); Sleep(12);\r
915                                 PutVidChars(29, 1, "\\", 1, GREEN|BGBLACK); Sleep(9);\r
916                                 PutVidChars(29, 1, " ",  1, GREEN|BGBLACK);\r
917                         }\r
918                         SetXY(0,12);\r
919             xprintf ("\r\n");\r
920                         break;\r
921         case 0x16:              /* F8 Reboot */\r
922                         xprintf("\r\nF8 again to reboot, any other key to cancel");\r
923                         erc = ReadKbd(&ccode1, 1);\r
924                         if ((ccode1 & 0xff) == 0x16)\r
925                                 Reboot();\r
926                         xprintf("...Cancelled\r\n");\r
927                         break;\r
928         case 0x18:              /* F10 Debug */\r
929                         GoDebug();\r
930                         break;\r
931         case 0x00:              /* No Key */\r
932                         Sleep(3);       /* Sleep for 30 ms */\r
933                         break;\r
934         case 0x12:              /* F4 - future use */\r
935         case 0x13:              /* F5  */\r
936         case 0x14:              /* F6  */\r
937         case 0x15:              /* F7  */\r
938         case 0x17:              /* F9  */\r
939         case 0x19:              /* F11 */\r
940         case 0x1A:              /* F12 */\r
941                         break;\r
942         default:\r
943                 if (((c > 0x1F) && (c < 0x80)) ||\r
944                         (c==0x0D) || (c==8))\r
945                         {\r
946                                 if (c==0x0D)\r
947                                         TTYOut (CRLF, 2, WHITE|BGBLACK);\r
948                                 else\r
949                                         TTYOut (&c, 1, WHITE|BGBLACK);\r
950                    }\r
951         }\r
952 \r
953         GetXY(&iCol, &iLine);\r
954         if (iLine >= 23)\r
955         {\r
956                 ScrollVid(0,1,80,23,1);\r
957                 SetXY(0,22);\r
958         }\r
959 \r
960 } /* for EVER */\r
961 \r
962 }\r
963 \r
964 \r
965 /*===========  THE END  =========================================*/\r