Skip to content
Snippets Groups Projects
loader.cc 7.23 KiB
Newer Older
  • Learn to ignore specific revisions
  • #include "drivers/isa-serial.hh"
    
    #include "fs/fs.hh"
    
    #include <boost/format.hpp>
    #include <cctype>
    
    #include "elf.hh"
    
    #include "tls.hh"
    #include "msr.hh"
    
    Avi Kivity's avatar
    Avi Kivity committed
    #include "exceptions.hh"
    
    #include "debug.hh"
    
    #include "drivers/pci.hh"
    
    #include "drivers/device-factory.hh"
    
    #include <string.h>
    
    #include <sys/stat.h>
    #include <unistd.h>
    
    #include "drivers/virtio-net.hh"
    
    #include "drivers/virtio-blk.hh"
    
    #include "drivers/driver-factory.hh"
    
    Avi Kivity's avatar
    Avi Kivity committed
    #include "sched.hh"
    
    Avi Kivity's avatar
    Avi Kivity committed
    #include "drivers/clock.hh"
    
    Avi Kivity's avatar
    Avi Kivity committed
    #include "drivers/clockevent.hh"
    #include "barrier.hh"
    
    Avi Kivity's avatar
    Avi Kivity committed
    asm(".pushsection \".debug_gdb_scripts\", \"MS\",@progbits,1 \n"
        ".byte 1 \n"
        ".asciz \"scripts/loader.py\" \n"
        ".popsection \n");
    
    
    namespace {
    
        void test_locale()
        {
    	auto loc = std::locale();
    	auto &fac = std::use_facet<std::ctype<char>>(loc);
    	bool ok = fac.is(std::ctype_base::digit, '3')
    	    && !fac.is(std::ctype_base::digit, 'x');
    
    	debug(ok ? "locale works" : "locale fails");
    
    Avi Kivity's avatar
    Avi Kivity committed
    elf::Elf64_Ehdr* elf_header;
    
    void setup_tls(elf::init_table inittab)
    {
        static char tcb0[1 << 15] __attribute__((aligned(4096)));
        assert(inittab.tls_size + sizeof(thread_control_block) <= sizeof(tcb0));
        memcpy(tcb0, inittab.tls, inittab.tls_size);
        auto p = reinterpret_cast<thread_control_block*>(tcb0 + inittab.tls_size);
        p->self = p;
        processor::wrmsr(msr::IA32_FS_BASE, reinterpret_cast<uint64_t>(p));
    }
    
    
    extern "C" { void premain(); }
    
    
    extern "C" { void vfs_init(void); }
    
    
    void premain()
    {
        auto inittab = elf::get_init(elf_header);
    
        setup_tls(inittab);
    
        for (auto init = inittab.start; init < inittab.start + inittab.count; ++init) {
            (*init)();
        }
    }
    
    
    Avi Kivity's avatar
    Avi Kivity committed
    void disable_pic()
    {
        outb(0xff, 0x21);
        outb(0xff, 0xa1);
    }
    
    
    Avi Kivity's avatar
    Avi Kivity committed
    static int test_ctr;
    
    using sched::thread;
    
    struct test_threads_data {
        thread* main;
        thread* t1;
        thread* t2;
    };
    
    void test_thread_1(test_threads_data& tt)
    {
        while (test_ctr < 1000) {
            thread::wait_until([&] { return (test_ctr % 2) == 0; });
            ++test_ctr;
            if (tt.t2) {
                tt.t2->wake();
            }
        }
        tt.t1 = nullptr;
        tt.main->wake();
    }
    
    void test_thread_2(test_threads_data& tt)
    {
        while (test_ctr < 1000) {
            thread::wait_until([&] { return (test_ctr % 2) == 1; });
            ++test_ctr;
            if (tt.t1) {
                tt.t1->wake();
            }
        }
        tt.t2 = nullptr;
        tt.main->wake();
    }
    
    void test_threads()
    {
        test_threads_data tt;
        tt.main = thread::current();
    
        char stk1[10000], stk2[10000];
        tt.t1 = new thread([&] { test_thread_1(tt); }, { stk1, 10000 });
        tt.t2 = new thread([&] { test_thread_2(tt); }, { stk2, 10000 });
    
    Avi Kivity's avatar
    Avi Kivity committed
    
        thread::wait_until([&] { return test_ctr >= 1000; });
        debug("threading test succeeded");
    }
    
    
    Avi Kivity's avatar
    Avi Kivity committed
    int main(int ac, char **av)
    {
    
        debug("Loader Copyright 2013 Unnamed");
    
    Avi Kivity's avatar
    Avi Kivity committed
        idt.load_on_cpu();
    
        vfs_init();
    
        filesystem fs;
    
    Avi Kivity's avatar
    Avi Kivity committed
        disable_pic();
    
    Avi Kivity's avatar
    Avi Kivity committed
        processor::sti();
    
    Avi Kivity's avatar
    Avi Kivity committed
    
    
    #if 1
        if (std::isdigit('1'))
    
    	debug("isgidit(1) = ok");
    
    	debug("isgidit(1) = bad");
    
        if (!std::isdigit('x'))
    
    	debug("isgidit(x) = ok");
    
    	debug("isgidit(x) = bad");
    
    #if 0
        auto &fac = std::use_facet<std::ctype<char> >(std::locale("C"));
        if (fac.is(std::ctype<char>::digit, '1'))
    
    	debug("facet works");
    
    	debug("facet !works");
    
        prog = new elf::program(fs);
        sched::init(*prog);
    
        static char main_stack[64*1024];
    
        void main_thread(int ac, char** av);
        new thread([&] { main_thread(ac, av); }, { main_stack, sizeof main_stack }, true);
    
    Avi Kivity's avatar
    Avi Kivity committed
    void test_clock_events()
    {
        struct test_callback : public clock_event_callback {
            test_callback() : n() {}
            virtual void fired() { t[n++] = clock::get()->time(); }
            unsigned n;
            u64 t[20];
        };
        test_callback t;
        clock_event_callback* old_callback = clock_event->callback();
        clock_event->set_callback(&t);
        for (unsigned i = 0; i < 10; ++i) {
            clock_event->set(clock::get()->time() + 1000000);
            while (t.n == i) {
                barrier();
            }
        }
        clock_event->set_callback(nullptr);
        for (unsigned i = 0; i < 10; ++i) {
            debug(fmt("clock_event: %d") % t.t[i]);
        }
        clock_event->set_callback(old_callback);
    }
    
    
    struct argblock {
        int ac;
        char** av;
    };
    
    void load_test(elf::program *prog, char *path)
    
        printf("running %s\n", path);
    
    
            = prog->lookup_function<int (int, const char **)>("main");
    
        std::string str = "test";
        const char *name = str.c_str();
        int ret = test_main(1, &name);
    
    Christoph Hellwig's avatar
    Christoph Hellwig committed
        if (ret)
    
            printf("failed.\n");
        else
            printf("ok.\n");
    
        prog->remove_object(path);
    
    int load_tests(elf::program *prog, struct argblock *args)
    
    {
    #define TESTDIR		"/tests"
        DIR *dir = opendir(TESTDIR);
        char path[PATH_MAX];
        struct dirent *d;
        struct stat st;
    
        if (!dir) {
            perror("failed to open testdir");
            return EXIT_FAILURE;
        }
    
        while ((d = readdir(dir))) {
            if (strcmp(d->d_name, ".") == 0 ||
                strcmp(d->d_name, "..") == 0)
               continue;
    
            snprintf(path, PATH_MAX, "%s/%s", TESTDIR, d->d_name);
            if (__xstat(1, path, &st) < 0) {
                printf("failed to stat %s\n", path);
                continue;
            }
            if (!S_ISREG(st.st_mode)) {
                printf("ignoring %s, not a regular file\n", path);
                continue;
            }
            load_test(prog, path);
        }
        if (closedir(dir) < 0) {
            perror("failed to close testdir");
            return EXIT_FAILURE;
        }
    
        return 0;
    
    void run_main(elf::program *prog, struct argblock *args)
    {
        auto av = args->av;
        auto ac = args->ac;
        prog->add_object(av[0]);
        ++av, --ac;
        auto main = prog->lookup_function<void (int, char**)>("main");
        main(ac, av);
    }
    
    void* do_main_thread(void *_args)
    
        auto args = static_cast<argblock*>(_args);
    
    Avi Kivity's avatar
    Avi Kivity committed
        test_clock_events();
    
        pci::pci_devices_print();
    
        pci::pci_device_enumeration();
        DeviceFactory::Instance()->DumpDevices();
    
        Driver *vnet = new virtio::virtio_net();
        DriverFactory::Instance()->RegisterDriver(vnet);
    
    
        virtio::virtio_blk *vblk = new virtio::virtio_blk();
    
        DriverFactory::Instance()->RegisterDriver(vblk);
    
    
        DeviceFactory::Instance()->InitializeDrivers();
    
    
        DriverFactory::Instance()->Destroy();
    
    Avi Kivity's avatar
    Avi Kivity committed
        auto t1 = clock::get()->time();
        auto t2 = clock::get()->time();
        debug(fmt("clock@t1 %1%") % t1);
        debug(fmt("clock@t2 %1%") % t2);
    
    
        timespec ts = {};
        ts.tv_nsec = 100;
        t1 = clock::get()->time();
        nanosleep(&ts, nullptr);
        t2 = clock::get()->time();
        debug(fmt("nanosleep(100) -> %d") % (t2 - t1));
        ts.tv_nsec = 100000;
        t1 = clock::get()->time();
        nanosleep(&ts, nullptr);
        t2 = clock::get()->time();
        debug(fmt("nanosleep(100000) -> %d") % (t2 - t1));
    
    
    //    load_tests(prog, args);
        run_main(prog, args);
    
    Avi Kivity's avatar
    Avi Kivity committed
        while (true)
    	;
    
    void main_thread(int ac, char **av)
    
    {
        pthread_t pthread;
        // run the payload in a pthread, so pthread_self() etc. work
    
        argblock args{ ac, av };
        pthread_create(&pthread, nullptr, do_main_thread, &args);
    
        sched::thread::wait_until([] { return false; });