From 708e903fb26e8f5a8a623579b82b894948e24aee Mon Sep 17 00:00:00 2001 From: Christian Vogelgsang Date: Thu, 23 Jan 2025 09:56:42 +0100 Subject: [PATCH] Added ACTION_SCREEN_MODE support for console --- amitools/vamos/lib/DosLibrary.py | 109 ++++++++++++------------ amitools/vamos/lib/ExecLibrary.py | 9 +- amitools/vamos/lib/dos/Error.py | 4 + amitools/vamos/lib/dos/FileManager.py | 60 +++++++++++-- amitools/vamos/lib/dos/action.py | 65 ++++++++++++++ amitools/vamos/lib/lexec/PortManager.py | 10 +++ 6 files changed, 188 insertions(+), 69 deletions(-) create mode 100644 amitools/vamos/lib/dos/action.py diff --git a/amitools/vamos/lib/DosLibrary.py b/amitools/vamos/lib/DosLibrary.py index a1f7a726..761ad4a4 100644 --- a/amitools/vamos/lib/DosLibrary.py +++ b/amitools/vamos/lib/DosLibrary.py @@ -5,7 +5,7 @@ from amitools.vamos.machine.regs import * from amitools.vamos.libcore import LibImpl -from amitools.vamos.astructs import AccessStruct, CSTR +from amitools.vamos.astructs import AccessStruct, CSTR, LONG from amitools.vamos.libstructs import ( DosLibraryStruct, DosInfoStruct, @@ -45,10 +45,6 @@ class DosLibrary(LibImpl): - DOSFALSE = 0 - DOSTRUE = 0xFFFFFFFF - DOSTRUE_S = -1 - LV_VAR = 0 # an variable LV_ALIAS = 1 # an alias LVF_IGNORE = 0x80 @@ -170,7 +166,7 @@ def Fault(self, ctx): else: txt = "%s" % err_str ctx.mem.w_cstr(buf_ptr, txt[: buf_len - 1]) - return self.DOSTRUE + return DOSTRUE def PrintFault(self, ctx): self.io_err = ctx.cpu.r_reg(REG_D1) @@ -199,7 +195,7 @@ def PrintFault(self, ctx): txt = "%s\n" % err_str fh = ctx.process.get_output() fh.write(txt.encode("latin-1")) - return self.DOSTRUE + return DOSTRUE # ----- current dir @@ -260,7 +256,7 @@ def DateToStr(self, ctx): ctx.mem.w_cstr(str_date_ptr, date_str) if str_time_ptr != 0: ctx.mem.w_cstr(str_time_ptr, time_str) - return self.DOSTRUE + return DOSTRUE def SetFileDate(self, ctx): ds_ptr = ctx.cpu.r_reg(REG_D2) @@ -278,15 +274,15 @@ def SetFileDate(self, ctx): if sys_path == None: log_dos.info("file not found: '%s' -> '%s'" % (name, sys_path)) self.setioerr(ctx, ERROR_OBJECT_NOT_FOUND) - return self.DOSFALSE + return DOSFALSE else: os.utime(sys_path, (seconds, seconds)) - return self.DOSTRUE + return DOSTRUE def SetComment(self, ctx): # the typical unixoid file system does not implement this log_dos.warning("SetComment: not implemented") - return self.DOSTRUE + return DOSTRUE def GetProgramName(self, ctx): buf_ptr = ctx.cpu.r_reg(REG_D1) @@ -296,10 +292,10 @@ def GetProgramName(self, ctx): # return error if name is too long, but copy buffer size if n > max_len - 1: self.setioerr(ctx, ERROR_LINE_TOO_LONG) - ret = self.DOSFALSE + ret = DOSFALSE prog_name = prog_name[0:max_len] else: - ret = self.DOSTRUE + ret = DOSTRUE ctx.mem.w_cstr(buf_ptr, prog_name) log_dos.info("GetProgramName() -> '%s' (%d)", prog_name, max_len) return ret @@ -384,7 +380,7 @@ def GetVar(self, ctx): flags = ctx.cpu.r_reg(REG_D4) if size == 0: self.setioerr(ctx, ERROR_BAD_NUMBER) - return self.DOSFALSE + return DOSFALSE name = ctx.mem.r_cstr(name_ptr) if not flags & self.GVF_GLOBAL_ONLY: node = self.find_var(ctx, name, flags & 0xFF) @@ -406,7 +402,7 @@ def GetVar(self, ctx): log_dos.info('GetVar("%s", 0x%x) -> %s' % (name, flags, value)) self.setioerr(ctx, len(value)) return min(nodelen - 1, size - 1) - return self.DOSFALSE + return DOSFALSE def FindVar(self, ctx): name_ptr = ctx.cpu.r_reg(REG_D1) @@ -435,7 +431,7 @@ def SetVar(self, ctx): node = self.find_var(ctx, name, vtype) if node != None: self.delete_var(ctx, node) - return self.DOSTRUE + return DOSTRUE else: if flags & self.GVF_BINARY_VAR: value = None @@ -450,7 +446,7 @@ def SetVar(self, ctx): node = self.create_var(ctx, name, flags) if node != None: self.set_var(ctx, node, buff_ptr, size, value, flags) - return self.DOSTRUE + return DOSTRUE return 0 def DeleteVar(self, ctx): @@ -462,7 +458,7 @@ def DeleteVar(self, ctx): log_dos.info('DeleteVar("%s")' % name) if node != None: self.delete_var(ctx, node) - return self.DOSTRUE + return DOSTRUE # ----- Signals ---------------------- @@ -553,33 +549,34 @@ def SelectOutput(self, ctx): ctx.process.set_output(fh) return cur_out - def SetMode(self, ctx, fh_b_addr, mode): + def SetMode(self, ctx, fh_b_addr, mode: LONG): fh = self.file_mgr.get_by_b_addr(fh_b_addr) + mode = mode.val log_dos.info("SetMode(fh=%s,mode=%d)", fh, mode) # check mode if mode == 0: cooked = True - elif mode == 1: + elif mode == 1 or mode == -1: cooked = False else: log_dos.warning("SetMode() mode=%d not supported!", mode) self.setioerr(ctx, ERROR_ACTION_NOT_KNOWN) - return self.DOSFALSE + return DOSFALSE if fh.is_interactive(): # try to use setmode in interactive ok = fh.set_mode(cooked) if ok: self.setioerr(ctx, 0) # no console window - return self.DOSTRUE + return DOSTRUE else: log_dos.warning("SetMode() not supported on this platform!") self.setioerr(ctx, ERROR_ACTION_NOT_KNOWN) - return self.DOSFALSE + return DOSFALSE else: log_dos.info("SetMode() not available on non-interactive FH") self.setioerr(ctx, ERROR_ACTION_NOT_KNOWN) - return self.DOSFALSE + return DOSFALSE def Open(self, ctx): name_ptr = ctx.cpu.r_reg(REG_D1) @@ -619,7 +616,7 @@ def Close(self, ctx): self.file_mgr.close(fh) log_dos.info("Close: %s" % fh) self.setioerr(ctx, 0) - return self.DOSTRUE + return DOSTRUE def Read(self, ctx): fh_b_addr = ctx.cpu.r_reg(REG_D1) @@ -901,9 +898,9 @@ def DeleteFile(self, ctx): self.setioerr(ctx, self.file_mgr.delete(self.get_current_dir(ctx), name)) log_dos.info("DeleteFile: '%s': err=%s" % (name, self.io_err)) if self.io_err == NO_ERROR: - return self.DOSTRUE + return DOSTRUE else: - return self.DOSFALSE + return DOSFALSE def Rename(self, ctx): old_name_ptr = ctx.cpu.r_reg(REG_D1) @@ -914,9 +911,9 @@ def Rename(self, ctx): self.setioerr(ctx, self.file_mgr.rename(lock, old_name, new_name)) log_dos.info("Rename: '%s' -> '%s': err=%s" % (old_name, new_name, self.io_err)) if self.io_err == NO_ERROR: - return self.DOSTRUE + return DOSTRUE else: - return self.DOSFALSE + return DOSFALSE def SetProtection(self, ctx): name_ptr = ctx.cpu.r_reg(REG_D1) @@ -926,22 +923,22 @@ def SetProtection(self, ctx): self.setioerr(ctx, self.file_mgr.set_protection(lock, name, mask)) log_dos.info("SetProtection: '%s' mask=%04x: err=%s", name, mask, self.io_err) if self.io_err == NO_ERROR: - return self.DOSTRUE + return DOSTRUE else: - return self.DOSFALSE + return DOSFALSE def IsInteractive(self, ctx): fh_b_addr = ctx.cpu.r_reg(REG_D1) log_dos.info("IsInteractive: @%06x" % fh_b_addr) if fh_b_addr == 0: - return self.DOSFALSE + return DOSFALSE fh = self.file_mgr.get_by_b_addr(fh_b_addr, False) res = fh.is_interactive() log_dos.info("IsInteractive(%s): %s" % (fh, res)) if res: - return self.DOSTRUE + return DOSTRUE else: - return self.DOSFALSE + return DOSFALSE def IsFileSystem(self, ctx): name_ptr = ctx.cpu.r_reg(REG_D1) @@ -951,9 +948,9 @@ def IsFileSystem(self, ctx): res = self.file_mgr.is_file_system(lock, name) log_dos.info("IsFileSystem('%s'): %s" % (name, res)) if res: - return self.DOSTRUE + return DOSTRUE else: - return self.DOSFALSE + return DOSFALSE # ----- Locks ----- @@ -1005,10 +1002,10 @@ def SameLock(self, ctx): lock1 = self.lock_mgr.get_by_b_addr(lock1_b_addr) lock2 = self.lock_mgr.get_by_b_addr(lock2_b_addr) if lock1 == lock2: - return self.DOSTRUE + return DOSTRUE if lock1 != None and lock2 != None: return lock1.key == lock2.key - return self.DOSFALSE + return DOSFALSE def Examine(self, ctx): lock_b_addr = ctx.cpu.r_reg(REG_D1) @@ -1022,9 +1019,9 @@ def Examine(self, ctx): log_dos.info("Examine: %s fib=%06x(%s) -> %s" % (lock, fib_ptr, name, err)) self.setioerr(ctx, err) if err == NO_ERROR: - return self.DOSTRUE + return DOSTRUE else: - return self.DOSFALSE + return DOSFALSE def ExamineFH(self, ctx): fh_b_addr = ctx.cpu.r_reg(REG_D1) @@ -1038,7 +1035,7 @@ def ExamineFH(self, ctx): ) if lock == None: self.setioerr(ctx, ERROR_OBJECT_NOT_FOUND) - return self.DOSFALSE + return DOSFALSE fib = AccessStruct(ctx.mem, FileInfoBlockStruct, struct_addr=fib_ptr) err = lock.examine_lock(fib) @@ -1050,9 +1047,9 @@ def ExamineFH(self, ctx): log_dos.info("UnLock: %s" % (lock)) self.lock_mgr.release_lock(lock) if err == NO_ERROR: - return self.DOSTRUE + return DOSTRUE else: - return self.DOSFALSE + return DOSFALSE def Info(self, ctx): lock_b_addr = ctx.cpu.r_reg(REG_D1) @@ -1071,10 +1068,10 @@ def Info(self, ctx): info.w_s("id_VolumeNode", vol) info.w_s("id_InUse", 0) log_dos.info("Info: %s info=%06x -> true" % (lock, info_ptr)) - return self.DOSTRUE + return DOSTRUE else: log_dos.info("Info: %s info=%06x -> false" % (lock, info_ptr)) - return self.DOSFALSE + return DOSFALSE def ExNext(self, ctx): lock_b_addr = ctx.cpu.r_reg(REG_D1) @@ -1088,10 +1085,10 @@ def ExNext(self, ctx): self.setioerr(ctx, err) if err == NO_ERROR: self.setioerr(ctx, 0) - return self.DOSTRUE + return DOSTRUE else: self.setioerr(ctx, err) - return self.DOSFALSE + return DOSFALSE def ParentDir(self, ctx): lock_b_addr = ctx.cpu.r_reg(REG_D1) @@ -1130,10 +1127,10 @@ def NameFromLock(self, ctx): log_dos.info("NameFromLock(%x,%d): %s -> %s", buf, buf_len, lock, name) if len(name) >= buf_len: self.setioerr(ctx, ERROR_LINE_TOO_LONG) - return self.DOSFALSE + return DOSFALSE else: ctx.mem.w_cstr(buf, name) - return self.DOSTRUE + return DOSTRUE def CreateDir(self, ctx): name_ptr = ctx.cpu.r_reg(REG_D1) @@ -1572,7 +1569,7 @@ def SystemTagList(self, ctx, cmd: CSTR, tag_list: TagList): output_fhci = None cli.w_s("cli_CurrentInput", new_input.mem.addr) cli.w_s("cli_StandardInput", new_stdin.mem.addr) - cli.w_s("cli_Background", self.DOSTRUE_S) + cli.w_s("cli_Background", DOSTRUE_S) # Create the Packet for the background process. packet = ctx.process.run_system() stack_size = cli.r_s("cli_DefaultStack") << 2 @@ -1601,7 +1598,7 @@ def SystemTagList(self, ctx, cmd: CSTR, tag_list: TagList): # shutdown cli.w_s("cli_CurrentInput", input_fhci) cli.w_s("cli_StandardInput", input_fhsi) - cli.w_s("cli_Background", self.DOSFALSE) + cli.w_s("cli_Background", DOSFALSE) cli.w_s("cli_Module", cur_module) if output_fhci != None: cli.w_s("cli_StandardOutput", output_fhci) @@ -1638,7 +1635,7 @@ def SystemTagList(self, ctx, cmd: CSTR, tag_list: TagList): binary, arg_str, ) - return self.DOSTRUE + return DOSTRUE return run_sub_process(ctx.scheduler, ctx.runner, proc) def LoadSeg(self, ctx): @@ -1742,9 +1739,9 @@ def AddPart(self, ctx): log_dos.info("AddPart: dn='%s' fn='%s' size=%d -> np='%s'", dn, fn, size, np) if np != None: ctx.mem.w_cstr(dn_addr, np) - return self.DOSTRUE + return DOSTRUE else: - return self.DOSFALSE + return DOSFALSE # ----- DosObjects ----- @@ -1922,7 +1919,7 @@ def SetCurrentDirName(self, ctx): cli = AccessStruct(ctx.mem, CLIStruct, struct_addr=cli_addr) setaddr = cli.r_s("cli_SetName") ctx.mem.w_bstr(setaddr, string) - return self.DOSTRUE + return DOSTRUE def SetPrompt(self, ctx): str_addr = ctx.cpu.r_reg(REG_D1) @@ -1931,7 +1928,7 @@ def SetPrompt(self, ctx): cli = AccessStruct(ctx.mem, CLIStruct, struct_addr=cli_addr) setaddr = cli.r_s("cli_Prompt") ctx.mem.w_bstr(setaddr, string) - return self.DOSTRUE + return DOSTRUE def DosGetString(self, ctx): errno = ctx.cpu.r_reg(REG_D1) diff --git a/amitools/vamos/lib/ExecLibrary.py b/amitools/vamos/lib/ExecLibrary.py index 1c440657..4d280187 100644 --- a/amitools/vamos/lib/ExecLibrary.py +++ b/amitools/vamos/lib/ExecLibrary.py @@ -80,9 +80,6 @@ def AllocSignal(self, ctx, signal_num: BYTE): task = self.get_my_task(ctx) old_mask = task.sig_alloc.val new_signal = signal_num.val - log_exec.info( - "AllocSignal(%d, %s) for task %s", new_signal, type(signal_num), task - ) if new_signal == -1: # find a free signal slot for bit in range(32): @@ -103,7 +100,7 @@ def AllocSignal(self, ctx, signal_num: BYTE): final_mask = old_mask log_exec.info( "AllocSignal(%d) for task %s -> %d (sig_mask %08x)", - new_signal, + signal_num.val, task, new_signal, final_mask, @@ -596,8 +593,8 @@ def WaitPort(self, ctx): raise UnsupportedFeatureError( "WaitPort on empty message queue called: Port (%06x)" % port_addr ) - msg_addr = self.port_mgr.get_msg(port_addr) - log_exec.info("WaitPort: got message %06x" % (msg_addr)) + msg_addr = self.port_mgr.peek_msg(port_addr) + log_exec.info("WaitPort: peek message %06x" % (msg_addr)) return msg_addr def AddTail(self, ctx): diff --git a/amitools/vamos/lib/dos/Error.py b/amitools/vamos/lib/dos/Error.py index 99b7733a..d0ef4f5c 100644 --- a/amitools/vamos/lib/dos/Error.py +++ b/amitools/vamos/lib/dos/Error.py @@ -1,3 +1,7 @@ +DOSFALSE = 0 +DOSTRUE = 0xFFFFFFFF +DOSTRUE_S = -1 + NO_ERROR = 0 ERROR_NO_FREE_STORE = 103 diff --git a/amitools/vamos/lib/dos/FileManager.py b/amitools/vamos/lib/dos/FileManager.py index 95840bed..6e2dd261 100644 --- a/amitools/vamos/lib/dos/FileManager.py +++ b/amitools/vamos/lib/dos/FileManager.py @@ -12,6 +12,7 @@ from .Error import * from .DosProtection import DosProtection from .FileHandle import FileHandle +from .action import DosAction class FileManager: @@ -262,14 +263,15 @@ def fs_put_msg(self, port_mgr, msg_addr): reply_port_addr = dos_pkt.r_s("dp_Port") pkt_type = dos_pkt.r_s("dp_Type") log_file.info( - "FS DosPacket: msg=%06x -> pkt=%06x: reply_port=%06x type=%06x", + "FS DosPacket: msg=%06x -> pkt=%06x: reply_port=%06x type=%06x (%s)", msg_addr, dos_pkt_addr, reply_port_addr, pkt_type, + DosAction(pkt_type).name, ) # handle packet - if pkt_type == ord("R"): # read + if pkt_type == DosAction.ACTION_READ: # read fh_b_addr = dos_pkt.r_s("dp_Arg1") buf_ptr = dos_pkt.r_s("dp_Arg2") size = dos_pkt.r_s("dp_Arg3") @@ -287,7 +289,7 @@ def fs_put_msg(self, port_mgr, msg_addr): fh, ) dos_pkt.w_s("dp_Res1", got) - elif pkt_type == ord("W"): # write + elif pkt_type == DosAction.ACTION_WRITE: # write fh_b_addr = dos_pkt.r_s("dp_Arg1") buf_ptr = dos_pkt.r_s("dp_Arg2") size = dos_pkt.r_s("dp_Arg3") @@ -305,7 +307,15 @@ def fs_put_msg(self, port_mgr, msg_addr): ) dos_pkt.w_s("dp_Res1", put) else: - raise UnsupportedFeatureError("Unsupported DosPacket: type=%d" % pkt_type) + log_file.warning( + "Unsupported Filesys Packet: %d (%s)", + pkt_type, + DosAction(pkt_type).name, + ) + # return error + dos_pkt.w_s("dp_Res1", DOSFALSE) + dos_pkg.w_s("dp_Res2", ACTION_NOT_KNOWN) + # do reply if not port_mgr.has_port(reply_port_addr): port_mgr.register_port(reply_port_addr) @@ -319,14 +329,50 @@ def console_put_msg(self, port_mgr, msg_addr): reply_port_addr = dos_pkt.r_s("dp_Port") pkt_type = dos_pkt.r_s("dp_Type") log_file.info( - "Console DosPacket: msg=%06x -> pkt=%06x: reply_port=%06x type=%06x", + "Console DosPacket: msg=%06x -> pkt=%06x: reply_port=%06x type=%d (%s)", msg_addr, dos_pkt_addr, reply_port_addr, pkt_type, + DosAction(pkt_type).name, ) - # fake result - dos_pkt.w_s("dp_Res1", 0) + + if pkt_type == DosAction.ACTION_SCREEN_MODE: + mode = dos_pkt.r_s("dp_Arg1") + if mode == 0: + cooked = True + elif mode == 1 or mode == -1: + cooked = False + else: + log_file.warning("Unsupported Console Mode: %d", mode) + # return error + pkt_result = (DOSFALSE, ERROR_BAD_NUMBER) + cooked = None + + res = False + if cooked is not None: + res = self.std_input.set_mode(cooked) + if res: + log_file.info("Set Console Mode %d -> cooked=%s", mode, cooked) + pkt_result = (DOSTRUE_S, 0) # 0=no window + else: + log_file.warning( + "Can't set Console Mode %d -> cooked=%s", mode, cooked + ) + # return error + pkt_result = (DOSFALSE, ERROR_ACTION_NOT_IMPLEMENTED) + else: + log_file.warning( + "Unsupported Console Packet: %d (%s)", + pkt_type, + DosAction(pkt_type).name, + ) + pkt_result = (DOSFALSE, ERROR_ACTION_NOT_KNOWN) + + # return set result + dos_pkt.w_s("dp_Res1", pkt_result[0]) + dos_pkt.w_s("dp_Res2", pkt_result[1]) + # do reply if not port_mgr.has_port(reply_port_addr): port_mgr.register_port(reply_port_addr) diff --git a/amitools/vamos/lib/dos/action.py b/amitools/vamos/lib/dos/action.py new file mode 100644 index 00000000..cb654a2f --- /dev/null +++ b/amitools/vamos/lib/dos/action.py @@ -0,0 +1,65 @@ +from enum import IntEnum + + +class DosAction(IntEnum): + ACTION_NIL = 0 + ACTION_STARTUP = 0 + ACTION_GET_BLOCK = 2 + ACTION_SET_MAP = 4 + ACTION_DIE = 5 + ACTION_EVENT = 6 + ACTION_CURRENT_VOLUME = 7 + ACTION_LOCATE_OBJECT = 8 + ACTION_RENAME_DISK = 9 + ACTION_WRITE = 87 + ACTION_READ = 82 + ACTION_FREE_LOCK = 15 + ACTION_DELETE_OBJECT = 16 + ACTION_RENAME_OBJECT = 17 + ACTION_MORE_CACHE = 18 + ACTION_COPY_DIR = 19 + ACTION_WAIT_CHAR = 20 + ACTION_SET_PROTECT = 21 + ACTION_CREATE_DIR = 22 + ACTION_EXAMINE_OBJECT = 23 + ACTION_EXAMINE_NEXT = 24 + ACTION_DISK_INFO = 25 + ACTION_INFO = 26 + ACTION_FLUSH = 27 + ACTION_SET_COMMENT = 28 + ACTION_PARENT = 29 + ACTION_TIMER = 30 + ACTION_INHIBIT = 31 + ACTION_DISK_TYPE = 32 + ACTION_DISK_CHANGE = 33 + ACTION_SET_DATE = 34 + ACTION_UNDISK_INFO = 513 + ACTION_SCREEN_MODE = 994 + ACTION_READ_RETURN = 1001 + ACTION_WRITE_RETURN = 1002 + ACTION_SEEK = 1008 + ACTION_FINDUPDATE = 1004 + ACTION_FINDINPUT = 1005 + ACTION_FINDOUTPUT = 1006 + ACTION_END = 1007 + ACTION_SET_FILE_SIZE = 1022 + ACTION_WRITE_PROTECT = 1023 + ACTION_SAME_LOCK = 40 + ACTION_CHANGE_SIGNAL = 995 + ACTION_FORMAT = 1020 + ACTION_MAKE_LINK = 1021 + ACTION_READ_LINK = 1024 + ACTION_FH_FROM_LOCK = 1026 + ACTION_IS_FILESYSTEM = 1027 + ACTION_CHANGE_MODE = 1028 + ACTION_COPY_DIR_FH = 1030 + ACTION_PARENT_FH = 1031 + ACTION_EXAMINE_ALL = 1033 + ACTION_EXAMINE_FH = 1034 + ACTION_LOCK_RECORD = 2008 + ACTION_FREE_RECORD = 2009 + ACTION_ADD_NOTIFY = 4097 + ACTION_REMOVE_NOTIFY = 4098 + ACTION_EXAMINE_ALL_END = 1035 + ACTION_SET_OWNER = 1036 + ACTION_SERIALIZE_DISK = 4200 diff --git a/amitools/vamos/lib/lexec/PortManager.py b/amitools/vamos/lib/lexec/PortManager.py index 51ef4f66..646605f8 100644 --- a/amitools/vamos/lib/lexec/PortManager.py +++ b/amitools/vamos/lib/lexec/PortManager.py @@ -39,6 +39,12 @@ def get_msg(self): else: return None + def peek_msg(self): + if self.queue is not None and len(self.queue) > 0: + return self.queue[0] + else: + return None + class PortManager: def __init__(self, alloc): @@ -88,3 +94,7 @@ def has_msg(self, port_addr): def get_msg(self, port_addr): port = self.ports[port_addr] return port.get_msg() + + def peek_msg(self, port_addr): + port = self.ports[port_addr] + return port.peek_msg()