예제 #1
0
class Vamos:
    def __init__(self, machine, cfg):
        self.machine = machine
        self.mem = machine.get_mem()
        self.raw_mem = self.mem
        self.ram_size = self.mem.get_ram_size_bytes()
        self.cpu = machine.get_cpu()
        self.cpu_type = machine.get_cpu_type()
        self.traps = machine.get_traps()
        self.cfg = cfg

        # too much RAM requested?
        # our "custom chips" start at $BFxxxx so we allow RAM only to be below
        if self.ram_size >= 0xbf0000 and self.cfg.hw_access != "disable":
            raise VamosConfigError(
                "Too much RAM configured! Only up to $BF0000 allowed.")

        # setup custom chips
        if self.cfg.hw_access != "disable":
            self.hw_access = HardwareAccess(self.mem)
            self._setup_hw_access()

        # path manager
        self.path_mgr = PathManager(cfg)

        # create a label manager and error tracker
        self.label_mgr = machine.get_label_mgr()

        # set a label for first region
        if self.label_mgr:
            label = LabelRange("vbr", 0, 0x400)
            self.label_mgr.add_label(label)
            # shutdown range
            label = LabelRange("machine", 0x400, 0x800)
            self.label_mgr.add_label(label)

        # create memory access
        self.trace_mgr = TraceManager(self.cpu, self.label_mgr)
        if cfg.internal_memory_trace:
            self.mem = TraceMemory(self.mem, self.trace_mgr)
            if not log_mem_int.isEnabledFor(logging.INFO):
                log_mem_int.setLevel(logging.INFO)
        # enable mem trace?
        if cfg.memory_trace:
            self.machine.set_cpu_mem_trace_hook(self.trace_mgr.trace_mem)
            if not log_mem.isEnabledFor(logging.INFO):
                log_mem.setLevel(logging.INFO)
        # instr trace
        if cfg.instr_trace:
            if not log_instr.isEnabledFor(logging.INFO):
                log_instr.setLevel(logging.INFO)
            cpu = self.cpu
            trace_mgr = self.trace_mgr
            state = CPUState()

            def instr_hook():
                # add register dump
                if cfg.reg_dump:
                    state.get(cpu)
                    res = state.dump()
                    for r in res:
                        log_instr.info(r)
                # disassemble line
                pc = cpu.r_reg(REG_PC)
                trace_mgr.trace_code_line(pc)

            self.machine.set_instr_hook(instr_hook)

        # create memory allocator
        self.mem_begin = 0x1000
        self.mem_size = self.ram_size - self.mem_begin
        self.alloc = MemoryAlloc(self.mem, self.mem_begin, self.mem_size,
                                 self.label_mgr)

        # create segment loader
        self.seg_loader = SegmentLoader(self.alloc, self.path_mgr)

        # setup lib manager
        profiler_cfg = self._get_profiler_config(cfg)
        self.exec_ctx = ExecLibCtx(self.machine, self.alloc, self.seg_loader,
                                   self.path_mgr)
        self.dos_ctx = DosLibCtx(self.machine, self.alloc, self.seg_loader,
                                 self.path_mgr, self.run_command,
                                 self.start_sub_process)
        self.lib_mgr = LibManager(self.machine,
                                  self.alloc,
                                  self.seg_loader,
                                  self.cfg,
                                  profiler_cfg=profiler_cfg)
        self.lib_mgr.add_ctx('exec.library', self.exec_ctx)
        self.lib_mgr.add_ctx('dos.library', self.dos_ctx)
        self.lib_mgr.bootstrap_exec()

        # no current process right now
        self.process = None
        self.proc_list = []

    def _get_profiler_config(self, cfg):
        profile_libs = cfg.profile_libs
        if profile_libs:
            profile_libs = profile_libs.split(",")
        profiler_cfg = LibProfilerConfig(profiling=cfg.profile,
                                         all_libs=cfg.profile_all_libs,
                                         libs=profile_libs,
                                         add_samples=cfg.profile_samples,
                                         file=cfg.profile_file,
                                         append=cfg.profile_file_append,
                                         dump=cfg.profile_dump)
        return profiler_cfg

    def init(self, binary, arg_str, stack_size, shell, cwd):
        self.create_old_dos_guard()
        self.open_base_libs()
        return self.setup_main_proc(binary, arg_str, stack_size, shell, cwd)

    def cleanup(self, ok):
        self.cleanup_main_proc()
        self.close_base_libs()
        # shutdown of libmgr needs temp stack
        sp = self.machine.get_ram_begin() - 4
        self.lib_mgr.shutdown(run_sp=sp)
        if ok:
            self.alloc.dump_orphans()

    # ----- system setup -----

    def _setup_hw_access(self):
        # direct hw access
        cfg = self.cfg
        if cfg.hw_access == "emu":
            self.hw_access.set_mode(HardwareAccess.MODE_EMU)
        elif cfg.hw_access == "ignore":
            self.hw_access.set_mode(HardwareAccess.MODE_IGNORE)
        elif cfg.hw_access == "abort":
            self.hw_access.set_mode(HardwareAccess.MODE_ABORT)
        elif cfg.hw_access == "disable":
            pass
        else:
            raise VamosConfigError("Invalid HW Access mode: %s" %
                                   cfg.hw_access)

    # ----- process handling -----

    def _set_this_task(self, proc):
        """tell exec about this process and all others referencing process from here"""
        self.process = proc
        self.exec_ctx.set_process(proc)
        self.exec_lib.set_this_task(proc)
        self.dos_ctx.set_process(proc)

    def get_current_process(self):
        return self.process

    def start_sub_process(self, proc):
        log_proc.info("start sub process: %s", proc)
        self.proc_list.append(proc)
        self._set_this_task(proc)

        # setup trampoline to enter sub process
        tr = Trampoline(self, "SubProcJump")
        # reserve a long for old stack
        old_stack_off = tr.dc_l(0)
        # code starts
        tr.save_all_but_d0()
        # new proc registers: d0=arg_len a0=arg_cptr
        tr.set_dx_l(0, proc.arg_len)
        tr.set_ax_l(0, proc.arg_base)
        # d2=stack_size.  this value is also in 4(sp) (see Process.init_stack), but
        # various C programs rely on it being present (1.3-3.1 at least have it).
        tr.set_dx_l(2, proc.stack_size)
        # to track old dos values
        tr.set_ax_l(2, self.dos_guard_base)
        tr.set_ax_l(5, self.dos_guard_base)
        tr.set_ax_l(6, self.dos_guard_base)
        # save old stack and set new stack
        tr.write_ax_l(7, old_stack_off,
                      True)  # write to data offset (dc.l above)
        new_stack = proc.stack_initial
        tr.set_ax_l(7, new_stack)
        # call code! (jmp - return value is on stack)
        tr.jmp(proc.prog_start)
        # restore stack (set a label to return from new stack - see below)
        return_off = tr.get_code_offset()
        tr.read_ax_l(7, old_stack_off,
                     True)  # read from data offset (dc.l above)
        # restore regs
        tr.restore_all_but_d0()

        # trap to clean up sub process resources
        def trap_stop_sub_process():
            self.stop_sub_process()

        tr.final_rts(trap_stop_sub_process)
        # realize trampoline in memory (data+code)
        tr.done()
        # get label addr -> set as return value of new stack
        return_addr = tr.get_code_addr(return_off)
        log_proc.debug("new_stack=%06x return_addr=%06x", new_stack,
                       return_addr)
        # place return address for new process
        self.mem.w32(new_stack, return_addr)

    def stop_sub_process(self):
        # get return value
        ret_code = self.cpu.r_reg(REG_D0)
        # pop process
        proc = self.proc_list.pop()
        log_proc.info("stop sub process: %s ret_code=%d", proc, ret_code)
        proc.free()

    # ----- overload a process for RunCommand -----

    def run_command(self, start_pc, argsptr, arglen, stacksize):
        newstack = self.alloc.alloc_memory("shell command stack", stacksize)
        newstackbase = newstack.addr
        newstacktop = newstackbase + stacksize
        oldstackbase = self.process.this_task.access.r_s("pr_Task.tc_SPLower")
        oldstacktop = self.process.this_task.access.r_s("pr_Task.tc_SPUpper")
        old_stackptr = self.cpu.r_reg(REG_A7)  # addr of sys call return
        # put stack size on top of stack
        self.mem.w32(newstacktop - 4, stacksize)
        # activate new stack
        new_stackptr = newstacktop - 8
        self.process.this_task.access.w_s("pr_Task.tc_SPLower", newstackbase)
        self.process.this_task.access.w_s("pr_Task.tc_SPUpper", newstacktop)
        # NOTE: the Manx fexec and BPCL mess is not (yet) setup here.
        # setup trampoline to enter sub process
        tr = Trampoline(self, "RunCommand")
        # reserve a long for old stack
        old_stack_off = tr.dc_l(0)
        # code starts
        tr.save_all_but_d0()
        # new proc registers: d0=arg_len a0=arg_cptr
        tr.set_dx_l(0, arglen)
        tr.set_ax_l(0, argsptr)
        # d2=stack_size.  this value is also in 4(sp) (see Process.init_stack), but
        # various C programs rely on it being present (1.3-3.1 at least have it).
        tr.set_dx_l(2, stacksize)
        # to track old dos values
        tr.set_ax_l(2, self.dos_guard_base)
        tr.set_ax_l(5, self.dos_guard_base)
        tr.set_ax_l(6, self.dos_guard_base)
        # save old stack and set new stack
        tr.write_ax_l(7, old_stack_off,
                      True)  # write to data offset (dc.l above)
        tr.set_ax_l(7, new_stackptr)
        # call code! (jmp - return value is on stack)
        tr.jmp(start_pc)
        # restore stack (set a label to return from new stack - see below)
        return_off = tr.get_code_offset()
        tr.read_ax_l(7, old_stack_off,
                     True)  # read from data offset (dc.l above)
        # restore regs
        tr.restore_all_but_d0()
        # keep the old input file handle
        input_fh = self.process.get_input()

        # trap to clean up sub process resources
        def trap_stop_run_command():
            ret_code = self.cpu.r_reg(REG_D0)
            log_proc.info("return from RunCommand: ret_code=%d", ret_code)
            self.cpu.w_reg(REG_A7, old_stackptr)
            self.process.this_task.access.w_s("pr_Task.tc_SPLower",
                                              oldstackbase)
            self.process.this_task.access.w_s("pr_Task.tc_SPUpper",
                                              oldstacktop)
            self.alloc.free_memory(newstack)
            input_fh.setbuf("")
            # The return code remains in d0 as is

        tr.final_rts(trap_stop_run_command)
        # realize trampoline in memory (data+code)
        tr.done()
        # get label addr -> set as return value of new stack
        return_addr = tr.get_code_addr(return_off)
        log_proc.debug("new_stack=%06x return_addr=%06x", new_stackptr,
                       return_addr)
        # place return address for new process
        self.mem.w32(new_stackptr, return_addr)

    def run_shell(self, start_pc, packet, stacksize, trap_stop_handler):
        newstack = self.alloc.alloc_memory("shell command stack", stacksize)
        newstackbase = newstack.addr
        newstacktop = newstackbase + stacksize
        oldstackbase = self.process.this_task.access.r_s("pr_Task.tc_SPLower")
        oldstacktop = self.process.this_task.access.r_s("pr_Task.tc_SPUpper")
        old_stackptr = self.cpu.r_reg(REG_A7)  # addr of sys call return
        # put stack size on top of stack
        self.mem.w32(newstacktop - 4, stacksize)
        # activate new stack
        new_stackptr = newstacktop - 8
        self.process.this_task.access.w_s("pr_Task.tc_SPLower", newstackbase)
        self.process.this_task.access.w_s("pr_Task.tc_SPUpper", newstacktop)
        # NOTE: the Manx fexec and BPCL mess is not (yet) setup here.
        # setup trampoline to enter sub process
        tr = Trampoline(self, "RunCommand")
        # reserve a long for old stack
        old_stack_off = tr.dc_l(0)
        # code starts
        tr.save_all_but_d0()
        # new proc registers: d1=packet
        tr.set_dx_l(1, packet >> 2)
        # d2=stack_size.  this value is also in 4(sp) (see Process.init_stack), but
        # various C programs rely on it being present (1.3-3.1 at least have it).
        tr.set_dx_l(2, stacksize)
        # to track old dos values
        tr.set_ax_l(2, self.dos_guard_base)
        tr.set_ax_l(5, self.dos_guard_base)
        tr.set_ax_l(6, self.dos_guard_base)
        # save old stack and set new stack
        tr.write_ax_l(7, old_stack_off,
                      True)  # write to data offset (dc.l above)
        tr.set_ax_l(7, new_stackptr)
        # call code! (jmp - return value is on stack)
        tr.jmp(start_pc)
        # restore stack (set a label to return from new stack - see below)
        return_off = tr.get_code_offset()
        tr.read_ax_l(7, old_stack_off,
                     True)  # read from data offset (dc.l above)
        # restore regs
        tr.restore_all_but_d0()

        def trap_stop_function():
            ret_code = self.cpu.r_reg(REG_D0)
            log_proc.info("return from SystemTagList: ret_code=%d", ret_code)
            self.cpu.w_reg(REG_A7, old_stackptr)
            self.process.this_task.access.w_s("pr_Task.tc_SPLower",
                                              oldstackbase)
            self.process.this_task.access.w_s("pr_Task.tc_SPUpper",
                                              oldstacktop)
            self.alloc.free_memory(newstack)
            trap_stop_handler(ret_code)

        tr.final_rts(trap_stop_function)
        # realize trampoline in memory (data+code)
        tr.done()
        # get label addr -> set as return value of new stack
        return_addr = tr.get_code_addr(return_off)
        log_proc.debug("new_stack=%06x return_addr=%06x", new_stackptr,
                       return_addr)
        # place return address for new process
        self.mem.w32(new_stackptr, return_addr)

    # ----- init environment -----

    def open_base_libs(self):
        log_main.info("open_base_libs")
        # open exec lib
        self.exec_addr = self.lib_mgr.open_lib('exec.library', 0)
        exec_vlib = self.lib_mgr.get_vlib_by_addr(self.exec_addr)
        self.exec_lib = exec_vlib.get_impl()
        # link exec to dos
        self.dos_ctx.set_exec_lib(self.exec_lib)
        # open dos lib
        self.dos_addr = self.lib_mgr.open_lib('dos.library', 0)
        dos_vlib = self.lib_mgr.get_vlib_by_addr(self.dos_addr)
        self.dos_lib = dos_vlib.get_impl()
        self.dos_ctx.set_dos_lib(self.dos_lib)
        # set exec base @4
        self.machine.set_zero_mem(0, self.exec_addr)

    def close_base_libs(self):
        log_main.info("close_base_libs")
        # close dos
        self.lib_mgr.close_lib(self.dos_addr)
        # close exec
        self.lib_mgr.close_lib(self.exec_addr)

    def create_old_dos_guard(self):
        # create a guard memory for tracking invalid old dos access
        self.dos_guard_base = self.raw_mem.reserve_special_range()
        self.dos_guard_size = 0x010000
        if self.label_mgr:
            label = LabelRange("old_dos guard", self.dos_guard_base,
                               self.dos_guard_size)
            self.label_mgr.add_label(label)
            log_mem_init.info(label)

    # ----- main process -----

    def setup_main_proc(self, binary, arg_str, stack_size, shell, cwd):
        proc = Process(self.dos_ctx,
                       binary,
                       arg_str,
                       stack_size=stack_size,
                       shell=shell,
                       cwd=cwd)
        if not proc.ok:
            return False
        log_proc.info("set main process: %s", proc)
        self.proc_list.append(proc)
        self._set_this_task(proc)
        self.main_proc = proc
        return True

    def get_initial_sp(self):
        return self.main_proc.get_initial_sp()

    def get_initial_pc(self):
        return self.main_proc.get_initial_pc()

    def get_initial_regs(self):
        regs = self.main_proc.get_initial_regs()
        # to track old dos values
        regs[REG_A2] = self.dos_guard_base
        regs[REG_A5] = self.dos_guard_base
        regs[REG_A6] = self.dos_guard_base
        return regs

    def cleanup_main_proc(self):
        self.main_proc.free()
