From 3bb78c08a6ec5d1a9880e8ae40f1094b9e584792 Mon Sep 17 00:00:00 2001 From: robjustice Date: Tue, 18 Dec 2018 15:30:48 +1100 Subject: [PATCH] Delete A3Driverutil.py --- A3Driverutil.py | 626 ------------------------------------------------ 1 file changed, 626 deletions(-) delete mode 100644 A3Driverutil.py diff --git a/A3Driverutil.py b/A3Driverutil.py deleted file mode 100644 index 3c291f4..0000000 --- a/A3Driverutil.py +++ /dev/null @@ -1,626 +0,0 @@ -#!/usr/bin/python -# - -# use unpack from struct and argv from sys -from struct import unpack,pack; import argparse; - -parser = argparse.ArgumentParser( - prog='A3Driverutil.py', - formatter_class=argparse.RawDescriptionHelpFormatter, - description='''\ -Driverutil.py - A Python script to work with A3 drivers - By Robert Justice - -The primary function is to convert an o65 relocatable 6502 binary -file to A3 driver format. This is to allow driver development using -the ca65 assembler - -Support to add, update the converted driver into a SOS.DRIVER file -and delete & list is also included. - -Finally, has some extract functions to extract driver code to allow -disassembly. One of these will relocate the extracted Driver to -0x2000 base address to minimise any confusion with zero page when -disassembling. - - https://github.com/rob_justice/A3Driverutil - - reuses some functions and ideas from Driv3rs.py, thank you - https://github.com/thecompu/Driv3rs - -''') - -subparsers = parser.add_subparsers(help='Command Description',dest="command") - -# Bin command -bin_parser = subparsers.add_parser( - 'bin', help='Convert o65 binary to A3 driver binary format, Comment + Code + RelocationTable') -bin_parser.add_argument( - 'o65file', action='store', - help='Input o65 code file to be converted') -bin_parser.add_argument( - 'binfile', action='store', - help='Binary output file') - -# Sos command -sos_parser = subparsers.add_parser( - 'sos', help='Convert o65 binary and output as SOS.DRIVER format(for use with scp)') -sos_parser.add_argument( - 'o65file', action='store', - help='Input o65 code file to be converted') -sos_parser.add_argument( - 'sosfile', action='store', - help='SOS.DRIVER Binary output file') - -# List command -add_parser = subparsers.add_parser( - 'list', help='List current drivers in a SOS.DRIVER file') -add_parser.add_argument( - 'sosfile', action='store', - help='SOS.DRIVER file to be updated') - -# Add command -add_parser = subparsers.add_parser( - 'add', help='Convert o65 binary and add as new driver to a existing SOS.DRIVER file') -add_parser.add_argument( - 'o65file', action='store', - help='Input o65 code file to be converted') -add_parser.add_argument( - 'sosfile', action='store', - help='SOS.DRIVER file to list the contained drivers') - -# Update command -update_parser = subparsers.add_parser( - 'update', help='Convert o65 binary and update existing driver in a SOS.DRIVER file') -update_parser.add_argument( - 'o65file', action='store', - help='Input o65 code file to be converted') -update_parser.add_argument( - 'sosfile', action='store', - help='SOS.DRIVER file to be updated') - -# Delete command -delete_parser = subparsers.add_parser( - 'delete', help='Delete a driver from an existing SOS.DRIVER file') -delete_parser.add_argument( - 'drivername', action='store', - help='Name of driver to be deleted (include . eg: ".console"') -delete_parser.add_argument( - 'sosfile', action='store', - help='SOS.DRIVER file to delete the driver from') - -# Extract command -extract_parser = subparsers.add_parser( - 'extract', help='Extract a driver from an existing SOS.DRIVER file') -extract_parser.add_argument( - 'drivername', action='store', - help='Name of driver to be extracted (include . eg: ".console"') -extract_parser.add_argument( - 'sosfile', action='store', - help='SOS.DRIVER file to extract the driver from') - -# Extract code and relocate to 0x2000 command -extract_parser = subparsers.add_parser( - 'extractcode', help='Extract a drivers code from an existing SOS.DRIVER file and relocate to 0x2000 to aid disassembly') -extract_parser.add_argument( - 'drivername', action='store', - help='Name of driver to be extracted (include . eg: ".console"') -extract_parser.add_argument( - 'sosfile', action='store', - help='SOS.DRIVER file to extract the driver from') - -args = parser.parse_args() - - -# this function unpacks several read operations -- -# text, binary, and single-byte. Each uses unpack from -# struct and attempts converts the resulting tuple into -# into either a string or integer, depending upon need. -def readUnpack(file,bytes, **options): - if options.get("type") == 't': - SOS = file.read(bytes) - text_unpacked = unpack('%ss' % bytes, SOS) - return ''.join(text_unpacked) - - if options.get("type") == 'b': - SOS = file.read(bytes) - offset_unpacked = unpack ('< H', SOS) - return int('.'.join(str(x) for x in offset_unpacked)) - - if options.get("type") == '1': - SOS = file.read(bytes) - offset_unpacked = unpack ('< B', SOS) - return int(ord(SOS)) - -# this function reads a word from a string at the specified -# offset and returns an integer -def readWord(data,startpos): - return ord(data[startpos+1])*256+ord(data[startpos]) - -# this function reads a byte from a string at the specified -# offset and returns an integer -def readByte(data,startpos): - return ord(data[startpos]) - -# -# this function reads in a o65 binary file of a driver and -# converts to the same format as contained in the SOS.DRIVER -# file for drivers, Comment, Code, RelocateTable -# input - filename of o65 file -# returns - converted driver as a string -# -def convert_o65(file): - o65file = open(file, 'rb') - - #parse the o65 file - byte = readUnpack(o65file,1,type = '1') #non-C64 marker, 2 bytes - byte = readUnpack(o65file,1,type = '1') - o65 = readUnpack(o65file,3,type = 't') # "o65" MAGIC number! - if o65 == 'o65': #valid file, lets keep going - version = readUnpack(o65file,1,type = '1') # version - mode = readUnpack(o65file,2,type = 'b') # mode word - tbase = readUnpack(o65file,2,type = 'b') # address to which text is assembled to originally - tlen = readUnpack(o65file,2,type = 'b') # length of text segment - dbase = readUnpack(o65file,2,type = 'b') # originating address for data segment - dlen = readUnpack(o65file,2,type = 'b') # length of data segment - bbase = readUnpack(o65file,2,type = 'b') # originating address for bss segment - blen = readUnpack(o65file,2,type = 'b') # length of bss segment - zbase = readUnpack(o65file,2,type = 'b') # originating address for zero segment - zlen = readUnpack(o65file,2,type = 'b') # length of zero segment - stack = readUnpack(o65file,2,type = 'b') # minimum needed stack size, 0= not known. - - #print ("mode: ",mode) - #print ("tbase: ",tbase) - #print ("tlen: ",tlen) - #print ("dbase: ",dbase) - #print ("dlen: ",dlen) - - #skip over header options - olen = readUnpack(o65file,1,type = '1') - while olen != 0 : #0 marks end of options header - otype = readUnpack(o65file,1,type = '1') - option_bytes = readUnpack(o65file,olen-2,type = 't') - olen = readUnpack(o65file,1,type = '1') - - driver='' #this will be the converted driver - - #add text segment - driver += o65file.read(tlen) #this is the comment part - - #trim off the comment 0xFFFF if there is a comment - if readWord(driver,0) == 0xFFFF: - driver = driver[2:] - - #add data segment length - driver += pack(' 254, so add this and get next byte - offset_address = offset_address + offset -1 #add 254 - offset = readUnpack(o65file,1,type = '1') - else: - typebyte = readUnpack(o65file,1,type = '1') - if typebyte == 0x83: #8=word offset and 3=data segment - offset_address = offset_address + offset - reloctable.append(offset_address) - offset = readUnpack(o65file,1,type = '1') - - #add the length of the relocation table - driver += pack('H',0x0400) #Number of Disk /// drives installed (4) - header += '?? ' #char set name, ?? indicates no char set included (16 chars long) - - for i in range(0,0x400): #pad out the char set with spaces - header += ' ' - - header += '?? ' #keyboard layout name (16 chars long) - - for i in range(0,0x100): #pad out with spaces - header += ' ' - - sos_file = args.sosfile - outfile = open(sos_file,'wb') - outfile.write(header + driver + pack('>H',0xFFFF)) #add the end marker - - print 'File converted and written as SOS.DRIVER binary file to:',sos_file - outfile.close() - -#Convert and add to an existing SOS.DRIVER file -elif args.command == 'add': - driver = convert_o65(args.o65file) #convert the driver code - - driver_name = getDriverName(driver) #extract the driver name from the driver - - sos_file = args.sosfile #read in the existing SOS.DRIVER file - sosdriver = open(sos_file,'rb') - sosdriverfile = sosdriver.read() - sosdriver.close() - - drivers_list = parsedriverfile(sosdriverfile)[0] #we just want the first item in the returned list - driver_end = parsedriverfile(sosdriverfile)[1] #this is the offset of the 0xFFFF end marker - - #lets check if it already exists in the SOS.DRIVER file - driver_details = [] - - for i in range(0,len(drivers_list)): - offset = drivers_list[i]['code_start'] - driver_details.append(parseDIB(sosdriverfile,offset,0)) #we always use dib0 - - i = find(driver_details,'name',driver_name.upper()) #find index of the driver to add, convert name to uppercase - - if i == -1: - #not found, lets add - trimmed_sosdriver = sosdriverfile[0:driver_end] #trim of the 0xFFFF end marker - newsosdriverfile = trimmed_sosdriver + driver + chr(0xFF) + chr(0xFF) - - sosdriver = open(sos_file,'wb') #write it back out, overwriting the old one - sosdriver.write(newsosdriverfile) - sosdriver.close() - - print 'Driver: ' + driver_name + ' added to ' + sos_file - - else: - #found, report error - print 'Driver: ' + driver_name + ' elready exists in ' + sos_file + ', not added' - - -#List drivers in a SOS.DRIVER file -elif args.command == 'list': - sos_file = args.sosfile - sosdriver = open(sos_file,'rb') - filedata = sosdriver.read() - drivers_list = parsedriverfile(filedata)[0] #we just want the first item in the returned list - - driver_details = [] - - for i in range(0,len(drivers_list)): - dib = 0 - offset = drivers_list[i]['code_start'] - driver_details.append(parseDIB(filedata,offset,dib)) - nextdib = readWord(filedata,offset+2) #next dib of this driver - while nextdib != 0: - dib += 1 - driver_details.append(parseDIB(filedata,offset+nextdib,dib)) - nextdib = readWord(filedata,offset+nextdib+2) #next dib of this driver - - print 'DriverName Status Slot Unit Manid Release' - for i in range(0,len(driver_details)): - #decode status byte - if driver_details[i]['status'] & 0x80 == 0x80: - status = 'active' - else: - status = 'inactive' - #decode slot - if driver_details[i]['slot'] == 0: - slot = 'N/A' - else: - slot = driver_details[i]['slot'] - - if driver_details[i]['dib_num'] == 0: #don't indent the first DIB - print '{:16} {:10} {:3} {:02X} {:04X} {:04X}'.format(driver_details[i]['name'], status, slot, driver_details[i]['unit'],driver_details[i]['manid'],driver_details[i]['release']) - else: #otherwise indent the rest, ie sub devices - print ' {:16}{:10} {:3} {:02X} {:04X} {:04X}'.format(driver_details[i]['name'], status, slot, driver_details[i]['unit'],driver_details[i]['manid'],driver_details[i]['release']) - - print '\n Total size: ',len(filedata) - - -#Convert and update an existing driver in a SOS.DRIVER file -elif args.command == 'update': - driver = convert_o65(args.o65file) #convert the driver code - - driver_name = getDriverName(driver) #extract the driver name from the driver - - print 'Driver in o65 file: ',driver_name - - sos_file = args.sosfile #read in the existing SOS.DRIVER file - sosdriver = open(sos_file,'rb') - sosdriverfile = sosdriver.read() - sosdriver.close() - - drivers_list = parsedriverfile(sosdriverfile)[0] - drivers_end = parsedriverfile(sosdriverfile)[1] - - driver_details = [] - - for i in range(0,len(drivers_list)): - offset = drivers_list[i]['code_start'] - driver_details.append(parseDIB(sosdriverfile,offset,0)) #we always use dib0 - - i = find(driver_details,'name',driver_name.upper()) #find index of the driver to update, convert name to uppercase - - if i != -1: - #found it - print 'Driver found in SOS.DRIVER, updating..' - #print drivers_list - - newsosdriverfile = sosdriverfile[0:drivers_list[i]['comment_start']] #part up to target driver - newsosdriverfile += driver #add the updated driver - - if i < len(drivers_list)-1: #check if its not the last one - newsosdriverfile += sosdriverfile[drivers_list[i+1]['comment_start']:] #add the rest after the target driver - else: #otherwise we use the end marker - newsosdriverfile += sosdriverfile[drivers_end:] #add the rest after the target driver - - sosdriver = open(sos_file,'wb') #write it back out - sosdriver.write(newsosdriverfile) - sosdriver.close() - - print 'Driver: ' + driver_name + ' updated!' - - else: - #not found - print 'Driver: ' + driver_name + ' not found in SOS.DRIVER file' - - -#Delete an existing driver in a SOS.DRIVER file -elif args.command == 'delete': - driver_name = args.drivername - - sos_file = args.sosfile #read in the SOS.DRIVER file - sosdriver = open(sos_file,'rb') - sosdriverfile = sosdriver.read() - sosdriver.close() - - drivers_list = parsedriverfile(sosdriverfile)[0] - drivers_end = parsedriverfile(sosdriverfile)[1] - - driver_details = [] - - for i in range(0,len(drivers_list)): - offset = drivers_list[i]['code_start'] - driver_details.append(parseDIB(sosdriverfile,offset,0)) #we always use dib0 - - i = find(driver_details,'name',driver_name.upper()) #find index of the driver to delete, convert name to uppercase - - if i != -1: - #found it - print 'Driver found in SOS.DRIVER, deleting..' - - newsosdriverfile = sosdriverfile[0:drivers_list[i]['comment_start']] #part up to target driver - - if i < len(drivers_list)-1: #check if its not the last one - newsosdriverfile += sosdriverfile[drivers_list[i+1]['comment_start']:] #add the rest after the target driver - else: #otherwise we use the end marker - newsosdriverfile += sosdriverfile[drivers_end:] #add the rest after the target driver - - sosdriver = open(sos_file,'wb') #write it back out - sosdriver.write(newsosdriverfile) - sosdriver.close() - - print 'Driver: ' + driver_name + ' deleted!' - - else: - #not found - print 'Driver: ' + driver_name + ' not found in SOS.DRIVER file' - - - -#Extract a driver from a SOS.DRIVER file -elif args.command == 'extract': - driver_name = args.drivername - - sos_file = args.sosfile #read in the SOS.DRIVER file - sosdriver = open(sos_file,'rb') - sosdriverfile = sosdriver.read() - sosdriver.close() - - drivers_list = parsedriverfile(sosdriverfile)[0] #parse the driver file to find the positions of the drivers - drivers_end = parsedriverfile(sosdriverfile)[1] #parse the driver file to find the end of the drivers - - driver_details = [] #now grab the details from dib0 of each them ie to find the names - for i in range(0,len(drivers_list)): - offset = drivers_list[i]['code_start'] - driver_details.append(parseDIB(sosdriverfile,offset,0)) #we always use dib0 - - i = find(driver_details,'name',driver_name.upper()) #find index of the driver to extract, convert name to uppercase - - if i != -1: - #found it - print 'Driver found in SOS.DRIVER, extracting..' - - if i < len(drivers_list)-1: #check if its not the last one in sos.driver - extracted_driver = sosdriverfile[drivers_list[i]['comment_start']:drivers_list[i+1]['comment_start']] - - else: #must be the last one, so we use the offset of the 0xFFFF marker - extracted_driver = sosdriverfile[drivers_list[i]['comment_start']:drivers_end] - - filename = driver_name[1:] + '.driver' #chop off the ., and add .driver to the end - driverfile = open(filename,'wb') #write the new driver out - driverfile.write(extracted_driver) - driverfile.close() - - print 'Driver: ' + driver_name + ' extracted and written to file: ' + filename - - else: - #not found - print 'Driver: ' + driver_name + ' not found in SOS.DRIVER file' - -#Extract a drivers code from a SOS.DRIVER file and relocate to 0x2000 to aid disassembly -# relocating to something other than 0x0000 helps to remove zero page ambiguities when -# disassembling the driver code -elif args.command == 'extractcode': - driver_name = args.drivername - - sos_file = args.sosfile #read in the SOS.DRIVER file - sosdriver = open(sos_file,'rb') - sosdriverfile = sosdriver.read() - sosdriver.close() - - drivers_list = parsedriverfile(sosdriverfile)[0] #parse the driver file to find the positions of the drivers - drivers_end = parsedriverfile(sosdriverfile)[1] #parse the driver file to find the end of the drivers - - driver_details = [] #now grab the details from dib0 of each them ie to find the names - for i in range(0,len(drivers_list)): - offset = drivers_list[i]['code_start'] - driver_details.append(parseDIB(sosdriverfile,offset,0)) #we always use dib0 - - i = find(driver_details,'name',driver_name.upper()) #find index of the driver to extract, convert name to uppercase - - if i != -1: - #found it - print 'Driver found in SOS.DRIVER, extracting code..' - - #grab the code - extracted_driver_code = sosdriverfile[drivers_list[i]['code_start']+2:drivers_list[i]['reloc_start']] #skip the code length(+2) - - #grab the relocate table - if i < len(drivers_list)-1: #check if its not the last one in sos.driver - extracted_driver_reloc = sosdriverfile[drivers_list[i]['reloc_start']+2:drivers_list[i+1]['comment_start']] #skip the reloc length(+2) - else: #must be the last one, so we use the offset of the 0xFFFF marker - extracted_driver_reloc = sosdriverfile[drivers_list[i]['reloc_start']+2:drivers_end] #skip the reloc length(+2) - #print extracted_driver_reloc.encode('hex') - - #convert the reloc table from little endian addresses to list of integers - offset_table = [] - for i in range (0,len(extracted_driver_reloc),2): - offset_table.append(readWord(extracted_driver_reloc,i)) - - #now lets relocate the code to 0x2000 - #just updates the high byte of the addresses to 0x20 - j = 0 - for i in range(0,len(extracted_driver_code)): - byte = readByte(extracted_driver_code,i) - if i == offset_table[j]+1: #looking at high byte - extracted_driver_code = extracted_driver_code[:i] + chr(byte + 0x20) + extracted_driver_code[i+1:] #add to the existing address high byte - if j < (len(offset_table)-1): - j += 1 - - filename = driver_name[1:] + '.driver_code_0x2000' #chop off the ., and add .driver_code_0x2000 to the end - driverfile = open(filename,'wb') #write the new driver out - driverfile.write(extracted_driver_code) - driverfile.close() - - print 'Driver: ' + driver_name + ' extracted, relocated and written to file: ' + filename - - else: - #not found - print 'Driver: ' + driver_name + ' not found in SOS.DRIVER file'