Initial Spring 2016 commit.
This commit is contained in:
216
kern/main/main.c
Normal file
216
kern/main/main.c
Normal file
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
|
||||
* The President and Fellows of Harvard College.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Main.
|
||||
*/
|
||||
|
||||
#include <types.h>
|
||||
#include <kern/errno.h>
|
||||
#include <kern/reboot.h>
|
||||
#include <kern/unistd.h>
|
||||
#include <lib.h>
|
||||
#include <spl.h>
|
||||
#include <clock.h>
|
||||
#include <thread.h>
|
||||
#include <proc.h>
|
||||
#include <current.h>
|
||||
#include <synch.h>
|
||||
#include <vm.h>
|
||||
#include <mainbus.h>
|
||||
#include <vfs.h>
|
||||
#include <device.h>
|
||||
#include <syscall.h>
|
||||
#include <test.h>
|
||||
#include <version.h>
|
||||
#include "autoconf.h" // for pseudoconfig
|
||||
|
||||
|
||||
/*
|
||||
* These two pieces of data are maintained by the makefiles and build system.
|
||||
* buildconfig is the name of the config file the kernel was configured with.
|
||||
* buildversion starts at 1 and is incremented every time you link a kernel.
|
||||
*
|
||||
* The purpose is not to show off how many kernels you've linked, but
|
||||
* to make it easy to make sure that the kernel you just booted is the
|
||||
* same one you just built.
|
||||
*/
|
||||
extern const int buildversion;
|
||||
extern const char buildconfig[];
|
||||
|
||||
/*
|
||||
* Copyright message for the OS/161 base code.
|
||||
*/
|
||||
static const char harvard_copyright[] =
|
||||
"Copyright (c) 2000, 2001-2005, 2008-2011, 2013, 2014\n"
|
||||
" President and Fellows of Harvard College. All rights reserved.\n";
|
||||
|
||||
|
||||
/*
|
||||
* Initial boot sequence.
|
||||
*/
|
||||
static
|
||||
void
|
||||
boot(void)
|
||||
{
|
||||
/*
|
||||
* The order of these is important!
|
||||
* Don't go changing it without thinking about the consequences.
|
||||
*
|
||||
* Among other things, be aware that console output gets
|
||||
* buffered up at first and does not actually appear until
|
||||
* mainbus_bootstrap() attaches the console device. This can
|
||||
* be remarkably confusing if a bug occurs at this point. So
|
||||
* don't put new code before mainbus_bootstrap if you don't
|
||||
* absolutely have to.
|
||||
*
|
||||
* Also note that the buffer for this is only 1k. If you
|
||||
* overflow it, the system will crash without printing
|
||||
* anything at all. You can make it larger though (it's in
|
||||
* dev/generic/console.c).
|
||||
*/
|
||||
|
||||
kprintf("\n");
|
||||
kprintf("OS/161 base system version %s\n", BASE_VERSION);
|
||||
kprintf("%s", harvard_copyright);
|
||||
kprintf("\n");
|
||||
|
||||
kprintf("Put-your-group-name-here's system version %s (%s #%d)\n",
|
||||
GROUP_VERSION, buildconfig, buildversion);
|
||||
kprintf("\n");
|
||||
|
||||
/* Early initialization. */
|
||||
ram_bootstrap();
|
||||
proc_bootstrap();
|
||||
thread_bootstrap();
|
||||
hardclock_bootstrap();
|
||||
vfs_bootstrap();
|
||||
kheap_nextgeneration();
|
||||
|
||||
/* Probe and initialize devices. Interrupts should come on. */
|
||||
kprintf("Device probe...\n");
|
||||
KASSERT(curthread->t_curspl > 0);
|
||||
mainbus_bootstrap();
|
||||
KASSERT(curthread->t_curspl == 0);
|
||||
/* Now do pseudo-devices. */
|
||||
pseudoconfig();
|
||||
kprintf("\n");
|
||||
kheap_nextgeneration();
|
||||
|
||||
/* Late phase of initialization. */
|
||||
vm_bootstrap();
|
||||
kprintf_bootstrap();
|
||||
thread_start_cpus();
|
||||
|
||||
/* Default bootfs - but ignore failure, in case emu0 doesn't exist */
|
||||
vfs_setbootfs("emu0");
|
||||
|
||||
kheap_nextgeneration();
|
||||
|
||||
/*
|
||||
* Make sure various things aren't screwed up.
|
||||
*/
|
||||
COMPILE_ASSERT(sizeof(userptr_t) == sizeof(char *));
|
||||
COMPILE_ASSERT(sizeof(*(userptr_t)0) == sizeof(char));
|
||||
}
|
||||
|
||||
/*
|
||||
* Shutdown sequence. Opposite to boot().
|
||||
*/
|
||||
static
|
||||
void
|
||||
shutdown(void)
|
||||
{
|
||||
|
||||
kprintf("Shutting down.\n");
|
||||
|
||||
vfs_clearbootfs();
|
||||
vfs_clearcurdir();
|
||||
vfs_unmountall();
|
||||
|
||||
thread_shutdown();
|
||||
|
||||
splhigh();
|
||||
}
|
||||
|
||||
/*****************************************/
|
||||
|
||||
/*
|
||||
* reboot() system call.
|
||||
*
|
||||
* Note: this is here because it's directly related to the code above,
|
||||
* not because this is where system call code should go. Other syscall
|
||||
* code should probably live in the "syscall" directory.
|
||||
*/
|
||||
int
|
||||
sys_reboot(int code)
|
||||
{
|
||||
switch (code) {
|
||||
case RB_REBOOT:
|
||||
case RB_HALT:
|
||||
case RB_POWEROFF:
|
||||
break;
|
||||
default:
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
shutdown();
|
||||
|
||||
switch (code) {
|
||||
case RB_HALT:
|
||||
kprintf("The system is halted.\n");
|
||||
mainbus_halt();
|
||||
break;
|
||||
case RB_REBOOT:
|
||||
kprintf("Rebooting...\n");
|
||||
mainbus_reboot();
|
||||
break;
|
||||
case RB_POWEROFF:
|
||||
kprintf("The system is halted.\n");
|
||||
mainbus_poweroff();
|
||||
break;
|
||||
}
|
||||
|
||||
panic("reboot operation failed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Kernel main. Boot up, then fork the menu thread; wait for a reboot
|
||||
* request, and then shut down.
|
||||
*/
|
||||
void
|
||||
kmain(char *arguments)
|
||||
{
|
||||
boot();
|
||||
|
||||
menu(arguments);
|
||||
|
||||
/* Should not get here */
|
||||
}
|
731
kern/main/menu.c
Normal file
731
kern/main/menu.c
Normal file
@@ -0,0 +1,731 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
|
||||
* The President and Fellows of Harvard College.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <types.h>
|
||||
#include <kern/errno.h>
|
||||
#include <kern/reboot.h>
|
||||
#include <kern/unistd.h>
|
||||
#include <limits.h>
|
||||
#include <lib.h>
|
||||
#include <uio.h>
|
||||
#include <clock.h>
|
||||
#include <thread.h>
|
||||
#include <proc.h>
|
||||
#include <vfs.h>
|
||||
#include <sfs.h>
|
||||
#include <syscall.h>
|
||||
#include <test.h>
|
||||
#include "opt-sfs.h"
|
||||
#include "opt-net.h"
|
||||
|
||||
/*
|
||||
* In-kernel menu and command dispatcher.
|
||||
*/
|
||||
|
||||
#define _PATH_SHELL "/bin/sh"
|
||||
|
||||
#define MAXMENUARGS 16
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Command menu functions
|
||||
|
||||
/*
|
||||
* Function for a thread that runs an arbitrary userlevel program by
|
||||
* name.
|
||||
*
|
||||
* Note: this cannot pass arguments to the program. You may wish to
|
||||
* change it so it can, because that will make testing much easier
|
||||
* in the future.
|
||||
*
|
||||
* It copies the program name because runprogram destroys the copy
|
||||
* it gets by passing it to vfs_open().
|
||||
*/
|
||||
static
|
||||
void
|
||||
cmd_progthread(void *ptr, unsigned long nargs)
|
||||
{
|
||||
char **args = ptr;
|
||||
char progname[128];
|
||||
int result;
|
||||
|
||||
KASSERT(nargs >= 1);
|
||||
|
||||
if (nargs > 2) {
|
||||
kprintf("Warning: argument passing from menu not supported\n");
|
||||
}
|
||||
|
||||
/* Hope we fit. */
|
||||
KASSERT(strlen(args[0]) < sizeof(progname));
|
||||
|
||||
strcpy(progname, args[0]);
|
||||
|
||||
result = runprogram(progname);
|
||||
if (result) {
|
||||
kprintf("Running program %s failed: %s\n", args[0],
|
||||
strerror(result));
|
||||
return;
|
||||
}
|
||||
|
||||
/* NOTREACHED: runprogram only returns on error. */
|
||||
}
|
||||
|
||||
/*
|
||||
* Common code for cmd_prog and cmd_shell.
|
||||
*
|
||||
* Note that this does not wait for the subprogram to finish, but
|
||||
* returns immediately to the menu. This is usually not what you want,
|
||||
* so you should have it call your system-calls-assignment waitpid
|
||||
* code after forking.
|
||||
*
|
||||
* Also note that because the subprogram's thread uses the "args"
|
||||
* array and strings, until you do this a race condition exists
|
||||
* between that code and the menu input code.
|
||||
*/
|
||||
static
|
||||
int
|
||||
common_prog(int nargs, char **args)
|
||||
{
|
||||
struct proc *proc;
|
||||
int result;
|
||||
|
||||
/* Create a process for the new program to run in. */
|
||||
proc = proc_create_runprogram(args[0] /* name */);
|
||||
if (proc == NULL) {
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
result = thread_fork(args[0] /* thread name */,
|
||||
proc /* new process */,
|
||||
cmd_progthread /* thread function */,
|
||||
args /* thread arg */, nargs /* thread arg */);
|
||||
if (result) {
|
||||
kprintf("thread_fork failed: %s\n", strerror(result));
|
||||
proc_destroy(proc);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* The new process will be destroyed when the program exits...
|
||||
* once you write the code for handling that.
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Command for running an arbitrary userlevel program.
|
||||
*/
|
||||
static
|
||||
int
|
||||
cmd_prog(int nargs, char **args)
|
||||
{
|
||||
if (nargs < 2) {
|
||||
kprintf("Usage: p program [arguments]\n");
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
/* drop the leading "p" */
|
||||
args++;
|
||||
nargs--;
|
||||
|
||||
return common_prog(nargs, args);
|
||||
}
|
||||
|
||||
/*
|
||||
* Command for starting the system shell.
|
||||
*/
|
||||
static
|
||||
int
|
||||
cmd_shell(int nargs, char **args)
|
||||
{
|
||||
(void)args;
|
||||
if (nargs != 1) {
|
||||
kprintf("Usage: s\n");
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
args[0] = (char *)_PATH_SHELL;
|
||||
|
||||
return common_prog(nargs, args);
|
||||
}
|
||||
|
||||
/*
|
||||
* Command for changing directory.
|
||||
*/
|
||||
static
|
||||
int
|
||||
cmd_chdir(int nargs, char **args)
|
||||
{
|
||||
if (nargs != 2) {
|
||||
kprintf("Usage: cd directory\n");
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
return vfs_chdir(args[1]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Command for printing the current directory.
|
||||
*/
|
||||
static
|
||||
int
|
||||
cmd_pwd(int nargs, char **args)
|
||||
{
|
||||
char buf[PATH_MAX+1];
|
||||
int result;
|
||||
struct iovec iov;
|
||||
struct uio ku;
|
||||
|
||||
(void)nargs;
|
||||
(void)args;
|
||||
|
||||
uio_kinit(&iov, &ku, buf, sizeof(buf)-1, 0, UIO_READ);
|
||||
result = vfs_getcwd(&ku);
|
||||
if (result) {
|
||||
kprintf("vfs_getcwd failed (%s)\n", strerror(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
/* null terminate */
|
||||
buf[sizeof(buf)-1-ku.uio_resid] = 0;
|
||||
|
||||
/* print it */
|
||||
kprintf("%s\n", buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Command for running sync.
|
||||
*/
|
||||
static
|
||||
int
|
||||
cmd_sync(int nargs, char **args)
|
||||
{
|
||||
(void)nargs;
|
||||
(void)args;
|
||||
|
||||
vfs_sync();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Command for doing an intentional panic.
|
||||
*/
|
||||
static
|
||||
int
|
||||
cmd_panic(int nargs, char **args)
|
||||
{
|
||||
(void)nargs;
|
||||
(void)args;
|
||||
|
||||
panic("User requested panic\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Command for shutting down.
|
||||
*/
|
||||
static
|
||||
int
|
||||
cmd_quit(int nargs, char **args)
|
||||
{
|
||||
(void)nargs;
|
||||
(void)args;
|
||||
|
||||
vfs_sync();
|
||||
sys_reboot(RB_POWEROFF);
|
||||
thread_exit();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Command for mounting a filesystem.
|
||||
*/
|
||||
|
||||
/* Table of mountable filesystem types. */
|
||||
static const struct {
|
||||
const char *name;
|
||||
int (*func)(const char *device);
|
||||
} mounttable[] = {
|
||||
#if OPT_SFS
|
||||
{ "sfs", sfs_mount },
|
||||
#endif
|
||||
};
|
||||
|
||||
static
|
||||
int
|
||||
cmd_mount(int nargs, char **args)
|
||||
{
|
||||
char *fstype;
|
||||
char *device;
|
||||
unsigned i;
|
||||
|
||||
if (nargs != 3) {
|
||||
kprintf("Usage: mount fstype device:\n");
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
fstype = args[1];
|
||||
device = args[2];
|
||||
|
||||
/* Allow (but do not require) colon after device name */
|
||||
if (device[strlen(device)-1]==':') {
|
||||
device[strlen(device)-1] = 0;
|
||||
}
|
||||
|
||||
for (i=0; i<ARRAYCOUNT(mounttable); i++) {
|
||||
if (!strcmp(mounttable[i].name, fstype)) {
|
||||
return mounttable[i].func(device);
|
||||
}
|
||||
}
|
||||
kprintf("Unknown filesystem type %s\n", fstype);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
cmd_unmount(int nargs, char **args)
|
||||
{
|
||||
char *device;
|
||||
|
||||
if (nargs != 2) {
|
||||
kprintf("Usage: unmount device:\n");
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
device = args[1];
|
||||
|
||||
/* Allow (but do not require) colon after device name */
|
||||
if (device[strlen(device)-1]==':') {
|
||||
device[strlen(device)-1] = 0;
|
||||
}
|
||||
|
||||
return vfs_unmount(device);
|
||||
}
|
||||
|
||||
/*
|
||||
* Command to set the "boot fs".
|
||||
*
|
||||
* The boot filesystem is the one that pathnames like /bin/sh with
|
||||
* leading slashes refer to.
|
||||
*
|
||||
* The default bootfs is "emu0".
|
||||
*/
|
||||
static
|
||||
int
|
||||
cmd_bootfs(int nargs, char **args)
|
||||
{
|
||||
char *device;
|
||||
|
||||
if (nargs != 2) {
|
||||
kprintf("Usage: bootfs device\n");
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
device = args[1];
|
||||
|
||||
/* Allow (but do not require) colon after device name */
|
||||
if (device[strlen(device)-1]==':') {
|
||||
device[strlen(device)-1] = 0;
|
||||
}
|
||||
|
||||
return vfs_setbootfs(device);
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
cmd_kheapstats(int nargs, char **args)
|
||||
{
|
||||
(void)nargs;
|
||||
(void)args;
|
||||
|
||||
kheap_printstats();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
cmd_kheapgeneration(int nargs, char **args)
|
||||
{
|
||||
(void)nargs;
|
||||
(void)args;
|
||||
|
||||
kheap_nextgeneration();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
cmd_kheapdump(int nargs, char **args)
|
||||
{
|
||||
if (nargs == 1) {
|
||||
kheap_dump();
|
||||
}
|
||||
else if (nargs == 2 && !strcmp(args[1], "all")) {
|
||||
kheap_dumpall();
|
||||
}
|
||||
else {
|
||||
kprintf("Usage: khdump [all]\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
//
|
||||
// Menus.
|
||||
|
||||
static
|
||||
void
|
||||
showmenu(const char *name, const char *x[])
|
||||
{
|
||||
int ct, half, i;
|
||||
|
||||
kprintf("\n");
|
||||
kprintf("%s\n", name);
|
||||
|
||||
for (i=ct=0; x[i]; i++) {
|
||||
ct++;
|
||||
}
|
||||
half = (ct+1)/2;
|
||||
|
||||
for (i=0; i<half; i++) {
|
||||
kprintf(" %-36s", x[i]);
|
||||
if (i+half < ct) {
|
||||
kprintf("%s", x[i+half]);
|
||||
}
|
||||
kprintf("\n");
|
||||
}
|
||||
|
||||
kprintf("\n");
|
||||
}
|
||||
|
||||
static const char *opsmenu[] = {
|
||||
"[s] Shell ",
|
||||
"[p] Other program ",
|
||||
"[mount] Mount a filesystem ",
|
||||
"[unmount] Unmount a filesystem ",
|
||||
"[bootfs] Set \"boot\" filesystem ",
|
||||
"[pf] Print a file ",
|
||||
"[cd] Change directory ",
|
||||
"[pwd] Print current directory ",
|
||||
"[sync] Sync filesystems ",
|
||||
"[panic] Intentional panic ",
|
||||
"[q] Quit and shut down ",
|
||||
NULL
|
||||
};
|
||||
|
||||
static
|
||||
int
|
||||
cmd_opsmenu(int n, char **a)
|
||||
{
|
||||
(void)n;
|
||||
(void)a;
|
||||
|
||||
showmenu("OS/161 operations menu", opsmenu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *testmenu[] = {
|
||||
"[at] Array test ",
|
||||
"[at2] Large array test ",
|
||||
"[bt] Bitmap test ",
|
||||
"[tlt] Threadlist test ",
|
||||
"[km1] Kernel malloc test ",
|
||||
"[km2] kmalloc stress test ",
|
||||
"[km3] Large kmalloc test ",
|
||||
"[km4] Multipage kmalloc test ",
|
||||
"[tt1] Thread test 1 ",
|
||||
"[tt2] Thread test 2 ",
|
||||
"[tt3] Thread test 3 ",
|
||||
#if OPT_NET
|
||||
"[net] Network test ",
|
||||
#endif
|
||||
"[sy1] Semaphore test ",
|
||||
"[sy2] Lock test (1) ",
|
||||
"[sy3] CV test (1) ",
|
||||
"[sy4] CV test #2 (1) ",
|
||||
"[semu1-22] Semaphore unit tests ",
|
||||
"[fs1] Filesystem test ",
|
||||
"[fs2] FS read stress ",
|
||||
"[fs3] FS write stress ",
|
||||
"[fs4] FS write stress 2 ",
|
||||
"[fs5] FS long stress ",
|
||||
"[fs6] FS create stress ",
|
||||
NULL
|
||||
};
|
||||
|
||||
static
|
||||
int
|
||||
cmd_testmenu(int n, char **a)
|
||||
{
|
||||
(void)n;
|
||||
(void)a;
|
||||
|
||||
showmenu("OS/161 tests menu", testmenu);
|
||||
kprintf(" (1) These tests will fail until you finish the "
|
||||
"synch assignment.\n");
|
||||
kprintf("\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *mainmenu[] = {
|
||||
"[?o] Operations menu ",
|
||||
"[?t] Tests menu ",
|
||||
"[kh] Kernel heap stats ",
|
||||
"[khgen] Next kernel heap generation ",
|
||||
"[khdump] Dump kernel heap ",
|
||||
"[q] Quit and shut down ",
|
||||
NULL
|
||||
};
|
||||
|
||||
static
|
||||
int
|
||||
cmd_mainmenu(int n, char **a)
|
||||
{
|
||||
(void)n;
|
||||
(void)a;
|
||||
|
||||
showmenu("OS/161 kernel menu", mainmenu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
//
|
||||
// Command table.
|
||||
|
||||
static struct {
|
||||
const char *name;
|
||||
int (*func)(int nargs, char **args);
|
||||
} cmdtable[] = {
|
||||
/* menus */
|
||||
{ "?", cmd_mainmenu },
|
||||
{ "h", cmd_mainmenu },
|
||||
{ "help", cmd_mainmenu },
|
||||
{ "?o", cmd_opsmenu },
|
||||
{ "?t", cmd_testmenu },
|
||||
|
||||
/* operations */
|
||||
{ "s", cmd_shell },
|
||||
{ "p", cmd_prog },
|
||||
{ "mount", cmd_mount },
|
||||
{ "unmount", cmd_unmount },
|
||||
{ "bootfs", cmd_bootfs },
|
||||
{ "pf", printfile },
|
||||
{ "cd", cmd_chdir },
|
||||
{ "pwd", cmd_pwd },
|
||||
{ "sync", cmd_sync },
|
||||
{ "panic", cmd_panic },
|
||||
{ "q", cmd_quit },
|
||||
{ "exit", cmd_quit },
|
||||
{ "halt", cmd_quit },
|
||||
|
||||
/* stats */
|
||||
{ "kh", cmd_kheapstats },
|
||||
{ "khgen", cmd_kheapgeneration },
|
||||
{ "khdump", cmd_kheapdump },
|
||||
|
||||
/* base system tests */
|
||||
{ "at", arraytest },
|
||||
{ "at2", arraytest2 },
|
||||
{ "bt", bitmaptest },
|
||||
{ "tlt", threadlisttest },
|
||||
{ "km1", kmalloctest },
|
||||
{ "km2", kmallocstress },
|
||||
{ "km3", kmalloctest3 },
|
||||
{ "km4", kmalloctest4 },
|
||||
#if OPT_NET
|
||||
{ "net", nettest },
|
||||
#endif
|
||||
{ "tt1", threadtest },
|
||||
{ "tt2", threadtest2 },
|
||||
{ "tt3", threadtest3 },
|
||||
{ "sy1", semtest },
|
||||
|
||||
/* synchronization assignment tests */
|
||||
{ "sy2", locktest },
|
||||
{ "sy3", cvtest },
|
||||
{ "sy4", cvtest2 },
|
||||
|
||||
/* semaphore unit tests */
|
||||
{ "semu1", semu1 },
|
||||
{ "semu2", semu2 },
|
||||
{ "semu3", semu3 },
|
||||
{ "semu4", semu4 },
|
||||
{ "semu5", semu5 },
|
||||
{ "semu6", semu6 },
|
||||
{ "semu7", semu7 },
|
||||
{ "semu8", semu8 },
|
||||
{ "semu9", semu9 },
|
||||
{ "semu10", semu10 },
|
||||
{ "semu11", semu11 },
|
||||
{ "semu12", semu12 },
|
||||
{ "semu13", semu13 },
|
||||
{ "semu14", semu14 },
|
||||
{ "semu15", semu15 },
|
||||
{ "semu16", semu16 },
|
||||
{ "semu17", semu17 },
|
||||
{ "semu18", semu18 },
|
||||
{ "semu19", semu19 },
|
||||
{ "semu20", semu20 },
|
||||
{ "semu21", semu21 },
|
||||
{ "semu22", semu22 },
|
||||
|
||||
/* file system assignment tests */
|
||||
{ "fs1", fstest },
|
||||
{ "fs2", readstress },
|
||||
{ "fs3", writestress },
|
||||
{ "fs4", writestress2 },
|
||||
{ "fs5", longstress },
|
||||
{ "fs6", createstress },
|
||||
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
/*
|
||||
* Process a single command.
|
||||
*/
|
||||
static
|
||||
int
|
||||
cmd_dispatch(char *cmd)
|
||||
{
|
||||
struct timespec before, after, duration;
|
||||
char *args[MAXMENUARGS];
|
||||
int nargs=0;
|
||||
char *word;
|
||||
char *context;
|
||||
int i, result;
|
||||
|
||||
for (word = strtok_r(cmd, " \t", &context);
|
||||
word != NULL;
|
||||
word = strtok_r(NULL, " \t", &context)) {
|
||||
|
||||
if (nargs >= MAXMENUARGS) {
|
||||
kprintf("Command line has too many words\n");
|
||||
return E2BIG;
|
||||
}
|
||||
args[nargs++] = word;
|
||||
}
|
||||
|
||||
if (nargs==0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i=0; cmdtable[i].name; i++) {
|
||||
if (*cmdtable[i].name && !strcmp(args[0], cmdtable[i].name)) {
|
||||
KASSERT(cmdtable[i].func!=NULL);
|
||||
|
||||
gettime(&before);
|
||||
|
||||
result = cmdtable[i].func(nargs, args);
|
||||
|
||||
gettime(&after);
|
||||
timespec_sub(&after, &before, &duration);
|
||||
|
||||
kprintf("Operation took %llu.%09lu seconds\n",
|
||||
(unsigned long long) duration.tv_sec,
|
||||
(unsigned long) duration.tv_nsec);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
kprintf("%s: Command not found\n", args[0]);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Evaluate a command line that may contain multiple semicolon-delimited
|
||||
* commands.
|
||||
*
|
||||
* If "isargs" is set, we're doing command-line processing; print the
|
||||
* comamnds as we execute them and panic if the command is invalid or fails.
|
||||
*/
|
||||
static
|
||||
void
|
||||
menu_execute(char *line, int isargs)
|
||||
{
|
||||
char *command;
|
||||
char *context;
|
||||
int result;
|
||||
|
||||
for (command = strtok_r(line, ";", &context);
|
||||
command != NULL;
|
||||
command = strtok_r(NULL, ";", &context)) {
|
||||
|
||||
if (isargs) {
|
||||
kprintf("OS/161 kernel: %s\n", command);
|
||||
}
|
||||
|
||||
result = cmd_dispatch(command);
|
||||
if (result) {
|
||||
kprintf("Menu command failed: %s\n", strerror(result));
|
||||
if (isargs) {
|
||||
panic("Failure processing kernel arguments\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Command menu main loop.
|
||||
*
|
||||
* First, handle arguments passed on the kernel's command line from
|
||||
* the bootloader. Then loop prompting for commands.
|
||||
*
|
||||
* The line passed in from the bootloader is treated as if it had been
|
||||
* typed at the prompt. Semicolons separate commands; spaces and tabs
|
||||
* separate words (command names and arguments).
|
||||
*
|
||||
* So, for instance, to mount an SFS on lhd0 and make it the boot
|
||||
* filesystem, and then boot directly into the shell, one would use
|
||||
* the kernel command line
|
||||
*
|
||||
* "mount sfs lhd0; bootfs lhd0; s"
|
||||
*/
|
||||
|
||||
void
|
||||
menu(char *args)
|
||||
{
|
||||
char buf[64];
|
||||
|
||||
menu_execute(args, 1);
|
||||
|
||||
while (1) {
|
||||
kprintf("OS/161 kernel [? for menu]: ");
|
||||
kgets(buf, sizeof(buf));
|
||||
menu_execute(buf, 0);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user