예제 #2
0
파일: setup.py 프로젝트: krutten/amitools
class SetupLibManager(object):
    def __init__(self,
                 machine,
                 mem_map,
                 scheduler,
                 path_mgr,
                 lib_cfg=None,
                 main_profiler=None):
        self.machine = machine
        self.mem_map = mem_map
        self.path_mgr = path_mgr
        self.scheduler = scheduler
        self.alloc = mem_map.get_alloc()
        self.lib_mgr_cfg = lib_cfg
        self.main_profiler = main_profiler
        # state
        self.seg_loader = None
        self.exec_ctx = None
        self.dos_ctx = None
        self.lib_mgr = None

    def parse_config(self, cfg):
        if not cfg:
            return True
        self.lib_mgr_cfg = LibMgrCfg.from_dict(cfg)
        return True

    def setup(self):
        # create def cfg
        if self.lib_mgr_cfg is None:
            self.lib_mgr_cfg = LibMgrCfg()
        # create segment loader
        self.seg_loader = SegmentLoader(self.alloc, self.path_mgr)
        # setup contexts
        odg_base = self.mem_map.get_old_dos_guard_base()
        self.exec_ctx = ExecLibCtx(self.machine, self.alloc, self.seg_loader,
                                   self.path_mgr)
        self.dos_ctx = DosLibCtx(self.machine, self.alloc, self.seg_loader,
                                 self.path_mgr, self.scheduler, odg_base)
        # create lib mgr
        self.lib_mgr = LibManager(self.machine,
                                  self.alloc,
                                  self.seg_loader,
                                  self.lib_mgr_cfg,
                                  main_profiler=self.main_profiler)
        self.lib_mgr.add_ctx('exec.library', self.exec_ctx)
        self.lib_mgr.add_ctx('dos.library', self.dos_ctx)
        # add all vamos libs
        for name in vamos_libs:
            cls = vamos_libs[name]
            self.lib_mgr.add_impl_cls(name, cls)
        # setup scheduler call back
        self.scheduler.set_cur_task_callback(self.cur_task_callback)
        # return lib_mgr
        return self.lib_mgr

    def cleanup(self):
        # shutdown of libmgr needs temp stack
        sp = self.machine.get_ram_begin() - 4
        self.lib_mgr.shutdown(run_sp=sp)

    def open_base_libs(self):
        log_libmgr.info("opening base libs...")
        # first bootstrap exec
        self.lib_mgr.bootstrap_exec()
        # open exec lib
        self.exec_addr = self.lib_mgr.open_lib('exec.library', 0)
        self.exec_vlib = self.lib_mgr.get_vlib_by_addr(self.exec_addr)
        self.exec_impl = self.exec_vlib.get_impl()
        log_libmgr.info("open base lib: exec: @%06x", self.exec_addr)
        # link exec to dos
        self.dos_ctx.set_exec_lib(self.exec_impl)
        # open dos lib
        self.dos_addr = self.lib_mgr.open_lib('dos.library', 0)
        self.dos_vlib = self.lib_mgr.get_vlib_by_addr(self.dos_addr)
        self.dos_impl = self.dos_vlib.get_impl()
        self.dos_ctx.set_dos_lib(self.dos_impl)
        log_libmgr.info("open base lib: dos:  @%06x", self.dos_addr)
        # set exec base @4
        log_libmgr.debug("setting execbase @4")
        self.machine.set_zero_mem(0, self.exec_addr)

    def close_base_libs(self):
        log_libmgr.info("closing base libs...")
        # close dos
        self.lib_mgr.close_lib(self.dos_addr)
        log_libmgr.info("closed dos")
        # close exec
        self.lib_mgr.close_lib(self.exec_addr)
        log_libmgr.info("closed exec")

    def cur_task_callback(self, task):
        log_libmgr.info("current task: %s", task)
        if task:
            proc = task.process
            self.exec_ctx.set_process(proc)
            self.exec_impl.set_this_task(proc)
            self.dos_ctx.set_process(proc)
