home *** CD-ROM | disk | FTP | other *** search
/ GEMini Atari / GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso / files / mint / mint095s / main.c < prev    next >
C/C++ Source or Header  |  1993-08-03  |  29KB  |  1,154 lines

  1. /*
  2. Copyright 1990,1991,1992 Eric R. Smith. All rights reserved.
  3. */
  4.  
  5. #include "mint.h"
  6. #include "version.h"
  7. #include "cookie.h"
  8. #include "xbra.h"
  9.  
  10. /* the kernel's stack size */
  11. #define STACK    8*1024L
  12.  
  13. /* if the user is holding down the magic shift key, we ask before booting */
  14. #define MAGIC_SHIFT 0x1        /* right shift */
  15.  
  16. static void xbra_install P_((xbra_vec *, long, void (*)()));
  17. static void init_intr P_((void));
  18. static void getmch P_((void));
  19. static void do_line P_((char *));
  20. static void shutmedown P_((PROC *));
  21. void shutdown P_((void));
  22. static void doset P_((char *,char *));
  23. static long mint_criticerr P_((long));
  24.  
  25. static int gem_active;    /* 0 if AES has started, 1 otherwise */
  26.  
  27. static int  check_for_gem P_((void));
  28. static void run_auto_prgs P_((void));
  29.  
  30. #ifdef LATTICE
  31. /*
  32.  * AGK: this is witchcraft to completely replace the startup code for
  33.  * Lattice; doing so saves around 10K on the final binary and pulls only
  34.  * long division & multitplication from the library (and not even those
  35.  * if you compile for native '030). The drawback of this code is it
  36.  * passes no environment or command line whatsoever. Since I always
  37.  * set MiNT options & environment in 'mint.cnf' this is not a personal
  38.  * downer, however at some point in the future we ought to have a kernel
  39.  * parseargs() like call which sets these things up.
  40.  */ 
  41. BASEPAGE *_base;
  42.  
  43. static void
  44. start(BASEPAGE *bp)
  45. {
  46.     long shrinklen;
  47.     
  48.     _base = bp;
  49.     shrinklen = bp->p_tlen + bp->p_dlen + bp->p_blen + STACK + 0x100;
  50.     if (bp->p_lowtpa + shrinklen <= bp->p_hitpa) {
  51.         static char null[1] = {""};
  52.         static char *argv[2] = {null, NULL};
  53.         extern __builtin_putreg P_((int, long));    /* totally bogus */
  54.  
  55.         __builtin_putreg(15, bp->p_lowtpa + shrinklen);
  56.         Mshrink((void *)bp->p_lowtpa, shrinklen);
  57.         main(1, argv, argv);
  58.     }
  59.     Pterm(ENSMEM);
  60. }
  61. #endif
  62.  
  63. #ifdef __GNUC__
  64. long _stksize = STACK;
  65. #include <minimal.h>
  66. #endif
  67.  
  68. int curs_off = 0;    /* set if we should turn the cursor off when exiting */
  69. int mint_errno = 0;    /* error return from open and creat filesystem calls */
  70.  
  71. /*
  72.  * AGK: for proper co-processors we must consider saving their context.
  73.  * This variable when non-zero indicates that the BIOS considers a true
  74.  * coprocessor to be present. We use this variable in the context switch
  75.  * code to decide whether to attempt an FPU context save.
  76.  */
  77. short fpu = 0;
  78.  
  79. /*
  80.  * "mch" holds what kind of machine we are running on
  81.  */
  82. long mch = 0;
  83.  
  84. /*
  85.  * variable holds processor type
  86.  */
  87. long mcpu = 0;
  88.  
  89. /*
  90.  * variable set to 1 iff on a 68010 (used by the context switch code)
  91.  * this is redundant with mcpu, but is kept for reasons of speed
  92.  */
  93. short m68010 = 0;
  94.  
  95. /*
  96.  * variable set if someone has already installed an flk cookie
  97.  */
  98. int flk = 0;
  99.  
  100. /* program to run at startup */
  101. char orig_init[] = "init.prg";
  102. char *init_prg = orig_init;
  103. char init_tail[128];
  104.  
  105. /* initial environment for that program */
  106. char *init_env = 0;
  107. /* temporary pointer into that environment for setenv */
  108. char *env_ptr;
  109. /* length of the environment */
  110. long env_len;
  111.  
  112. /* flag that's set if we want pseudo-drives to have BIOS entries:
  113.  * 0 means no BIOS interaction with pseudo-drives at all
  114.  * 1 means the drives show up in _drvbits and Drvmap()
  115.  * 2 means the above + fake handlers for Rwabs, Mediach, etc.
  116.  */
  117.  
  118. int pseudodrives = 2;
  119.  
  120. /* GEMDOS pointer to current basepage */
  121. BASEPAGE **tosbp;
  122.  
  123. /* pointer to the BIOS keyboard shift variable */
  124. extern char *kbshft;    /* see bios.c */
  125.  
  126. /* version of TOS we're running over */
  127. int tosvers;
  128.  
  129. /* structures for keyboard/MIDI interrupt vectors */
  130. KBDVEC *syskey, oldkey;
  131. xbra_vec old_ikbd;            /* old ikbd vector */
  132.  
  133. /* values the user sees for the DOS, BIOS, and XBIOS vectors */
  134. long save_dos, save_bios, save_xbios;
  135.  
  136. /* values for original system vectors */
  137. xbra_vec old_dos, old_bios, old_xbios, old_timer, old_vbl, old_5ms;
  138. xbra_vec old_criticerr;
  139.  
  140. long old_term;
  141.  
  142. xbra_vec old_resvec;    /* old reset vector */
  143. long old_resval;    /* old reset validation */
  144.  
  145. #ifdef EXCEPTION_SIGS
  146. /* bus error, address error, illegal instruction, etc. vectors */
  147. xbra_vec old_bus, old_addr, old_ill, old_divzero, old_trace, old_priv;
  148. #endif
  149.  
  150. /* BIOS disk vectors */
  151. xbra_vec old_mediach, old_getbpb, old_rwabs;
  152.  
  153. /* BIOS drive map */
  154. long olddrvs;
  155.  
  156. extern Func bios_tab[], dos_tab[];
  157.  
  158. /* kernel info that is passed to loaded file systems and device drivers */
  159.  
  160. struct kerinfo kernelinfo = {
  161.     MAJ_VERSION, MIN_VERSION,
  162.     DEFAULT_MODE, 0,
  163.     bios_tab, dos_tab,
  164.     changedrv,
  165.     TRACE, DEBUG, ALERT, FATAL,
  166.     kmalloc, kfree, umalloc, ufree,
  167.     strnicmp, stricmp, strlwr, strupr, ksprintf,
  168.     ms_time, unixtim, dostim,
  169.     nap, sleep, wake, wakeselect,
  170.     denyshare, denylock
  171. };
  172.  
  173. /* temporary stack for resets -- see intr.s */
  174. char tmpstack[256];
  175.  
  176. /* TOS and MiNT cookie jars, respectively. See the comments and code 
  177.  * after main() for further details
  178.  */
  179.  
  180. COOKIE *oldcookie, *newcookie;
  181.  
  182. /*
  183.  * install a new vector for address "addr", using the XBRA protocol.
  184.  * must run in supervisor mode!
  185.  */
  186.  
  187. static void
  188. xbra_install(xv, addr, func)
  189.     xbra_vec *xv;
  190.     long addr;
  191.     void (*func)();
  192. {
  193.     xv->xbra_magic = XBRA_MAGIC;
  194.     xv->xbra_id = MINT_MAGIC;
  195.     xv->jump = JMP_OPCODE;
  196.     xv->this = func;
  197.     xv->next = *((struct xbra **)addr);
  198.     *((short **)addr) = &xv->jump;
  199. }
  200.  
  201. /*
  202.  * MiNT critical error handler; all it does is to jump through
  203.  * the vector for the current process
  204.  */
  205.  
  206. static long
  207. mint_criticerr(error)
  208.     long error;    /* high word is error, low is drive */
  209. {
  210.     return (*curproc->criticerr)(error);
  211. }
  212.  
  213. /* initialize all interrupt vectors and new trap routines
  214.  * we also get here any TOS variables that we're going to change
  215.  * (e.g. the pointer to the cookie jar) so that rest_intr can
  216.  * restore them.
  217.  */
  218.  
  219. static void
  220. init_intr()
  221. {
  222.     extern void mint_bios(), mint_dos(), mint_timer(), mint_vbl();
  223.     extern void mint_5ms();        /* AKP */
  224.     extern void mint_xbios(), reset();
  225.     extern void new_ikbd();
  226.     extern void new_bus(), new_addr(), new_ill(), new_divzero(),
  227.         new_trace(), new_priv();
  228.     short savesr;
  229.  
  230.     syskey = (KBDVEC *)Kbdvbase();
  231.     oldkey = *syskey;
  232.  
  233.     xbra_install(&old_ikbd, (long)(&syskey->ikbdsys), new_ikbd);
  234.  
  235. /* gratuitous (void *) for Lattice */
  236.     old_term = (long)Setexc(0x102, (void *)-1L);
  237.  
  238.     savesr = spl7();
  239.  
  240.     xbra_install(&old_dos, 0x84L, mint_dos);
  241.     save_dos = (long)old_dos.next;
  242.  
  243.     xbra_install(&old_bios, 0xb4L, mint_bios);
  244.     save_bios = (long)old_bios.next;
  245.  
  246.     xbra_install(&old_xbios, 0xb8L, mint_xbios);
  247.     save_xbios = (long)old_xbios.next;
  248.  
  249.     xbra_install(&old_timer, 0x400L, mint_timer);
  250.     xbra_install(&old_criticerr, 0x404L, (void (*)())mint_criticerr);
  251.     xbra_install(&old_5ms, 0x114L, mint_5ms);
  252.     xbra_install(&old_vbl, 4*0x1cL, mint_vbl);
  253.     xbra_install(&old_resvec, 0x42aL, reset);
  254.     old_resval = *((long *)0x426L);
  255.  
  256.     spl(savesr);
  257.  
  258. #ifdef EXCEPTION_SIGS
  259. /* set up signal handlers */
  260.     xbra_install(&old_bus, 8L, new_bus);
  261.     xbra_install(&old_addr, 12L, new_addr);
  262.     xbra_install(&old_ill, 16L, new_ill);
  263.     xbra_install(&old_divzero, 20L, new_divzero);
  264.     xbra_install(&old_trace, 36L, new_trace);
  265. # ifdef STRICT_PRIV
  266. /* don't do this */
  267.     xbra_install(&old_priv, 32L, new_priv);
  268. # endif
  269. #endif
  270.  
  271. /* set up disk vectors */
  272.     xbra_install(&old_mediach, 0x47eL, new_mediach);
  273.     xbra_install(&old_rwabs, 0x476L, new_rwabs);
  274.     xbra_install(&old_getbpb, 0x472L, new_getbpb);
  275.     olddrvs = *((long *)0x4c2L);
  276.  
  277. /* set up cookie jar */
  278.     oldcookie = *CJAR;    /* CJAR defined in cookie.h */
  279.     install_cookies();
  280. }
  281.  
  282. /* restore all interrupt vectors and trap routines */
  283. /*
  284.  * NOTE: This is *not* the approved way of unlinking XBRA trap handlers.
  285.  * Normally, one should trace through the XBRA chain. However, this is
  286.  * a very unusual situation: when MiNT exits, any TSRs or programs running
  287.  * under MiNT will no longer exist, and so any vectors that they have
  288.  * caught will be pointing to never-never land! So we do something that
  289.  * would normally be considered rude, and restore the vectors to
  290.  * what they were before we ran.
  291.  * BUG: we should restore *all* vectors, not just the ones that MiNT caught.
  292.  */
  293.  
  294. void
  295. restr_intr()
  296. {
  297.     short savesr;
  298.  
  299.     savesr = spl7();
  300.     *syskey = oldkey;        /* restore keyboard vectors */
  301.     *tosbp = _base;            /* restore GEMDOS basepage pointer */
  302.     *CJAR = oldcookie;        /* restore old cookie jar */
  303.  
  304. #ifdef EXCEPTION_SIGS
  305.     *((long *)0x08L) = (long) old_bus.next;
  306.     *((long *)0x0cL) = (long) old_addr.next;
  307.     *((long *)0x10L) = (long) old_ill.next;
  308.     *((long *)0x14L) = (long) old_divzero.next;
  309. # ifdef STRICT_PRIV
  310.     *((long *)0x20L) = (long) old_priv.next;
  311. # endif
  312.     *((long *)0x24L) = (long) old_trace.next;
  313. #endif
  314.     *((long *)0x84L) = (long) old_dos.next;
  315.     *((long *)0xb4L) = (long) old_bios.next;
  316.     *((long *)0xb8L) = (long) old_xbios.next;
  317.     *((long *)0x408L) = old_term;
  318.     *((long *)0x404L) = (long) old_criticerr.next;
  319.     *((long *)0x114L) = (long) old_5ms.next;
  320.     *((long *)0x400L) = (long) old_timer.next;
  321.     *((long *)0x70L) = (long) old_vbl.next;
  322.     *((long *)0x426L) = old_resval;
  323.     *((long *)0x42aL) = (long) old_resvec.next;
  324.     *((long *)0x476L) = (long) old_rwabs.next;
  325.     *((long *)0x47eL) = (long) old_mediach.next;
  326.     *((long *)0x472L) = (long) old_getbpb.next;
  327.     *((long *)0x4c2L) = olddrvs;
  328.  
  329.     spl(savesr);
  330. }
  331.  
  332.  
  333. /* we save the TOS supervisor stack pointer so that we can reset it when
  334.    calling Pterm() (not that anyone will ever want to leave MiNT :-)).
  335.  */
  336.  
  337. long tosssp;        /* TOS supervisor stack pointer */
  338.  
  339.  
  340. /*
  341.  * enter_kernel: called every time we enter the MiNT kernel via a trap
  342.  * call. Sets up the GEMDOS and BIOS vectors to point to TOS, and
  343.  * sets up other vectors and system variables appropriately. Note that
  344.  * calling enter_kernel multiple times should not be harmful!
  345.  */
  346.  
  347. short in_kernel = 0;
  348.  
  349. void
  350. enter_kernel()
  351. {
  352.     short save_sr;
  353.  
  354.     if (in_kernel) return;
  355.  
  356.     save_sr = spl7();
  357.     save_dos = *((long *) 0x84L);
  358.     save_bios = *((long *) 0xb4L);
  359.     save_xbios = *((long *) 0xb8L);
  360.     *((long *) 0x84L) = (long)old_dos.next;
  361.     *((long *) 0xb4L) = (long)old_bios.next;
  362.     *((long *) 0xb8L) = (long)old_xbios.next;
  363.     *tosbp = rootproc->base;
  364.  
  365.     in_kernel = 1;
  366.     spl(save_sr);
  367. }
  368.  
  369. /*
  370.  * leave_kernel: called before leaving the kernel, either back to
  371.  * user mode or when calling a signal handler or the GEMDOS
  372.  * terminate vector. Note that interrupts should be disabled before
  373.  * this routine is called.
  374.  */
  375.  
  376. void
  377. leave_kernel()
  378. {
  379.     if (!in_kernel) {
  380.         ALERT("leave_kernel: not in kernel??");
  381.     }
  382.     *((long *) 0x84L) = save_dos;
  383.     *((long *) 0xb4L) = save_bios;
  384.     *((long *) 0xb8L) = save_xbios;
  385.     *tosbp = curproc->base;
  386.     in_kernel = 0;
  387. }
  388.  
  389. /*
  390.  * shut down processes; this involves waking them all up, and sending
  391.  * them SIGTERM to give them a chance to clean up after themselves
  392.  */
  393.  
  394. static void
  395. shutmedown(p)
  396.     PROC *p;
  397. {
  398.     curproc->wait_cond = 0;
  399. }
  400.  
  401. void
  402. shutdown()
  403. {
  404.     PROC *p;
  405.     int proc_left = 0;
  406.  
  407.     curproc->sighandle[SIGCHLD] = SIG_IGN;
  408.  
  409.     for (p = proclist; p; p = p->gl_next) {
  410.         if (p->pid == 0) continue;
  411.         if (p->wait_q != ZOMBIE_Q && p->wait_q != TSR_Q) {
  412.             if (p->wait_q != READY_Q) {
  413.                 rm_q(p->wait_q, p);
  414.                 add_q(READY_Q, p);
  415.             }
  416.             post_sig(p, SIGTERM);
  417.             proc_left++;
  418.         }
  419.     }
  420.  
  421.     if (proc_left) {
  422.         /* sleep a little while, to give the other processes a chance to
  423.            shut down
  424.          */
  425.  
  426.         addtimeout(1000, shutmedown);
  427.         do {
  428.             sleep(WAIT_Q, (long)&shutdown);
  429.         } while (curproc->wait_cond == (long)&shutdown);
  430.     }
  431. }
  432.  
  433. #ifdef ZEROEXIT
  434. /*
  435.  * a horrible kludge: TOS 1.4 has a bug that causes GEM to get upset
  436.  * if a large AUTO folder program runs and leaves non-zero memory
  437.  * behind. So, before we leave, we zero as much of ourselves as
  438.  * possible. To do this, we copy a short, position independent
  439.  * assembly language function into the basepage, and then execute
  440.  * it; the function will take care of exiting.
  441.  * Note: the GEM bug doesn't usually bite because most AUTO folder
  442.  * programs are TSRs and hence GEM doesn't reuse their memory.
  443.  */
  444.  
  445. static short exitfunc[] = {
  446.     0x41fa, 0x0012,        /*    lea    end(pc), a0    */
  447.     0x226f, 0x0004,        /*    move.l    4(sp), a1    */
  448.     0x4240,            /*    clr.w    d0        */
  449.     0x30c0,            /* L1:    move.w    d0, a0@+    */
  450.     0xb3c8,            /*    cmp.l    a0, a1        */
  451.     0x66fa,            /*    bne    L1        */
  452.     0x3f00,            /*    move.w    d0, sp@-    */
  453.     0x4e41            /*    trap    #1        */
  454. };                /* end:                */
  455.  
  456. void zeroexit()
  457. {
  458.     int i;
  459.     short *to, *from;
  460.     void (*func)();
  461.  
  462.     if (mcpu > 10) {   /* on 68020+, we could run into cache problems */
  463.         Pterm0();  /* let's hope we're running a fixed version of TOS */
  464.     }
  465.  
  466.     to = (short *)_base->p_cmdlin;
  467.     func = (void (*)()) to;
  468.     from = exitfunc;
  469.     for (i = 0; i < sizeof(exitfunc); i++) {
  470.         *to++ = *from++;
  471.     }
  472.     (*P_((void (*)(long)))func)(_base->p_hitpa);
  473. }
  474. #else    /* zerofunc */
  475. void zeroexit() { Pterm0(); }
  476. #endif
  477.  
  478. int
  479. main(argc, argv, envp)
  480.     int argc;
  481.     char **argv;
  482.     char **envp;
  483. {
  484.     long *sysbase;
  485.     long r;
  486.     extern int debug_level;        /* in debug.c */
  487.     static char buf[SPRINTF_MAX];
  488.     static char curpath[128];
  489.     int yn;
  490.     FILEPTR *f;
  491.  
  492. /* Allow the user to abort the boot if the magic combination of shift keys
  493.  * is held down (see MAGIC_SHIFT above)
  494.  */
  495.     if ((Kbshift(-1) & MAGIC_SHIFT) == MAGIC_SHIFT) {
  496.         Cconws("Boot MiNT? (y/n) ");
  497.         yn = Cconin() & 0x7f;
  498.         if (yn != 'y' && yn != 'Y') {
  499.             Cconws("\r\n\r\nMiNT not booted, at user's request.\r\n");
  500.             Pterm0();
  501.         }
  502.     }
  503.  
  504.     if (argv[0][0] == 0) {    /* maybe started from the desktop */
  505.         curs_off = 1;
  506.     }
  507.  
  508.     if (argc > 1) {
  509.         debug_level++;
  510.     }
  511.     if (argc > 2) {
  512.         debug_level++;
  513.     }
  514.  
  515. /* greetings */
  516.     Cconws("\r\n\033eMiNT is Not TOS: MiNT version ");
  517. #ifdef PATCHLEVEL
  518.     ksprintf(buf, VERS_STRING, MAJ_VERSION, MIN_VERSION, PATCHLEVEL);
  519. #else
  520.     ksprintf(buf, VERS_STRING, MAJ_VERSION, MIN_VERSION);
  521. #endif
  522.     Cconws(buf);
  523.     Cconws("\r\nCopyright 1990,1991,1992 Eric R. Smith\r\n");
  524.     Cconws("Use this program at your own risk!\r\n");
  525.     Cconws("See the file \"copying\" for distribution conditions\r\n");
  526.  
  527.     gem_active = check_for_gem();    /* this must be done from user mode */
  528.  
  529. /*
  530.  * get the current directory, so that we can switch back to it after
  531.  * the file systems are properly initialized
  532.  */
  533. /* set the current directory for the current process */
  534.     (void)Dgetpath(curpath, 0);
  535.  
  536.     tosssp = (long)Super(0L);    /* enter supervisor mode */
  537.  
  538. /* figure out what kind of machine we're running on */
  539. /* biosfs wants to know this, so we have to do it very
  540.  * early in our initialization
  541.  */
  542.     getmch();
  543.  
  544. /* get GEMDOS pointer to current basepage */
  545. /* 0x4f2 points to the base of the OS; here we can find the OS compilation
  546.    date, and (in newer versions of TOS) where the current basepage pointer
  547.    is kept; in older versions of TOS, it's at 0x602c
  548.  */
  549.     sysbase = *((long **)(0x4f2L));    /* gets the RAM OS header */
  550.     sysbase = (long *)sysbase[2];    /* gets the ROM one */
  551.  
  552.     tosvers = (sysbase[0] & 0x0000ffff);
  553.     if (tosvers == 0x100) {
  554.         if ((sysbase[7] & 0xfffe0000) == 0x00080000)
  555.             tosbp = (BASEPAGE **)0x873cL;    /* SPANISH ROM */
  556.         else
  557.             tosbp = (BASEPAGE **) 0x602cL;
  558.         kbshft = (char *) 0x0e1bL;
  559.     } else {
  560.         tosbp = (BASEPAGE **) sysbase[10];
  561.         kbshft = (char *) sysbase[9];
  562.     }
  563.  
  564. /* The TT TOS release notes are wrong... this is the real way to test
  565.  * for Bconmap ability
  566.  */
  567.     has_bconmap = (Bconmap(0) == 0);
  568.  
  569. /* initialize memory */
  570.     init_mem();
  571. TRACE("back from init_mem");
  572.  
  573. /* initialize the basic file systems */
  574.     init_filesys();
  575. TRACE("back from init_filesys");
  576.  
  577. /* initialize processes */
  578.     init_proc();
  579. TRACE("back from init_proc");
  580.  
  581. /* initialize system calls */
  582.     init_dos();
  583.     init_bios();
  584.     init_xbios();
  585.  
  586. /* NOTE: there's a call to kmalloc embedded in install_cookies, which
  587.  * is called by init_intr; so make sure this is the last of the
  588.  * init_* things called!
  589.  */
  590.     init_intr();
  591.     enter_kernel();
  592.  
  593. /* set up standard file handles for the current process
  594.  * do this here, *after* init_intr has set the Rwabs vector,
  595.  * so that AHDI doesn't get upset by references to drive U:
  596.  */
  597.     f = do_open("U:\\DEV\\CONSOLE", O_RDWR, 0, (XATTR *)0);
  598.     if (!f) {
  599.         FATAL("unable to open CONSOLE device");
  600.     }
  601.     curproc->control = f;
  602.     curproc->handle[0] = f;
  603.     curproc->handle[1] = f;
  604.     f->links = 3;
  605.  
  606.     f = do_open("U:\\DEV\\MODEM1", O_RDWR, 0, (XATTR *)0);
  607.     curproc->aux = f;
  608.     if (has_bconmap) {
  609.     /* If someone has already done a Bconmap call, then
  610.      * MODEM1 may no longer be the default
  611.      */
  612.         bconmap(curbconmap);
  613.         f = curproc->aux;    /* bconmap can change curproc->aux */
  614.     }
  615.     if (f) {
  616.         curproc->handle[2] = f;
  617.         f->links++;
  618.     }
  619.     f = do_open("U:\\DEV\\CENTR", O_RDWR, 0, (XATTR *)0);
  620.     if (f) {
  621.         curproc->handle[3] = curproc->prn = f;
  622.         f->links = 2;
  623.     }
  624.     if (f) {
  625.         f = do_open("U:\\DEV\\MIDI", O_RDWR, 0, (XATTR *)0);
  626.         curproc->midiin = curproc->midiout = f;
  627.         f->links = 2;
  628.     }
  629.  
  630. /* load external file systems */
  631.     if (*curpath) {
  632.         (void)d_setpath(curpath);
  633.     }
  634.     
  635.     load_filesys();
  636.  
  637. /* note that load_filesys changed the
  638.  * directory on us!!
  639.  */
  640.     if (*curpath) {
  641.         (void)d_setpath(curpath);
  642.     }
  643.     
  644. /* load the configuration file */
  645.     load_config();
  646.  
  647. /* if we want pseudo-drives, set the drive map accordingly */
  648.     if (pseudodrives > 0) {
  649.         *((long *)0x4c2L) |= PSEUDODRVS;
  650.     };
  651.     if (pseudodrives < 2) {        /* restore old Rwabs, etc. */
  652.         *((long *)0x476L) = (long) old_rwabs.next;
  653.         *((long *)0x47eL) = (long) old_mediach.next;
  654.         *((long *)0x472L) = (long) old_getbpb.next;
  655.     }
  656.  
  657.     if (init_env == 0)
  658.         init_env = (char *)_base->p_env;
  659.  
  660. /* empty environment? Set the PATH variable to the root of the current drive */
  661.     if (init_env[0] == 0) {
  662.         static char path_env[] = "PATH=\0C:\0";
  663.         path_env[6] = curproc->curdrv + 'A';
  664.         init_env = path_env;
  665.     }
  666.  
  667. /* run any programs appearing after us in the AUTO folder */
  668.     run_auto_prgs();
  669.  
  670. /* run the initial program */
  671.  
  672.     r = p_exec(0, init_prg, init_tail, init_env);
  673.  
  674. /* if it isn't found, and the user didn't say otherwise, try GEM */
  675.     if (r == EFILNF && init_prg == orig_init) {
  676.         if (!gem_active) {
  677.             BASEPAGE *bp; int pid;
  678.             bp = (BASEPAGE *)p_exec(7, (char *)7L, (char *)"\0", init_env);
  679.             bp->p_tbase = *((long *) 0x4feL );
  680.             pid = p_exec(106, (char *)"GEM", bp, 0L);
  681.             if (pid > 0) {
  682.             do {
  683.                 r = p_wait3(0, (long *)0);
  684.             } while(pid != ((r & 0xffff0000) >> 16));
  685.             r &= 0x0000ffff;
  686.             }
  687.         } else {
  688. Cconws("If MiNT is run after GEM starts, you must specify a program\r\n");
  689. Cconws("to run initially in MINT.CNF, with an INIT= line\r\n");
  690.             r = 0;
  691.         }
  692.     }
  693.  
  694.     if (r < 0) {
  695.         ksprintf(buf, "FATAL: couldn't run %s\r\n", init_prg);
  696.         Cconws(buf);
  697.     }
  698.  
  699.     if (r) {
  700.         ksprintf(buf, "exit code: %ld\r\n", r);
  701.         Cconws(buf);
  702.     }
  703.  
  704. /* shut down all processes gracefully */
  705.     shutdown();
  706.  
  707. /* put everything back and exit */
  708.     restr_intr();
  709.     close_filesys();
  710.  
  711.     (void)Super((void *)tosssp);    /* gratuitous (void *) for Lattice */
  712.     Cconws("leaving MiNT\r\n");
  713.  
  714.     if (curs_off)
  715.         Cconws("\033f");    /* disable cursor */
  716.  
  717.     zeroexit();
  718.     return 0;    /* dummy -- this should never be reached */
  719. }
  720.  
  721.  
  722. /*
  723.  * cookie jar handling routines. The "cookie jar" is an area of memory
  724.  * reserved by TOS for TSR's and utility programs; the idea is that
  725.  * you put a cookie in the jar to notify people of available services.
  726.  * The BIOS uses the cookie jar in TOS 1.6 and higher; for earlier versions
  727.  * of TOS, the jar is always empty (unless someone added a cookie before
  728.  * us; POOLFIX does, for example).
  729.  * MiNT establishes an entirely new cookie jar (with the old cookies copied
  730.  * over) and frees it on exit. That's because TSR's run under MiNT
  731.  * will no longer be accessible after MiNT exits.
  732.  * MiNT also puts a cookie in the jar, with tag field 'MiNT' (of course)
  733.  * and with the major version of MiNT in the high byte of the low word,
  734.  * and the minor version in the low byte.
  735.  */
  736.  
  737. void
  738. install_cookies()
  739. {
  740.     COOKIE *cookie;
  741.     int i, ncookies;
  742.  
  743.     /* note that init_intr sets oldcookie to the old cookie jar */
  744.  
  745.     ncookies = 0;
  746.     cookie = oldcookie;
  747.     if (cookie) {
  748.         while (cookie->tag.aslong != 0) {
  749.         /* check for true FPU co-processor */
  750.             if (!strncmp(cookie->tag.aschar, "_FPU",4) &&
  751.                  (cookie->value >> 16) >= 2)
  752.                 fpu = 1;
  753.         /* check for _FLK cookie */
  754.             else if (!strncmp(cookie->tag.aschar, "_FLK",4))
  755.                 flk = 1;
  756.             cookie++; ncookies++;
  757.         }
  758.     }
  759.  
  760. /* NOTE: obviously, we can do this only if init_intr is called
  761.  * _after_ memory, processes, etc. have been initialized
  762.  */
  763.     newcookie = (COOKIE *)kmalloc((ncookies + 16)*sizeof(COOKIE));
  764.     assert(newcookie);
  765.  
  766. /* copy the old cookies to the new jar */
  767.  
  768.     for (i = 0; i < ncookies; i++) {
  769.         newcookie[i] = oldcookie[i];
  770.     }
  771.  
  772. /* install MiNT cookie */
  773.     strncpy(newcookie[i].tag.aschar, "MiNT", 4);
  774.     newcookie[i].value = (MAJ_VERSION << 8) | MIN_VERSION;
  775.     i++;
  776.  
  777. /* install _FLK cookie to indicate that file locking works */
  778.     if (!flk) {
  779.         strncpy(newcookie[i].tag.aschar, "_FLK", 4);
  780.         newcookie[i].value = 0;
  781.         i++;
  782.     }
  783.  
  784. /* the last cookie should have a 0 tag, and a value indicating the number
  785.  * of slots, total
  786.  */
  787.  
  788.     newcookie[i].tag.aslong = 0;
  789.     newcookie[i].value = ncookies+16;
  790.  
  791.     *CJAR = newcookie;
  792.  
  793. }
  794.  
  795. /*
  796.  * get the value of the _MCH cookie, if one exists
  797.  * this must be done in a separate routine because the machine type
  798.  * is needed when initializing the bios file system, whereas
  799.  * install_cookies is not called until everything is installed
  800.  * In fact, getmch() should be called before *anything* else is
  801.  * initialized, so that if we find a MiNT cookie already in the
  802.  * jar we can bail out early.
  803.  */
  804.  
  805. static void
  806. getmch()
  807. {
  808.     COOKIE *jar;
  809.  
  810.     jar = *CJAR;    /* CJAR defined in cookie.h */
  811.     if (jar) {
  812.         while (jar->tag.aslong != 0) {
  813.         /* check for machine type */
  814.             if (!strncmp(jar->tag.aschar, "_MCH",4)) {
  815.                 mch = jar->value;
  816.             } else if (!strncmp(jar->tag.aschar, "_CPU", 4)) {
  817.                 mcpu = jar->value;
  818.                 if (mcpu == 10)
  819.                     m68010 = 1;
  820.             } else if (!strncmp(jar->tag.aschar, "MiNT",4)) {
  821.                 Cconws("MiNT is already installed!!\r\n");
  822.                 (void)Super((void *)tosssp);
  823.                 Pterm(2);
  824.             }
  825.             jar++;
  826.         }
  827.     }
  828. }
  829.  
  830. /*
  831.  * routines for reading the configuration file
  832.  * we allow the following commands in the file:
  833.  * # anything        -- comment
  834.  * INIT=file        -- specify boot program
  835.  * cd dir        -- change directory/drive
  836.  * ren file1 file2    -- rename a file
  837.  * sln file1 file2    -- create a symbolic link
  838.  * echo message        -- print a message on the screen
  839.  * setenv var value    -- set an environment variable
  840.  *
  841.  * BUG: if you use setenv in mint.cnf, *none* of the original environment
  842.  * gets passed to children. This is rarely a problem if mint.prg is
  843.  * in the auto folder.
  844.  */
  845.  
  846. extern short bconbdev, bconbsiz;    /* from bios.c */
  847.  
  848. static void
  849. doset(name, val)
  850.     char *name, *val;
  851. {
  852.     char *t;
  853.  
  854.     if (!strcmp(name, "INIT")) {
  855.         t = kmalloc(strlen(val)+1);
  856.         if (!t) return;
  857.         strcpy(t, val);
  858.         init_prg = t;
  859.         while (*t && !isspace(*t)) t++;
  860. /* get the command tail, too */
  861.         if (*t) {
  862.             *t++ = 0;
  863.             strncpy(init_tail+1, t, 125);
  864.             init_tail[0] = strlen(init_tail+1);
  865.         }
  866.         return;
  867.     }
  868.     if (!strcmp(name, "CON")) {
  869.         FILEPTR *f;
  870.         int i;
  871.  
  872.         f = do_open(val, O_RDWR, 0, (XATTR *)0);
  873.         if (f) {
  874.             for (i = -1; i < 2; i++) {
  875.                 do_close(curproc->handle[i]);
  876.                 curproc->handle[i] = f;
  877.                 f->links++;
  878.             }
  879.             f->links--;    /* correct for overdoing it */
  880.         }
  881.         return;
  882.     }
  883.     if (!strcmp(name, "PRN")) {
  884.         FILEPTR *f;
  885.  
  886.         f = do_open(val, O_RDWR|O_CREAT|O_TRUNC, 0, (XATTR *)0);
  887.         if (f) {
  888.             do_close(curproc->handle[2]);
  889.             do_close(curproc->prn);
  890.             curproc->prn = curproc->handle[2] = f;
  891.             f->links = 2;
  892.         }
  893.         return;
  894.     }
  895.     if (!strcmp(name, "BIOSBUF")) {
  896.         if (*val == 'n' || *val == 'N') {
  897.             if (bconbsiz) bflush();
  898.             bconbdev = -1;
  899.         }
  900.         return;
  901.     }
  902.     if (!strcmp(name, "PSEUDODRIVES")) {
  903.         if (*val == 'n' || *val == 'N') {
  904.             pseudodrives = 0;
  905.         } else if (*val == 'm' || *val == 'M') {
  906.             pseudodrives = 1;
  907.         }
  908.         return;
  909.     }
  910.     if (!strcmp(name, "DEBUG_LEVEL")) {
  911.         extern int debug_level;
  912.         if (*val >= '0' && *val <= '9') debug_level = atoi(val);
  913.         else ALERT("Bad arg to \"DEBUG_LEVEL\" in cnf file");
  914.         return;
  915.     }
  916.     if (!strcmp(name, "DEBUG_DEVNO")) {
  917.         extern int out_device;
  918.         if (*val >= '0' && *val <= '9') out_device= atoi(val);
  919.         else ALERT("Bad arg to \"DEBUG_DEVNO\" in cnf file");
  920.         return;
  921.     }
  922.  
  923. #ifdef FASTTEXT
  924.     if (!strcmp(name, "HARDSCROLL")) {
  925.         int i = 0;
  926.         extern int hardscroll;
  927.  
  928.         i = *val++;
  929.         if (i < '0' || i > '9') return;
  930.         hardscroll = i-'0';
  931.         i = *val;
  932.         if (i < '0' || i > '9') return;
  933.         hardscroll = 10*hardscroll + i - '0';
  934.         return;
  935.     }
  936. #endif
  937.     ALERT("Unknown variable `%s'", name);
  938. }
  939.  
  940. /* Execute a line from the config file */
  941. static void
  942. do_line(line)
  943.     char *line;
  944. {
  945.     char *cmd, *arg1, *arg2;
  946.     char *newenv;
  947.     char *t;
  948.     int i;
  949.  
  950.     while (*line == ' ') line++;
  951.     if (*line == '#') return;    /* ignore comments */
  952.     if (!*line) return;        /* and also blank lines */
  953.  
  954.     cmd = line;
  955. /* check for variable assignments (e.g. INIT=, etc.) */
  956. /*
  957.  * AGK: note we check for spaces whilst scanning so that an environment
  958.  * variable may include an =, this has the unfortunate side effect that
  959.  * the '=' _has_ to be concatenated to the variable name (INIT etc.)
  960.  */
  961.     for (t = cmd; *t && *t != ' '; t++) {
  962.         if (*t == '=') {
  963.             *t++ = 0;
  964.             doset(cmd, t);
  965.             return;
  966.         }
  967.     }
  968.  
  969. /* OK, assume a regular command; break it up into 'cmd', 'arg1', arg2' */
  970.  
  971.     while (*line && *line != ' ') line++;
  972.     if (*line == ' ') {
  973.         *line++ = 0;
  974.         while (*line == ' ') line++;
  975.     }
  976.  
  977.     if (!strcmp(cmd, "echo")) {
  978.         c_conws(line); c_conws("\r\n");
  979.         return;
  980.     }
  981.     arg1 = line;
  982.     while (*line && *line != ' ') line++;
  983.     if (*line) {
  984.         *line++ = 0;
  985.         while (*line == ' ') line++;
  986.     }
  987.     if (!strcmp(cmd, "cd")) {
  988.         int drv;
  989.         (void)d_setpath(arg1);
  990.         drv = toupper(*arg1) - 'A';
  991.         if (arg1[1] == ':') (void)d_setdrv(drv);
  992.         return;
  993.     }
  994.     if (!strcmp(cmd, "exec")) {
  995.         static char cmdline[128];
  996.         int i;
  997.  
  998.         i = strlen(line);
  999.         if (i > 126) i = 126;
  1000.         cmdline[0] = i;
  1001.         strncpy(cmdline+1, line, i);
  1002.         cmdline[i+1] = 0;
  1003.         i = p_exec(0, arg1, cmdline, init_env);
  1004.         if (i == -33) {
  1005.             ALERT("%s: file not found", arg1);
  1006.         } else if (i < 0) {
  1007.             ALERT("%s: error while attempting to execute", arg1);
  1008.         }
  1009.         return;
  1010.     }
  1011.     if (!strcmp(cmd, "setenv")) {
  1012.         if (strlen(arg1) + strlen(line) + 4 + (env_ptr - init_env) >
  1013.                              env_len) {
  1014.             newenv = umalloc(env_len + 1024L);
  1015.             t = init_env;
  1016.             env_ptr = newenv;
  1017.             for (i = 0; i < env_len; i++)
  1018.                 *env_ptr++ = *t++;
  1019.             env_len += 1024;
  1020.             if (init_env)
  1021.                 ufree(init_env);
  1022.             init_env = newenv;
  1023.         }
  1024.         while (*arg1) {
  1025.             *env_ptr++ = *arg1++; env_len++;
  1026.         }
  1027.         *env_ptr++ = '=';
  1028.         while (*line) {
  1029.             *env_ptr++ = *line++; env_len++;
  1030.         }
  1031.         *env_ptr++ = 0;
  1032.         *env_ptr = 0;
  1033.         return;
  1034.     }
  1035.  
  1036.     arg2 = line;
  1037.     while (*line && *line != ' ') line++;
  1038.     if (*line) {
  1039.         *line++ = 0;
  1040.     }
  1041.     if (!strcmp(cmd, "sln")) {
  1042.         (void)f_symlink(arg1, arg2);
  1043.         return;
  1044.     }
  1045.     if (!strcmp(cmd, "ren")) {
  1046.         (void)f_rename(0, arg1, arg2);
  1047.         return;
  1048.     }
  1049.     ALERT("syntax error in mint.cnf");
  1050. }
  1051.  
  1052. #define BUF 512
  1053. #define LINE 256
  1054.  
  1055. void
  1056. load_config()
  1057. {
  1058.     int fd;
  1059.     long r;
  1060.     char buf[BUF+1], c;
  1061.     char line[LINE+1];
  1062.     char *from;
  1063.     int count = 0;
  1064.  
  1065.     TRACE("reading configuration file");
  1066.     fd = f_open("mint.cnf", 0);
  1067.     if (fd < 0)
  1068.         fd = f_open("\\mint\\mint.cnf", 0);
  1069.     if (fd < 0) return;
  1070.     buf[BUF] = 0;
  1071.     from = &buf[BUF];
  1072.     line[LINE] = 0;
  1073.  
  1074.     for(;;) {
  1075.         c = *from++;
  1076.         if (!c) {
  1077.             r = f_read(fd, (long)BUF, buf);
  1078.             if (r <= 0) break;
  1079.             buf[r] = 0;
  1080.             from = buf;
  1081.         } else if (c == '\r') {
  1082.             continue;
  1083.         } else if (c == '\n') {
  1084.             line[count] = 0;
  1085.             do_line(line);
  1086.             count = 0;
  1087.         } else {
  1088.             if (count < LINE) {
  1089.                 line[count++] = c;
  1090.             }
  1091.         }
  1092.     }
  1093.     f_close(fd);
  1094. }
  1095.  
  1096. /*
  1097.  * run programs in the AUTO folder that appear after MINT.PRG
  1098.  * some things to watch out for:
  1099.  * (1) make sure GEM isn't active
  1100.  * (2) make sure there really is a MINT.PRG in the auto folder
  1101.  */
  1102.  
  1103. /*
  1104.  * some global variables used to see if GEM is active
  1105.  */
  1106. static short aes_intout[64];
  1107. static short aes_dummy[64];
  1108. static short aes_globl[15];
  1109. static short aes_cntrl[6] = { 10, 0, 1, 0, 0 };
  1110.  
  1111. short *aes_pb[6] = { aes_cntrl, aes_globl, aes_dummy, aes_intout,
  1112.              aes_dummy, aes_dummy };
  1113.  
  1114. /* check for whether GEM is active; remember, this *must* be done in
  1115.  * user mode
  1116.  */
  1117.  
  1118. static int
  1119. check_for_gem()
  1120. {
  1121.     call_aes(aes_pb);    /* does an appl_init */
  1122.     return aes_globl[0];
  1123. }
  1124.  
  1125. static void
  1126. run_auto_prgs()
  1127. {
  1128.     DTABUF *dta;
  1129.     long r;
  1130.     static char pathspec[32] = "\\AUTO\\";
  1131.     short runthem = 0;    /* set to 1 after we find MINT.PRG */
  1132.  
  1133. /* if the AES is running, don't check AUTO */
  1134.  
  1135.     if (gem_active) {
  1136.         return;
  1137.     }
  1138.  
  1139. /* OK, now let's run through \\AUTO looking for
  1140.  * programs...
  1141.  */
  1142.     dta = (DTABUF *)f_getdta();
  1143.     r = f_sfirst("\\AUTO\\*.PRG", 0);
  1144.     while (r >= 0) {
  1145.         if (!strcmp(dta->dta_name, "MINT.PRG"))
  1146.             runthem = 1;
  1147.         else if (runthem) {
  1148.             strcpy(pathspec+6, dta->dta_name);
  1149.             (void)p_exec(0, pathspec, (char *)"", init_env);
  1150.         }
  1151.         r = f_snext();
  1152.     }
  1153. }
  1154.