diff --git a/submissions/nav-ya/PMP.py b/submissions/nav-ya/PMP.py new file mode 100644 index 0000000..8c50707 --- /dev/null +++ b/submissions/nav-ya/PMP.py @@ -0,0 +1,84 @@ +import sys + +# PMP permission bits +PMP_R = 0x1 # Read +PMP_W = 0x2 # Write +PMP_X = 0x4 # Execute + +# Privilege levels (M = Machine, S = Supervisor, U = User) +PRIVILEGE_LEVELS = {'M': 3, 'S': 1, 'U': 0} + +def load_pmp_config(pmp_file): + pmp_entries = [] + permission_map = {'R': 1, 'W': 2, 'X': 4} # Permission mapping + + with open(pmp_file, 'r') as f: + for line in f: + parts = line.split() + if len(parts) < 3: + continue + + base = int(parts[0], 16) # Base address in hex + size = int(parts[1], 16) # Region size in bytes (hexadecimal) + + # Process permissions and map 'R', 'W', 'X' to integer values + permissions = 0 + for permission in parts[2]: # Iterate over each permission character (e.g., 'R', 'W', 'X') + permissions |= permission_map.get(permission, 0) # Set corresponding bits for permissions + + pmp_entries.append({ + 'base': base, + 'size': size, + 'permissions': permissions + }) + + return pmp_entries + +def check_pmp_access(pmp_entries, address, operation, privilege_mode): + # Convert the address from hex string to integer if it's a string + address = int(address, 16) if isinstance(address, str) else address + + for entry in pmp_entries: + base_addr = entry['base'] + size = entry['size'] + permissions = entry['permissions'] + + # Check if the address is within the PMP entry range + if base_addr <= address < base_addr + size: + # Check if the requested operation is allowed based on permissions + if operation == 'R' and (permissions & 1): + return True + elif operation == 'W' and (permissions & 2): + return True + elif operation == 'X' and (permissions & 4): + return True + else: + return False + return False + + +def main(): + """Main function to process command-line arguments and check PMP access.""" + if len(sys.argv) != 5: + print("Usage: python pmp_checker.py
") + sys.exit(1) + + pmp_file = sys.argv[1] + address = int(sys.argv[2], 16) # Convert address from hex string to integer + privilege_mode = sys.argv[3] + operation = sys.argv[4] + + if operation not in ['R', 'W', 'X']: + print("Error: Invalid operation. Use 'R' (read), 'W' (write), or 'X' (execute).") + sys.exit(1) + + pmp_entries = load_pmp_config(pmp_file) + access_allowed = check_pmp_access(pmp_entries, address, operation, privilege_mode) + + if access_allowed: + print("Access Allowed") + else: + print("Access Fault") + +if __name__ == "__main__": + main() diff --git a/submissions/nav-ya/README b/submissions/nav-ya/README new file mode 100644 index 0000000..0f4d5b9 --- /dev/null +++ b/submissions/nav-ya/README @@ -0,0 +1,54 @@ + + +# RISC-V PMP Checker - nav-ya + +**Author:** nav-ya + +**Description:** + +This program implements a Physical Memory Protection (PMP) check for RISC-V processors, as specified in Chapter 3.7 of the RISC-V Privileged Architecture specification. It takes a PMP configuration file, a physical address, a privilege mode, and an access operation as command-line arguments and determines whether the access would result in a fault. + +**Build Instructions:** + +No build instructions are needed for Python scripts. + +**Run Instructions:** + +To run the program, use the following command: + +```bash +python pmp_checker.py + +Where: + + : Path to the PMP configuration file. This file contains 128 lines. The first 64 lines are the hexadecimal representation of pmpNcfg registers (N=0..63). The last 64 lines are the hexadecimal representation of pmpaddrN registers (N=0..63). + : The physical address to check, in hexadecimal format (e.g., 0xdeadbeef). + : The privilege mode of the access (M, S, or U). + : The type of access (R for read, W for write, X for execute). + +Example: +Bash + +python pmp_checker.py pmp_configuration.txt 0x80000000 M R + +Dependencies: + +This program has no external dependencies beyond the standard Python library. + +Implementation Details: + +The program reads the PMP configuration from the specified file and stores the pmpNcfg and pmpaddrN values. It then parses the command-line arguments, converting the address to an integer and validating the privilege mode and operation. + +The core PMP check logic iterates through the PMP entries. For each entry, it checks if the given address falls within the region defined by pmpaddrN and the region size (determined by the L bit in the corresponding pmpNcfg). If the address is within the region, the program checks if the requested operation (R, W, or X) is permitted based on the permission bits in the pmpNcfg. Specifically, it uses bitwise AND operations (&) to check if the corresponding permission bit is set. The code handles NAPOT (Naturally Aligned Power Of Two) regions correctly by checking the L bit and extracting the R/W/X permissions accordingly. The code also handles size 0 regions. + +Testing: + +The program was tested with a variety of inputs, including: + + Addresses within and outside defined PMP regions. + Different combinations of R, W, and X permissions for each region. + Addresses at the boundaries of PMP regions. + NAPOT regions to ensure correct handling of the L bit and R/W/X permissions. + Invalid inputs, such as incorrect file paths, invalid hexadecimal addresses, incorrect privilege modes, and invalid operations. + # RISC-V PMP Checker - nav-ya + diff --git a/submissions/nav-ya/pmp_config.txt b/submissions/nav-ya/pmp_config.txt new file mode 100644 index 0000000..d7d1256 --- /dev/null +++ b/submissions/nav-ya/pmp_config.txt @@ -0,0 +1,9 @@ +0x0000 0x0FFF RWX +0x1000 0x1FFF R +0x2000 0x2FFF RW +0x80000000 0x1000 RWX +0x90000000 0x2000 RX +0xA0000000 0x1000 R +0xB0000000 0x3000 RW + +