예제 #3
0
파일: setup.py 프로젝트: nattfalk/act
class SetupLibManager(object):
    def __init__(self,
                 machine,
                 mem_map,
                 path_mgr,
                 lib_cfg=None,
                 profiler_cfg=None):
        self.machine = machine
        self.mem_map = mem_map
        self.path_mgr = path_mgr
        self.alloc = mem_map.get_alloc()
        self.lib_mgr_cfg = lib_cfg
        self.profiler_cfg = profiler_cfg
        # state
        self.seg_loader = None
        self.exec_ctx = None
        self.dos_ctx = None
        self.lib_mgr = None

    def parse_config(self, main_cfg):
        if not main_cfg:
            return True
        cfg = main_cfg.get_profile_dict().profile
        self.parse_profiler_cfg(cfg)
        cfg = main_cfg.get_libs_dict()
        self.parse_lib_mgr_cfg(cfg)
        return True

    def parse_lib_mgr_cfg(self, cfg):
        self.lib_mgr_cfg = LibMgrCfg.from_dict(cfg)

    def parse_profiler_cfg(self, cfg):
        names = cfg.libs.names
        if names:
            profiling = True
            all_libs = 'all' in names
        else:
            profiling = False
            all_libs = False
        self.profiler_cfg = LibProfilerConfig(profiling=profiling,
                                              all_libs=all_libs,
                                              libs=names,
                                              add_samples=cfg.libs.calls,
                                              file=cfg.output.file,
                                              append=cfg.output.append,
                                              dump=cfg.output.dump)

    def setup(self, vamos_legacy):
        # create def cfg
        if self.lib_mgr_cfg is None:
            self.lib_mgr_cfg = LibMgrCfg()
        # create segment loader
        self.seg_loader = SegmentLoader(self.alloc, self.path_mgr)
        # setup contexts
        self.exec_ctx = ExecLibCtx(self.machine, self.alloc, self.seg_loader,
                                   self.path_mgr)
        self.dos_ctx = DosLibCtx(self.machine, self.alloc, self.seg_loader,
                                 self.path_mgr, vamos_legacy)
        # create lib mgr
        self.lib_mgr = LibManager(self.machine,
                                  self.alloc,
                                  self.seg_loader,
                                  self.lib_mgr_cfg,
                                  profiler_cfg=self.profiler_cfg)
        self.lib_mgr.add_ctx('exec.library', self.exec_ctx)
        self.lib_mgr.add_ctx('dos.library', self.dos_ctx)
        # add all vamos libs
        for name in vamos_libs:
            cls = vamos_libs[name]
            self.lib_mgr.add_impl_cls(name, cls)
        # finally bootstrap exec
        self.lib_mgr.bootstrap_exec()
        # return lib_mgr
        return self.lib_mgr

    def cleanup(self):
        # shutdown of libmgr needs temp stack
        sp = self.machine.get_ram_begin() - 4
        self.lib_mgr.shutdown(run_sp=sp)

    def open_base_libs(self):
        log_libmgr.info("opening base libs...")
        # open exec lib
        self.exec_addr = self.lib_mgr.open_lib('exec.library', 0)
        self.exec_vlib = self.lib_mgr.get_vlib_by_addr(self.exec_addr)
        self.exec_impl = self.exec_vlib.get_impl()
        log_libmgr.info("open base lib: exec: @%06x", self.exec_addr)
        # link exec to dos
        self.dos_ctx.set_exec_lib(self.exec_impl)
        # open dos lib
        self.dos_addr = self.lib_mgr.open_lib('dos.library', 0)
        self.dos_vlib = self.lib_mgr.get_vlib_by_addr(self.dos_addr)
        self.dos_impl = self.dos_vlib.get_impl()
        self.dos_ctx.set_dos_lib(self.dos_impl)
        log_libmgr.info("open base lib: dos:  @%06x", self.dos_addr)
        # set exec base @4
        log_libmgr.debug("setting execbase @4")
        self.machine.set_zero_mem(0, self.exec_addr)

    def close_base_libs(self):
        log_libmgr.info("closing base libs...")
        # close dos
        self.lib_mgr.close_lib(self.dos_addr)
        log_libmgr.info("closed dos")
        # close exec
        self.lib_mgr.close_lib(self.exec_addr)
        log_libmgr.info("closed exec")
