//+++2004-08-31 // Copyright (C) 2004 Mike Rieker, Beverly, MA USA // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; version 2 of the License. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA //---2004-08-31 /************************************************************************/ /* */ /* Diag module - invoked by pressing control-shift-D */ /* */ /************************************************************************/ #include "ozone.h" #include "oz_knl_boot.h" #include "oz_knl_debug.h" #include "oz_knl_devio.h" #include "oz_knl_event.h" #include "oz_knl_hw.h" #include "oz_knl_image.h" #include "oz_knl_kmalloc.h" #include "oz_knl_lock.h" #include "oz_knl_logname.h" #include "oz_knl_logon.h" #include "oz_knl_malloc.h" #include "oz_knl_printk.h" #include "oz_knl_process.h" #include "oz_knl_procmode.h" #include "oz_knl_sdata.h" #include "oz_knl_status.h" #include "oz_knl_thread.h" #include "oz_io_console.h" #include "oz_io_fs.h" #include "oz_io_timer.h" #include "oz_sys_callknl.h" #include "oz_sys_condhand.h" #include "oz_sys_dateconv.h" #include "oz_sys_image.h" #include "oz_usr_debug.h" #define USER_STACK_SIZE (1024*1024 >> OZ_HW_L2PAGESIZE) typedef struct { uLong addr, data; int io, sz; } Pp; static volatile int halted = 0; static Long donthaltme = -1; static char imagename[64]; static void softint_level (OZ_Mchargs *mchargs); static uLong thread_level (void *dummy); static uLong reboot_thread (void *dummy); static OZ_Thread *assignthread (int consiz, char *conbuf); static uLong ztoul (char *b, char **p); static uLong peek_try (void *ppv); static uLong poke_try (void *ppv); static void readcons (int size, char *buff, char *prompt); static OZ_Iochan *openfile (char *filename, OZ_Lockmode lockmode, int verbose); static OZ_Iochan *createfile (char *filename, uLong filattrflags); static uLong thread_init (void *dummy); /************************************************************************/ /* */ /* This routine is called by the hardware layer at softint level on */ /* all cpu's as a result of a control-shift-D */ /* */ /* Input: */ /* */ /* cpuidx = current cpu index number */ /* first = 1 : this is the first cpu to respond */ /* 0 : this isn't the first cpu to respond */ /* mchargs = point of interrupt */ /* */ /************************************************************************/ void oz_knl_diag (Long cpuidx, int first, OZ_Mchargs *mchargs) { uLong ts; /* If called because we're shutting down, print message and hang forever */ if (oz_s_shutdown >= 0) { if (cpuidx == oz_s_shutdown) return; /* don't shutdown the cpu that's doing the shutdown */ oz_knl_halt (); /* halt */ } /* Set the 'halted' flag no matter which cpu we are */ /* This will cause the 'while halted' loop to hang for sure */ halted = 1; OZ_HW_MB; /* This is the first cpu to get here, use it for processing */ /* Clear the halted flag when done so as to release the other cpus */ if (first) { donthaltme = cpuidx; oz_knl_printk ("oz_knl_diag: activated on cpu %d\n", cpuidx); softint_level (mchargs); donthaltme = -1; halted = 0; oz_knl_printk ("oz_knl_diag: cpu %d resuming\n", cpuidx); } /* If this isn't the first cpu to come here, just */ /* wait for the first cpu to clear the halted flag */ else if (cpuidx != donthaltme) { oz_knl_printk ("oz_knl_diag: cpu %d halted\n", cpuidx); while (halted) {} oz_knl_printk ("oz_knl_diag: cpu %d resuming\n", cpuidx); } } /************************************************************************/ /* */ /* This is the main processing routine - it runs on the first cpu to */ /* respond at softint level */ /* */ /************************************************************************/ static void softint_level (OZ_Mchargs *mchargs) { char conbuf[64], *p; int hwi, i, usedup; OZ_Datebin now; OZ_Devunit *devunit; OZ_Thread *thread; uLong sts; /* Read command number from console */ read_command: readcons (sizeof conbuf, conbuf, "\n 1=ShowProcs 10=ShowDate 15=ShowDevs 20=ThreadTrace" "\n 2=ShowThreads 11=PeekPoke 16=AbortThread" "\n 3=Reboot 12=Exit 17=SuspendThread" "\n 4=ThreadLevel 13=DumpNpp 18=ResumeThread" "\n 5=Logon 14=DumpEvents 19=CallDebugger" "\noz_knl_diag# "); /* Show processes and threads */ if (strcmp (conbuf, "1") == 0) { oz_knl_printk ("Process list:\n"); oz_knl_process_dump_all (); oz_knl_printkp ("done"); goto read_command; } if (strcmp (conbuf, "2") == 0) { oz_knl_printk ("Thread list:\n"); oz_knl_thread_dump_all (); oz_knl_printkp ("done"); goto read_command; } if (strcmp (conbuf, "3") == 0) { sts = oz_knl_thread_create (oz_s_systemproc, -1, NULL, NULL, NULL, 0, reboot_thread, NULL, OZ_ASTMODE_INHIBIT, 25, "oz_knl_diag reboot_thread", NULL, &thread); if (sts == OZ_SUCCESS) return; oz_knl_printk ("error %u creating reboot thread\n", sts); goto read_command; } /* Enter thread level */ if (strcmp (conbuf, "4") == 0) { oz_knl_printk ("creating thread\n"); sts = oz_knl_thread_create (oz_s_systemproc, -1, NULL, NULL, NULL, 0, thread_level, NULL, OZ_ASTMODE_ENABLE, 24, "oz_knl_diag thread_level", NULL, &thread); if (sts != OZ_SUCCESS) oz_knl_printk ("error %u creating thread\n", sts); else { oz_knl_thread_orphan (thread); oz_knl_printk ("thread %p created - you must exit diag mode for it to start\n", thread); oz_knl_thread_increfc (thread, -1); } goto read_command; } /* Start logon thread */ if (strcmp (conbuf, "5") == 0) { readcons (sizeof conbuf, conbuf, "Enter terminal device name [console] > "); if ((conbuf[0] == 0) || (strcmp (conbuf, "console") == 0)) { oz_knl_printk ("oz_knl_diag: starting console logon - exit diag mode to complete\n", conbuf); oz_knl_logon_iochan (oz_s_coniochan); } else { devunit = oz_knl_devunit_lookup (conbuf); if (devunit == NULL) oz_knl_printk ("oz_knl_diag: unable to find device unit %s\n", conbuf); else { oz_knl_printk ("oz_knl_diag: starting logon on %s - exit diag mode to complete\n", conbuf); oz_knl_logon_devunit (devunit); oz_knl_devunit_increfc (devunit, -1); } } goto read_command; } /* Show current date/time */ if (strcmp (conbuf, "10") == 0) { oz_knl_printk ("oz_knl_diag: calling oz_hw_tod_getnow\n"); now = oz_hw_tod_getnow (); oz_knl_printk ("datebin 0x%x:0x%x\n", (uLong)(now >> 32), (uLong)now); oz_sys_datebin_decstr (0, now, sizeof conbuf, conbuf); oz_knl_printk (" %s\n", conbuf); goto read_command; } /* Peek and Poke - platform dependent */ #if defined (OZ_HW_TYPE_486) if (strcmp (conbuf, "11") == 0) { Pp pp; pp_read: readcons (sizeof conbuf, conbuf, "\n > "); /* read address [ mode ] [ size ] [ = data ] */ if (conbuf[0] == 0) goto read_command; /* if blank line, all done */ if (conbuf[0] == '?') goto pp_help; /* ? print help line */ pp.addr = ztoul (conbuf, &p); /* convert hex to address */ pp.io = 0; /* default is memory */ pp.sz = 0; /* default size is byte */ while (1) { while (*p == ' ') p ++; /* skip spaces */ if (*p == 0) break; /* done if end of line */ switch (*(p ++)) { case 'I': case 'i': pp.io = 1; break; /* I/O */ case 'M': case 'm': pp.io = 0; break; /* MEMORY */ case 'B': case 'b': pp.sz = 0; break; /* BYTE */ case 'W': case 'w': pp.sz = 1; break; /* WORD */ case 'L': case 'l': pp.sz = 2; break; /* LONG */ case '=': { pp.data = ztoul (p, &p); /* convert hex to data */ while (*p == ' ') p ++; if (*p != 0) goto pp_help; sts = oz_sys_condhand_try (poke_try, &pp, oz_sys_condhand_rtnanysig, NULL); if (sts != OZ_SUCCESS) oz_knl_printk (" - status %u\n", sts); goto pp_read; } default: goto pp_help; } } sts = oz_sys_condhand_try (peek_try, &pp, oz_sys_condhand_rtnanysig, NULL); if (sts != OZ_SUCCESS) oz_knl_printk (" - status %u\n", sts); goto pp_read; pp_help: oz_knl_printk ("\n
{Io Mem} {Byte Word Long} [ = value ]\n"); goto pp_read; } #endif /* Exit */ if (strcmp (conbuf, "12") == 0) return; /* Dump Non-paged pool usage */ if (strcmp (conbuf, "13") == 0) { oz_knl_npp_dump (); oz_knl_printkp (" done> "); goto read_command; } /* Dump Events */ if (strcmp (conbuf, "14") == 0) { oz_knl_event_dump (); goto read_command; } /* Show Devices */ if (strcmp (conbuf, "15") == 0) { oz_knl_devdump (1); goto read_command; } /* Abort thread */ if (strcmp (conbuf, "16") == 0) { thread = assignthread (sizeof conbuf, conbuf); if (thread == NULL) goto read_command; readcons (sizeof conbuf, conbuf, "Enter abort status [ABORTEDBYCLI] > "); sts = OZ_ABORTEDBYCLI; if (conbuf[0] != 0) { sts = oz_hw_atoi (conbuf, &usedup); if (conbuf[usedup] != 0) { oz_knl_printk ("oz_knl_diag: invalid status value %s\n", conbuf); oz_knl_thread_increfc (thread, -1); goto read_command; } } oz_knl_printk ("oz_knl_diag: aborting thread %p with %u\n", thread, sts); oz_knl_thread_abort (thread, sts); oz_knl_thread_increfc (thread, -1); goto read_command; } /* Suspend thread */ if (strcmp (conbuf, "17") == 0) { thread = assignthread (sizeof conbuf, conbuf); if (thread == NULL) goto read_command; oz_knl_printk ("oz_knl_diag: suspend thread %p\n", thread); i = oz_knl_thread_suspend (thread); if (i) oz_knl_printk ("oz_knl_diag: thread was already marked for suspension\n"); else oz_knl_printk ("oz_knl_diag: thread is now marked for suspension\n"); oz_knl_thread_increfc (thread, -1); goto read_command; } /* Resume thread */ if (strcmp (conbuf, "18") == 0) { thread = assignthread (sizeof conbuf, conbuf); if (thread == NULL) goto read_command; oz_knl_printk ("oz_knl_diag: resume thread %p\n", thread); i = oz_knl_thread_resume (thread); if (i) oz_knl_printk ("oz_knl_diag: thread was marked for suspension\n"); else oz_knl_printk ("oz_knl_diag: thread was not marked for suspension\n"); oz_knl_thread_increfc (thread, -1); goto read_command; } /* Call debugger */ if (strcmp (conbuf, "19") == 0) { hwi = oz_hw_cpu_sethwints (0); oz_knl_debug_exception (NULL, mchargs); oz_hw_cpu_sethwints (hwi); goto read_command; } /* Thread trace dump */ if (strcmp (conbuf, "20") == 0) { thread = assignthread (sizeof conbuf, conbuf); if (thread == NULL) goto read_command; oz_knl_thread_tracedump (thread); oz_knl_thread_increfc (thread, -1); goto read_command; } oz_knl_printk ("unknown command code %s\n", conbuf); goto read_command; } /************************************************************************/ /* */ /* This routine executes as a thread of the system process in kernel */ /* mode. It can do things that cause pagefaults, however the other */ /* cpu's are running and so is the scheduler. */ /* */ /************************************************************************/ static uLong thread_level (void *dummy) { char conbuf[64], diskdevname[256], filbuf[1024], *fileidstrbf, *p; char tempdevname[64], volname[32]; int i; OZ_IO_fs_getinfo1 fs_getinfo1; OZ_IO_fs_getinfo3 fs_getinfo3; OZ_IO_fs_initvol fs_initvol; OZ_IO_fs_mountvol fs_mountvol; OZ_IO_fs_open fs_open; OZ_IO_fs_readdir fs_readdir; OZ_IO_fs_readrec fs_readrec; OZ_IO_fs_writerec fs_writerec; OZ_Iochan *filioch, *tempiochan; OZ_Logname *logname, *lognamtbl; OZ_Logvalue lnmvals[16]; OZ_Process *process; OZ_Thread *thread; uLong rlen, sts; void *fileidbuff; static const char trmbuff[1] = { '\n' }; /* Most of these routines assume software interrupt delivery is inhibited */ /* (Like oz_knl_process_create barfs if it isn't) */ oz_hw_cpu_setsoftint (0); /* Read command number from console */ read_command: readcons (sizeof conbuf, conbuf, "\n 1=SoftintLevel 5=DisplayFile 9=CreateDir 13=Reboot" "\n 2=RunImage 6=InitVol 10=CopyFile" "\n 3=ShowLogical 7=MountVol 11=DismVol" "\n 4=CreateLnm 8=ListDir 12=Exit" "\noz_knl_diag> "); /* Return to softint level */ if (strcmp (conbuf, "1") == 0) { oz_knl_printk ("oz_knl_diag: returning to softint level\n"); oz_hw_diag (); oz_hw_cpu_setsoftint (1); return (OZ_SUCCESS); } /* Run an executable */ if (strcmp (conbuf, "2") == 0) { readcons (sizeof imagename, imagename, "Enter image name to run > "); if (imagename[0] == 0) goto read_command; oz_knl_printk ("oz_knl_diag: creating process\n"); sts = oz_knl_process_create (oz_s_systemjob, 0, 0, strlen (imagename), imagename, NULL, &process); if (sts != OZ_SUCCESS) { oz_knl_printk ("oz_knl_diag: error %u creating process\n", sts); goto read_command; } oz_knl_printk ("oz_knl_diag: creating input, output and error logical names\n"); lognamtbl = oz_knl_process_getlognamtbl (process); sts = oz_knl_logname_creobj (lognamtbl, OZ_PROCMODE_KNL, NULL, oz_s_secattr_syslogname, 0, 8, "OZ_ERROR", oz_s_coniochan, NULL); if (sts != OZ_SUCCESS) oz_knl_printk ("oz_knl_diag: error %u creating logical OZ_ERROR\n", sts); sts = oz_knl_logname_creobj (lognamtbl, OZ_PROCMODE_KNL, NULL, oz_s_secattr_syslogname, 0, 8, "OZ_INPUT", oz_s_coniochan, NULL); if (sts != OZ_SUCCESS) oz_knl_printk ("oz_knl_diag: error %u creating logical OZ_INPUT\n", sts); sts = oz_knl_logname_creobj (lognamtbl, OZ_PROCMODE_KNL, NULL, oz_s_secattr_syslogname, 0, 9, "OZ_OUTPUT", oz_s_coniochan, NULL); if (sts != OZ_SUCCESS) oz_knl_printk ("oz_knl_diag: error %u creating logical OZ_OUTPUT\n", sts); sts = oz_knl_logname_crestr (lognamtbl, OZ_PROCMODE_KNL, NULL, oz_s_secattr_syslogname, 0, 8, "OZ_IMAGE", imagename, NULL); if (sts != OZ_SUCCESS) oz_knl_printk ("oz_knl_diag: error %u creating logical OZ_IMAGE\n", sts); sts = oz_knl_logname_create (lognamtbl, OZ_PROCMODE_KNL, NULL, oz_s_secattr_syslogname, 0, 9, "OZ_PARAMS", 0, NULL, NULL); if (sts != OZ_SUCCESS) oz_knl_printk ("oz_knl_diag: error %u creating logical OZ_PARAMS\n", sts); oz_knl_printk ("oz_knl_diag: creating thread\n"); sts = oz_knl_thread_create (process, -2, NULL, NULL, NULL, USER_STACK_SIZE, thread_init, NULL, OZ_ASTMODE_ENABLE, strlen (imagename), imagename, NULL, &thread); if (sts != OZ_SUCCESS) oz_knl_printk ("error %u creating thread\n", sts); else { oz_knl_thread_orphan (thread); oz_knl_printk ("oz_knl_diag: thread %p created\n", thread); oz_knl_thread_increfc (thread, -1); } oz_knl_process_increfc (process, -1); goto read_command; } /* Show Logicals */ if (strcmp (conbuf, "3") == 0) { readcons (sizeof tempdevname, tempdevname, "Enter logical name [OZ_SYSTEM_DIRECTORY] > "); if (tempdevname[0] == 0) { oz_knl_logname_dump (0, oz_s_systemdirectory); } else { sts = oz_knl_logname_lookup (oz_s_systemdirectory, OZ_PROCMODE_USR, strlen (tempdevname), tempdevname, NULL, NULL, NULL, NULL, &logname, NULL); if (sts != OZ_SUCCESS) { oz_knl_printk ("oz_knl_diag: error %u looking up %s\n", sts, tempdevname); } else { oz_knl_logname_dump (0, logname); oz_knl_logname_increfc (logname, -1); } } goto read_command; } /* Create logical name */ if (strcmp (conbuf, "4") == 0) { readcons (sizeof tempdevname, tempdevname, "Enter logical name > "); if (tempdevname[0] == 0) goto read_command; for (i = 0; i < sizeof lnmvals / sizeof lnmvals[0]; i ++) { oz_sys_sprintf (sizeof conbuf, conbuf, "Enter value[%d] > ", i); readcons (sizeof diskdevname, diskdevname, conbuf); if (diskdevname[0] == 0) break; lnmvals[i].attr = OZ_LOGVALATR_TERMINAL; lnmvals[i].buff = OZ_KNL_PGPMALLOC (strlen (diskdevname) + 1); strcpy (lnmvals[i].buff, diskdevname); } if (i == 0) goto read_command; sts = oz_knl_logname_create (oz_s_systemtable, OZ_PROCMODE_KNL, NULL, oz_s_secattr_syslogname, 0, strlen (tempdevname), tempdevname, i, lnmvals, NULL); if (sts == OZ_SUCCESS) oz_knl_printk ("oz_knl_diag: logical %s created\n", tempdevname); else if (sts == OZ_SUPERSEDED) oz_knl_printk ("oz_knl_diag: logical %s superseded\n", tempdevname); else oz_knl_printk ("oz_knl_diag: error %u creating logical %s\n", tempdevname); while (-- i >= 0) OZ_KNL_PGPFREE (lnmvals[i].buff); goto read_command; } /* Display a file */ if (strcmp (conbuf, "5") == 0) { readcons (sizeof conbuf, conbuf, "Enter disk:file to display > "); oz_knl_printk ("oz_knl_diag: going to display file %s\n", conbuf); /* Assign a channel to the disk drive */ filioch = openfile (conbuf, OZ_LOCKMODE_CR, 1); if (filioch == NULL) goto read_command; /* Read a record from the file */ display_loop: memset (&fs_readrec, 0, sizeof fs_readrec); fs_readrec.size = sizeof filbuf - 1; fs_readrec.buff = filbuf; fs_readrec.trmsize = 1; fs_readrec.trmbuff = trmbuff; fs_readrec.rlen = &rlen; sts = oz_knl_io (filioch, OZ_IO_FS_READREC, sizeof fs_readrec, &fs_readrec); if (sts != OZ_SUCCESS) { if (sts == OZ_ENDOFFILE) oz_knl_printk ("oz_knl_diag: end of input file\n"); else oz_knl_printk ("oz_knl_diag: error %u reading file\n", sts); goto display_done; } filbuf[rlen] = 0; /* Write it to console */ oz_knl_printk ("%s\n", filbuf); goto display_loop; display_done: oz_knl_iochan_increfc (filioch, -1); filioch = NULL; goto read_command; } /* Initialize volume */ if (strcmp (conbuf, "6") == 0) { readcons (sizeof tempdevname, tempdevname, "Enter fs template device name > "); readcons (sizeof diskdevname, diskdevname, "Enter disk device name > "); readcons (sizeof volname, volname, "Enter volume name > "); readcons (sizeof conbuf, conbuf, "Enter cluster factor > "); sts = oz_knl_iochan_crbynm (tempdevname, OZ_LOCKMODE_PW, OZ_PROCMODE_KNL, NULL, &tempiochan); if (sts != OZ_SUCCESS) { oz_knl_printk ("oz_knl_diag: error %u assigning channel to %s\n", sts, tempdevname); goto read_command; } memset (&fs_initvol, 0, sizeof fs_initvol); fs_initvol.devname = diskdevname; fs_initvol.volname = volname; fs_initvol.clusterfactor = oz_hw_atoi (conbuf, NULL); sts = oz_knl_io (tempiochan, OZ_IO_FS_INITVOL, sizeof fs_initvol, &fs_initvol); if (sts == OZ_SUCCESS) oz_knl_printk ("oz_knl_diag: volume initialized\n"); else oz_knl_printk ("oz_knl_diag: error %u initializing volume\n", sts); oz_knl_iochan_increfc (tempiochan, -1); goto read_command; } /* Mount volume */ if (strcmp (conbuf, "7") == 0) { readcons (sizeof tempdevname, tempdevname, "Enter fs template device name > "); readcons (sizeof diskdevname, diskdevname, "Enter disk device name > "); sts = oz_knl_iochan_crbynm (tempdevname, OZ_LOCKMODE_PW, OZ_PROCMODE_KNL, NULL, &tempiochan); if (sts != OZ_SUCCESS) { oz_knl_printk ("oz_knl_diag: error %u assigning channel to %s\n", sts, tempdevname); goto read_command; } memset (&fs_mountvol, 0, sizeof fs_mountvol); fs_mountvol.devname = diskdevname; sts = oz_knl_io (tempiochan, OZ_IO_FS_MOUNTVOL, sizeof fs_mountvol, &fs_mountvol); if (sts != OZ_SUCCESS) { oz_knl_printk ("oz_knl_diag: error %u mounting volume\n", sts); } else { oz_knl_printk ("oz_knl_diag: volume mounted on device %s\n", oz_knl_devunit_devname (oz_knl_iochan_getdevunit (tempiochan))); } oz_knl_iochan_increfc (tempiochan, -1); goto read_command; } /* List Directory */ if (strcmp (conbuf, "8") == 0) { readcons (sizeof filbuf, filbuf, "Enter fs device name:directory > "); tempiochan = openfile (filbuf, OZ_LOCKMODE_CR, 1); if (tempiochan == NULL) goto read_command; p = filbuf + strlen (filbuf); memset (&fs_getinfo3, 0, sizeof fs_getinfo3); sts = oz_knl_io (tempiochan, OZ_IO_FS_GETINFO3, sizeof fs_getinfo3, &fs_getinfo3); if ((sts != OZ_SUCCESS) && (sts != OZ_BADIOFUNC)) { oz_knl_printk ("oz_knl_diag: error %u getting volume info\n"); } if ((sts == OZ_SUCCESS) && (fs_getinfo3.fileidsize != 0) && (fs_getinfo3.fileidstrsz != 0) && (fs_getinfo3.fidtoa != NULL)) { fileidbuff = OZ_KNL_PGPMALLOC (fs_getinfo3.fileidsize); fileidstrbf = OZ_KNL_PGPMALLOC (fs_getinfo3.fileidstrsz); } else { fs_getinfo3.fileidsize = 0; fs_getinfo3.fileidstrsz = 0; fs_getinfo3.fidtoa = NULL; fileidbuff = NULL; fileidstrbf = NULL; } readdir_loop: memset (&fs_readdir, 0, sizeof fs_readdir); fs_readdir.filenamsize = filbuf - p + sizeof filbuf; fs_readdir.filenambuff = p; fs_readdir.fileidsize = fs_getinfo3.fileidsize; fs_readdir.fileidbuff = fileidbuff; sts = oz_knl_io (tempiochan, OZ_IO_FS_READDIR, sizeof fs_readdir, &fs_readdir); if (sts != OZ_SUCCESS) { if (sts == OZ_ENDOFFILE) oz_knl_printk ("oz_knl_diag: end of directory\n"); else oz_knl_printk ("oz_knl_diag: error %u reading directory\n", sts); goto readdir_done; } if (fs_getinfo3.fidtoa == NULL) oz_knl_printk (" %s\n", p); else { (*(fs_getinfo3.fidtoa)) (fileidbuff, fs_getinfo3.fileidstrsz, fileidstrbf); oz_knl_printk (" %s %s\n", p, fileidstrbf); } filioch = openfile (filbuf, OZ_LOCKMODE_NL, 0); if (filioch == NULL) goto readdir_loop; memset (&fs_getinfo1, 0, sizeof fs_getinfo1); sts = oz_knl_io (filioch, OZ_IO_FS_GETINFO1, sizeof fs_getinfo1, &fs_getinfo1); if (sts != OZ_SUCCESS) { oz_knl_printk (" error %u getting info for file %s\n", sts, fs_open.name); oz_knl_iochan_increfc (filioch, -1); p[i] = 0; goto readdir_loop; } oz_knl_printk (" eof: %u.%u all: %u flags: %x\n", fs_getinfo1.eofblock, fs_getinfo1.eofbyte, fs_getinfo1.hiblock, fs_getinfo1.filattrflags); oz_knl_printk (" created: %t\n", fs_getinfo1.create_date); oz_knl_printk (" changed: %t\n", fs_getinfo1.change_date); oz_knl_printk (" accessed: %t\n", fs_getinfo1.access_date); oz_knl_printk (" modified: %t\n", fs_getinfo1.modify_date); oz_knl_iochan_increfc (filioch, -1); goto readdir_loop; readdir_done: oz_knl_iochan_increfc (tempiochan, -1); if (fileidbuff != NULL) OZ_KNL_PGPFREE (fileidbuff); if (fileidstrbf != NULL) OZ_KNL_PGPFREE (fileidstrbf); goto read_command; } /* Create Directory */ if (strcmp (conbuf, "9") == 0) { readcons (sizeof tempdevname, tempdevname, "Enter fs disk:directory > "); tempiochan = createfile (tempdevname, OZ_FS_FILATTRFLAG_DIRECTORY); if (tempiochan != NULL) oz_knl_iochan_increfc (tempiochan, -1); goto read_command; } /* Copy file */ if (strcmp (conbuf, "10") == 0) { readcons (sizeof tempdevname, tempdevname, "From > "); if (tempdevname[0] == 0) goto read_command; tempiochan = openfile (tempdevname, OZ_LOCKMODE_CR, 1); if (tempiochan == NULL) goto read_command; readcons (sizeof diskdevname, diskdevname, "To > "); if (diskdevname[0] == 0) goto copy_doney; filioch = createfile (diskdevname, 0); if (filioch == NULL) goto copy_doney; memset (&fs_readrec, 0, sizeof fs_readrec); fs_readrec.size = sizeof conbuf; fs_readrec.buff = conbuf; fs_readrec.trmsize = 1; fs_readrec.trmbuff = trmbuff; fs_readrec.pmtsize = 1; fs_readrec.pmtbuff = ">"; fs_readrec.rlen = &fs_writerec.size; memset (&fs_writerec, 0, sizeof fs_writerec); fs_writerec.buff = conbuf; fs_writerec.trmbuff = trmbuff; fs_writerec.append = 1; rlen = 0; copy_loop: sts = oz_knl_io (tempiochan, OZ_IO_FS_READREC, sizeof fs_readrec, &fs_readrec); if ((sts != OZ_SUCCESS) && (sts != OZ_NOTERMINATOR)) { if (sts == OZ_ENDOFFILE) oz_knl_printk ("oz_knl_diag: end of input file\n"); else oz_knl_printk ("oz_knl_diag: error %u reading input file\n", sts); goto copy_done; } fs_writerec.trmsize = (sts == OZ_SUCCESS); rlen += fs_writerec.size + fs_writerec.trmsize; sts = oz_knl_io (filioch, OZ_IO_FS_WRITEREC, sizeof fs_writerec, &fs_writerec); if (sts != OZ_SUCCESS) { oz_knl_printk ("oz_knl_diag: error %u writing output file\n", sts); goto copy_done; } goto copy_loop; copy_done: sts = oz_knl_io (filioch, OZ_IO_FS_CLOSE, 0, NULL); if (sts != OZ_SUCCESS) { oz_knl_printk ("oz_knl_diag: error %u closing output file\n", sts); } oz_knl_printk ("oz_knl_diag: %u bytes copied\n", rlen); oz_knl_iochan_increfc (filioch, -1); copy_doney: oz_knl_iochan_increfc (tempiochan, -1); filioch = NULL; tempiochan = NULL; goto read_command; } /* Dismount volume */ if (strcmp (conbuf, "11") == 0) { readcons (sizeof tempdevname, tempdevname, "Enter fs device name > "); sts = oz_knl_iochan_crbynm (tempdevname, OZ_LOCKMODE_PW, OZ_PROCMODE_KNL, NULL, &tempiochan); if (sts != OZ_SUCCESS) { oz_knl_printk ("oz_knl_diag: error %u assigning channel to %s\n", sts, tempdevname); goto read_command; } sts = oz_knl_io (tempiochan, OZ_IO_FS_DISMOUNT, 0, NULL); if (sts == OZ_SUCCESS) oz_knl_printk ("volume dismounted\n"); else oz_knl_printk ("oz_knl_diag: error %u dismounting volume\n", sts); oz_knl_iochan_increfc (tempiochan, -1); goto read_command; } /* Exit */ if (strcmp (conbuf, "12") == 0) { oz_knl_printk ("oz_knl_diag: exiting\n"); oz_hw_cpu_setsoftint (1); return (OZ_SUCCESS); } /* Reboot */ if (strcmp (conbuf, "13") == 0) reboot_thread (NULL); oz_knl_printk ("unknown command code %s\n", conbuf); goto read_command; } /************************************************************************/ /* */ /* This runs as a thread to reboot the computer */ /* */ /************************************************************************/ static uLong reboot_thread (void *dummy) { oz_hw_cpu_setsoftint (0); oz_knl_shutdown (); oz_knl_printk ("oz_knl_diag: rebooting...\n"); oz_hw_stl_microwait (1000000, NULL, NULL); oz_hw_reboot (); return (OZ_BUGCHECK); } /************************************************************************/ /* */ /* Select and assign handle to thread */ /* */ /************************************************************************/ static OZ_Thread *assignthread (int consiz, char *conbuf) { OZ_Process *lastprocess, *process; OZ_Thread *lastthread, *thread; lastprocess = NULL; while (1) { process = oz_knl_process_getnext (lastprocess, NULL); if (lastprocess != NULL) oz_knl_process_increfc (lastprocess, -1); if (process == NULL) break; oz_knl_process_dump (process, 0); lastthread = NULL; while (1) { thread = oz_knl_thread_getnext (lastthread, process); if (lastthread != NULL) oz_knl_thread_increfc (lastthread, -1); if (thread == NULL) break; oz_knl_thread_dump (thread); do { readcons (consiz, conbuf, "yes, [no], quit? "); if (strcmp (conbuf, "quit") == 0) { oz_knl_process_increfc (process, -1); oz_knl_thread_increfc (thread, -1); return (NULL); } if (strcmp (conbuf, "yes") == 0) { oz_knl_process_increfc (process, -1); return (thread); } } while ((strcmp (conbuf, "no") != 0) && (conbuf[0] != 0)); lastthread = thread; } lastprocess = process; } return (NULL); } /************************************************************************/ /* */ /* Utility routines for peek/poke */ /* */ /************************************************************************/ #if defined (OZ_HW_TYPE_486) /* Convert hexadecimal ascii string to binary */ static uLong ztoul (char *b, char **p) { char c; uLong value; while (*b == ' ') b ++; value = 0; while (1) { c = *b; if ((c >= 'a') && (c <= 'f')) c -= 'a' - 'A'; if ((c >= '0') && (c <= '9')) value = value * 16 + c - '0'; else if ((c >= 'A') && (c <= 'F')) value = value * 16 + c - 'A' + 10; else break; b ++; } *p = b; return (value); } static const char *const pptypes[6] = { "MB", "IB", "MW", "IW", "ML", "IL" }; static uLong peek_try (void *ppv) { Pp *pp; uLong pp_data; pp = ppv; oz_knl_printk (" %X %s / ", pp -> addr, pptypes[pp->io+pp->sz*2]); switch (pp -> io + pp -> sz * 2) { case 0: pp_data = *(uByte *)(pp -> addr); break; case 1: pp_data = oz_hw486_inb (pp -> addr); break; case 2: pp_data = *(uWord *)(pp -> addr); break; case 3: pp_data = oz_hw486_inw (pp -> addr); break; case 4: pp_data = *(uLong *)(pp -> addr); break; case 5: pp_data = oz_hw486_inl (pp -> addr); break; } oz_knl_printk ("%*.*X ok\n", 2 << pp -> sz, 2 << pp -> sz, pp_data); return (OZ_SUCCESS); } static uLong poke_try (void *ppv) { Pp *pp; pp = ppv; oz_knl_printk (" %X %s = %*.*X ", pp -> addr, pptypes[pp->io+pp->sz*2], 2 << pp -> sz, 2 << pp -> sz, pp -> data); switch (pp -> io + pp -> sz * 2) { case 0: *(uByte *)(pp -> addr) = pp -> data; break; case 1: oz_hw486_outb (pp -> data, pp -> addr); break; case 2: *(uWord *)(pp -> addr) = pp -> data; break; case 3: oz_hw486_outw (pp -> data, pp -> addr); break; case 4: *(uLong *)(pp -> addr) = pp -> data; break; case 5: oz_hw486_outl (pp -> data, pp -> addr); break; } oz_knl_printk ("ok\n"); return (OZ_SUCCESS); } #endif /************************************************************************/ /* */ /* Read command line from console */ /* */ /************************************************************************/ static void readcons (int size, char *buff, char *prompt) { int hwi; hwi = oz_hw_cpu_sethwints (0); oz_hw_getcon (size, buff, strlen (prompt), prompt); oz_hw_cpu_sethwints (hwi); } /************************************************************************/ /* */ /* Used by thread-level routine to open a file */ /* */ /************************************************************************/ static OZ_Iochan *openfile (char *filename, OZ_Lockmode lockmode, int verbose) { char *p; uLong sts; OZ_IO_fs_open fs_open; OZ_Iochan *iochan; /* Assign a channel to the disk drive */ p = strchr (filename, ':'); if (p == NULL) { oz_knl_printk ("oz_knl_diag: missing : in %s\n", filename); return (NULL); } *p = 0; if (verbose) oz_knl_printk ("oz_knl_diag: assigning channel to device %s\n", filename); sts = oz_knl_iochan_crbynm (filename, OZ_LOCKMODE_CR, OZ_PROCMODE_KNL, NULL, &iochan); if (sts != OZ_SUCCESS) { oz_knl_printk ("oz_knl_diag: error %u assigning channel to %s\n", sts, filename); *(p ++) = ':'; return (NULL); } *(p ++) = ':'; /* Open the file */ memset (&fs_open, 0, sizeof fs_open); fs_open.name = p; fs_open.lockmode = lockmode; if (verbose) oz_knl_printk ("oz_knl_diag: opening file %s\n", fs_open.name); sts = oz_knl_io (iochan, OZ_IO_FS_OPEN, sizeof fs_open, &fs_open); if (sts != OZ_SUCCESS) { oz_knl_printk ("oz_knl_diag: error %u opening file %s\n", sts, p); oz_knl_iochan_increfc (iochan, -1); return (NULL); } if (verbose) oz_knl_printk ("oz_knl_diag: open complete\n"); return (iochan); } static OZ_Iochan *createfile (char *filename, uLong filattrflags) { char *p; uLong sts; OZ_IO_fs_create fs_create; OZ_Iochan *iochan; /* Assign a channel to the disk drive */ p = strchr (filename, ':'); if (p == NULL) { oz_knl_printk ("oz_knl_diag: missing : in %s\n", filename); return (NULL); } *p = 0; oz_knl_printk ("oz_knl_diag: assigning channel to device %s\n", filename); sts = oz_knl_iochan_crbynm (filename, OZ_LOCKMODE_CW, OZ_PROCMODE_KNL, NULL, &iochan); if (sts != OZ_SUCCESS) { oz_knl_printk ("oz_knl_diag: error %u assigning channel to %s\n", sts, filename); *(p ++) = ':'; return (NULL); } *(p ++) = ':'; /* Create the file */ memset (&fs_create, 0, sizeof fs_create); fs_create.name = p; fs_create.lockmode = OZ_LOCKMODE_CW; fs_create.filattrflags = filattrflags; oz_knl_printk ("oz_knl_diag: creating file %s\n", fs_create.name); sts = oz_knl_io (iochan, OZ_IO_FS_CREATE, sizeof fs_create, &fs_create); if (sts != OZ_SUCCESS) { oz_knl_printk ("oz_knl_diag: error %u creating file %s\n", sts, p); oz_knl_iochan_increfc (iochan, -1); return (NULL); } oz_knl_printk ("oz_knl_diag: create complete\n"); return (iochan); } /************************************************************************/ /* */ /* This is used by the run command - it is the thread that loads and */ /* runs the image */ /* */ /* Note that the thread_init routine runs in user mode */ /* */ /************************************************************************/ static uLong getimagename (OZ_Procmode cprocmode, void *uimagename); static uLong dumpthreadstuff (OZ_Procmode cprocmode, void *baseaddr); static uLong thread_init (void *dummy) { char uimagename[64]; uLong exsts, sts; OZ_Handle h_image; uLong (*entrypoint) (void *dummy); void *baseaddr, *startaddr; sts = oz_sys_callknl (getimagename, uimagename); if (sts != OZ_SUCCESS) { oz_sys_printkp (0, "oz_knl_diag thread_init: error %u getting imagename to %p\n", sts, uimagename); return (sts); } oz_sys_printkp (0, "oz_knl_diag thread_init: loading image %s ...\n", uimagename); sts = oz_sys_image_load (OZ_PROCMODE_KNL, uimagename, 0, &baseaddr, &startaddr, &h_image); if (sts != OZ_SUCCESS) { oz_sys_printkp (0, "oz_knl_diag thread_init: error %u loading image %s\n", sts, uimagename); return (sts); } oz_sys_printkp (0, "oz_knl_diag thread_init: image loaded at address %p, handle %x\n", baseaddr, h_image); oz_sys_printkp (0, "oz_knl_diag thread_init: entrypoint at %p (%X)\n", startaddr, *(uLong *)startaddr); oz_sys_callknl (dumpthreadstuff, baseaddr); oz_sys_callknl (dumpthreadstuff, startaddr); #if 000 oz_sys_printkp (0, "oz_knl_diag thread_init: starting debugger\n"); exsts = oz_usr_debug_init (startaddr, NULL); #else entrypoint = startaddr; oz_sys_printkp (0, "oz_knl_diag thread_init: calling entrypoint %p\n", entrypoint); exsts = (*entrypoint) (NULL); #endif oz_sys_printkp (0, "oz_knl_diag thread_init: - routine returned status %u\n", exsts); oz_sys_printkp (0, "oz_knl_diag thread_init: unloading image ...\n"); sts = oz_sys_handle_release (OZ_PROCMODE_KNL, h_image); oz_sys_printkp (0, "oz_knl_diag thread_init: - unload status %u\n", sts); return (exsts); } static uLong getimagename (OZ_Procmode cprocmode, void *uimagename) { memcpy (uimagename, imagename, 64); return (OZ_SUCCESS); } static uLong dumpthreadstuff (OZ_Procmode cprocmode, void *baseaddr) { int si; si = oz_hw_cpu_setsoftint (0); oz_hw_pte_print (baseaddr); if (OZ_HW_READABLE (32, baseaddr, cprocmode)) oz_knl_dumpmem (32, baseaddr); else oz_knl_printk ("oz_knl_diag thread_init: ... not readable\n"); oz_hw_cpu_setsoftint (si); return (OZ_SUCCESS); } /************************************************************************/ /* */ /* Halt the cpu so it looks like it was never here */ /* */ /************************************************************************/ oz_knl_halt () { Long cpuidx; cpuidx = oz_hw_cpu_getcur (); oz_knl_printk ("oz_knl_halt: cpu %d halting (%X)\n", cpuidx, oz_hw_cpu_smplevel ()); // print a message oz_hw_atomic_and_long (&oz_s_cpusavail, ~(1 << cpuidx)); // say I'm no longer available for anything oz_hw_halt (); // call the hardware layer halt routine }