def init_args(self, arg_str, fh): # Tripos makes the input line available as buffered input for ReadItem() fh.setbuf(arg_str) # alloc and fill arg buffer self.arg_len = len(arg_str) self.arg = self.ctx.alloc.alloc_memory(self.bin_basename + "_args", self.arg_len + 1) self.arg_base = self.arg.addr self.ctx.mem.w_cstr(self.arg_base, arg_str) log_proc.info("args: '%s' (%d)", arg_str[:-1], self.arg_len) log_proc.info(self.arg)
def init_args(self, arg_str, fh): # Tripos makes the input line available as buffered input for ReadItem() fh.setbuf(arg_str) # alloc and fill arg buffer self.arg_len = len(arg_str) self.arg = self.ctx.alloc.alloc_memory(self.bin_basename + "_args", self.arg_len + 1) self.arg_base = self.arg.addr self.ctx.mem.w_cstr(self.arg_base, arg_str) log_proc.info("args: '%s' (%d)", arg_str[:-1], self.arg_len) log_proc.info(self.arg)
def init_stack(self, stack_size): self.stack_size = stack_size self.stack = self.ctx.alloc.alloc_memory( self.bin_basename + "_stack", self.stack_size ) self.stack_base = self.stack.addr self.stack_end = self.stack_base + self.stack_size log_proc.info("stack: base=%06x end=%06x", self.stack_base, self.stack_end) log_proc.info(self.stack) # prepare stack # TOP: size # TOP-4: return from program self.stack_initial = self.stack_end - 4 self.ctx.mem.w32(self.stack_initial, self.stack_size) self.stack_initial -= 4
def init_cwd(self, cwd, cwd_lock): self.cwd = cwd if cwd is not None and cwd_lock is None: lock_mgr = self.ctx.dos_lib.lock_mgr dos_list = self.ctx.dos_lib.dos_list entry = dos_list.get_entry_by_name('root') lock = entry.locks[0] self.cwd_lock = lock_mgr.create_lock(lock, cwd, False) log_proc.info("current dir: cwd=%s create lock=%s", cwd, self.cwd_lock) self.cwd_shared = False else: self.cwd_lock = cwd_lock self.cwd_shared = True log_proc.info("current dir: cwd=%s shared lock=%s", cwd, self.cwd_lock)
def init_cwd(self, cwd, cwd_lock): self.cwd = cwd if cwd is not None and cwd_lock is None: lock_mgr = self.ctx.dos_lib.lock_mgr dos_list = self.ctx.dos_lib.dos_list entry = dos_list.get_entry_by_name('root') lock = entry.locks[0] self.cwd_lock = lock_mgr.create_lock(lock, cwd, False) log_proc.info("current dir: cwd=%s create lock=%s", cwd, self.cwd_lock) self.cwd_shared = False else: self.cwd_lock = cwd_lock self.cwd_shared = True log_proc.info("current dir: cwd=%s shared lock=%s", cwd, self.cwd_lock)
def run_command(scheduler, process, start_pc, args_ptr, args_len, stack_size, reg_d1=0): ctx = process.ctx alloc = ctx.alloc new_stack = Stack.alloc(alloc, stack_size) # save old stack oldstack_upper = process.this_task.access.r_s("pr_Task.tc_SPLower") oldstack_lower = process.this_task.access.r_s("pr_Task.tc_SPUpper") # activate new stack process.this_task.access.w_s("pr_Task.tc_SPLower", new_stack.get_upper()) process.this_task.access.w_s("pr_Task.tc_SPUpper", new_stack.get_lower()) # NOTE: the Manx fexec and BPCL mess is not (yet) setup here. # setup sub task sp = new_stack.get_initial_sp() # new proc registers: d0=arg_len a0=arg_cptr # 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). set_regs = { REG_D0: args_len, REG_D1: reg_d1, REG_A0: args_ptr, REG_D2: stack_size, REG_A2: ctx.odg_base, REG_A5: ctx.odg_base, REG_A6: ctx.odg_base, } get_regs = [REG_D0] task = Task("RunCommand", start_pc, new_stack, set_regs, get_regs) # run sub task scheduler.run_sub_task(task) # return value run_state = task.get_run_state() ret_code = run_state.regs[REG_D0] log_proc.info("return from RunCommand: ret_code=%d", ret_code) # restore stack values process.this_task.access.w_s("pr_Task.tc_SPLower", oldstack_lower) process.this_task.access.w_s("pr_Task.tc_SPUpper", oldstack_upper) # result code return ret_code
def run_sub_process(scheduler, proc): log_proc.info("start sub process: %s", proc) task = proc.get_task() scheduler.add_task(task) # return value run_state = task.get_run_state() ret_code = run_state.regs[REG_D0] log_proc.info("return from sub process: ret_code=%d", ret_code) # cleanup proc proc.free() return ret_code
def run_sub_process(scheduler, proc): log_proc.info("start sub process: %s", proc) task = proc.get_task() scheduler.add_task(task) # return value run_state = task.get_run_state() ret_code = run_state.regs[REG_D0] log_proc.info("return from sub process: ret_code=%d", ret_code) # cleanup proc proc.free() return ret_code
def __init__( self, ctx, bin_file, arg_str, input_fh=None, output_fh=None, stack_size=4096, shell=False, cwd=None, cwd_lock=None, ): """bin_file Amiga path to binary for process arg_str Shell-style parameter string with trailing newline """ self.ctx = ctx if input_fh == None: input_fh = self.ctx.dos_lib.file_mgr.get_input() if output_fh == None: output_fh = self.ctx.dos_lib.file_mgr.get_output() self.init_cwd(cwd, cwd_lock) self.ok = self.load_binary(self.cwd_lock, bin_file, shell) if not self.ok: return # setup stack self.stack = Stack.alloc(self.ctx.alloc, stack_size) log_proc.info(self.stack) # thor: the boot shell creates its own CLI if it is not there. # but for now, supply it with the Vamos CLI and let it initialize # it through the private CliInit() call of the dos.library if not shell: self.shell = False self.init_args(arg_str, input_fh) self.init_cli_struct(input_fh, output_fh, self.bin_basename) else: self.arg = None self.arg_base = 0 self.shell = True self.init_cli_struct(None, None, None) self.shell_message = None self.shell_packet = None self.shell_port = None self.init_task_struct(input_fh, output_fh) self.set_cwd() self._init_task()
def run_command(scheduler, process, start_pc, args_ptr, args_len, stack_size, reg_d1=0): ctx = process.ctx alloc = ctx.alloc new_stack = Stack.alloc(alloc, stack_size) # save old stack oldstack_upper = process.this_task.access.r_s("pr_Task.tc_SPLower") oldstack_lower = process.this_task.access.r_s("pr_Task.tc_SPUpper") # activate new stack process.this_task.access.w_s("pr_Task.tc_SPLower", new_stack.get_upper()) process.this_task.access.w_s("pr_Task.tc_SPUpper", new_stack.get_lower()) # NOTE: the Manx fexec and BPCL mess is not (yet) setup here. # setup sub task sp = new_stack.get_initial_sp() # new proc registers: d0=arg_len a0=arg_cptr # 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). set_regs = { REG_D0: args_len, REG_D1: reg_d1, REG_A0: args_ptr, REG_D2: stack_size, REG_A2: ctx.odg_base, REG_A5: ctx.odg_base, REG_A6: ctx.odg_base } get_regs = [REG_D0] task = Task("RunCommand", start_pc, new_stack, set_regs, get_regs) # run sub task scheduler.run_sub_task(task) # return value run_state = task.get_run_state() ret_code = run_state.regs[REG_D0] log_proc.info("return from RunCommand: ret_code=%d", ret_code) # restore stack values process.this_task.access.w_s("pr_Task.tc_SPLower", oldstack_lower) process.this_task.access.w_s("pr_Task.tc_SPUpper", oldstack_upper) # result code return ret_code
def init_cli_struct(self, input_fh, output_fh, name): self.cli = self.ctx.alloc.alloc_struct(self.bin_basename + "_CLI",CLIStruct) self.cli.access.w_s("cli_DefaultStack", self.stack.get_size() / 4) # in longs if input_fh != None: self.cli.access.w_s("cli_StandardInput", input_fh.b_addr << 2) self.cli.access.w_s("cli_CurrentInput", input_fh.b_addr << 2) if output_fh != None: self.cli.access.w_s("cli_StandardOutput", output_fh.b_addr << 2) self.cli.access.w_s("cli_CurrentOutput", output_fh.b_addr << 2) self.prompt = self.ctx.alloc.alloc_memory("cli_Prompt",60) self.cmdname = self.ctx.alloc.alloc_memory("cli_CommandName",104) self.cmdfile = self.ctx.alloc.alloc_memory("cli_CommandFile",40) self.setname = self.ctx.alloc.alloc_memory("cli_SetName",80) self.cli.access.w_s("cli_Prompt",self.prompt.addr) self.cli.access.w_s("cli_CommandName",self.cmdname.addr) self.cli.access.w_s("cli_CommandFile",self.cmdfile.addr) self.cli.access.w_s("cli_SetName",self.setname.addr) if name != None: self.ctx.mem.w_bstr(self.cmdname.addr,name) log_proc.info(self.cli)
def init_cli_struct(self, input_fh, output_fh, name): self.cli = self.ctx.alloc.alloc_struct(self.bin_basename + "_CLI",CLIStruct) self.cli.access.w_s("cli_DefaultStack", self.stack_size / 4) # in longs if input_fh != None: self.cli.access.w_s("cli_StandardInput", input_fh.b_addr) self.cli.access.w_s("cli_CurrentInput", input_fh.b_addr) if output_fh != None: self.cli.access.w_s("cli_StandardOutput", output_fh.b_addr) self.cli.access.w_s("cli_CurrentOutput", output_fh.b_addr) self.prompt = self.ctx.alloc.alloc_memory("cli_Prompt",60) self.cmdname = self.ctx.alloc.alloc_memory("cli_CommandName",104) self.cmdfile = self.ctx.alloc.alloc_memory("cli_CommandFile",40) self.setname = self.ctx.alloc.alloc_memory("cli_SetName",80) self.cli.access.w_s("cli_Prompt",self.prompt.addr) self.cli.access.w_s("cli_CommandName",self.cmdname.addr) self.cli.access.w_s("cli_CommandFile",self.cmdfile.addr) self.cli.access.w_s("cli_SetName",self.setname.addr) if name != None: self.ctx.mem.w_bstr(self.cmdname.addr,name) log_proc.info(self.cli)
def load_binary(self, lock, ami_bin_file, shell=False): self.bin_basename = self.ctx.path_mgr.ami_name_of_path(lock,ami_bin_file) self.bin_file = ami_bin_file sys_path = self.ctx.path_mgr.ami_command_to_sys_path(lock, ami_bin_file) if not sys_path or not os.path.exists(sys_path): log_proc.error("failed loading binary: %s -> %s", ami_bin_file, sys_path) return False self.bin_seg_list = self.ctx.seg_loader.load_sys_seglist(sys_path) info = self.ctx.seg_loader.get_info(self.bin_seg_list) self.prog_start = info.seglist.get_segment().get_addr() # THOR: If this is a shell, then the seglist requires BCPL linkage and # initialization of the GlobVec. Fortunately, for the 3.9 shell all this # magic is not really required, and the BCPL call-in (we use) is at # offset +8 if shell: self.prog_start += 8 self.shell_start = self.prog_start log_proc.info("loaded binary: %s", info) for seg in info.seglist: log_proc.info(seg) return True
def load_binary(self, lock, ami_bin_file, shell=False): self.bin_basename = self.ctx.path_mgr.ami_name_of_path(lock,ami_bin_file) self.bin_file = ami_bin_file sys_path, ami_path = self.ctx.path_mgr.ami_command_to_sys_path(lock, ami_bin_file) if not sys_path: log_proc.error("failed loading binary: %s -> %s", ami_bin_file, sys_path) return False self.bin_seg_list = self.ctx.seg_loader.load_sys_seglist(sys_path) info = self.ctx.seg_loader.get_info(self.bin_seg_list) self.prog_start = info.seglist.get_segment().get_addr() # set home dir and get lock self.home_dir = self.ctx.path_mgr.ami_dir_of_path(lock, ami_path) lock_mgr = self.ctx.dos_lib.lock_mgr self.home_lock = lock_mgr.create_lock(lock, self.home_dir, False) log_proc.info("home dir: %s", self.home_lock) # THOR: If this is a shell, then the seglist requires BCPL linkage and # initialization of the GlobVec. Fortunately, for the 3.9 shell all this # magic is not really required, and the BCPL call-in (we use) is at # offset +8 if shell: self.prog_start += 8 self.shell_start = self.prog_start log_proc.info("loaded binary: %s", info) for seg in info.seglist: log_proc.info(seg) return True
def create_main_proc(cls, proc_cfg, path_mgr, dos_ctx): # a single Amiga-like raw arg was passed cmd_cfg = proc_cfg.command if cmd_cfg.raw_arg: # check args if len(cmd_cfg.args) > 0: log_proc.error("raw arg only allows a single argument!") return None # parse raw arg cl = CommandLine() res = cl.parse_line(cmd_cfg.binary) if res != cl.LINE_OK: log_proc.error("raw arg is invalid! (error %d)", res) return None binary = cl.get_cmd() arg_str = cl.get_arg_str() else: # setup binary binary = cmd_cfg.binary if not cmd_cfg.pure_ami_path: # if path exists on host system then make an ami path if os.path.exists(binary): sys_binary = binary binary = path_mgr.from_sys_path(binary) if not binary: log_proc.error("can't map binary: %s", sys_binary) return None # combine remaining args to arg_str arg_str = sys_args_to_ami_arg_str(cmd_cfg.args) # summary stack_size = proc_cfg.stack * 1024 shell = proc_cfg.command.shell log_proc.info("binary: '%s'", binary) log_proc.info("args: '%s'", arg_str[:-1]) log_proc.info("stack: %d", stack_size) cwd = str(path_mgr.get_cwd()) proc = cls(dos_ctx, binary, arg_str, stack_size=stack_size, shell=shell, cwd=cwd) if not proc.ok: return None log_proc.info("set main process: %s", proc) return proc
def __init__(self, ctx, bin_file, arg_str, input_fh=None, output_fh=None, stack_size=4096, shell=False, cwd=None, cwd_lock=None): """bin_file Amiga path to binary for process arg_str Shell-style parameter string with trailing newline """ self.ctx = ctx if input_fh == None: input_fh = self.ctx.dos_lib.file_mgr.get_input() if output_fh == None: output_fh = self.ctx.dos_lib.file_mgr.get_output() self.init_cwd(cwd, cwd_lock) self.ok = self.load_binary(self.cwd_lock,bin_file,shell) if not self.ok: return # setup stack self.stack = Stack.alloc(self.ctx.alloc, stack_size) log_proc.info(self.stack) # thor: the boot shell creates its own CLI if it is not there. # but for now, supply it with the Vamos CLI and let it initialize # it through the private CliInit() call of the dos.library if not shell: self.shell = False self.init_args(arg_str, input_fh) self.init_cli_struct(input_fh, output_fh,self.bin_basename) else: self.arg = None self.arg_base = 0 self.shell = True self.init_cli_struct(None,None,None) self.shell_message = None self.shell_packet = None self.shell_port = None self.init_task_struct(input_fh, output_fh) self.set_cwd() self._init_task()
def init_cli_struct(self, input_fh, output_fh, name): self.cli = self.ctx.alloc.alloc_struct(CLIStruct, label=self.bin_basename + "_CLI") self.cli.access.w_s("cli_DefaultStack", self.stack.get_size() // 4) # in longs if input_fh != None: self.cli.access.w_s("cli_StandardInput", input_fh.b_addr << 2) self.cli.access.w_s("cli_CurrentInput", input_fh.b_addr << 2) if output_fh != None: self.cli.access.w_s("cli_StandardOutput", output_fh.b_addr << 2) self.cli.access.w_s("cli_CurrentOutput", output_fh.b_addr << 2) self.prompt = self.ctx.alloc.alloc_memory(60, label="cli_Prompt") self.cmdname = self.ctx.alloc.alloc_memory(104, label="cli_CommandName") self.cmdfile = self.ctx.alloc.alloc_memory(40, label="cli_CommandFile") self.setname = self.ctx.alloc.alloc_memory(80, label="cli_SetName") self.cli.access.w_s("cli_Prompt", self.prompt.addr) self.cli.access.w_s("cli_CommandName", self.cmdname.addr) self.cli.access.w_s("cli_CommandFile", self.cmdfile.addr) self.cli.access.w_s("cli_SetName", self.setname.addr) if name != None: self.ctx.mem.w_bstr(self.cmdname.addr, name) log_proc.info(self.cli)
def create_main_proc(cls, proc_cfg, path_mgr, dos_ctx): # a single Amiga-like raw arg was passed cmd_cfg = proc_cfg.command if cmd_cfg.raw_arg: # check args if len(cmd_cfg.args) > 0: log_proc.error("raw arg only allows a single argument!") return None # parse raw arg cl = CommandLine() res = cl.parse_line(cmd_cfg.binary) if res != cl.LINE_OK: log_proc.error("raw arg is invalid! (error %d)", res) return None binary = cl.get_cmd() arg_str = cl.get_arg_str() else: # setup binary binary = cmd_cfg.binary if not cmd_cfg.pure_ami_path: # if path exists on host system then make an ami path if os.path.exists(binary): sys_binary = binary binary = path_mgr.from_sys_path(binary) if not binary: log_proc.error("can't map binary: %s", sys_binary) return None # combine remaining args to arg_str arg_str = sys_args_to_ami_arg_str(cmd_cfg.args) # summary stack_size = proc_cfg.stack * 1024 shell = proc_cfg.command.shell log_proc.info("binary: '%s'", binary) log_proc.info("args: '%s'", arg_str[:-1]) log_proc.info("stack: %d", stack_size) cwd = str(path_mgr.get_cwd()) proc = cls(dos_ctx, binary, arg_str, stack_size=stack_size, shell=shell, cwd=cwd) if not proc.ok: return None log_proc.info("set main process: %s", proc) return proc
def free_cwd(self): if self.cwd_lock is not None and not self.cwd_shared: log_proc.info("current_dir: free lock=%s", self.cwd_lock) lock_mgr = self.ctx.dos_lib.lock_mgr lock_mgr.release_lock(self.cwd_lock)
def free_cwd(self): if self.cwd_lock is not None and not self.cwd_shared: log_proc.info("current_dir: free lock=%s", self.cwd_lock) lock_mgr = self.ctx.dos_lib.lock_mgr lock_mgr.release_lock(self.cwd_lock)