├── .gitignore
├── README.md
├── build
├── bulletin.xml
├── component
│ └── VMW-esx-7.0.1-thpimon-1.0-0.00001.zip
├── sverify
│ └── thpimon.sva
├── thpimon
├── thpimon-nostrip
├── thpimon.map
└── vib
│ └── thpimon-0.1.0-1OEM.701.1.0.40650718.aarch64.vib
├── pimon.h
├── pimon_charDev.c
├── pimon_charDev.h
├── pimon_os.c
├── pimon_types.h
├── pyUtil
├── pimonLib
│ └── __init__.py
└── pimon_util.py
├── rpiq_drv.c
└── rpiq_drv.h
/.gitignore:
--------------------------------------------------------------------------------
1 | *.sh
2 | *.sc
3 | pimon_acpi_device.py
4 | bump*
5 | #build
6 | .build
7 | .vscode
8 | Makefile
9 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Note: all the source code contained in this repository is for educational use only, and is provided with no support, endorsement, warranty, guarantee or implied fitness for a particular purpose. It does not constitute sample driver code. Do not reach out to VMware to support this code. Do not copy and reuse in any commercial or product setting.
2 |
3 | # thpimon
4 | Native ESXi on Arm hardware status driver for the Raspberry Pi.
5 |
6 | Using the Python library, you can currently get the board revision and temperature.
7 |
8 | Currently work-in-progress, the driver is capable of communicating with the VideoCore firmware using fixed-size buffers (so no console).
9 |
10 | ### Sample Output
11 |
12 | Taken from a Raspberry Pi 4B:
13 |
14 | ```
15 | $ /scratch/downloads/pyUtil/pimon_util.py
16 | Firmware Revision: 0x5f440c10
17 | Board Model: 0
18 | Board Revision: 0xc03111
19 | Board MAC Address: d6:51:4:32:a6:dc
20 | Board Serial: 0x000000664b0067
21 | Temp: 60.0 (deg. C)
22 | ```
23 |
24 | ### Installation
25 |
26 | To install the driver, download the VIB file in the build directory and copy it to your RPi.
27 |
28 | Install it as described here: https://kb.vmware.com/s/article/2008939
29 |
30 | Note: you will need to reboot the RPi after installing the VIB.
31 |
32 | I would recommend downloading the Python library in ./pyUtil/pimonLib/ to interact with the thpimon character device.
33 |
34 | Note: You may need to manually change the `PIMON_DEVICE_PATH` variable in `./pyUtil/gpioLib/__init__.py` to reflect the correct name for the character device. I'm digging through the VMKAPI to find a way to name the character device upon creation, so stay tuned.
35 |
36 | ### Other Branches
37 |
38 | If you want to try auto-configuring the name of the `PIMON_DEVICE_PATH`, check out: https://github.com/thebel1/thpimon/tree/autoconf
39 |
40 | If you want to take screenshots of your Pi, check out: https://github.com/thebel1/thpimon/tree/fbuf
41 |
--------------------------------------------------------------------------------
/build/bulletin.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | thpimon_1.0-0.00001
6 |
7 |
8 |
9 | Tom Hebel
10 |
11 |
12 |
13 | thpimon: Native RPi hardware monitoring driver
14 |
15 |
16 | general
17 |
18 |
19 | enhancement
20 |
21 |
22 | important
23 |
24 |
25 | extension
26 |
27 |
28 |
29 | Native RPi hardware monitoring driver module for vmkernel
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 | 2020-11-06T22:17:09+00:00
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 | THX_bootbank_thpimon_0.1.0-1OEM.701.1.0.40650718
--------------------------------------------------------------------------------
/build/component/VMW-esx-7.0.1-thpimon-1.0-0.00001.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thebel1/thpimon/42cc75e3c0b089e1f4822a19fbd0ae01b620c0e9/build/component/VMW-esx-7.0.1-thpimon-1.0-0.00001.zip
--------------------------------------------------------------------------------
/build/sverify/thpimon.sva:
--------------------------------------------------------------------------------
1 | vmware-esx-nativeddk-devtools-7.0.0-1.0.15843807.x86_64
2 | vmware-esx-nativeddkarm64-devtools-7.0.1-1.0.40650718.x86_64
3 | vmware-esx-nativeddk-devtools-7.0.0-1.0.16966451.x86_64
4 | vmware-esx-nativeddkarm64-toolchain-2.0.0-1.x86_64
5 | vmware-esx-nativeddkarm64-devtools-sockets-7.0.1-1.0.40650718.x86_64
6 | aarch64-vmk-linux-gnu-gcc (GCC) 6.4.0
7 | Copyright (C) 2017 Free Software Foundation, Inc.
8 | This is free software; see the source for copying conditions. There is NO
9 | warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10 |
11 | aarch64-vmk-linux-gnu-g++ (GCC) 6.4.0
12 | Copyright (C) 2017 Free Software Foundation, Inc.
13 | This is free software; see the source for copying conditions. There is NO
14 | warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15 |
16 | LLD 8.0.1 (compatible with GNU linkers)
17 | /opt/vmware/toolchain/cayman_esx_toolchain_gcc6-978272870a6446e021754e84f5d75e0c6c53a9b7/usr/bin/aarch64-vmk-linux-gnu-gcc -march="armv8-a" --sysroot="/opt/vmware/toolchain/cayman_esx_glibc_2_17-8ef7e61952433909958dd15ee027ca4e03896da7/sysroot-aarch64" -fwrapv -pipe -fno-strict-aliasing -Wno-unused-but-set-variable -fno-working-directory -g -O2 -ffreestanding -nostdinc -fno-common -funwind-tables -fasynchronous-unwind-tables -Wall -Werror -Wno-error="inline" -Wformat-nonliteral -Wstrict-prototypes -fno-strict-aliasing -freg-struct-return -falign-jumps="1" -falign-functions="4" -falign-loops="1" -march="armv8-a" -mgeneral-regs-only -DVMK_ARM_BRINGUP -finline-limit="2000" -fomit-frame-pointer -Wlogical-op -Wno-pointer-sign -Wno-strict-prototypes -Wno-enum-compare -Wno-declaration-after-statement -std="gnu90" -DNO_FLOATING_POINT -DUSE_32_BIT -DVMKERNEL -DVMKERNEL_MODULE -DVMK_DEVKIT_HAS_API_VMKAPI_BASE -DVMK_DEVKIT_HAS_API_VMKAPI_ENS -DVMK_DEVKIT_HAS_API_VMKAPI_GPU -DVMK_DEVKIT_HAS_API_VMKAPI_ISCSI -DVMK_DEVKIT_HAS_API_VMKAPI_NET -DVMK_DEVKIT_HAS_API_VMKAPI_NPIV -DVMK_DEVKIT_HAS_API_VMKAPI_NVME_DRV -DVMK_DEVKIT_HAS_API_VMKAPI_RDMA -DVMK_DEVKIT_HAS_API_VMKAPI_SCSI -DVMK_DEVKIT_HAS_API_VMKAPI_SOCKETS -DVMK_DEVKIT_HAS_NATIVE_DDK -DVMK_DEVKIT_USES_BINARY_COMPATIBLE_APIS -DVMK_DEVKIT_USES_PUBLIC_APIS -DVMX86_RELEASE -DVMX86_SERVER -D_GLIBCXX_USE_CXX11_ABI="0" -D__KERNEL__ -D__KMDK__ -D__MODULE_LICENSE__="ThirdParty:MIT" -D__MODULE_VERSION__="0.1.0-1OEM.701.1.0.40650718" -Ipartners/samples/public/thrpi/thpimon -Ipartners/samples/public/thrpi/thpimon/.build/build/version -Ipartners/samples/public/thrpi/thpimon/.build/build/HEADERS/vmkapi-current-all-public-bincomp/generic/release -isystem /opt/vmware/toolchain/cayman_esx_toolchain_gcc6-978272870a6446e021754e84f5d75e0c6c53a9b7/usr/lib/gcc/aarch64-vmk-linux-gnu/6.4.0/include -E bora/modules/vmkapi/module_info/module_info.c -U__TIME__ -U__DATE__
18 | WD: /opt/vmware/nativeddkarm64-7.0.1-40650718/src
19 | BD: /opt/vmware/nativeddkarm64-7.0.1-40650718/src/partners/samples/public/thrpi/thpimon/.build
20 | ff5edde8b8fc17827f6a83cb952b9832 partners/samples/public/thrpi/thpimon/.build/build/vmkdriver-thpimon/release/vmkernel64-arm64/SUBDIRS/bora/modules/vmkapi/module_info/module_info.i
21 | /opt/vmware/toolchain/cayman_esx_toolchain_gcc6-978272870a6446e021754e84f5d75e0c6c53a9b7/usr/bin/aarch64-vmk-linux-gnu-gcc -march="armv8-a" --sysroot="/opt/vmware/toolchain/cayman_esx_glibc_2_17-8ef7e61952433909958dd15ee027ca4e03896da7/sysroot-aarch64" -fwrapv -pipe -fno-strict-aliasing -Wno-unused-but-set-variable -fno-working-directory -g -O2 -ffreestanding -nostdinc -fno-common -funwind-tables -fasynchronous-unwind-tables -Wall -Werror -Wno-error="inline" -Wformat-nonliteral -Wstrict-prototypes -fno-strict-aliasing -freg-struct-return -falign-jumps="1" -falign-functions="4" -falign-loops="1" -march="armv8-a" -mgeneral-regs-only -DVMK_ARM_BRINGUP -finline-limit="2000" -fomit-frame-pointer -Wlogical-op -Wno-pointer-sign -Wno-strict-prototypes -Wno-enum-compare -Wno-declaration-after-statement -std="gnu90" -DNO_FLOATING_POINT -DUSE_32_BIT -DVMKERNEL -DVMKERNEL_MODULE -DVMK_DEVKIT_HAS_API_VMKAPI_BASE -DVMK_DEVKIT_HAS_API_VMKAPI_ENS -DVMK_DEVKIT_HAS_API_VMKAPI_GPU -DVMK_DEVKIT_HAS_API_VMKAPI_ISCSI -DVMK_DEVKIT_HAS_API_VMKAPI_NET -DVMK_DEVKIT_HAS_API_VMKAPI_NPIV -DVMK_DEVKIT_HAS_API_VMKAPI_NVME_DRV -DVMK_DEVKIT_HAS_API_VMKAPI_RDMA -DVMK_DEVKIT_HAS_API_VMKAPI_SCSI -DVMK_DEVKIT_HAS_API_VMKAPI_SOCKETS -DVMK_DEVKIT_HAS_NATIVE_DDK -DVMK_DEVKIT_USES_BINARY_COMPATIBLE_APIS -DVMK_DEVKIT_USES_PUBLIC_APIS -DVMX86_RELEASE -DVMX86_SERVER -D_GLIBCXX_USE_CXX11_ABI="0" -D__KERNEL__ -D__KMDK__ -Ipartners/samples/public/thrpi/thpimon -Ipartners/samples/public/thrpi/thpimon/.build/build/version -Ipartners/samples/public/thrpi/thpimon/.build/build/HEADERS/vmkapi-current-all-public-bincomp/generic/release -isystem /opt/vmware/toolchain/cayman_esx_toolchain_gcc6-978272870a6446e021754e84f5d75e0c6c53a9b7/usr/lib/gcc/aarch64-vmk-linux-gnu/6.4.0/include -E partners/samples/public/thrpi/thpimon/pimon_os.c -U__TIME__ -U__DATE__
22 | WD: /opt/vmware/nativeddkarm64-7.0.1-40650718/src
23 | BD: /opt/vmware/nativeddkarm64-7.0.1-40650718/src/partners/samples/public/thrpi/thpimon/.build
24 | 63cecb2bec063de6295b8f43472abf57 partners/samples/public/thrpi/thpimon/.build/build/vmkdriver-thpimon/release/vmkernel64-arm64/SUBDIRS/opt/vmware/nativeddkarm64-7.0.1-40650718/src/partners/samples/public/thrpi/thpimon/pimon_os.i
25 | /opt/vmware/toolchain/cayman_esx_toolchain_gcc6-978272870a6446e021754e84f5d75e0c6c53a9b7/usr/bin/aarch64-vmk-linux-gnu-gcc -march="armv8-a" --sysroot="/opt/vmware/toolchain/cayman_esx_glibc_2_17-8ef7e61952433909958dd15ee027ca4e03896da7/sysroot-aarch64" -fwrapv -pipe -fno-strict-aliasing -Wno-unused-but-set-variable -fno-working-directory -g -O2 -ffreestanding -nostdinc -fno-common -funwind-tables -fasynchronous-unwind-tables -Wall -Werror -Wno-error="inline" -Wformat-nonliteral -Wstrict-prototypes -fno-strict-aliasing -freg-struct-return -falign-jumps="1" -falign-functions="4" -falign-loops="1" -march="armv8-a" -mgeneral-regs-only -DVMK_ARM_BRINGUP -finline-limit="2000" -fomit-frame-pointer -Wlogical-op -Wno-pointer-sign -Wno-strict-prototypes -Wno-enum-compare -Wno-declaration-after-statement -std="gnu90" -DNO_FLOATING_POINT -DUSE_32_BIT -DVMKERNEL -DVMKERNEL_MODULE -DVMK_DEVKIT_HAS_API_VMKAPI_BASE -DVMK_DEVKIT_HAS_API_VMKAPI_ENS -DVMK_DEVKIT_HAS_API_VMKAPI_GPU -DVMK_DEVKIT_HAS_API_VMKAPI_ISCSI -DVMK_DEVKIT_HAS_API_VMKAPI_NET -DVMK_DEVKIT_HAS_API_VMKAPI_NPIV -DVMK_DEVKIT_HAS_API_VMKAPI_NVME_DRV -DVMK_DEVKIT_HAS_API_VMKAPI_RDMA -DVMK_DEVKIT_HAS_API_VMKAPI_SCSI -DVMK_DEVKIT_HAS_API_VMKAPI_SOCKETS -DVMK_DEVKIT_HAS_NATIVE_DDK -DVMK_DEVKIT_USES_BINARY_COMPATIBLE_APIS -DVMK_DEVKIT_USES_PUBLIC_APIS -DVMX86_RELEASE -DVMX86_SERVER -D_GLIBCXX_USE_CXX11_ABI="0" -D__KERNEL__ -D__KMDK__ -Ipartners/samples/public/thrpi/thpimon -Ipartners/samples/public/thrpi/thpimon/.build/build/version -Ipartners/samples/public/thrpi/thpimon/.build/build/HEADERS/vmkapi-current-all-public-bincomp/generic/release -isystem /opt/vmware/toolchain/cayman_esx_toolchain_gcc6-978272870a6446e021754e84f5d75e0c6c53a9b7/usr/lib/gcc/aarch64-vmk-linux-gnu/6.4.0/include -E partners/samples/public/thrpi/thpimon/pimon_charDev.c -U__TIME__ -U__DATE__
26 | WD: /opt/vmware/nativeddkarm64-7.0.1-40650718/src
27 | BD: /opt/vmware/nativeddkarm64-7.0.1-40650718/src/partners/samples/public/thrpi/thpimon/.build
28 | a9ebbadbb495a5bbbed41cd345679f79 partners/samples/public/thrpi/thpimon/.build/build/vmkdriver-thpimon/release/vmkernel64-arm64/SUBDIRS/opt/vmware/nativeddkarm64-7.0.1-40650718/src/partners/samples/public/thrpi/thpimon/pimon_charDev.i
29 | /opt/vmware/toolchain/cayman_esx_toolchain_gcc6-978272870a6446e021754e84f5d75e0c6c53a9b7/usr/bin/aarch64-vmk-linux-gnu-gcc -march="armv8-a" --sysroot="/opt/vmware/toolchain/cayman_esx_glibc_2_17-8ef7e61952433909958dd15ee027ca4e03896da7/sysroot-aarch64" -fwrapv -pipe -fno-strict-aliasing -Wno-unused-but-set-variable -fno-working-directory -g -O2 -ffreestanding -nostdinc -fno-common -funwind-tables -fasynchronous-unwind-tables -Wall -Werror -Wno-error="inline" -Wformat-nonliteral -Wstrict-prototypes -fno-strict-aliasing -freg-struct-return -falign-jumps="1" -falign-functions="4" -falign-loops="1" -march="armv8-a" -mgeneral-regs-only -DVMK_ARM_BRINGUP -finline-limit="2000" -fomit-frame-pointer -Wlogical-op -Wno-pointer-sign -Wno-strict-prototypes -Wno-enum-compare -Wno-declaration-after-statement -std="gnu90" -DNO_FLOATING_POINT -DUSE_32_BIT -DVMKERNEL -DVMKERNEL_MODULE -DVMK_DEVKIT_HAS_API_VMKAPI_BASE -DVMK_DEVKIT_HAS_API_VMKAPI_ENS -DVMK_DEVKIT_HAS_API_VMKAPI_GPU -DVMK_DEVKIT_HAS_API_VMKAPI_ISCSI -DVMK_DEVKIT_HAS_API_VMKAPI_NET -DVMK_DEVKIT_HAS_API_VMKAPI_NPIV -DVMK_DEVKIT_HAS_API_VMKAPI_NVME_DRV -DVMK_DEVKIT_HAS_API_VMKAPI_RDMA -DVMK_DEVKIT_HAS_API_VMKAPI_SCSI -DVMK_DEVKIT_HAS_API_VMKAPI_SOCKETS -DVMK_DEVKIT_HAS_NATIVE_DDK -DVMK_DEVKIT_USES_BINARY_COMPATIBLE_APIS -DVMK_DEVKIT_USES_PUBLIC_APIS -DVMX86_RELEASE -DVMX86_SERVER -D_GLIBCXX_USE_CXX11_ABI="0" -D__KERNEL__ -D__KMDK__ -Ipartners/samples/public/thrpi/thpimon -Ipartners/samples/public/thrpi/thpimon/.build/build/version -Ipartners/samples/public/thrpi/thpimon/.build/build/HEADERS/vmkapi-current-all-public-bincomp/generic/release -isystem /opt/vmware/toolchain/cayman_esx_toolchain_gcc6-978272870a6446e021754e84f5d75e0c6c53a9b7/usr/lib/gcc/aarch64-vmk-linux-gnu/6.4.0/include -E partners/samples/public/thrpi/thpimon/rpiq_drv.c -U__TIME__ -U__DATE__
30 | WD: /opt/vmware/nativeddkarm64-7.0.1-40650718/src
31 | BD: /opt/vmware/nativeddkarm64-7.0.1-40650718/src/partners/samples/public/thrpi/thpimon/.build
32 | 53da446020842a550d509b004a003f00 partners/samples/public/thrpi/thpimon/.build/build/vmkdriver-thpimon/release/vmkernel64-arm64/SUBDIRS/opt/vmware/nativeddkarm64-7.0.1-40650718/src/partners/samples/public/thrpi/thpimon/rpiq_drv.i
33 | /opt/vmware/toolchain/cayman_llvm-e51314a6e421afc0fc8856057af8b195bb9805f3/lin64/usr/bin+glibc212/ld.lld -r -o partners/samples/public/thrpi/thpimon/.build/build/vmkdriver-thpimon/release/vmkernel64-arm64/thpimon.sv --whole-archive partners/samples/public/thrpi/thpimon/.build/build/vmkdriver-thpimon/release/vmkernel64-arm64/thpimon
34 | WD: /opt/vmware/nativeddkarm64-7.0.1-40650718/src
35 | BD: /opt/vmware/nativeddkarm64-7.0.1-40650718/src/partners/samples/public/thrpi/thpimon/.build
36 | c17016a5bf11bcb43c3809b4b8393dd6 partners/samples/public/thrpi/thpimon/.build/build/vmkdriver-thpimon/release/vmkernel64-arm64/thpimon
37 | 6d53071299e7516bad552dd7fdbaa957 partners/samples/public/thrpi/thpimon/.build/build/vmkdriver-thpimon/release/vmkernel64-arm64/signed/thpimon
38 |
--------------------------------------------------------------------------------
/build/thpimon:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thebel1/thpimon/42cc75e3c0b089e1f4822a19fbd0ae01b620c0e9/build/thpimon
--------------------------------------------------------------------------------
/build/thpimon-nostrip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thebel1/thpimon/42cc75e3c0b089e1f4822a19fbd0ae01b620c0e9/build/thpimon-nostrip
--------------------------------------------------------------------------------
/build/thpimon.map:
--------------------------------------------------------------------------------
1 | regtype=native,bus=acpi,id=RPIQ,driver=thpimon
2 |
--------------------------------------------------------------------------------
/build/vib/thpimon-0.1.0-1OEM.701.1.0.40650718.aarch64.vib:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thebel1/thpimon/42cc75e3c0b089e1f4822a19fbd0ae01b620c0e9/build/vib/thpimon-0.1.0-1OEM.701.1.0.40650718.aarch64.vib
--------------------------------------------------------------------------------
/pimon.h:
--------------------------------------------------------------------------------
1 | /******************************************************************************\
2 | * Native ESXi on Arm driver for hardware monitoring on the Raspberry Pi.
3 | * Copyright (c) 2020 Tom Hebel
4 | *
5 | * Permission is hereby granted, free of charge, to any person obtaining a copy
6 | * of this software and associated documentation files (the "Software"), to deal
7 | * in the Software without restriction, including without limitation the rights
8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | * copies of the Software, and to permit persons to whom the Software is
10 | * furnished to do so, subject to the following conditions:
11 | *
12 | * The above copyright notice and this permission notice shall be included in
13 | * all copies or substantial portions of the Software.
14 | *
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | * SOFTWARE.
22 | \******************************************************************************/
23 |
24 | #ifndef PIMON_H
25 | #define PIMON_H
26 |
27 | #define VMKAPI_ONLY
28 | #include "vmkapi.h"
29 |
30 | #define PIMON_DEBUG
31 |
32 | #define PIMON_DRIVER_NAME "thpimon"
33 |
34 | // Probably overkill
35 | #define PIMON_HEAP_INITIAL_SIZE (1024 * 1024)
36 | #define PIMON_HEAP_MAX_SIZE (2 * 1024 * 1024)
37 |
38 | #define PIMON_INT_MAX ((vmk_uint32)~0)
39 |
40 | #define PIMON_LOG_ERR 1
41 | #define PIMON_LOG_WARN 2
42 | #define PIMON_LOG_NOTE 3
43 | #define PIMON_LOG_INIT 4
44 | #define PIMON_LOG_DISC 5
45 | #define PIMON_LOG_INFO 6
46 | #define PIMON_LOG_FUNC 7
47 | #define PIMON_LOG_TRACEIO 8
48 |
49 | #endif /* PIMON_H */
--------------------------------------------------------------------------------
/pimon_charDev.c:
--------------------------------------------------------------------------------
1 | /******************************************************************************\
2 | * Native ESXi on Arm driver for hardware monitoring on the Raspberry Pi.
3 | * Copyright (c) 2020 Tom Hebel
4 | *
5 | * Permission is hereby granted, free of charge, to any person obtaining a copy
6 | * of this software and associated documentation files (the "Software"), to deal
7 | * in the Software without restriction, including without limitation the rights
8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | * copies of the Software, and to permit persons to whom the Software is
10 | * furnished to do so, subject to the following conditions:
11 | *
12 | * The above copyright notice and this permission notice shall be included in
13 | * all copies or substantial portions of the Software.
14 | *
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | * SOFTWARE.
22 | \******************************************************************************/
23 |
24 | /*
25 | * pimon_charDev.c --
26 | *
27 | * Generic character device driver implementation.
28 | */
29 |
30 | #include "pimon_charDev.h"
31 |
32 | /***********************************************************************/
33 |
34 | static vmk_ModuleID pimon_moduleID;
35 | static vmk_HeapID pimon_heapID;
36 | static vmk_LogComponent pimon_logger;
37 |
38 | static vmk_CharDevOps pimon_charDevFileOps = {
39 | .open = pimon_charDevOpen,
40 | .close = pimon_charDevClose,
41 | .ioctl = pimon_charDevIoctl,
42 | .poll = pimon_charDevPoll,
43 | .read = pimon_charDevRead,
44 | .write = pimon_charDevWrite,
45 | };
46 |
47 | static vmk_CharDevRegOps pimon_CharDevOps = {
48 | .associate = pimon_charDevAssoc,
49 | .disassociate = pimon_charDevDisassoc,
50 | .fileOps = &pimon_charDevFileOps,
51 | };
52 |
53 | /*
54 | * Dev ops for the new vmk_Device associated with the char dev
55 | */
56 | static vmk_DeviceOps pimon_CharVmkDevOps = {
57 | .removeDevice = pimon_charVmkDevRemove,
58 | };
59 |
60 | /*
61 | * Call backs that glue the char dev to the GPIO driver
62 | */
63 | static pimon_CharDevCallbacks_t *pimon_CharDevCBs;
64 |
65 | /***********************************************************************/
66 |
67 | static vmk_TimerQueue pimon_charDevTimerQueue;
68 |
69 | /*
70 | ***********************************************************************
71 | * pimon_charDevInit --
72 | *
73 | * Initialize the character device driver. Onyl called once, as it sets
74 | * a number of global variables.
75 | *
76 | * Results:
77 | * VMK_OK on success, error code otherwise
78 | *
79 | * Side Effects:
80 | * None.
81 | ***********************************************************************
82 | */
83 | VMK_ReturnStatus
84 | pimon_charDevInit(vmk_ModuleID moduleID,
85 | vmk_HeapID heapID,
86 | vmk_LogComponent logger)
87 | {
88 | VMK_ReturnStatus status = VMK_OK;
89 |
90 | pimon_moduleID = moduleID;
91 | pimon_heapID = heapID;
92 | pimon_logger = logger;
93 |
94 | return status;
95 | }
96 |
97 | /*
98 | ***********************************************************************
99 | * pimon_charDevRegister --
100 | *
101 | * Register a character device with the vmkernel chardev layer.
102 | *
103 | * Results:
104 | * VMK_OK on success, error code otherwise
105 | *
106 | * Side Effects:
107 | * None.
108 | ***********************************************************************
109 | */
110 | VMK_ReturnStatus
111 | pimon_charDevRegister(pimon_CharDevProps_t *props)
112 | {
113 | VMK_ReturnStatus status = VMK_OK;
114 | vmk_Device newDevice;
115 | vmk_DeviceID devID;
116 | vmk_AddrCookie registeringDriverData;
117 | vmk_AddrCookie registrationData;
118 | vmk_DeviceProps deviceProps;
119 | pimon_CharDev_t *charDev;
120 | vmk_AddrCookie charDevPriv;
121 |
122 | devID.busType = props->logicalBusType;
123 | status = vmk_LogicalCreateBusAddress(props->driverHandle,
124 | props->parentDevice,
125 | props->logicalPort,
126 | &devID.busAddress,
127 | &devID.busAddressLen);
128 | if (status != VMK_OK) {
129 | goto logical_bus_failed;
130 | }
131 |
132 | charDev = props->charDev;
133 |
134 | /*
135 | * As per vmkapi_char.h it can only be graphics or a test device
136 | */
137 | devID.busIdentifier = VMK_CHARDEV_IDENTIFIER_GRAPHICS;
138 | devID.busIdentifierLen = vmk_Strnlen(devID.busIdentifier, VMK_MISC_NAME_MAX);
139 |
140 | charDevPriv.ptr = props->privData;
141 |
142 | /*
143 | * Set up char dev registration
144 | */
145 |
146 | charDev->regData.moduleID = pimon_moduleID;
147 | charDev->regData.deviceOps = &pimon_CharDevOps;
148 | charDev->regData.devicePrivate = charDevPriv;
149 |
150 | registrationData.ptr = &charDev->regData;
151 | registeringDriverData.ptr = props->charDev;
152 |
153 | deviceProps.registeringDriver = props->driverHandle;
154 | deviceProps.deviceID = &devID;
155 | deviceProps.deviceOps = &pimon_CharVmkDevOps;
156 | deviceProps.registeringDriverData = registeringDriverData;
157 | deviceProps.registrationData = registrationData;
158 |
159 | status = vmk_DeviceRegister(&deviceProps, props->parentDevice, &newDevice);
160 | if (status != VMK_OK) {
161 | vmk_Warning(pimon_logger,
162 | "failed to register device: %s",
163 | vmk_StatusToString(status));
164 | goto register_device_failed;
165 | }
166 |
167 | status = vmk_LogicalFreeBusAddress(props->driverHandle,
168 | devID.busAddress);
169 | if (status != VMK_OK) {
170 | vmk_Warning(pimon_logger,
171 | "failed to free logical bus: %s",
172 | vmk_StatusToString(status));
173 | goto free_bus_failed;
174 | }
175 |
176 | /*
177 | * Set CBs
178 | */
179 | pimon_CharDevCBs = props->callbacks;
180 |
181 | return VMK_OK;
182 |
183 | free_bus_failed:
184 | vmk_LogicalFreeBusAddress(props->driverHandle,
185 | devID.busAddress);
186 | register_device_failed:
187 | logical_bus_failed:
188 | return status;
189 | }
190 |
191 | /*
192 | ***********************************************************************
193 | * pimon_charVmkDevRemove --
194 | *
195 | * Remove character device.
196 | *
197 | * Results:
198 | * VMK_OK on success, error code otherwise
199 | *
200 | * Side Effects:
201 | * None.
202 | ***********************************************************************
203 | */
204 | VMK_ReturnStatus
205 | pimon_charVmkDevRemove(vmk_Device logicalDev)
206 | {
207 | VMK_ReturnStatus status = VMK_OK;
208 |
209 | status = vmk_DeviceUnregister(logicalDev);
210 | if (status != VMK_OK)
211 | {
212 | vmk_Warning(pimon_logger,
213 | "failed to unregister device: %s",
214 | vmk_StatusToString(status));
215 | }
216 |
217 | return status;
218 | }
219 |
220 | /*
221 | ***********************************************************************
222 | * pimon_charDevAssoc --
223 | *
224 | * Associate a char device with a device.
225 | *
226 | * Results:
227 | * VMK_OK on success, error code otherwise
228 | *
229 | * Side Effects:
230 | * None.
231 | ***********************************************************************
232 | */
233 | VMK_ReturnStatus
234 | pimon_charDevAssoc(vmk_AddrCookie charDevPriv,
235 | vmk_CharDevHandle charDevHandle)
236 | {
237 | VMK_ReturnStatus status = VMK_OK;
238 | vmk_Name charDevAlias;
239 |
240 | status = vmk_CharDeviceGetAlias(charDevHandle, &charDevAlias);
241 | if (status != VMK_OK) {
242 | vmk_Warning(pimon_logger,
243 | "failed to obtain logical device alias: %s",
244 | vmk_StatusToString(status));
245 | goto get_alias_failed;
246 | }
247 |
248 | #ifdef PIMON_DEBUG
249 | {
250 | vmk_Log(pimon_logger,
251 | "obtained logical device alias %s",
252 | charDevAlias.string);
253 | }
254 | #endif /* PIMON_DEBUG */
255 |
256 | return VMK_OK;
257 |
258 | get_alias_failed:
259 | return status;
260 | }
261 |
262 | /*
263 | ***********************************************************************
264 | * pimon_charDevDisassoc --
265 | *
266 | * Disassociate a char device with a device.
267 | *
268 | * Results:
269 | * VMK_OK on success, error code otherwise
270 | *
271 | * Side Effects:
272 | * None.
273 | ***********************************************************************
274 | */
275 | VMK_ReturnStatus
276 | pimon_charDevDisassoc(vmk_AddrCookie charDevPriv)
277 | {
278 | VMK_ReturnStatus status = VMK_OK;
279 |
280 | return status;
281 | }
282 |
283 | /*
284 | ***********************************************************************
285 | * pimon_charDevOpen --
286 | *
287 | * Opens a file.
288 | *
289 | * Results:
290 | * VMK_OK on success, error code otherwise
291 | *
292 | * Side Effects:
293 | * None.
294 | ***********************************************************************
295 | */
296 | VMK_ReturnStatus
297 | pimon_charDevOpen(vmk_CharDevFdAttr *attr)
298 | {
299 | VMK_ReturnStatus status = VMK_OK;
300 | pimon_CharFileData_t *fileData;
301 | vmk_SpinlockCreateProps lockProps;
302 |
303 | /*
304 | * Init private file data
305 | */
306 |
307 | fileData = vmk_HeapAlloc(pimon_heapID, sizeof(*fileData));
308 | if (fileData == NULL) {
309 | status = VMK_NO_MEMORY;
310 | vmk_Warning(pimon_logger,
311 | "failed to create file private data: %s",
312 | vmk_StatusToString(status));
313 | goto file_priv_alloc_failed;
314 | }
315 | vmk_Memset(fileData, 0, sizeof(*fileData));
316 |
317 | /*
318 | * Init lock
319 | */
320 |
321 | lockProps.moduleID = pimon_moduleID;
322 | lockProps.heapID = pimon_heapID;
323 | status = vmk_NameInitialize(&lockProps.name, PIMON_DRIVER_NAME);
324 | if (status != VMK_OK) {
325 | vmk_Warning(pimon_logger,
326 | "failed to init lock name: %s",
327 | vmk_StatusToString(status));
328 | goto lock_init_failed;
329 | }
330 |
331 | lockProps.type = VMK_SPINLOCK;
332 | lockProps.domain = VMK_LOCKDOMAIN_INVALID;
333 | lockProps.rank = VMK_SPINLOCK_UNRANKED;
334 | status = vmk_SpinlockCreate(&lockProps, &fileData->lock);
335 | if (status != VMK_OK) {
336 | vmk_Warning(pimon_logger,
337 | "failed to create spinlock: %s",
338 | vmk_StatusToString(status));
339 | goto lock_init_failed;
340 | }
341 |
342 | /*
343 | * We don't use this buffer, so set it to NULL
344 | */
345 | fileData->data = NULL;
346 |
347 | /*
348 | * Prep file for I/O
349 | */
350 | fileData->timerPending = VMK_FALSE;
351 | fileData->deathPending = VMK_FALSE;
352 | fileData->pollMask = VMKAPI_POLL_WRITE;
353 | fileData->timeoutUS = PIMON_CHARDEV_POLL_TIMEOUT_US;
354 | attr->clientInstanceData.ptr = fileData;
355 |
356 | #ifdef PIMON_DEBUG
357 | {
358 | vmk_Log(pimon_logger,
359 | "opened file; priv %p lock %p",
360 | fileData,
361 | fileData->lock);
362 | }
363 | #endif /* PIMON_DEBUG */
364 |
365 | /* Call CB */
366 | status = pimon_CharDevCBs->open(attr);
367 |
368 | return status;
369 |
370 | lock_init_failed:
371 | vmk_HeapFree(pimon_heapID, fileData);
372 |
373 | file_priv_alloc_failed:
374 | return status;
375 | }
376 |
377 | /*
378 | ***********************************************************************
379 | * pimon_charDevClose --
380 | *
381 | * Closes a file.
382 | *
383 | * Results:
384 | * VMK_OK on success, error code otherwise
385 | *
386 | * Side Effects:
387 | * None.
388 | ***********************************************************************
389 | */
390 | VMK_ReturnStatus
391 | pimon_charDevClose(vmk_CharDevFdAttr *attr)
392 | {
393 | VMK_ReturnStatus status = VMK_OK;
394 | pimon_CharFileData_t *fileData = attr->clientInstanceData.ptr;
395 |
396 | if (fileData == NULL) {
397 | status = VMK_BAD_PARAM;
398 | vmk_Warning(pimon_logger, "file data null");
399 | goto file_data_null;
400 | }
401 |
402 | vmk_SpinlockLock(fileData->lock);
403 |
404 | fileData->deathPending = VMK_TRUE;
405 |
406 | if (fileData->timerPending == VMK_FALSE) {
407 | vmk_SpinlockUnlock(fileData->lock);
408 | pimon_charDevFileDestroy(fileData);
409 | }
410 |
411 | /* Call CB */
412 | status = pimon_CharDevCBs->close(attr);
413 |
414 | file_data_null:
415 | return status;
416 | }
417 |
418 | /*
419 | ***********************************************************************
420 | * pimon_charDevIoctl --
421 | *
422 | * GPIO chardev-specific I/O ops. Used for programming reads to input
423 | * pins.
424 | *
425 | * Results:
426 | * VMK_OK on success, error code otherwise
427 | *
428 | * Side Effects:
429 | * None.
430 | ***********************************************************************
431 | */
432 | VMK_ReturnStatus
433 | pimon_charDevIoctl(vmk_CharDevFdAttr *attr,
434 | unsigned int cmd,
435 | vmk_uintptr_t userData,
436 | vmk_IoctlCallerSize callerSize,
437 | vmk_int32 *result)
438 | {
439 | VMK_ReturnStatus status = VMK_OK;
440 | void *ioctlData;
441 | vmk_ByteCount ioctlDataLen;
442 | pimon_CharFileData_t *fileData = attr->clientInstanceData.ptr;
443 |
444 | if (fileData == NULL) {
445 | status = VMK_BAD_PARAM;
446 | vmk_Warning(pimon_logger, "file data null");
447 | goto file_data_null;
448 | }
449 |
450 | /*
451 | * Allocate ioctl data
452 | */
453 | ioctlDataLen = ((pimon_CharDevPriv_t *)attr->clientDeviceData.ptr)->ioctlDataLen;
454 | ioctlData = vmk_HeapAlloc(pimon_heapID, ioctlDataLen);
455 | if (ioctlData == NULL) {
456 | status = VMK_NO_MEMORY;
457 | vmk_Warning(pimon_logger,
458 | "failed to allocate memory for ioctl data: %s",
459 | vmk_StatusToString(status));
460 | goto ioctl_alloc_failed;
461 | }
462 |
463 | #ifdef PIMON_DEBUG
464 | {
465 | vmk_Log(pimon_logger,
466 | "copying ioctl data from %p (UW) to %p (vmk)",
467 | (vmk_VA)userData,
468 | (vmk_VA)ioctlData);
469 | }
470 | #endif /* PIMON_DEBUG */
471 |
472 | /*
473 | * Copy ioctl data from UW
474 | */
475 | status = vmk_CopyFromUser((vmk_VA)ioctlData,
476 | (vmk_VA)userData,
477 | ioctlDataLen);
478 | if (status != VMK_OK) {
479 | vmk_Warning(pimon_logger,
480 | "unable to copy ioctl data from UW ptr %p: %s",
481 | userData,
482 | vmk_StatusToString(status));
483 | goto ioctl_uw2vmk_failed;
484 | }
485 |
486 | #ifdef PIMON_DEBUG
487 | {
488 | vmk_Log(pimon_logger,
489 | "executing ioctl cmd %d with data %p",
490 | cmd,
491 | userData);
492 | }
493 | #endif
494 |
495 | /*
496 | * Call CB
497 | */
498 | vmk_SpinlockLock(fileData->lock);
499 | status = pimon_CharDevCBs->ioctl(cmd, ioctlData, ioctlDataLen);
500 | vmk_SpinlockUnlock(fileData->lock);
501 | if (status != VMK_OK) {
502 | vmk_Warning(pimon_logger,
503 | "ioctl cmd %d with data %p failed: %s",
504 | cmd,
505 | userData,
506 | vmk_StatusToString(status));
507 | goto ioctl_cmd_failed;
508 | }
509 |
510 | /*
511 | * Copy iotl data back to UW
512 | */
513 | status = vmk_CopyToUser((vmk_VA)userData,
514 | (vmk_VA)ioctlData,
515 | ioctlDataLen);
516 | if (status != VMK_OK) {
517 | vmk_Warning(pimon_logger,
518 | "unable to copy ioctl data back to UW: %s",
519 | vmk_StatusToString(status));
520 | goto ioctl_vmk2uw_failed;
521 | }
522 |
523 | vmk_HeapFree(pimon_heapID, ioctlData);
524 |
525 | return VMK_OK;
526 |
527 | ioctl_vmk2uw_failed:
528 | ioctl_cmd_failed:
529 | ioctl_uw2vmk_failed:
530 | vmk_HeapFree(pimon_heapID, ioctlData);
531 |
532 | ioctl_alloc_failed:
533 | file_data_null:
534 | return status;
535 | }
536 |
537 | /*
538 | ***********************************************************************
539 | * pimon_charDevRead --
540 | *
541 | * Reads from a file. Not supported for now, as we only allow writing
542 | * commands of sorts to the chardev file.
543 | *
544 | * Results:
545 | * VMK_OK on success, error code otherwise
546 | *
547 | * Side Effects:
548 | * None.
549 | ***********************************************************************
550 | */
551 | VMK_ReturnStatus
552 | pimon_charDevRead(vmk_CharDevFdAttr *attr,
553 | char *buffer,
554 | vmk_ByteCount nbytes,
555 | vmk_loff_t *ppos,
556 | vmk_ByteCountSigned *nread)
557 | {
558 | return pimon_charDevIO(attr, buffer, nbytes, ppos, nread, VMK_FALSE);
559 | }
560 |
561 | /*
562 | ***********************************************************************
563 | * pimon_charDevWrite --
564 | *
565 | * Writes to a file.
566 | *
567 | * Results:
568 | * VMK_OK on success, error code otherwise
569 | *
570 | * Side Effects:
571 | * None.
572 | ***********************************************************************
573 | */
574 | VMK_ReturnStatus
575 | pimon_charDevWrite(vmk_CharDevFdAttr *attr,
576 | char *buffer,
577 | vmk_ByteCount nbytes,
578 | vmk_loff_t *ppos,
579 | vmk_ByteCountSigned *nwritten)
580 | {
581 | return pimon_charDevIO(attr, buffer, nbytes, ppos, nwritten, VMK_TRUE);
582 | }
583 |
584 | /*
585 | ***********************************************************************
586 | * pimon_charDevIO --
587 | *
588 | * Read/write to file.
589 | *
590 | * Results:
591 | * VMK_OK on success, error code otherwise
592 | *
593 | * Side Effects:
594 | * None.
595 | ***********************************************************************
596 | */
597 | VMK_ReturnStatus
598 | pimon_charDevIO(vmk_CharDevFdAttr *attr,
599 | char *buffer,
600 | vmk_ByteCount nbytes,
601 | vmk_loff_t *ppos,
602 | vmk_ByteCountSigned *ndone,
603 | vmk_Bool isWrite)
604 | {
605 | return VMK_NOT_SUPPORTED;
606 | }
607 |
608 | /*
609 | ***********************************************************************
610 | * pimon_charDevPoll --
611 | *
612 | * Polls a file.
613 | *
614 | * Results:
615 | * VMK_OK on success, error code otherwise
616 | *
617 | * Side Effects:
618 | * None.
619 | ***********************************************************************
620 | */
621 | VMK_ReturnStatus
622 | pimon_charDevPoll(vmk_CharDevFdAttr *attr,
623 | vmk_PollContext pollCtx,
624 | vmk_uint32 *pollMask)
625 | {
626 | VMK_ReturnStatus status = VMK_OK;
627 | pimon_CharFileData_t *fileData = attr->clientInstanceData.ptr;
628 | vmk_TimerCookie tmrCookie;
629 |
630 | if (fileData == NULL) {
631 | status = VMK_BAD_PARAM;
632 | vmk_Warning(pimon_logger, "file data null");
633 | goto file_data_null;
634 | }
635 |
636 | vmk_SpinlockLock(fileData->lock);
637 |
638 | if (fileData->pollMask == VMK_FALSE
639 | && fileData->timerPending == VMK_FALSE
640 | && fileData->deathPending == VMK_FALSE) {
641 | tmrCookie.ptr = fileData;
642 | status = vmk_TimerSchedule(pimon_charDevTimerQueue,
643 | pimon_charDevTimerCB,
644 | tmrCookie,
645 | PIMON_CHARDEV_POLL_TIMEOUT_US,
646 | VMK_TIMER_DEFAULT_TOLERANCE,
647 | VMK_TIMER_ATTR_NONE,
648 | VMK_LOCKDOMAIN_INVALID,
649 | VMK_SPINLOCK_UNRANKED,
650 | &fileData->timer);
651 | if (status == VMK_OK) {
652 | fileData->timerPending = VMK_TRUE;
653 | }
654 | else {
655 | vmk_Warning(pimon_logger,
656 | "failed to create poll timer: %s",
657 | vmk_StatusToString(status));
658 | goto create_poll_timer_failed;
659 | }
660 | }
661 |
662 | vmk_CharDevSetPollContext(pollCtx, (void *)fileData);
663 | *pollMask = fileData->pollMask;
664 |
665 | vmk_SpinlockUnlock(fileData->lock);
666 |
667 | return VMK_OK;
668 |
669 | create_poll_timer_failed:
670 | vmk_SpinlockUnlock(fileData->lock);
671 |
672 | file_data_null:
673 | return status;
674 | }
675 |
676 | /*
677 | ***********************************************************************
678 | * pimon_charDevTimerCB --
679 | *
680 | * Callback for char device poll timer.
681 | *
682 | * Results:
683 | * VMK_OK on success, error code otherwise
684 | *
685 | * Side Effects:
686 | * None.
687 | ***********************************************************************
688 | */
689 | void
690 | pimon_charDevTimerCB(vmk_TimerCookie data)
691 | {
692 | pimon_CharFileData_t *fileData = (pimon_CharFileData_t *)data.ptr;
693 |
694 | if (fileData == NULL) {
695 | vmk_Warning(pimon_logger, "file data null");
696 | goto file_data_null;
697 | }
698 |
699 | vmk_SpinlockLock(fileData->lock);
700 |
701 | fileData->timerPending = VMK_FALSE;
702 | fileData->pollMask = VMKAPI_POLL_WRITE;
703 |
704 | if (fileData->deathPending == VMK_FALSE) {
705 | /* Wake up pollers in UW */
706 | vmk_CharDevWakePollers(fileData);
707 | }
708 | else {
709 | vmk_SpinlockUnlock(fileData->lock);
710 | pimon_charDevFileDestroy(fileData);
711 | goto death_pending;
712 | }
713 |
714 | vmk_SpinlockUnlock(fileData->lock);
715 |
716 | death_pending:
717 | file_data_null:
718 | return;
719 | }
720 |
721 | /*
722 | ***********************************************************************
723 | * pimon_charDevFileDestroy --
724 | *
725 | * Destroy a file.
726 | *
727 | * Results:
728 | * VMK_OK on success, error code otherwise
729 | *
730 | * Side Effects:
731 | * None.
732 | ***********************************************************************
733 | */
734 | void
735 | pimon_charDevFileDestroy(pimon_CharFileData_t *fileData)
736 | {
737 | #ifdef PIMON_DEBUG
738 | {
739 | vmk_Log(pimon_logger,
740 | "destroying file %p",
741 | fileData);
742 | }
743 | #endif /* PIMON_DEBUG */
744 |
745 | vmk_SpinlockDestroy(fileData->lock);
746 | vmk_HeapFree(pimon_heapID, fileData);
747 | }
--------------------------------------------------------------------------------
/pimon_charDev.h:
--------------------------------------------------------------------------------
1 | /******************************************************************************\
2 | * Native ESXi on Arm driver for hardware monitoring on the Raspberry Pi.
3 | * Copyright (c) 2020 Tom Hebel
4 | *
5 | * Permission is hereby granted, free of charge, to any person obtaining a copy
6 | * of this software and associated documentation files (the "Software"), to deal
7 | * in the Software without restriction, including without limitation the rights
8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | * copies of the Software, and to permit persons to whom the Software is
10 | * furnished to do so, subject to the following conditions:
11 | *
12 | * The above copyright notice and this permission notice shall be included in
13 | * all copies or substantial portions of the Software.
14 | *
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | * SOFTWARE.
22 | \******************************************************************************/
23 |
24 | /*
25 | * pimon_charDev.h --
26 | */
27 |
28 | #ifndef PIMON_CHARDEV_H
29 | #define PIMON_CHARDEV_H
30 |
31 | /***********************************************************************/
32 |
33 | #define VMKAPI_ONLY
34 | #include "vmkapi.h"
35 |
36 | #include "pimon.h"
37 |
38 | /***********************************************************************/
39 |
40 | #define PIMON_CHARDEV_BUFFER_SIZE 4096 /* Probably overkill */
41 | #define PIMON_CHARDEV_POLL_TIMEOUT_US 1000000
42 |
43 | /***********************************************************************/
44 |
45 | /*
46 | * Callbacks for gluing the char dev driver to the THX driver
47 | */
48 | typedef VMK_ReturnStatus (*pimon_CharDevOpenCB_t)(vmk_CharDevFdAttr *attr);
49 | typedef VMK_ReturnStatus (*pimon_CharDevCloseCB_t)(vmk_CharDevFdAttr *attr);
50 |
51 | typedef VMK_ReturnStatus (*pimon_CharDevIoctlCB_t)(unsigned int cmd,
52 | void *ioctlData,
53 | vmk_ByteCount dataLen);
54 | typedef VMK_ReturnStatus (*pimon_CharDevReadCB_t)(char *buffer,
55 | vmk_ByteCount nbytes,
56 | vmk_loff_t *ppos,
57 | vmk_ByteCountSigned *nread);
58 | typedef VMK_ReturnStatus (*pimon_CharDevWriteCB_t)(char *buffer,
59 | vmk_ByteCount nbytes,
60 | vmk_loff_t *ppos,
61 | vmk_ByteCountSigned *nread);
62 | typedef struct pimon_CharDevCallbacks_t {
63 | pimon_CharDevOpenCB_t open;
64 | pimon_CharDevCloseCB_t close;
65 | pimon_CharDevIoctlCB_t ioctl;
66 | pimon_CharDevReadCB_t read;
67 | pimon_CharDevWriteCB_t write;
68 | } pimon_CharDevCallbacks_t;
69 |
70 | typedef struct pimon_CharDevPriv_t {
71 | /* The size of the data being passed via ioctl */
72 | vmk_ByteCount ioctlDataLen;
73 | } pimon_CharDevPriv_t;
74 |
75 | typedef struct pimon_CharDev_t {
76 | vmk_Device vmkDevice;
77 | vmk_CharDevRegData regData;
78 | pimon_CharDevCallbacks_t devCBs;
79 | } pimon_CharDev_t;
80 |
81 | typedef struct pimon_CharFileData_t {
82 | vmk_Lock lock;
83 | char *data;
84 | vmk_Bool timerPending;
85 | vmk_Bool deathPending;
86 | vmk_Timer timer;
87 | vmk_int32 timeoutUS;
88 | vmk_uint32 pollMask;
89 | } pimon_CharFileData_t;
90 |
91 | typedef struct pimon_CharDevProps_t {
92 | vmk_Driver driverHandle;
93 | vmk_BusType logicalBusType;
94 | vmk_Device parentDevice;
95 | pimon_CharDev_t *charDev;
96 | pimon_CharDevPriv_t *privData;
97 | vmk_uint32 logicalPort;
98 | pimon_CharDevCallbacks_t *callbacks;
99 | } pimon_CharDevProps_t;
100 |
101 | /***********************************************************************/
102 |
103 | VMK_ReturnStatus pimon_charDevInit(vmk_ModuleID moduleID,
104 | vmk_HeapID heapID,
105 | vmk_LogComponent logger);
106 |
107 | VMK_ReturnStatus pimon_charDevRegister(pimon_CharDevProps_t *props);
108 |
109 | VMK_ReturnStatus pimon_charVmkDevRemove(vmk_Device logicalDev);
110 |
111 | VMK_ReturnStatus pimon_charDevAssoc(vmk_AddrCookie charDevPriv,
112 | vmk_CharDevHandle charDevHandle);
113 |
114 | VMK_ReturnStatus pimon_charDevDisassoc(vmk_AddrCookie charDevPriv);
115 |
116 | VMK_ReturnStatus pimon_charDevOpen(vmk_CharDevFdAttr *attr);
117 |
118 | VMK_ReturnStatus pimon_charDevClose(vmk_CharDevFdAttr *attr);
119 |
120 | VMK_ReturnStatus pimon_charDevIoctl(vmk_CharDevFdAttr *attr,
121 | vmk_uint32 cmd,
122 | vmk_uintptr_t userData,
123 | vmk_IoctlCallerSize callerSize,
124 | vmk_int32 *result);
125 |
126 | VMK_ReturnStatus pimon_charDevRead(vmk_CharDevFdAttr *attr,
127 | char *buffer,
128 | vmk_ByteCount nbytes,
129 | vmk_loff_t *ppos,
130 | vmk_ByteCountSigned *nread);
131 |
132 | VMK_ReturnStatus pimon_charDevWrite(vmk_CharDevFdAttr *attr,
133 | char *buffer,
134 | vmk_ByteCount nbytes,
135 | vmk_loff_t *ppos,
136 | vmk_ByteCountSigned *nwritten);
137 |
138 | VMK_ReturnStatus pimon_charDevIO(vmk_CharDevFdAttr *attr,
139 | char *buffer,
140 | vmk_ByteCount nbytes,
141 | vmk_loff_t *ppos,
142 | vmk_ByteCountSigned *ndone,
143 | vmk_Bool isWrite);
144 |
145 | VMK_ReturnStatus pimon_charDevPoll(vmk_CharDevFdAttr *attr,
146 | vmk_PollContext pollCtx,
147 | vmk_uint32 *pollMask);
148 |
149 | void pimon_charDevTimerCB(vmk_TimerCookie data);
150 |
151 | void pimon_charDevFileDestroy(pimon_CharFileData_t *fileData);
152 |
153 | /***********************************************************************/
154 |
155 | #endif /* PIMON_CHARDEV_H */
--------------------------------------------------------------------------------
/pimon_os.c:
--------------------------------------------------------------------------------
1 | /******************************************************************************\
2 | * Native ESXi on Arm driver for hardware monitoring on the Raspberry Pi.
3 | * Copyright (c) 2020 Tom Hebel
4 | *
5 | * Permission is hereby granted, free of charge, to any person obtaining a copy
6 | * of this software and associated documentation files (the "Software"), to deal
7 | * in the Software without restriction, including without limitation the rights
8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | * copies of the Software, and to permit persons to whom the Software is
10 | * furnished to do so, subject to the following conditions:
11 | *
12 | * The above copyright notice and this permission notice shall be included in
13 | * all copies or substantial portions of the Software.
14 | *
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | * SOFTWARE.
22 | \******************************************************************************/
23 |
24 | // TODO:
25 | // - Implement a fail-safe for when the requested DMA heap is above 1GB, and
26 | // program the DMA controller to move the DMA aperture upwards to match the
27 | // heap start MA.
28 |
29 | /*
30 | * pimon_os.c --
31 | *
32 | * Module initialization and other OS stuff.
33 | */
34 |
35 | #include "pimon.h"
36 | #include "pimon_types.h"
37 | #include "rpiq_drv.h"
38 | #include "pimon_charDev.h"
39 |
40 | /***********************************************************************/
41 |
42 | static pimon_Driver_t pimon_Driver;
43 | static rpiq_Device_t rpiq_Device;
44 |
45 | /* For RPIQ char dev */
46 | static pimon_CharDev_t rpiq_CharDev;
47 | static vmk_BusType rpiq_logicalBusType;
48 |
49 | VMK_ReturnStatus pimon_attachDevice(vmk_Device device);
50 | VMK_ReturnStatus pimon_scanDevice(vmk_Device device);
51 | VMK_ReturnStatus pimon_detachDevice(vmk_Device device);
52 | VMK_ReturnStatus pimon_quiesceDevice(vmk_Device device);
53 | VMK_ReturnStatus pimon_startDevice(vmk_Device device);
54 | void pimon_forgetDevice(vmk_Device device);
55 |
56 | static vmk_DriverOps pimon_DriverOps = {
57 | .attachDevice = pimon_attachDevice,
58 | .scanDevice = pimon_scanDevice,
59 | .detachDevice = pimon_detachDevice,
60 | .quiesceDevice = pimon_quiesceDevice,
61 | .startDevice = pimon_startDevice,
62 | .forgetDevice = pimon_forgetDevice,
63 | };
64 |
65 | /*
66 | * Callbacks gluing the chardev driver to the RPIQ driver.
67 | */
68 | static pimon_CharDevCallbacks_t rpiq_CharDevCBs = {
69 | .open = rpiq_mmioOpenCB,
70 | .close = rpiq_mmioCloseCB,
71 | .ioctl = rpiq_mmioIoctlCB,
72 | .read = rpiq_mmioReadCB,
73 | .write = rpiq_mmioWriteCB,
74 | };
75 |
76 | /*
77 | ***********************************************************************
78 | * init_module --
79 | *
80 | * Entry point for vmkernel module.
81 | *
82 | * Results:
83 | * VMK_OK on success, error code otherwise
84 | *
85 | * Side Effects:
86 | * None
87 | ***********************************************************************
88 | */
89 | int
90 | init_module(void)
91 | {
92 | VMK_ReturnStatus status = VMK_OK;
93 | vmk_HeapID heapID;
94 | vmk_HeapCreateProps heapProps;
95 | vmk_DriverProps driverProps;
96 | vmk_LogProperties logProps;
97 | vmk_Name charDevBusName;
98 |
99 | status = vmk_NameInitialize(&pimon_Driver.driverName, PIMON_DRIVER_NAME);
100 | VMK_ASSERT(status == VMK_OK);
101 |
102 | pimon_Driver.moduleID = vmk_ModuleCurrentID;
103 | rpiq_Device.initialized = VMK_FALSE;
104 |
105 | /*
106 | * Create module heap
107 | */
108 |
109 | heapProps.type = VMK_HEAP_TYPE_SIMPLE;
110 | status = vmk_NameInitialize(&heapProps.name, PIMON_DRIVER_NAME);
111 | VMK_ASSERT(status == VMK_OK);
112 | heapProps.module = pimon_Driver.moduleID;
113 | heapProps.initial = PIMON_HEAP_INITIAL_SIZE;
114 | heapProps.creationTimeoutMS = VMK_TIMEOUT_NONBLOCKING;
115 | heapProps.max = PIMON_HEAP_MAX_SIZE;
116 |
117 | status = vmk_HeapCreate(&heapProps, &heapID);
118 | if (status != VMK_OK) {
119 | vmk_WarningMessage("%s: %s: failed to create heap: %s",
120 | PIMON_DRIVER_NAME,
121 | __FUNCTION__,
122 | vmk_StatusToString(status));
123 | goto heap_create_failed;
124 | }
125 |
126 | vmk_ModuleSetHeapID(pimon_Driver.moduleID, heapID);
127 | VMK_ASSERT(vmk_ModuleGetHeapID(pimon_Driver.moduleID) == heapID);
128 | pimon_Driver.heapID = heapID;
129 |
130 | /*
131 | * Set up logger
132 | */
133 |
134 | status = vmk_NameInitialize(&logProps.name, PIMON_DRIVER_NAME);
135 | VMK_ASSERT(status == VMK_OK);
136 | logProps.module = pimon_Driver.moduleID;
137 | logProps.heap = pimon_Driver.heapID;
138 | logProps.defaultLevel = 0;
139 | logProps.throttle = NULL;
140 |
141 | status = vmk_LogRegister(&logProps, &pimon_Driver.logger);
142 | if (status != VMK_OK) {
143 | vmk_WarningMessage("%s: %s: failed to register logger: %s",
144 | PIMON_DRIVER_NAME,
145 | __FUNCTION__,
146 | vmk_StatusToString(status));
147 | goto logger_reg_failed;
148 | }
149 |
150 | /*
151 | * Init logical bus for char dev
152 | */
153 |
154 | status = vmk_NameInitialize(&charDevBusName, VMK_LOGICAL_BUS_NAME);
155 | status = vmk_BusTypeFind(&charDevBusName, &rpiq_logicalBusType);
156 | if (status != VMK_OK) {
157 | vmk_Warning(pimon_Driver.logger,
158 | "failed to find logical bus: %s",
159 | vmk_StatusToString(status));
160 | goto chardev_bus_failed;
161 | }
162 |
163 | /*
164 | * Register driver
165 | */
166 |
167 | vmk_Memset(&driverProps, 0, sizeof(driverProps));
168 | status = vmk_NameInitialize(&driverProps.name, PIMON_DRIVER_NAME);
169 | VMK_ASSERT(status == VMK_OK);
170 | driverProps.moduleID = pimon_Driver.moduleID;
171 | driverProps.ops = &pimon_DriverOps;
172 |
173 | status = vmk_DriverRegister(&driverProps,
174 | &(pimon_Driver.driverHandle));
175 | if (status == VMK_OK) {
176 | vmk_Log(pimon_Driver.logger,
177 | "driver registration successful",
178 | PIMON_DRIVER_NAME,
179 | __FUNCTION__);
180 | }
181 | else {
182 | vmk_Warning(pimon_Driver.logger,
183 | "driver registration failed: %s",
184 | vmk_StatusToString(status));
185 | goto driver_register_failed;
186 | }
187 |
188 | /*
189 | * Init char dev driver
190 | */
191 | pimon_charDevInit(pimon_Driver.moduleID,
192 | pimon_Driver.heapID,
193 | pimon_Driver.logger);
194 |
195 | return VMK_OK;
196 |
197 | driver_register_failed:
198 | chardev_bus_failed:
199 | vmk_LogUnregister(pimon_Driver.logger);
200 |
201 | logger_reg_failed:
202 | vmk_HeapDestroy(pimon_Driver.heapID);
203 |
204 | heap_create_failed:
205 | return 0;
206 | }
207 |
208 | /*
209 | ***********************************************************************
210 | * cleanup_module --
211 | *
212 | * Cleanup code for when module is unloaded.
213 | *
214 | * Results:
215 | * VMK_OK on success, error code otherwise
216 | *
217 | * Side Effects:
218 | * None
219 | ***********************************************************************
220 | */
221 | void
222 | cleanup_module(void)
223 | {
224 | rpiq_drvCleanUp();
225 | vmk_HeapDestroy(rpiq_Device.dmaHeapID);
226 | vmk_ACPIUnmapIOResource(pimon_Driver.moduleID, rpiq_Device.acpiDevice, 0);
227 | vmk_LogUnregister(pimon_Driver.logger);
228 | vmk_BusTypeRelease(rpiq_logicalBusType);
229 | vmk_HeapDestroy(pimon_Driver.heapID);
230 | vmk_DriverUnregister(pimon_Driver.driverHandle);
231 | }
232 |
233 | /*
234 | ***********************************************************************
235 | * pimon_attachDevice --
236 | *
237 | * Driver callback that attaches RPIQ logical device to the driver.
238 | *
239 | * Results:
240 | * VMK_OK on success, error code otherwise
241 | *
242 | * Side Effects:
243 | * None
244 | ***********************************************************************
245 | */
246 | VMK_ReturnStatus
247 | pimon_attachDevice(vmk_Device device)
248 | {
249 | VMK_ReturnStatus status = VMK_OK;
250 | vmk_ACPIDevice acpiDev;
251 | vmk_ACPIInfo acpiInfo;
252 | vmk_MappedResourceAddress mappedAddr;
253 | vmk_HeapAllocationDescriptor heapAllocDesc;
254 | vmk_ByteCount dmaHeapSize;
255 | vmk_HeapCreateProps heapProps;
256 | vmk_HeapID dmaHeapID;
257 | rpiq_Device_t *adapter = &rpiq_Device;
258 |
259 | /*
260 | * Since there is only one RPIQ device on the system board, we're making
261 | * sure we're not initializing more.
262 | */
263 | if (adapter->initialized != VMK_FALSE) {
264 | vmk_Warning(pimon_Driver.logger,
265 | "RPIQ device %p already initialized as %p",
266 | device,
267 | adapter->vmkDevice);
268 | status = VMK_EXISTS;
269 | goto device_already_exists;
270 | }
271 |
272 | /*
273 | * Get vmk ACPI dev
274 | */
275 | status = vmk_DeviceGetRegistrationData(device, (vmk_AddrCookie *)&acpiDev);
276 | if (status != VMK_OK) {
277 | vmk_Warning(pimon_Driver.logger,
278 | "failed to get ACPI dev for vmk dev %p: %s",
279 | device,
280 | vmk_StatusToString(status));
281 | goto get_acpi_dev_failed;
282 | }
283 |
284 | /*
285 | * Find out if this is an ACPI dev
286 | */
287 | status = vmk_ACPIQueryInfo(acpiDev, &acpiInfo);
288 | if (status != VMK_OK) {
289 | goto not_an_acpi_dev;
290 | }
291 |
292 | vmk_Log(pimon_Driver.logger,
293 | "retrieved ACPI dev %p for vmk dev %p",
294 | acpiDev,
295 | device);
296 |
297 | /*
298 | * Map io resources
299 | */
300 |
301 | status = vmk_ACPIMapIOResource(pimon_Driver.moduleID,
302 | acpiDev,
303 | 0,
304 | &mappedAddr);
305 | if (status != VMK_OK) {
306 | vmk_Warning(pimon_Driver.logger,
307 | "unable to acquire io resources"
308 | " for device %p: %s",
309 | device,
310 | vmk_StatusToString(status));
311 | goto iores_map_failed;
312 | }
313 | else if (mappedAddr.type != VMK_IORESOURCE_MEM) {
314 | vmk_Warning(pimon_Driver.logger,
315 | "mapped io space %p of type %d, expecting %d",
316 | mappedAddr,
317 | mappedAddr.type,
318 | VMK_IORESOURCE_MEM);
319 | goto iores_map_failed;
320 | }
321 |
322 | vmk_Log(pimon_Driver.logger,
323 | "mapped io space at %p of length %d for device %p",
324 | (void*)mappedAddr.address.vaddr,
325 | mappedAddr.len,
326 | device);
327 |
328 | /*
329 | * Create DMA heap for device
330 | */
331 |
332 | heapProps.type = VMK_HEAP_TYPE_CUSTOM;
333 | heapProps.module = pimon_Driver.moduleID;
334 | heapProps.creationTimeoutMS = VMK_TIMEOUT_NONBLOCKING;
335 | heapProps.typeSpecific.custom.physContiguity = VMK_MEM_PHYS_CONTIGUOUS;
336 |
337 | /*
338 | * The DMA addresses accessible by the DMA engine are below 1GB by default,
339 | * so the below may not be sufficient.
340 | */
341 | // TODO: Make more robust by programming DMA controller to move aperture.
342 | heapProps.typeSpecific.custom.physRange = VMK_PHYS_ADDR_BELOW_2GB;
343 |
344 | status = vmk_NameInitialize(&heapProps.name, RPIQ_DMA_HEAP_NAME);
345 | VMK_ASSERT(status == VMK_OK);
346 |
347 | heapAllocDesc.size = sizeof(rpiq_MboxBuffer_t);
348 | heapAllocDesc.alignment = RPIQ_DMA_MBOX_ALIGNMENT;
349 | heapAllocDesc.count = RPIQ_DMA_MBOX_OBJ_MAX;
350 |
351 | status = vmk_HeapDetermineMaxSize(&heapAllocDesc, 1, &dmaHeapSize);
352 | if (status != VMK_OK) {
353 | vmk_Warning(pimon_Driver.logger,
354 | "failed to determine DMA max heap size: %s",
355 | vmk_StatusToString(status));
356 | goto dma_heap_size_failed;
357 | }
358 |
359 | heapProps.initial = dmaHeapSize;
360 | heapProps.max = dmaHeapSize;
361 |
362 | status = vmk_HeapCreate(&heapProps, &dmaHeapID);
363 | if (status != VMK_OK) {
364 | vmk_Warning(pimon_Driver.logger,
365 | "failed to create DMA heap: %s",
366 | vmk_StatusToString(status));
367 | goto dma_heap_create_failed;
368 | }
369 |
370 | /*
371 | * Init adapter
372 | */
373 |
374 | vmk_Memset(adapter, 0, sizeof(*adapter));
375 | adapter->vmkDevice = device;
376 | adapter->acpiDevice = acpiDev;
377 | adapter->acpiInfo = acpiInfo;
378 | vmk_AtomicWrite64(&adapter->refCount, 0);
379 |
380 | vmk_Memcpy(&adapter->mmioMappedAddr,
381 | &mappedAddr,
382 | sizeof(adapter->mmioMappedAddr));
383 | adapter->mmioBase = (void *)mappedAddr.address.vaddr;
384 | adapter->mmioLen = mappedAddr.len;
385 | adapter->dmaHeapID = dmaHeapID;
386 | adapter->initialized = VMK_TRUE;
387 |
388 | /*
389 | * Init RPIQ driver
390 | */
391 | status = rpiq_drvInit(&pimon_Driver, &rpiq_Device);
392 | if (status != VMK_OK) {
393 | vmk_Warning(pimon_Driver.logger,
394 | "failed to initialize RPIQ driver: %s",
395 | vmk_StatusToString(status));
396 | goto rpiq_drv_init_failed;
397 | }
398 |
399 | /*
400 | * Attach device
401 | */
402 | status = vmk_DeviceSetAttachedDriverData(adapter->vmkDevice, adapter);
403 | if (status != VMK_OK) {
404 | vmk_Warning(pimon_Driver.logger,
405 | "failed to attach device %p: %s",
406 | adapter->vmkDevice,
407 | vmk_StatusToString(status));
408 | goto device_attach_failed;
409 | }
410 |
411 | #ifdef PIMON_DEBUG
412 | {
413 | vmk_Log(pimon_Driver.logger,
414 | "DMA heap %p",
415 | adapter->dmaHeapID);
416 | }
417 | #endif /* PIMON_DEBUG */
418 |
419 | return VMK_OK;
420 |
421 | device_attach_failed:
422 | rpiq_drv_init_failed:
423 | vmk_HeapDestroy(rpiq_Device.dmaHeapID);
424 |
425 | dma_heap_create_failed:
426 | dma_heap_size_failed:
427 | vmk_ACPIUnmapIOResource(pimon_Driver.moduleID, acpiDev, 0);
428 |
429 | iores_map_failed:
430 | not_an_acpi_dev:
431 | get_acpi_dev_failed:
432 | device_already_exists:
433 | vmk_Warning(pimon_Driver.logger,
434 | "no device attached",
435 | PIMON_DRIVER_NAME,
436 | __FUNCTION__);
437 | return status;
438 | }
439 |
440 | /*
441 | ***********************************************************************
442 | * pimon_scanDevice --
443 | *
444 | * Register char dev.
445 | *
446 | * Results:
447 | * VMK_OK on success, error code otherwise
448 | *
449 | * Side Effects:
450 | * None
451 | ***********************************************************************
452 | */
453 | VMK_ReturnStatus
454 | pimon_scanDevice(vmk_Device device)
455 | {
456 | VMK_ReturnStatus status = VMK_OK;
457 | pimon_CharDevPriv_t *privData;
458 | pimon_CharDevProps_t charDevProps;
459 |
460 | /* We only allow data to be transmitted in a particular size */
461 | privData = vmk_HeapAlloc(pimon_Driver.heapID, sizeof(*privData));
462 | if (privData == NULL) {
463 | status = VMK_NO_MEMORY;
464 | vmk_Warning(pimon_Driver.logger, "unable to allocate char dev priv data");
465 | goto priv_alloc_failed;
466 | }
467 | privData->ioctlDataLen = sizeof(rpiq_MboxBuffer_t);
468 |
469 | charDevProps.driverHandle = pimon_Driver.driverHandle;
470 | charDevProps.logicalBusType = rpiq_logicalBusType;
471 | charDevProps.parentDevice = device;
472 | charDevProps.charDev = &rpiq_CharDev;
473 | charDevProps.logicalPort = 0;
474 | charDevProps.privData = privData;
475 | charDevProps.callbacks = &rpiq_CharDevCBs;
476 |
477 | status = pimon_charDevRegister(&charDevProps);
478 |
479 | priv_alloc_failed:
480 | return status;
481 | }
482 |
483 | /*
484 | ***********************************************************************
485 | * pimon_detachDevice --
486 | *
487 | * Detaches the device from the driver.
488 | *
489 | * Results:
490 | * VMK_OK on success, error code otherwise
491 | *
492 | * Side Effects:
493 | * None
494 | ***********************************************************************
495 | */
496 | VMK_ReturnStatus
497 | pimon_detachDevice(vmk_Device device)
498 | {
499 | VMK_ReturnStatus status = VMK_OK;
500 |
501 | return status;
502 | }
503 |
504 | /*
505 | ***********************************************************************
506 | * pimon_quiesceDevice --
507 | *
508 | * Do nothing.
509 | *
510 | * Results:
511 | * VMK_OK on success, error code otherwise
512 | *
513 | * Side Effects:
514 | * None
515 | ***********************************************************************
516 | */
517 | VMK_ReturnStatus
518 | pimon_quiesceDevice(vmk_Device device)
519 | {
520 | VMK_ReturnStatus status = VMK_OK;
521 |
522 | return status;
523 | }
524 |
525 | /*
526 | ***********************************************************************
527 | * pimon_startDevice --
528 | *
529 | * Start the GPIO device.
530 | *
531 | * Results:
532 | * VMK_OK on success, error code otherwise
533 | *
534 | * Side Effects:
535 | * None
536 | ***********************************************************************
537 | */
538 | VMK_ReturnStatus
539 | pimon_startDevice(vmk_Device device)
540 | {
541 | VMK_ReturnStatus status = VMK_OK;
542 |
543 | return status;
544 | }
545 |
546 | /*
547 | ***********************************************************************
548 | * pimon_forgetDevice --
549 | *
550 | * Do nothing.
551 | *
552 | * Results:
553 | * None.
554 | *
555 | * Side Effects:
556 | * None
557 | ***********************************************************************
558 | */
559 | void
560 | pimon_forgetDevice(vmk_Device device)
561 | {
562 | return;
563 | }
--------------------------------------------------------------------------------
/pimon_types.h:
--------------------------------------------------------------------------------
1 | /******************************************************************************\
2 | * Native ESXi on Arm driver for hardware monitoring on the Raspberry Pi.
3 | * Copyright (c) 2020 Tom Hebel
4 | *
5 | * Permission is hereby granted, free of charge, to any person obtaining a copy
6 | * of this software and associated documentation files (the "Software"), to deal
7 | * in the Software without restriction, including without limitation the rights
8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | * copies of the Software, and to permit persons to whom the Software is
10 | * furnished to do so, subject to the following conditions:
11 | *
12 | * The above copyright notice and this permission notice shall be included in
13 | * all copies or substantial portions of the Software.
14 | *
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | * SOFTWARE.
22 | \******************************************************************************/
23 |
24 | /*
25 | * pimon_types.h --
26 | *
27 | * Pimon module/driver types.
28 | */
29 |
30 | #ifndef PIMON_TYPES_H
31 | #define PIMON_TYPES_H
32 |
33 | /***********************************************************************/
34 |
35 | typedef struct pimon_Driver_t {
36 | vmk_Name driverName;
37 | vmk_ModuleID moduleID;
38 | vmk_HeapID heapID;
39 | vmk_Driver driverHandle;
40 | vmk_IOResource resHandle;
41 | vmk_LogComponent logger;
42 | } pimon_Driver_t;
43 |
44 | /***********************************************************************/
45 |
46 | #endif /* PIMON_TYPES_H */
--------------------------------------------------------------------------------
/pyUtil/pimonLib/__init__.py:
--------------------------------------------------------------------------------
1 | ################################################################################
2 | # UW library interfacing with the PiMon driver.
3 | # Copyright (c) 2020 Tom Hebel
4 | #
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 | #
12 | # The above copyright notice and this permission notice shall be included in
13 | # all copies or substantial portions of the Software.
14 | #
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | # SOFTWARE.
22 | ################################################################################
23 |
24 | import math
25 | import struct
26 | import fcntl
27 |
28 | #########################################################################
29 |
30 | PIMON_DEVICE_PATH = '/dev/vmgfx33'
31 |
32 | #########################################################################
33 |
34 | RPIQ_BUFFER_LEN = 32
35 |
36 | RPIQ_PROCESS_REQ = 0
37 |
38 | #
39 | # PiMon ioctl commands
40 | #
41 | RPIQ_CHAN_MBOX_PROP_ARM2VC = 8
42 |
43 | #
44 | # RPIQ tags
45 | #
46 |
47 | RPIQ_MBOX_TAG_FWREV = 0x00000001
48 | RPIQ_MBOX_FWREV_LEN = 0x4
49 |
50 | RPIQ_MBOX_TAG_BOARDMODEL = 0x00010001
51 | RPIQ_MBOX_BOARDMODEL_LEN = 0x4
52 |
53 | RPIQ_MBOX_TAG_BOARDREV = 0x00010002
54 | RPIQ_MBOX_BOARDREV_LEN = 0x4
55 |
56 | RPIQ_MBOX_TAG_BOARDMAC = 0x00010003
57 | RPIQ_MBOX_BOARDMAC_LEN = 0x6
58 |
59 | RPIQ_MBOX_TAG_BOARDSERIAL = 0x00010004
60 | RPIQ_MBOX_BOARDSERIAL_LEN = 0x8
61 |
62 | RPIQ_MBOX_TAG_GET_TEMP = 0x00030006
63 | RPIQ_MBOX_GET_TEMP_LEN = 0x8
64 |
65 | RPIQ_MBOX_TAG_ARMMEM = 0x00010005
66 | RPIQ_MBOX_ARMMEM_LEN = 0x8
67 |
68 | #########################################################################
69 | # PiMon --
70 | #
71 | # PiMon char dev interface class.
72 | #########################################################################
73 | class PiMon:
74 | pimonDev = open(PIMON_DEVICE_PATH, 'r+b')
75 | def __del__(self):
76 | self.pimonDev.close()
77 |
78 | #########################################################################
79 | # getFWFev --
80 | #
81 | #########################################################################
82 | def getFWRev(self):
83 | try:
84 | ioctlData = bytearray(struct.pack('Q', unpacked)
159 | masked = int(struct.unpack('> macShift
160 | out = masked
161 | except Exception as e:
162 | print(e)
163 | return 0
164 | return out
165 |
166 | #########################################################################
167 | # getBoardSerial --
168 | #
169 | #########################################################################
170 | def getBoardSerial(self):
171 | try:
172 | ioctlData = bytearray(struct.pack('dmaHeapID,
77 | sizeof(*rpiq_MboxDMABuffer.ptr),
78 | RPIQ_DMA_MBOX_ALIGNMENT);
79 |
80 | /* Verify that mbox buffer is below 2GB */
81 | vmk_VA2MA((vmk_VA)rpiq_MboxDMABuffer.ptr, 0, &dmaBufPtrMA);
82 | if (dmaBufPtrMA > RPIQ_DMA_MAX_ADDR) {
83 | status = VMK_NO_MEMORY;
84 | vmk_Warning(pimon_Driver->logger,
85 | "unable to allocate below 2GB");
86 | goto dma_addr_invalid;
87 | }
88 |
89 | /*
90 | * Init lock
91 | */
92 |
93 | lockProps.moduleID = pimon_Driver->moduleID;
94 | lockProps.heapID = pimon_Driver->heapID;
95 | status = vmk_NameInitialize(&lockProps.name, RPIQ_DMA_LOCK_NAME);
96 | if (status != VMK_OK) {
97 | vmk_Warning(pimon_Driver->logger,
98 | "failed to init DMA buffer lock name: %s",
99 | vmk_StatusToString(status));
100 | goto lock_init_failed;
101 | }
102 |
103 | lockProps.type = VMK_SPINLOCK;
104 | lockProps.domain = VMK_LOCKDOMAIN_INVALID;
105 | lockProps.rank = VMK_SPINLOCK_UNRANKED;
106 | status = vmk_SpinlockCreate(&lockProps, &rpiq_MboxDMABuffer.lock);
107 | if (status != VMK_OK) {
108 | vmk_Warning(pimon_Driver->logger,
109 | "failed to create DMA buffer spinlock: %s",
110 | vmk_StatusToString(status));
111 | goto lock_init_failed;
112 | }
113 |
114 | lock_init_failed:
115 | dma_addr_invalid:
116 | vmk_HeapFree(rpiq_Device->dmaHeapID, rpiq_MboxDMABuffer.ptr);
117 | return status;
118 | }
119 |
120 | /*
121 | ***********************************************************************
122 | * rpiq_drvCleanUp --
123 | *
124 | * Clean up the RPIQ driver.
125 | *
126 | * Results:
127 | * VMK_OK on success, error code otherwise
128 | *
129 | * Side Effects:
130 | * None
131 | ***********************************************************************
132 | */
133 | void
134 | rpiq_drvCleanUp()
135 | {
136 | vmk_SpinlockDestroy(rpiq_MboxDMABuffer.lock);
137 | vmk_HeapFree(rpiq_Device->dmaHeapID, rpiq_MboxDMABuffer.ptr);
138 | }
139 |
140 | /*
141 | ***********************************************************************
142 | * rpiq_mboxDrain --
143 | *
144 | * Drain the VideoCore mailbox.
145 | *
146 | * Results:
147 | * VMK_OK on success
148 | * VMK_TIMEOUT otherwise
149 | *
150 | * Side Effects:
151 | * None.
152 | ***********************************************************************
153 | */
154 | VMK_ReturnStatus
155 | rpiq_mboxDrain()
156 | {
157 | int retries = 0;
158 | vmk_uint32 mboxStatus, mboxVal;
159 |
160 | do {
161 | vmk_MappedResourceRead32(&rpiq_Device->mmioMappedAddr,
162 | RPIQ_MBOX_STATUS,
163 | &mboxStatus);
164 | if (mboxStatus == RPIQ_MBOX_EMPTY) {
165 | return VMK_OK;
166 | }
167 | RPIQ_MEM_BARRIER();
168 | vmk_MappedResourceRead32(&rpiq_Device->mmioMappedAddr,
169 | RPIQ_MBOX_READ,
170 | &mboxVal);
171 | } while (++retries < RPIQ_MBOX_MAX_RETRIES);
172 |
173 | return VMK_TIMEOUT;
174 | }
175 |
176 | /*
177 | ***********************************************************************
178 | * rpiq_mboxStatusCleared --
179 | *
180 | * Spin until VC mailbox status flag is clear.
181 | *
182 | * Results:
183 | * VMK_OK on success
184 | * VMK_TIMEOUT otherwise
185 | *
186 | * Side Effects:
187 | * None.
188 | ***********************************************************************
189 | */
190 | VMK_ReturnStatus
191 | rpiq_mboxStatusCleared(vmk_uint32 status)
192 | {
193 | int retries = 0;
194 | vmk_uint32 mboxStatus;
195 |
196 | do {
197 | vmk_MappedResourceRead32(&rpiq_Device->mmioMappedAddr,
198 | RPIQ_MBOX_STATUS,
199 | &mboxStatus);
200 | if ((mboxStatus & status) == 0) {
201 | return VMK_OK;
202 | }
203 | RPIQ_MEM_BARRIER();
204 | } while (++retries < RPIQ_MBOX_MAX_RETRIES);
205 |
206 | return VMK_TIMEOUT;
207 | }
208 |
209 | /*
210 | ***********************************************************************
211 | * rpiq_mboxSend --
212 | *
213 | * Send a request to a VideoCore mailbox and receive its response.
214 | *
215 | * Results:
216 | * VMK_OK on success, error code otherwise
217 | *
218 | * Side Effects:
219 | * None.
220 | ***********************************************************************
221 | */
222 | VMK_ReturnStatus
223 | rpiq_mboxSend(rpiq_MboxChannel_t channel, // IN
224 | rpiq_MboxBuffer_t *buffer) // IN/OUT
225 | {
226 | VMK_ReturnStatus status = VMK_OK;
227 | rpiq_MboxDMABuffer_t *dmaBuf = &rpiq_MboxDMABuffer;
228 | rpiq_MboxBuffer_t *dmaBufPtr = dmaBuf->ptr;
229 | vmk_MA dmaBufPtrMA;
230 | vmk_uint32 mboxIn;
231 | vmk_uint32 mboxOut;
232 | vmk_uint32 mboxReadRetries = 0;
233 |
234 | /*
235 | * Drain mbox
236 | */
237 | if (rpiq_mboxDrain() != VMK_OK) {
238 | status = VMK_TIMEOUT;
239 | vmk_Warning(pimon_Driver->logger, "failed to drain mailbox");
240 | goto mbox_drain_timeout;
241 | }
242 |
243 | /* Lock the DMA buffer */
244 | vmk_SpinlockLock(dmaBuf->lock);
245 |
246 | /*
247 | *-------------------------------------------------------------------
248 | * MBOX WRITE
249 | *-------------------------------------------------------------------
250 | */
251 |
252 | /*
253 | * Wait for mbox to become empty
254 | */
255 | if (rpiq_mboxStatusCleared(RPIQ_MBOX_FULL) != VMK_OK) {
256 | status = VMK_TIMEOUT;
257 | vmk_Warning(pimon_Driver->logger,
258 | "timeout waiting for mbox to become empty");
259 | goto mbox_empty_timeout;
260 | }
261 |
262 | /*
263 | * Copy buffer to location accessible by VC DMA
264 | */
265 | vmk_Memcpy(dmaBufPtr, buffer, sizeof(*dmaBufPtr));
266 |
267 | /*
268 | * Prepare mbox input data
269 | */
270 | vmk_VA2MA((vmk_VA)dmaBufPtr, 0, &dmaBufPtrMA);
271 | mboxIn = ((vmk_uint32)dmaBufPtrMA
272 | | RPIQ_DMA_COHERENT_ADDR
273 | | (vmk_uint32)channel);
274 |
275 | RPIQ_MEM_BARRIER();
276 |
277 | vmk_MappedResourceWrite32(&rpiq_Device->mmioMappedAddr,
278 | RPIQ_MBOX_WRITE,
279 | mboxIn);
280 |
281 | RPIQ_MEM_BARRIER();
282 |
283 | /*
284 | * This needs to be here.
285 | */
286 | RPIQ_INVAL_DCACHE((void *)dmaBufPtr);
287 |
288 | /*
289 | *-------------------------------------------------------------------
290 | * MBOX READ
291 | *-------------------------------------------------------------------
292 | */
293 |
294 | /*
295 | * Wait for mbox to fill up
296 | */
297 | if (rpiq_mboxStatusCleared(RPIQ_MBOX_EMPTY) != VMK_OK) {
298 | status = VMK_TIMEOUT;
299 | vmk_Warning(pimon_Driver->logger,
300 | "timeout waiting for mbox to become full");
301 | goto mbox_full_timeout;
302 | }
303 |
304 | RPIQ_MEM_BARRIER();
305 |
306 | /*
307 | * Perform read
308 | */
309 | do {
310 | vmk_MappedResourceRead32(&rpiq_Device->mmioMappedAddr,
311 | RPIQ_MBOX_READ,
312 | &mboxOut);
313 |
314 | RPIQ_MEM_BARRIER();
315 |
316 | ++mboxReadRetries;
317 | if (mboxReadRetries >= RPIQ_MBOX_MAX_RETRIES) {
318 | status = VMK_TIMEOUT;
319 | vmk_Warning(pimon_Driver->logger,
320 | "RPIQ mailbox read failed after %d retries",
321 | mboxReadRetries);
322 | goto mbox_read_attempts;
323 | }
324 | } while ((mboxOut & RPIQ_MBOX_CHAN_MASK) != channel);
325 |
326 | RPIQ_MEM_BARRIER();
327 |
328 | /*
329 | * Something went wrong, in & out buffers don't match
330 | */
331 | if (mboxOut != mboxIn) {
332 | status = VMK_FAILURE;
333 | vmk_Warning(pimon_Driver->logger,
334 | "mismatch in mbox input %p and output %p",
335 | mboxIn,
336 | mboxOut);
337 | goto mbox_response_mismatch;
338 | }
339 |
340 | /*
341 | * Invalidate cache and copy data back to in/out buffer
342 | */
343 |
344 | RPIQ_INVAL_DCACHE((void *)dmaBufPtr);
345 | vmk_Memcpy(buffer, dmaBufPtr, sizeof(*buffer));
346 | if (buffer->header.requestResponse != RPIQ_MBOX_SUCCESS) {
347 | status = VMK_FAILURE;
348 | vmk_Warning(pimon_Driver->logger,
349 | "no response data received");
350 | }
351 |
352 | /* Unlock the DMA buffer */
353 | vmk_SpinlockUnlock(dmaBuf->lock);
354 |
355 | return VMK_OK;
356 |
357 | mbox_response_mismatch:
358 | mbox_read_attempts:
359 | mbox_full_timeout:
360 | mbox_empty_timeout:
361 | mbox_drain_timeout:
362 | vmk_SpinlockUnlock(dmaBuf->lock);
363 | return status;
364 | }
365 |
366 | /*
367 | ***********************************************************************
368 | * rpiq_mmioOpenCB --
369 | *
370 | * Callback used by char dev driver when the /dev/vmgfx32 file is
371 | * opened.
372 | *
373 | * Results:
374 | * VMK_OK on success, error code otherwise
375 | *
376 | * Side Effects:
377 | * None.
378 | ***********************************************************************
379 | */
380 | VMK_ReturnStatus
381 | rpiq_mmioOpenCB(vmk_CharDevFdAttr *attr)
382 | {
383 | VMK_ReturnStatus status = VMK_OK;
384 |
385 | vmk_Log(pimon_Driver->logger, "Opening file.");
386 |
387 | return status;
388 | }
389 |
390 | /*
391 | ***********************************************************************
392 | * rpiq_mmioCloseCB --
393 | *
394 | * Callback used by char dev driver when the /dev/vmgfx32 file is
395 | * closed.
396 | *
397 | * Results:
398 | * VMK_OK on success, error code otherwise
399 | *
400 | * Side Effects:
401 | * None.
402 | ***********************************************************************
403 | */
404 | VMK_ReturnStatus
405 | rpiq_mmioCloseCB(vmk_CharDevFdAttr *attr)
406 | {
407 | VMK_ReturnStatus status = VMK_OK;
408 |
409 | vmk_Log(pimon_Driver->logger, "Closing file.");
410 |
411 | return status;
412 | }
413 |
414 | /*
415 | ***********************************************************************
416 | * rpiq_mmioIoctlCB --
417 | *
418 | * Callback used by char dev driver for I/O control. The RPIQ char dev
419 | * file only supports access via ioctl, since it allows for sending
420 | * and receiving data structures easily.
421 | *
422 | * Results:
423 | * VMK_OK on success, error code otherwise
424 | *
425 | * Side Effects:
426 | * None.
427 | ***********************************************************************
428 | */
429 | VMK_ReturnStatus
430 | rpiq_mmioIoctlCB(unsigned int channel, // IN
431 | void *data, // IN/OUT
432 | vmk_ByteCount ioctlDataLen) // IN
433 | {
434 | VMK_ReturnStatus status = VMK_OK;
435 | rpiq_MboxBuffer_t *buffer;
436 |
437 | // TODO: add support for arbitrary length mailbox data, to allow for things
438 | // like requesting console data.
439 |
440 | /*
441 | * Sanity checks
442 | */
443 |
444 | if (data == NULL || ioctlDataLen != sizeof(*buffer)) {
445 | status = VMK_BAD_PARAM;
446 | vmk_Warning(pimon_Driver->logger, "invalid ioctl data");
447 | goto invalid_ioctl_data;
448 | }
449 |
450 | if (channel < RPIQ_CHAN_MBOX_MIN
451 | || channel > RPIQ_CHAN_MBOX_MAX) {
452 | status = VMK_BAD_PARAM;
453 | vmk_Warning(pimon_Driver->logger, "ioctl command %d invalid", channel);
454 | goto invalid_ioct_channel;
455 | }
456 |
457 | // TODO: Should we check the tag validity too?
458 | buffer = (rpiq_MboxBuffer_t *)data;
459 | if (buffer->endTag != 0
460 | || buffer->padding[0] != 0
461 | || buffer->padding[1] != 0
462 | || buffer->header.bufLen != sizeof(*buffer)) {
463 | status = VMK_BAD_PARAM;
464 | vmk_Warning(pimon_Driver->logger, "invalid mailbox buffer");
465 |
466 | goto invalid_mbox_buffer;
467 | }
468 |
469 | #ifdef RPIQ_DEBUG
470 | {
471 | vmk_Log(pimon_Driver->logger,
472 | "bufLen=%d rqRp=%d tag=0x%x rpLen=%d rqLen=%d endTag=%d"
473 | " padding[0]=%d padding[1]=%d",
474 | buffer->header.bufLen,
475 | buffer->header.requestResponse,
476 | buffer->header.tag,
477 | buffer->header.responseLen,
478 | buffer->header.requestLen,
479 | buffer->endTag,
480 | buffer->padding[0],
481 | buffer->padding[1]);
482 | }
483 | #endif /* RPIQ_DEBUG */
484 |
485 | /*
486 | * Mbox I/O
487 | */
488 |
489 | status = rpiq_mboxSend(channel, buffer);
490 | if (status != VMK_OK) {
491 | vmk_Warning(pimon_Driver->logger,
492 | "unable to send to mailbox: %s",
493 | vmk_StatusToString(status));
494 | goto mbox_send_failed;
495 | }
496 |
497 | return VMK_OK;
498 |
499 | mbox_send_failed:
500 | invalid_mbox_buffer:
501 | invalid_ioct_channel:
502 | invalid_ioctl_data:
503 | return status;
504 | }
505 |
506 | /*
507 | ***********************************************************************
508 | * rpiq_mmioReadCB --
509 | *
510 | * Callback used by char dev driver when the file is read. Currently
511 | * not supported, as all I/O is done via ioctl.
512 | *
513 | * Results:
514 | * VMK_OK on success, error code otherwise
515 | *
516 | * Side Effects:
517 | * None.
518 | ***********************************************************************
519 | */
520 | VMK_ReturnStatus
521 | rpiq_mmioReadCB(char *buffer,
522 | vmk_ByteCount nbytes,
523 | vmk_loff_t *ppos,
524 | vmk_ByteCountSigned *nread)
525 | {
526 | return VMK_NOT_SUPPORTED;
527 | }
528 |
529 | /*
530 | ***********************************************************************
531 | * rpiq_mmioWrite --
532 | *
533 | * Callback used by char dev driver when the file is written to.
534 | * Currently not supported, as all I/O is done via ioctl.
535 | *
536 | * Results:
537 | * VMK_OK on success, error code otherwise
538 | *
539 | * Side Effects:
540 | * None.
541 | ***********************************************************************
542 | */
543 | VMK_ReturnStatus
544 | rpiq_mmioWriteCB(char *buffer,
545 | vmk_ByteCount nbytes,
546 | vmk_loff_t *ppos,
547 | vmk_ByteCountSigned *nwritten)
548 | {
549 | return VMK_NOT_SUPPORTED;
550 | }
--------------------------------------------------------------------------------
/rpiq_drv.h:
--------------------------------------------------------------------------------
1 | /******************************************************************************\
2 | * Native ESXi on Arm driver for hardware monitoring on the Raspberry Pi.
3 | * Copyright (c) 2020 Tom Hebel
4 | *
5 | * Permission is hereby granted, free of charge, to any person obtaining a copy
6 | * of this software and associated documentation files (the "Software"), to deal
7 | * in the Software without restriction, including without limitation the rights
8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | * copies of the Software, and to permit persons to whom the Software is
10 | * furnished to do so, subject to the following conditions:
11 | *
12 | * The above copyright notice and this permission notice shall be included in
13 | * all copies or substantial portions of the Software.
14 | *
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | * SOFTWARE.
22 | \******************************************************************************/
23 |
24 | /*
25 | * rpiq_drv.h --
26 | *
27 | * Definition for RPIQ device layer interface.
28 | */
29 |
30 | #ifndef RPIQ_DRV_H
31 | #define RPIQ_DRV_H
32 |
33 | #include "pimon.h"
34 | #include "pimon_types.h"
35 |
36 | #define RPIQ_DEBUG
37 |
38 | /***********************************************************************/
39 |
40 | #define RPIQ_DMA_HEAP_NAME "rpiqDmaHeap"
41 |
42 | #define RPIQ_DMA_COHERENT_ADDR 0xC0000000
43 | #define RPIQ_DMA_MAX_ADDR ((vmk_VA)1<<32)
44 | #define RPIQ_DMA_MBOX_ALIGNMENT 16
45 |
46 | /* Maximum mbox objects to allocate on DMA heap */
47 | #define RPIQ_DMA_MBOX_OBJ_MAX 256
48 |
49 | #define RPIQ_MBOX_CHAN_MASK 15
50 |
51 | /* Very generous to avoid sporadic timeouts */
52 | #define RPIQ_MBOX_MAX_RETRIES 0x4000
53 |
54 | /***********************************************************************/
55 |
56 | /*
57 | * Offsets from RPIQ MMIO base
58 | */
59 | #define RPIQ_MBOX_READ 0x0
60 | #define RPIQ_MBOX_STATUS 0x18
61 | #define RPIQ_MBOX_WRITE 0x20
62 |
63 | #define RPIQ_PROCESS_REQ 0x0
64 | #define RPIQ_MBOX_FULL (1 << 31)
65 | #define RPIQ_MBOX_EMPTY (1 << 30)
66 | #define RPIQ_MBOX_SUCCESS 0x80000000
67 |
68 | /*
69 | * Mbox tags
70 | */
71 |
72 | /* Firmware */
73 | #define RPIQ_MBOX_TAG_FWREV 0x00000001
74 |
75 | /* Hardware */
76 | #define RPIQ_MBOX_TAG_BOARDMODEL 0x00010001
77 | #define RPIQ_MBOX_TAG_BOARDREV 0x00010002
78 | #define RPIQ_MBOX_TAG_BOARDMAC 0x00010003
79 | #define RPIQ_MBOX_TAG_BOARDSERIAL 0x00010004
80 | #define RPIQ_MBOX_TAG_ARMMEM 0x00010005
81 | #define RPIQ_MBOX_TAG_VCMEM 0x00010006
82 | #define RPIQ_MBOX_TAG_CLKS 0x00010007
83 |
84 | /* Config */
85 | #define RPIQ_MBOX_TAG_CMDLINE 0x00050001
86 |
87 | /* Shared resources */
88 | #define RPIQ_MBOX_TAG_DMACHAN 0x00060001
89 |
90 | /* Power */
91 | #define RPIQ_MBOX_TAG_GETPWR 0x00020001
92 | #define RPIQ_MBOX_TAG_TIMING 0x00020002
93 | #define RPIQ_MBOX_TAG_SETPWR 0x00028001
94 |
95 | /* Clocks */
96 | #define RPIQ_MBOX_TAG_GETCLK_STATE 0x00030001
97 | #define RPIQ_MBOX_TAG_SETCLK_STATE 0x00038001
98 | #define RPIQ_MBOX_TAG_GETCLK_RATE 0x00030002
99 | #define RPIQ_MBOX_TAG_SETCLK_RATE 0x00038002
100 | #define RPIQ_MBOX_TAG_GETCLK_MAX 0x00030004
101 | #define RPIQ_MBOX_TAG_GETCLK_MIN 0x00038007
102 | #define RPIQ_MBOX_TAG_GETCLK_TURBO 0x00030009
103 | #define RPIQ_MBOX_TAG_SETCLK_TURBO 0x00038009
104 |
105 | // TODO: the resto fot he mbox tags...
106 |
107 | #define RPIQ_MBOX_TAG_GET_TEMP 0x00030006
108 |
109 | #define RPIQ_INVALID_RESPONSE (~((vmk_uint32)0))
110 |
111 | /***********************************************************************/
112 |
113 | #define RPIQ_DMA_LOCK_NAME "dmaBufLock"
114 |
115 | #define RPIQ_MEM_BARRIER() asm volatile ("dsb sy" ::: "memory")
116 |
117 | /*
118 | * Should be sufficient as per p. 33 in:
119 | * https://web.wpi.edu/Pubs/ETD/Available/etd-012017-170924/unrestricted/green_archive.pdf
120 | */
121 | #define RPIQ_INVAL_DCACHE(_va) \
122 | asm volatile ("dc ivac, %0" :: "r" (_va))
123 |
124 | #define RPIQ_DMA_CLEAN_DCACHE(_va) \
125 | asm volatile ("dc civac, %0" :: "r" (_va))
126 |
127 | /***********************************************************************/
128 |
129 | typedef struct rpiq_Device_t {
130 | /* Object */
131 | vmk_Bool initialized;
132 | vmk_atomic64 refCount;
133 | /* Device */
134 | vmk_Device vmkDevice;
135 | vmk_ACPIDevice acpiDevice;
136 | vmk_ACPIInfo acpiInfo;
137 | /* MMIO */
138 | vmk_MappedResourceAddress mmioMappedAddr;
139 | char *mmioBase;
140 | vmk_ByteCount mmioLen;
141 | /* DMA */
142 | vmk_HeapID dmaHeapID;
143 | } rpiq_Device_t;
144 |
145 | /*
146 | * Data structures for passing data between UW and RPIQ interface.
147 | */
148 |
149 | typedef struct rpiq_MboxHeader_t {
150 | vmk_uint32 bufLen;
151 | vmk_uint32 requestResponse;
152 | vmk_uint32 tag;
153 | vmk_uint32 responseLen;
154 | vmk_uint32 requestLen;
155 | } rpiq_MboxHeader_t;
156 |
157 | typedef struct rpiq_MboxBuffer_t {
158 | rpiq_MboxHeader_t header;
159 | /* Everything below be set to zero! */
160 | vmk_uint32 endTag;
161 | vmk_uint32 padding[2];
162 | } rpiq_MboxBuffer_t, rpiq_IoctlData_t;
163 |
164 | /*
165 | * RPIQ mailbox channels which selected using the ioctl cmd.
166 | */
167 | typedef enum rpiq_MboxChannel_t {
168 | /* Update the min value when adding elements */
169 | RPIQ_CHAN_MBOX_MIN = 8,
170 | RPIQ_CHAN_MBOX_PROP_ARM2VC = 8,
171 | RPIQ_CHAN_MBOX_MAX = RPIQ_CHAN_MBOX_PROP_ARM2VC,
172 | } rpiq_MboxChannel_t, rpiq_IoctlCommand_t;
173 |
174 | typedef struct rpiq_MboxDMABuffer_t {
175 | rpiq_MboxBuffer_t *ptr;
176 | vmk_Lock lock;
177 | } rpiq_MboxDMABuffer_t;
178 |
179 | /***********************************************************************/
180 |
181 | VMK_ReturnStatus rpiq_drvInit(pimon_Driver_t *driver,
182 | rpiq_Device_t *adapter);
183 |
184 | void rpiq_drvCleanUp();
185 |
186 | VMK_ReturnStatus rpiq_mboxRead(rpiq_MboxChannel_t channel,
187 | vmk_uint32 *response);
188 |
189 | VMK_ReturnStatus rpiq_mboxWrite(rpiq_MboxChannel_t channel,
190 | rpiq_MboxBuffer_t *buffer);
191 |
192 | VMK_ReturnStatus rpiq_mmioOpenCB(vmk_CharDevFdAttr *attr);
193 |
194 | VMK_ReturnStatus rpiq_mmioCloseCB(vmk_CharDevFdAttr *attr);
195 |
196 | VMK_ReturnStatus rpiq_mmioIoctlCB(unsigned int cmd,
197 | void *data,
198 | vmk_ByteCount ioctlDataLen);
199 |
200 | VMK_ReturnStatus rpiq_mmioReadCB(char *buffer,
201 | vmk_ByteCount nbytes,
202 | vmk_loff_t *ppos,
203 | vmk_ByteCountSigned *nread);
204 |
205 | VMK_ReturnStatus rpiq_mmioWriteCB(char *buffer,
206 | vmk_ByteCount nbytes,
207 | vmk_loff_t *ppos,
208 | vmk_ByteCountSigned *nwritten);
209 |
210 | /***********************************************************************/
211 |
212 | #endif /* RPIQ_DRV_H */
--------------------------------------------------------------------------------