blob: a5d57664241945324fbf010499b31a93ecada5ba [file] [log] [blame] [edit]
/*
* Copyright (c) 2009 The Regents of the University of California
* Barret Rhoden <brho@cs.berkeley.edu>
* See LICENSE for details.
*/
#include <ros/common.h>
#include <smp.h>
#include <arch/init.h>
#include <mm.h>
#include <elf.h>
#include <kmalloc.h>
#include <assert.h>
#include <manager.h>
#include <process.h>
#include <schedule.h>
#include <syscall.h>
#include <ktest.h>
#include <stdio.h>
#include <time.h>
#include <monitor.h>
#include <string.h>
#include <pmap.h>
#include <arch/console.h>
#include <time.h>
/*
* Currently, if you leave this function by way of proc_run (process_workqueue
* that proc_runs), you will never come back to where you left off, and the
* function will start from the top. Hence the hack 'progress'.
*/
void manager(void)
{
// LoL
#define MANAGER_FUNC(dev) PASTE(manager_,dev)
#if !defined(DEVELOPER_NAME) && \
(defined(CONFIG_KERNEL_TESTING) || \
defined(CONFIG_USERSPACE_TESTING))
#define DEVELOPER_NAME jenkins
#endif
#ifndef DEVELOPER_NAME
#define DEVELOPER_NAME brho
#endif
void MANAGER_FUNC(DEVELOPER_NAME)(void);
MANAGER_FUNC(DEVELOPER_NAME)();
}
char *p_argv[] = {0, 0, 0};
/* Helper macro for quickly running a process. Pass it a string, *file, and a
* *proc. */
#define quick_proc_run(x, p, f) \
(f) = do_file_open((x), O_READ, 0); \
assert((f)); \
p_argv[0] = file_name((f)); \
(p) = proc_create((f), p_argv, NULL); \
kref_put(&(f)->f_kref); \
spin_lock(&(p)->proc_lock); \
__proc_set_state((p), PROC_RUNNABLE_S); \
spin_unlock(&(p)->proc_lock); \
proc_run_s((p)); \
proc_decref((p));
#define quick_proc_create(x, p, f) \
(f) = do_file_open((x), O_READ, 0); \
assert((f)); \
p_argv[0] = file_name((f)); \
(p) = proc_create((f), p_argv, NULL); \
kref_put(&(f)->f_kref); \
spin_lock(&(p)->proc_lock); \
__proc_set_state((p), PROC_RUNNABLE_S); \
spin_unlock(&(p)->proc_lock);
#define quick_proc_color_run(x, p, c, f) \
(f) = do_file_open((x), O_READ, 0); \
assert((f)); \
p_argv[0] = file_name((f)); \
(p) = proc_create((f), p_argv, NULL); \
kref_put(&(f)->f_kref); \
spin_lock(&(p)->proc_lock); \
__proc_set_state((p), PROC_RUNNABLE_S); \
spin_unlock(&(p)->proc_lock); \
p->cache_colors_map = cache_colors_map_alloc(); \
for (int i = 0; i < (c); i++) \
cache_color_alloc(llc_cache, p->cache_colors_map); \
proc_run_s((p)); \
proc_decref((p));
#define quick_proc_color_create(x, p, c, f) \
(f) = do_file_open((x), O_READ, 0); \
assert((f)); \
p_argv[0] = file_name((f)); \
(p) = proc_create((f), p_argv, NULL); \
kref_put(&(f)->f_kref); \
spin_lock(&(p)->proc_lock); \
__proc_set_state((p), PROC_RUNNABLE_S); \
spin_unlock(&(p)->proc_lock); \
p->cache_colors_map = cache_colors_map_alloc(); \
for (int i = 0; i < (c); i++) \
cache_color_alloc(llc_cache, p->cache_colors_map);
void manager_brho(void)
{
static bool first = TRUE;
struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
if (first) {
printk("*** IRQs must be enabled for input emergency codes ***\n");
#ifdef CONFIG_X86
printk("*** Hit ctrl-g to enter the monitor. ***\n");
printk("*** Hit ctrl-q to force-enter the monitor. ***\n");
printk("*** Hit ctrl-b for a backtrace of core 0 ***\n");
#else
printk("*** Hit ctrl-g to enter the monitor. ***\n");
#warning "***** ctrl-g untested on riscv, check k/a/r/trap.c *****"
#endif
first = FALSE;
}
/* just idle, and deal with things via interrupts. or via face. */
smp_idle();
/* whatever we do in the manager, keep in mind that we need to not do
* anything too soon (like make processes), since we'll drop in here during
* boot if the boot sequence required any I/O (like EXT2), and we need to
* PRKM() */
assert(0);
#if 0 /* ancient tests below: (keeping around til we ditch the manager) */
// for testing taking cores, check in case 1 for usage
uint32_t corelist[MAX_NUM_CORES];
uint32_t num = 3;
struct file *temp_f;
static struct proc *p;
static uint8_t RACY progress = 0; /* this will wrap around. */
switch (progress++) {
case 0:
printk("Top of the manager to ya!\n");
/* 124 is half of the available boxboro colors (with the kernel
* getting 8) */
//quick_proc_color_run("msr_dumb_while", p, 124, temp_f);
quick_proc_run("/bin/hello", p, temp_f);
#if 0
// this is how you can transition to a parallel process manually
// make sure you don't proc run first
__proc_set_state(p, PROC_RUNNING_S);
__proc_set_state(p, PROC_RUNNABLE_M);
p->resources[RES_CORES].amt_wanted = 5;
spin_unlock(&p->proc_lock);
core_request(p);
panic("This is okay");
#endif
break;
case 1:
#if 0
udelay(10000000);
// this is a ghetto way to test restarting an _M
printk("\nattempting to ghetto preempt...\n");
spin_lock(&p->proc_lock);
proc_take_allcores(p, __death);
__proc_set_state(p, PROC_RUNNABLE_M);
spin_unlock(&p->proc_lock);
udelay(5000000);
printk("\nattempting to restart...\n");
core_request(p); // proc still wants the cores
panic("This is okay");
// this tests taking some cores, and later killing an _M
printk("taking 3 cores from p\n");
for (int i = 0; i < num; i++)
corelist[i] = 7-i; // 7, 6, and 5
spin_lock(&p->proc_lock);
proc_take_cores(p, corelist, &num, __death);
spin_unlock(&p->proc_lock);
udelay(5000000);
printk("Killing p\n");
proc_destroy(p);
printk("Killed p\n");
panic("This is okay");
envs[0] = kfs_proc_create(kfs_lookup_path("roslib_hello"));
__proc_set_state(envs[0], PROC_RUNNABLE_S);
proc_run(envs[0]);
warn("DEPRECATED");
break;
#endif
case 2:
/*
test_smp_call_functions();
test_checklists();
test_barrier();
test_print_info();
test_lapic_status_bit();
test_ipi_sending();
test_pit();
*/
default:
printd("Manager Progress: %d\n", progress);
// delay if you want to test rescheduling an MCP that yielded
//udelay(15000000);
run_scheduler();
}
panic("If you see me, then you probably screwed up");
monitor(0);
/*
printk("Servicing syscalls from Core 0:\n\n");
while (1) {
process_generic_syscalls(&envs[0], 1);
cpu_relax();
}
*/
return;
#endif
}
void manager_jenkins()
{
#ifdef CONFIG_KERNEL_TESTING
printk("<-- BEGIN_KERNEL_TESTS -->\n");
run_registered_ktest_suites();
printk("<-- END_KERNEL_TESTS -->\n");
#endif
// Run userspace tests (from config specified path).
#ifdef CONFIG_USERSPACE_TESTING
if (strlen(CONFIG_USERSPACE_TESTING_SCRIPT) != 0) {
char exec[] = "/bin/ash";
char *p_argv[] = {exec, CONFIG_USERSPACE_TESTING_SCRIPT, 0};
struct file *program = do_file_open(exec, O_READ, 0);
struct proc *p = proc_create(program, p_argv, NULL);
proc_wakeup(p);
proc_decref(p); /* let go of the reference created in proc_create() */
kref_put(&program->f_kref);
run_scheduler();
// Need a way to wait for p to finish
} else {
printk("No user-space launcher file specified.\n");
}
#endif
smp_idle();
assert(0);
}
void manager_klueska()
{
static struct proc *envs[256];
static volatile uint8_t progress = 0;
if (progress == 0) {
progress++;
panic("what do you want to do?");
//envs[0] = kfs_proc_create(kfs_lookup_path("fillmeup"));
__proc_set_state(envs[0], PROC_RUNNABLE_S);
proc_run_s(envs[0]);
warn("DEPRECATED");
}
run_scheduler();
panic("DON'T PANIC");
}
void manager_waterman()
{
static bool first = true;
if (first)
mon_shell(0, 0, 0);
smp_idle();
assert(0);
}
void manager_yuzhu()
{
static uint8_t progress = 0;
static struct proc *p;
// for testing taking cores, check in case 1 for usage
uint32_t corelist[MAX_NUM_CORES];
uint32_t num = 3;
//create_server(init_num_cores, loop);
monitor(0);
// quick_proc_run("hello", p);
}