Skip to content
Snippets Groups Projects
loader.cc 7.44 KiB
Newer Older
  • Learn to ignore specific revisions
  • #include "drivers/isa-serial.hh"
    
    #include "fs/fs.hh"
    
    #include <bsd/net.hh>
    
    #include <boost/format.hpp>
    
    #include <boost/program_options.hpp>
    #include <boost/algorithm/string.hpp>
    
    #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 "smp.hh"
    
    Avi Kivity's avatar
    Avi Kivity committed
    #include "xen.hh"
    
    Avi Kivity's avatar
    Avi Kivity committed
    #include "ioapic.hh"
    
    #include "drivers/virtio-net.hh"
    
    #include "drivers/virtio-blk.hh"
    
    Glauber Costa's avatar
    Glauber Costa committed
    #include "drivers/xenfront-xenbus.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"
    
    Glauber Costa's avatar
    Glauber Costa committed
    #include "drivers/console.hh"
    
    Avi Kivity's avatar
    Avi Kivity committed
    #include "barrier.hh"
    
    #include "arch.hh"
    
    Avi Kivity's avatar
    Avi Kivity committed
    #include "osv/trace.hh"
    
    #include <osv/power.hh>
    
    #include <osv/rcu.hh>
    
    #include "mempool.hh"
    
    #include <bsd/porting/networking.h>
    #include "dhcp.hh"
    
    using namespace osv;
    
    
    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\n" : "locale fails\n");
    
    Avi Kivity's avatar
    Avi Kivity committed
    elf::Elf64_Ehdr* elf_header;
    
    elf::tls_data tls_data;
    
    void setup_tls(elf::init_table inittab)
    {
    
        tls_data = inittab.tls;
    
        sched::init_tls(tls_data);
    
        memset(tls_data.start + tls_data.filesize, 0, tls_data.size - tls_data.filesize);
    
        extern char tcb0[]; // defined by linker script
    
        memcpy(tcb0, inittab.tls.start, 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();
        void vfs_init(void);
    
    Christoph Hellwig's avatar
    Christoph Hellwig committed
        void mount_usr(void);
    
        void ramdisk_init(void);
    }
    
    void disable_pic()
    {
    
    Avi Kivity's avatar
    Avi Kivity committed
        // PIC not present in Xen
        XENPV_ALTERNATIVE({ outb(0xff, 0x21); outb(0xff, 0xa1); }, {});
    
        disable_pic();
    
        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
    int main(int ac, char **av)
    {
    
    Glauber Costa's avatar
    Glauber Costa committed
        debug("Loader Copyright 2013 Cloudius Systems\n");
    
    Avi Kivity's avatar
    Avi Kivity committed
        idt.load_on_cpu();
    
        void main_cont(int ac, char** av);
    
        sched::init([=] { main_cont(ac, av); });
    
    static bool opt_leak = false;
    
    static bool opt_noshutdown = false;
    
    static bool opt_log_backtrace = false;
    
    std::tuple<int, char**> parse_options(int ac, char** av)
    {
        namespace bpo = boost::program_options;
        namespace bpos = boost::program_options::command_line_style;
    
        std::vector<const char*> args = { "osv" };
    
        // due to https://svn.boost.org/trac/boost/ticket/6991, we can't terminate
        // command line parsing on the executable name, so we need to look for it
        // ourselves
    
        auto nr_options = std::find_if(av, av + ac,
                                       [](const char* arg) { return arg[0] != '-'; }) - av;
        std::copy(av, av + nr_options, std::back_inserter(args));
    
    
        bpo::options_description desc("osv options:\n");
    
        desc.add_options()
    
            ("help", "show help text\n")
            ("trace", bpo::value<std::vector<std::string>>(), "tracepoints to enable\n")
    
            ("trace-backtrace", "log backtraces in the tracepoint log\n")
    
            ("leak", "start leak detector after boot\n")
    
            ("noshutdown", "continue running after main() returns\n")
    
        ;
        bpo::variables_map vars;
        // don't allow --foo bar (require --foo=bar) so we can find the first non-option
        // argument
        int style = bpos::unix_style & ~(bpos::long_allow_next | bpos::short_allow_next);
        bpo::store(bpo::parse_command_line(args.size(), args.data(), desc, style), vars);
        bpo::notify(vars);
    
        if (vars.count("help")) {
            std::cout << desc << "\n";
        }
    
    
        if (vars.count("leak")) {
            opt_leak = true;
        }
    
    
        if (vars.count("noshutdown")) {
            opt_noshutdown = true;
        }
    
    
        if (vars.count("trace-backtrace")) {
            opt_log_backtrace = true;
        }
    
    
        if (vars.count("trace")) {
            auto tv = vars["trace"].as<std::vector<std::string>>();
            for (auto t : tv) {
                std::vector<std::string> tmp;
                boost::split(tmp, t, boost::is_any_of(" ,"), boost::token_compress_on);
                for (auto t : tmp) {
                    enable_tracepoint(t);
                }
            }
        }
        av += nr_options;
        ac -= nr_options;
        return std::make_tuple(ac, av);
    }
    
    
    Nadav Har'El's avatar
    Nadav Har'El committed
    // Java uses this global variable (supplied by Glibc) to figure out the
    // initial thread's stack end.
    void *__libc_stack_end;
    
    
    void run_main(elf::program *prog, struct argblock *args)
    {
        auto av = args->av;
        auto ac = args->ac;
    
        auto obj = prog->add_object(av[0]);
    
        if (!obj) {
            debug("run_main(): cannot execute %s. Aborting.\n", av[0]);
            abort();
        }
    
        auto main = obj->lookup<void (int, char**)>("main");
        assert(main);
    
    
        if (opt_leak) {
            debug("Enabling leak detector.\n");
            memory::tracker_enabled = true;
        }
    
    
    Nadav Har'El's avatar
    Nadav Har'El committed
        __libc_stack_end = __builtin_frame_address(0);
    
    
    void* do_main_thread(void *_args)
    
        auto args = static_cast<argblock*>(_args);
    
        pci::pci_device_enumeration();
    
        // Initialize all drivers
        hw::driver_manager* drvman = hw::driver_manager::instance();
    
        drvman->register_driver(virtio::virtio_blk::probe);
        drvman->register_driver(virtio::virtio_net::probe);
    
    Glauber Costa's avatar
    Glauber Costa committed
        drvman->register_driver(xenfront::xenbus::probe);
    
        drvman->load_all();
        drvman->list_drivers();
    
        mount_usr();
    
        // Start DHCP by default and wait for an IP
        osv_start_if("eth0", "0.0.0.0", "255.255.255.0");
        osv_ifup("eth0");
        dhcp_start(true);
    
    
        run_main(prog, args);
    
    namespace pthread_private {
        void init_detached_pthreads_reaper();
    }
    
    
    void main_cont(int ac, char** av)
    
        std::tie(ac, av) = parse_options(ac, av);
    
    Avi Kivity's avatar
    Avi Kivity committed
        ioapic::init();
    
        smp_launch();
    
    Glauber Costa's avatar
    Glauber Costa committed
        console::console_init();
    
    Avi Kivity's avatar
    Avi Kivity committed
        memory::enable_debug_allocator();
    
        enable_trace();
    
        if (opt_log_backtrace) {
            // can only do this after smp_launch, otherwise the IDT is not initialized,
            // and backtrace_safe() fails as soon as we get an exception
            tracepoint_base::log_backtraces();
        }
    
        sched::init_detached_threads_reaper();
    
    
        vfs_init();
        ramdisk_init();
    
        filesystem fs;
    
        net_init();
    
        processor::sti();
    
        prog = new elf::program(fs);
    
        prog->set_search_path({"/", "/usr/lib"});
    
        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);
    
        void* retval;
        pthread_join(pthread, &retval);
    
    
        if (opt_noshutdown) {
            // If the --noshutdown option is given, continue running the system,
            // and whatever threads might be running, even after main returns
            debug("main() returned.\n");
            sched::thread::wait_until([] { return false; });
        }
    
    
        if (memory::tracker_enabled) {
            debug("Leak testing done. Please use 'osv leak show' in gdb to analyze results.\n");
            osv::halt();
        } else {
            debug("Powering off.\n");
            osv::poweroff();
        }