예제 #4
0
파일: setup.py 프로젝트: cnvogelg/amitools
class SetupLibManager(object):
  def __init__(self, machine, mem_map, scheduler, path_mgr,
               lib_cfg=None, main_profiler=None):
    self.machine = machine
    self.mem_map = mem_map
    self.path_mgr = path_mgr
    self.scheduler = scheduler
    self.alloc = mem_map.get_alloc()
    self.lib_mgr_cfg = lib_cfg
    self.main_profiler = main_profiler
    # state
    self.seg_loader = None
    self.exec_ctx = None
    self.dos_ctx = None
    self.lib_mgr = None

  def parse_config(self, cfg):
    if not cfg:
      return True
    self.lib_mgr_cfg = LibMgrCfg.from_dict(cfg)
    return True

  def setup(self):
    # create def cfg
    if self.lib_mgr_cfg is None:
      self.lib_mgr_cfg = LibMgrCfg()
    # create segment loader
    self.seg_loader = SegmentLoader(self.alloc, self.path_mgr)
    # setup contexts
    odg_base = self.mem_map.get_old_dos_guard_base()
    self.exec_ctx = ExecLibCtx(self.machine, self.alloc,
                               self.seg_loader, self.path_mgr)
    self.dos_ctx = DosLibCtx(self.machine, self.alloc,
                             self.seg_loader, self.path_mgr, self.scheduler,
                             odg_base)
    # create lib mgr
    self.lib_mgr = LibManager(self.machine, self.alloc, self.seg_loader,
                              self.lib_mgr_cfg,
                              main_profiler=self.main_profiler)
    self.lib_mgr.add_ctx('exec.library', self.exec_ctx)
    self.lib_mgr.add_ctx('dos.library', self.dos_ctx)
    # add all vamos libs
    for name in vamos_libs:
      cls = vamos_libs[name]
      self.lib_mgr.add_impl_cls(name, cls)
    # setup scheduler call back
    self.scheduler.set_cur_task_callback(self.cur_task_callback)
    # return lib_mgr
    return self.lib_mgr

  def cleanup(self):
    # shutdown of libmgr needs temp stack
    sp = self.machine.get_ram_begin() - 4
    self.lib_mgr.shutdown(run_sp=sp)

  def open_base_libs(self):
    log_libmgr.info("opening base libs...")
    # first bootstrap exec
    self.lib_mgr.bootstrap_exec()
    # open exec lib
    self.exec_addr = self.lib_mgr.open_lib('exec.library', 0)
    self.exec_vlib = self.lib_mgr.get_vlib_by_addr(self.exec_addr)
    self.exec_impl = self.exec_vlib.get_impl()
    log_libmgr.info("open base lib: exec: @%06x", self.exec_addr)
    # link exec to dos
    self.dos_ctx.set_exec_lib(self.exec_impl)
    # open dos lib
    self.dos_addr = self.lib_mgr.open_lib('dos.library', 0)
    self.dos_vlib = self.lib_mgr.get_vlib_by_addr(self.dos_addr)
    self.dos_impl = self.dos_vlib.get_impl()
    self.dos_ctx.set_dos_lib(self.dos_impl)
    log_libmgr.info("open base lib: dos:  @%06x", self.dos_addr)

  def close_base_libs(self):
    log_libmgr.info("closing base libs...")
    # close dos
    self.lib_mgr.close_lib(self.dos_addr)
    log_libmgr.info("closed dos")
    # close exec
    self.lib_mgr.close_lib(self.exec_addr)
    log_libmgr.info("closed exec")

  def cur_task_callback(self, task):
    log_libmgr.info("current task: %s", task)
    if task:
      proc = task.process
      self.exec_ctx.set_process(proc)
      self.exec_impl.set_this_task(proc)
      self.dos_ctx.set_process(proc)