diff --git a/config.txt b/config.txt new file mode 100644 index 0000000..fb6c6b9 --- /dev/null +++ b/config.txt @@ -0,0 +1,128 @@ +0x5 +0x8 +0x81 +0xe +0x9 +0xc +0x1a +0x98 +0x8d +0x19 +0x16 +0x5 +0x18 +0x98 +0x88 +0xd +0x97 +0x6 +0x9e +0x85 +0x4 +0x1e +0x8e +0x8b +0x87 +0x81 +0x9b +0x1b +0x88 +0x90 +0x80 +0x4 +0x80 +0x1 +0x1a +0xe +0x1e +0x96 +0x99 +0x9b +0x6 +0x9c +0x1d +0x17 +0xb +0x8b +0x8e +0x8b +0x99 +0x8f +0x92 +0x8f +0x90 +0xa +0x83 +0x81 +0x4 +0x8d +0x90 +0x9b +0xb +0x18 +0x9d +0x16 +0x3ea1b10b +0xf5f85463 +0x938d0cac +0xf5668bf5 +0x92c9b788 +0xe3342ec1 +0x87fe14e4 +0xcde1965d +0xffc732f7 +0x2f5d9985 +0xa7036d3 +0x35a7951b +0xc70c114d +0xa5b5c0e8 +0x82d9b130 +0xd047735e +0xabda84de +0xe1133225 +0xae1557fe +0x52ed43f7 +0x5200c1ed +0x61cad969 +0xc3b64ba5 +0x7ecdf78 +0xd6940c6b +0xd17b765d +0xbf118fc3 +0xdd21e0b2 +0x55e98b63 +0x51b10bb1 +0xbb51bae4 +0x13babd74 +0x4c4979da +0x40626e4b +0x77c27e18 +0x371455ef +0x3c4fc2a4 +0x9f75c5f7 +0x42d1a9bc +0x6b64368f +0x66c71463 +0xaf4e25bb +0x4f01628a +0x9e0357ff +0x39f4ed0d +0x5c610a0c +0x91e56dc2 +0x654f9678 +0x6cba35f5 +0x8399baed +0x509d45b3 +0xbf44df5f +0xa2a2e4cc +0x20b46f34 +0x36d8e64e +0x2dd102e7 +0x5333edf8 +0xcc082ff +0xbeabde62 +0xbf5d75fd +0x44070f87 +0xb69cda41 +0xf85d9a84 +0x3d83c479 diff --git a/pmp_access.py b/pmp_access.py new file mode 100644 index 0000000..89a013e --- /dev/null +++ b/pmp_access.py @@ -0,0 +1,181 @@ +import sys + +def load_pmp_config(file_path): + + pmp_config_addr = [] + pmp_config_addr_0x = [] + pmp_config_read = [] + pmp_config_write = [] + pmp_config_fetch = [] + pmp_config_range = [] + pmp_config_lock = [] + + with open(file_path,'r') as file: + for line_number, line in enumerate(file): + stripped_line = line.strip() + if stripped_line.startswith('0x'): + hex_value = stripped_line[2:] + + if line_number < 64: + hexToInt = int(hex_value,16) + intToBin = [(hexToInt >> i) & 1 for i in range(7,-1,-1)] + read_config = intToBin[0] + write_config = intToBin[1] + fetch_config = intToBin[2] + range_config = 2*intToBin[4] + intToBin[3] + #No checking here, assume input of bit[6:5] is correct, i.e. 2'b0 + lock_config = intToBin[7] + pmp_config_read.append(read_config) + pmp_config_write.append(write_config) + pmp_config_fetch.append(fetch_config) + pmp_config_range.append(range_config) + pmp_config_lock.append(lock_config) + else: + #print(f"Convert pmp[{line_number-64}] 0x:{hex_value} 0b:{format(int(hex_value,16), '032b')} Config lock:{pmp_config_lock[line_number-64]} range:{pmp_config_range[line_number-64]} read:{pmp_config_read[line_number-64]} write:{pmp_config_write[line_number-64]} fetch:{pmp_config_fetch[line_number-64]}") + pmp_config_addr.append(int(hex_value,16)) + pmp_config_addr_0x.append(format(int(hex_value,16), '032b')) + else : + raise ValueError(f"Line {line_number+1} config format invalid at line:{stripped_line} ") + + return pmp_config_read, pmp_config_write, pmp_config_fetch, pmp_config_range, pmp_config_lock, pmp_config_addr, pmp_config_addr_0x + +def check_access(pmp_config_read, pmp_config_write, pmp_config_fetch, pmp_config_range, pmp_config_lock, pmp_config_addr, pmp_config_addr_0x, physical_addr,privilege_mode,operation) : + #initalize local variable: + # previous address as 0, anyPMPEnabled = 0 + previous_addr = 0 + any_PMP_enabled = 0 + # for i from 0 to 63 + for i in range(64): + addr_in_range = 0 + # check if any PMP is enabled + # get address range of pmpaddr + pmp_config_range + # pmp_config_range: + # 0: disabled, skip, if anyone not 0, anyPMPEnabled = 1 + # 1: Top of range, previous address <= addr < pmpaddr + # 2: NA4, 4-bytes start from pmp addr, pmpaddr <= addr < pmpaddr + 3 + # 3: NAPOT: read pmpaddr as two parts, seperated by 0 + # yyyy...y011: base = yyyy...y000, range: 2^(3 + count(number of 1 after 0)) + # yyyy...y000 <= addr < yyyy...y000 + 2^(3+n)-1 + # Remarks: remember to start reading from LSB, MSB may have 0s like 100111001... + if(pmp_config_range[i] == 0) : + continue + elif(pmp_config_range[i] == 1) : + if(previous_addr < pmp_config_addr[i]) : + any_PMP_enabled = 1 + addr_in_range = (previous_addr <= physical_addr) & (physical_addr < pmp_config_addr[i]) + elif(pmp_config_range[i] == 2) : + any_PMP_enabled = 1 + addr_in_range = (pmp_config_addr[i] <= physical_addr) & (physical_addr < pmp_config_addr[i] + 4) + elif(pmp_config_range[i] == 3) : + any_PMP_enabled = 1 + j = 31 + num_of_byte = 8 + while(pmp_config_addr_0x[i][j] != '0'): + pmp_config_addr_0x[i] = (pmp_config_addr_0x[i][:j] + '0' + pmp_config_addr_0x[i][j + 1:]) + num_of_byte = num_of_byte * 2 + j = j - 1 + if j == -1: + break + start_addr = int(pmp_config_addr_0x[i], 2) + addr_in_range = (start_addr <= physical_addr) & (physical_addr < (start_addr + num_of_byte)) + else : + print(f"PMP range config read error: value{pmp_config_range[i]} should be 0-3") + + previous_addr = pmp_config_addr[i] + + # check whether physical addr in range + # if not, skip to next one + # else, check permission + # 1.L bit, if L=1, M-mode need to check for R/W/X permission + # 1.1 if L=0, M-mode access always success, S/U-mode check R/W/X premission + # if the physical addr is not in range of any pmp addr config: + # M-mode success, S/U-mode success if all pmpconfig is disabled(create a flag to save whether atleast one is programmed), else fail + if addr_in_range : + #print(f"Address matched reg[{i}], request target:{physical_addr} config_addr:{pmp_config_addr[i]}") + #print(f"Config lock:{pmp_config_lock[i]} range:{pmp_config_range[i]} read:{pmp_config_read[i]} write:{pmp_config_write[i]} fetch:{pmp_config_fetch[i]}") + if(pmp_config_lock[i] == 1): + if(operation == 'R'): + if(pmp_config_read[i]) : + return 0 + else : + return 1 + elif(operation == 'W') : + if(pmp_config_write[i]) : + return 0 + else : + return 1 + elif(operation == 'X') : + if(pmp_config_fetch[i]) : + return 0 + else : + return 1 + else : + if(privilege_mode == 'M') : + return 0 + else : + if(operation == 'R'): + if(pmp_config_read[i]) : + return 0 + else : + return 1 + elif(operation == 'W') : + if(pmp_config_write[i]) : + return 0 + else : + return 1 + elif(operation == 'X') : + if(pmp_config_fetch[i]) : + return 0 + else : + return 1 + else : + if (i == 63): + #print("No address matched, try pprivilege_mode checking or no register enabled checking") + if privilege_mode == 'M' : + return 0 + else : + return any_PMP_enabled + else: + continue + +def main(args): + if len(args) != 4: + print("Please provide exactly four arguments.") + return + + config_file, physical_addr_str, privilege_mode, operation = args + #print("Arguments received:") + #print(f"1: {config_file}") + #print(f"2: {physical_addr_str}") + #print(f"3: {privilege_mode}") + #print(f"4: {operation}") + + if not physical_addr_str.startswith("0x") : + print("Physical address must start with '0x'.") + return + + if not privilege_mode.startswith(("M","S","U")) : + print("Privilege mode must be 'M', 'S', or 'U'.") + return + + if not operation.startswith(("R","W","X")) : + print("Operation must be 'R', 'W', or 'X'.") + return + + try: + pmp_config_read, pmp_config_write, pmp_config_fetch, pmp_config_range, pmp_config_lock, pmp_config_addr, pmp_config_addr_0x = load_pmp_config(config_file) + except ValueError as e: + print(f"Error loading config file: {e}") + return + + physical_addr = int(physical_addr_str,16) + + fault = check_access(pmp_config_read, pmp_config_write, pmp_config_fetch, pmp_config_range, pmp_config_lock, pmp_config_addr, pmp_config_addr_0x, physical_addr,privilege_mode,operation) + + if fault: + print("Access failed") + else : + print("Access success") + +if __name__ == "__main__": + main(sys.argv[1:]) \ No newline at end of file diff --git a/pmp_config_gen.py b/pmp_config_gen.py new file mode 100644 index 0000000..9148adb --- /dev/null +++ b/pmp_config_gen.py @@ -0,0 +1,63 @@ +import random + + +# generate pmp address +# 1. 32-bit random +# 2. conversion + + + + +def generate_random_binary_parameters(): + # Generate three random binary parameters (1 bit each) + lock = random.randint(0, 1) + range_0 = random.randint(0, 1) + range_1 = random.randint(0,1) + fetch = random.randint(0, 1) + write = random.randint(0, 1) + read = random.randint(0, 1) + + return lock, range_1, range_0, fetch, write, read + +def concatenate_to_binary(lock, range_1, range_0, fetch, write, read): + # Concatenate the binary parameters into a single binary number + x = f"{lock}00{range_1}{range_0}{fetch}{write}{read}" # This creates a string representation + return x + +def convert_to_hexadecimal(binary_str): + # Convert the binary string to an integer, then to hexadecimal + x_int = int(binary_str, 2) # Convert binary string to integer + x_hex = hex(x_int) # Convert integer to hexadecimal + return x_hex + +def write_to_file(hex_value): + with open('config.txt', 'w') as file: + file.write(hex_value + '\n') # Write the hex value to the file + +def main(): + hex_values = [] # List to store hex values for all iterations + + for _ in range(64): # Loop for 64 times + lock, range_1, range_0, fetch, write, read = generate_random_binary_parameters() # Generate parameters + binary_str = concatenate_to_binary(lock, range_1, range_0, fetch, write, read) # Concatenate to binary + hex_value = convert_to_hexadecimal(binary_str) # Convert to hexadecimal + hex_values.append(hex_value) # Store hex value + + #...another loop for line 64 to 128... + for _ in range(64): + addr = random.randint(0,2**32-1) + hex_value = hex(addr) + hex_values.append(hex_value) + + # Write all hex values to the file, replacing previous content + with open('config.txt', 'w') as file: + for hex_value in hex_values: + print(f"writing{hex_value}") + file.write(hex_value + '\n') # Write each hex value to the file + + #print("Generated hexadecimal values:") + #for hex_value in hex_values: + # print(hex_value) + +if __name__ == "__main__": + main() \ No newline at end of file