162306a36Sopenharmony_ci#!/usr/bin/env python3
262306a36Sopenharmony_ci# SPDX-License-Identifier: GPL-2.0
362306a36Sopenharmony_ci
462306a36Sopenharmony_cifrom struct import pack
562306a36Sopenharmony_cifrom time import sleep
662306a36Sopenharmony_ci
762306a36Sopenharmony_ciimport errno
862306a36Sopenharmony_ciimport glob
962306a36Sopenharmony_ciimport os
1062306a36Sopenharmony_ciimport subprocess
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_citry:
1362306a36Sopenharmony_ci    import pytest
1462306a36Sopenharmony_ciexcept ImportError:
1562306a36Sopenharmony_ci    print("Unable to import pytest python module.")
1662306a36Sopenharmony_ci    print("\nIf not already installed, you may do so with:")
1762306a36Sopenharmony_ci    print("\t\tpip3 install pytest")
1862306a36Sopenharmony_ci    exit(1)
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ciSOCKETS = glob.glob('/sys/bus/auxiliary/devices/intel_vsec.sdsi.*')
2162306a36Sopenharmony_ciNUM_SOCKETS = len(SOCKETS)
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ciMODULE_NAME = 'intel_sdsi'
2462306a36Sopenharmony_ciDEV_PREFIX = 'intel_vsec.sdsi'
2562306a36Sopenharmony_ciCLASS_DIR = '/sys/bus/auxiliary/devices'
2662306a36Sopenharmony_ciGUID = "0x6dd191"
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cidef read_bin_file(file):
2962306a36Sopenharmony_ci    with open(file, mode='rb') as f:
3062306a36Sopenharmony_ci        content = f.read()
3162306a36Sopenharmony_ci    return content
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_cidef get_dev_file_path(socket, file):
3462306a36Sopenharmony_ci    return CLASS_DIR + '/' + DEV_PREFIX + '.' + str(socket) + '/' + file
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_cidef kmemleak_enabled():
3762306a36Sopenharmony_ci    kmemleak = "/sys/kernel/debug/kmemleak"
3862306a36Sopenharmony_ci    return os.path.isfile(kmemleak)
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ciclass TestSDSiDriver:
4162306a36Sopenharmony_ci    def test_driver_loaded(self):
4262306a36Sopenharmony_ci        lsmod_p = subprocess.Popen(('lsmod'), stdout=subprocess.PIPE)
4362306a36Sopenharmony_ci        result = subprocess.check_output(('grep', '-q', MODULE_NAME), stdin=lsmod_p.stdout)
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci@pytest.mark.parametrize('socket', range(0, NUM_SOCKETS))
4662306a36Sopenharmony_ciclass TestSDSiFilesClass:
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci    def read_value(self, file):
4962306a36Sopenharmony_ci        f = open(file, "r")
5062306a36Sopenharmony_ci        value = f.read().strip("\n")
5162306a36Sopenharmony_ci        return value
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci    def get_dev_folder(self, socket):
5462306a36Sopenharmony_ci        return CLASS_DIR + '/' + DEV_PREFIX + '.' + str(socket) + '/'
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci    def test_sysfs_files_exist(self, socket):
5762306a36Sopenharmony_ci        folder = self.get_dev_folder(socket)
5862306a36Sopenharmony_ci        print (folder)
5962306a36Sopenharmony_ci        assert os.path.isfile(folder + "guid") == True
6062306a36Sopenharmony_ci        assert os.path.isfile(folder + "provision_akc") == True
6162306a36Sopenharmony_ci        assert os.path.isfile(folder + "provision_cap") == True
6262306a36Sopenharmony_ci        assert os.path.isfile(folder + "state_certificate") == True
6362306a36Sopenharmony_ci        assert os.path.isfile(folder + "registers") == True
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci    def test_sysfs_file_permissions(self, socket):
6662306a36Sopenharmony_ci        folder = self.get_dev_folder(socket)
6762306a36Sopenharmony_ci        mode = os.stat(folder + "guid").st_mode & 0o777
6862306a36Sopenharmony_ci        assert mode == 0o444    # Read all
6962306a36Sopenharmony_ci        mode = os.stat(folder + "registers").st_mode & 0o777
7062306a36Sopenharmony_ci        assert mode == 0o400    # Read owner
7162306a36Sopenharmony_ci        mode = os.stat(folder + "provision_akc").st_mode & 0o777
7262306a36Sopenharmony_ci        assert mode == 0o200    # Read owner
7362306a36Sopenharmony_ci        mode = os.stat(folder + "provision_cap").st_mode & 0o777
7462306a36Sopenharmony_ci        assert mode == 0o200    # Read owner
7562306a36Sopenharmony_ci        mode = os.stat(folder + "state_certificate").st_mode & 0o777
7662306a36Sopenharmony_ci        assert mode == 0o400    # Read owner
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci    def test_sysfs_file_ownership(self, socket):
7962306a36Sopenharmony_ci        folder = self.get_dev_folder(socket)
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci        st = os.stat(folder + "guid")
8262306a36Sopenharmony_ci        assert st.st_uid == 0
8362306a36Sopenharmony_ci        assert st.st_gid == 0
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci        st = os.stat(folder + "registers")
8662306a36Sopenharmony_ci        assert st.st_uid == 0
8762306a36Sopenharmony_ci        assert st.st_gid == 0
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci        st = os.stat(folder + "provision_akc")
9062306a36Sopenharmony_ci        assert st.st_uid == 0
9162306a36Sopenharmony_ci        assert st.st_gid == 0
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci        st = os.stat(folder + "provision_cap")
9462306a36Sopenharmony_ci        assert st.st_uid == 0
9562306a36Sopenharmony_ci        assert st.st_gid == 0
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci        st = os.stat(folder + "state_certificate")
9862306a36Sopenharmony_ci        assert st.st_uid == 0
9962306a36Sopenharmony_ci        assert st.st_gid == 0
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci    def test_sysfs_file_sizes(self, socket):
10262306a36Sopenharmony_ci        folder = self.get_dev_folder(socket)
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci        if self.read_value(folder + "guid") == GUID:
10562306a36Sopenharmony_ci            st = os.stat(folder + "registers")
10662306a36Sopenharmony_ci            assert st.st_size == 72
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci        st = os.stat(folder + "provision_akc")
10962306a36Sopenharmony_ci        assert st.st_size == 1024
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci        st = os.stat(folder + "provision_cap")
11262306a36Sopenharmony_ci        assert st.st_size == 1024
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci        st = os.stat(folder + "state_certificate")
11562306a36Sopenharmony_ci        assert st.st_size == 4096
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci    def test_no_seek_allowed(self, socket):
11862306a36Sopenharmony_ci        folder = self.get_dev_folder(socket)
11962306a36Sopenharmony_ci        rand_file = bytes(os.urandom(8))
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci        f = open(folder + "provision_cap", "wb", 0)
12262306a36Sopenharmony_ci        f.seek(1)
12362306a36Sopenharmony_ci        with pytest.raises(OSError) as error:
12462306a36Sopenharmony_ci            f.write(rand_file)
12562306a36Sopenharmony_ci        assert error.value.errno == errno.ESPIPE
12662306a36Sopenharmony_ci        f.close()
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci        f = open(folder + "provision_akc", "wb", 0)
12962306a36Sopenharmony_ci        f.seek(1)
13062306a36Sopenharmony_ci        with pytest.raises(OSError) as error:
13162306a36Sopenharmony_ci            f.write(rand_file)
13262306a36Sopenharmony_ci        assert error.value.errno == errno.ESPIPE
13362306a36Sopenharmony_ci        f.close()
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci    def test_registers_seek(self, socket):
13662306a36Sopenharmony_ci        folder = self.get_dev_folder(socket)
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci        # Check that the value read from an offset of the entire
13962306a36Sopenharmony_ci        # file is none-zero and the same as the value read
14062306a36Sopenharmony_ci        # from seeking to the same location
14162306a36Sopenharmony_ci        f = open(folder + "registers", "rb")
14262306a36Sopenharmony_ci        data = f.read()
14362306a36Sopenharmony_ci        f.seek(64)
14462306a36Sopenharmony_ci        id = f.read()
14562306a36Sopenharmony_ci        assert id != bytes(0)
14662306a36Sopenharmony_ci        assert data[64:] == id
14762306a36Sopenharmony_ci        f.close()
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci@pytest.mark.parametrize('socket', range(0, NUM_SOCKETS))
15062306a36Sopenharmony_ciclass TestSDSiMailboxCmdsClass:
15162306a36Sopenharmony_ci    def test_provision_akc_eoverflow_1017_bytes(self, socket):
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci        # The buffer for writes is 1k, of with 8 bytes must be
15462306a36Sopenharmony_ci        # reserved for the command, leaving 1016 bytes max.
15562306a36Sopenharmony_ci        # Check that we get an overflow error for 1017 bytes.
15662306a36Sopenharmony_ci        node = get_dev_file_path(socket, "provision_akc")
15762306a36Sopenharmony_ci        rand_file = bytes(os.urandom(1017))
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci        f = open(node, 'wb', 0)
16062306a36Sopenharmony_ci        with pytest.raises(OSError) as error:
16162306a36Sopenharmony_ci            f.write(rand_file)
16262306a36Sopenharmony_ci        assert error.value.errno == errno.EOVERFLOW
16362306a36Sopenharmony_ci        f.close()
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci@pytest.mark.parametrize('socket', range(0, NUM_SOCKETS))
16662306a36Sopenharmony_ciclass TestSdsiDriverLocksClass:
16762306a36Sopenharmony_ci    def test_enodev_when_pci_device_removed(self, socket):
16862306a36Sopenharmony_ci        node = get_dev_file_path(socket, "provision_akc")
16962306a36Sopenharmony_ci        dev_name = DEV_PREFIX + '.' + str(socket)
17062306a36Sopenharmony_ci        driver_dir = CLASS_DIR + '/' + dev_name + "/driver/"
17162306a36Sopenharmony_ci        rand_file = bytes(os.urandom(8))
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci        f = open(node, 'wb', 0)
17462306a36Sopenharmony_ci        g = open(node, 'wb', 0)
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci        with open(driver_dir + 'unbind', 'w') as k:
17762306a36Sopenharmony_ci            print(dev_name, file = k)
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci        with pytest.raises(OSError) as error:
18062306a36Sopenharmony_ci            f.write(rand_file)
18162306a36Sopenharmony_ci        assert error.value.errno == errno.ENODEV
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci        with pytest.raises(OSError) as error:
18462306a36Sopenharmony_ci            g.write(rand_file)
18562306a36Sopenharmony_ci        assert error.value.errno == errno.ENODEV
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci        f.close()
18862306a36Sopenharmony_ci        g.close()
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci        # Short wait needed to allow file to close before pulling driver
19162306a36Sopenharmony_ci        sleep(1)
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci        p = subprocess.Popen(('modprobe', '-r', 'intel_sdsi'))
19462306a36Sopenharmony_ci        p.wait()
19562306a36Sopenharmony_ci        p = subprocess.Popen(('modprobe', '-r', 'intel_vsec'))
19662306a36Sopenharmony_ci        p.wait()
19762306a36Sopenharmony_ci        p = subprocess.Popen(('modprobe', 'intel_vsec'))
19862306a36Sopenharmony_ci        p.wait()
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci        # Short wait needed to allow driver time to get inserted
20162306a36Sopenharmony_ci        # before continuing tests
20262306a36Sopenharmony_ci        sleep(1)
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci    def test_memory_leak(self, socket):
20562306a36Sopenharmony_ci        if not kmemleak_enabled():
20662306a36Sopenharmony_ci            pytest.skip("kmemleak not enabled in kernel")
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci        dev_name = DEV_PREFIX + '.' + str(socket)
20962306a36Sopenharmony_ci        driver_dir = CLASS_DIR + '/' + dev_name + "/driver/"
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci        with open(driver_dir + 'unbind', 'w') as k:
21262306a36Sopenharmony_ci            print(dev_name, file = k)
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci        sleep(1)
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci        subprocess.check_output(('modprobe', '-r', 'intel_sdsi'))
21762306a36Sopenharmony_ci        subprocess.check_output(('modprobe', '-r', 'intel_vsec'))
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci        with open('/sys/kernel/debug/kmemleak', 'w') as f:
22062306a36Sopenharmony_ci            print('scan', file = f)
22162306a36Sopenharmony_ci        sleep(5)
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci        assert os.stat('/sys/kernel/debug/kmemleak').st_size == 0
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci        subprocess.check_output(('modprobe', 'intel_vsec'))
22662306a36Sopenharmony_ci        sleep(1)
227