Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions submissions/nav-ya/PMP.py
Original file line number Diff line number Diff line change
@@ -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 <pmp_config_file> <address> <privilege_mode> <operation>")
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()
54 changes: 54 additions & 0 deletions submissions/nav-ya/README
Original file line number Diff line number Diff line change
@@ -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 <pmp_config_file> <physical_address> <privilege_mode> <operation>

Where:

<pmp_config_file>: 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).
<physical_address>: The physical address to check, in hexadecimal format (e.g., 0xdeadbeef).
<privilege_mode>: The privilege mode of the access (M, S, or U).
<operation>: 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

9 changes: 9 additions & 0 deletions submissions/nav-ya/pmp_config.txt
Original file line number Diff line number Diff line change
@@ -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