summaryrefslogtreecommitdiffstats
path: root/userspace/sdks/nv570/nvalloc
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-09-13 18:36:21 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-09-13 18:36:21 -0400
commit00e54c13c7c9030c4d5f7151467f2d85a3730e29 (patch)
tree17a45239df8d2e4912ff3697ed06e85a10b969de /userspace/sdks/nv570/nvalloc
downloadopen-iov-00e54c13c7c9030c4d5f7151467f2d85a3730e29.tar.gz
open-iov-00e54c13c7c9030c4d5f7151467f2d85a3730e29.zip
Initial commit: Open-IOV vGPU-IO complete stack
- Firmware decompilation: GSP 570.144W (28.5MB ELF, RV64IMAC), 132 decompiled C files - Kernel modules: nvidia.ko (34MB, OpenRM), open-iov-vfio.ko (2.8MB, VFIO mdev), gsp-vgpu.ko (1.8MB, guest driver) - Userspace: libiov.so/libvgpu.so (76KB), example_vgpu (28KB), rpc_emulator.c - PCI config space emulation (256B with PM, MSI, MSI-X, PCIe caps) - 12 RPC types fully mapped from firmware decompilation - BAR trap, WPR, scheduling, notification, migration emulation - Helper scripts: load_vgpu_stack, create_mdev, launch_qemu_vgpu, test_vgpu_stack, setup_guest_driver, unload_vgpu_stack - Architecture documentation - Wiki: 10 technical documents - Git LFS for large binaries (.ko, .bin, .iso, .img, .o, ghidra repos) - nvidia-open-gpu-kernel-modules as submodule
Diffstat (limited to 'userspace/sdks/nv570/nvalloc')
-rw-r--r--userspace/sdks/nv570/nvalloc/common/inc/conf_compute/cc_keyrotation.h34
-rw-r--r--userspace/sdks/nv570/nvalloc/common/inc/conf_compute/cc_keystore.h487
-rw-r--r--userspace/sdks/nv570/nvalloc/common/inc/dev_ctrl_defines.h87
-rw-r--r--userspace/sdks/nv570/nvalloc/common/inc/flcnifcmn.h141
-rw-r--r--userspace/sdks/nv570/nvalloc/common/inc/flcnretval.h305
-rw-r--r--userspace/sdks/nv570/nvalloc/common/inc/fsp/fsp_caps_query_rpc.h51
-rw-r--r--userspace/sdks/nv570/nvalloc/common/inc/fsp/fsp_clock_boost_rpc.h44
-rw-r--r--userspace/sdks/nv570/nvalloc/common/inc/fsp/fsp_emem_channels.h39
-rw-r--r--userspace/sdks/nv570/nvalloc/common/inc/fsp/fsp_tnvl_rpc.h137
-rw-r--r--userspace/sdks/nv570/nvalloc/common/inc/fsp/nvdm_payload_cmd_response.h44
-rw-r--r--userspace/sdks/nv570/nvalloc/common/inc/gsp/gsp_fmc_error_code_formatting.h79
-rw-r--r--userspace/sdks/nv570/nvalloc/common/inc/gsp/gsp_fw_sr_meta.h74
-rw-r--r--userspace/sdks/nv570/nvalloc/common/inc/gsp/gsp_fw_wpr_meta.h242
-rw-r--r--userspace/sdks/nv570/nvalloc/common/inc/gsp/gsp_proxy_reg.h83
-rw-r--r--userspace/sdks/nv570/nvalloc/common/inc/gsp/gspifpub.h181
-rw-r--r--userspace/sdks/nv570/nvalloc/common/inc/inforom/ifrdem.h43
-rw-r--r--userspace/sdks/nv570/nvalloc/common/inc/inforom/ifrecc.h119
-rw-r--r--userspace/sdks/nv570/nvalloc/common/inc/inforom/ifrnvl.h1561
-rw-r--r--userspace/sdks/nv570/nvalloc/common/inc/inforom/ifrstruct.h110
-rw-r--r--userspace/sdks/nv570/nvalloc/common/inc/inforom/omsdef.h116
-rw-r--r--userspace/sdks/nv570/nvalloc/common/inc/inforom/types.h79
-rw-r--r--userspace/sdks/nv570/nvalloc/common/inc/mctp_format.h120
-rw-r--r--userspace/sdks/nv570/nvalloc/common/inc/nv-firmware-chip-family-select.h230
-rw-r--r--userspace/sdks/nv570/nvalloc/common/inc/nv-firmware.h145
-rw-r--r--userspace/sdks/nv570/nvalloc/common/inc/nvcst.h460
-rw-r--r--userspace/sdks/nv570/nvalloc/common/inc/nvdm_format.h63
-rw-r--r--userspace/sdks/nv570/nvalloc/common/inc/nvpcie.h545
-rw-r--r--userspace/sdks/nv570/nvalloc/common/inc/nvrangetypes.h162
-rw-r--r--userspace/sdks/nv570/nvalloc/common/inc/oob/smbpbi.h2925
-rw-r--r--userspace/sdks/nv570/nvalloc/common/inc/oob/smbpbi_impl.h45
-rw-r--r--userspace/sdks/nv570/nvalloc/common/inc/oob/smbpbi_priv.h59
-rw-r--r--userspace/sdks/nv570/nvalloc/common/inc/rmRiscvUcode.h95
-rw-r--r--userspace/sdks/nv570/nvalloc/common/inc/rm_state_monitor.h72
-rw-r--r--userspace/sdks/nv570/nvalloc/common/inc/rmflcnbl.h147
-rw-r--r--userspace/sdks/nv570/nvalloc/common/inc/rmgspseq.h66
-rw-r--r--userspace/sdks/nv570/nvalloc/common/inc/rmifrif.h123
-rw-r--r--userspace/sdks/nv570/nvalloc/common/inc/rmlsfm.h579
-rw-r--r--userspace/sdks/nv570/nvalloc/common/inc/rmpbicmdif.h140
-rw-r--r--userspace/sdks/nv570/nvalloc/common/inc/sec2/nvdm_payload_cmd_response.h44
-rw-r--r--userspace/sdks/nv570/nvalloc/common/inc/sec2/sec2_emem_channels.h39
-rw-r--r--userspace/sdks/nv570/nvalloc/common/inc/spdm/rmspdmrsakeys.h160
-rw-r--r--userspace/sdks/nv570/nvalloc/common/inc/spdm/rmspdmtransport.h97
-rw-r--r--userspace/sdks/nv570/nvalloc/common/inc/spdm/rmspdmvendordef.h161
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/include/nv-caps.h94
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/include/nv-chardev-numbers.h43
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/include/nv-gpu-info.h47
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/include/nv-ioctl-lockless-diag.h43
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/include/nv-ioctl-numa.h81
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/include/nv-ioctl-numbers.h48
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/include/nv-ioctl.h158
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/include/nv-kernel-rmapi-ops.h61
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/include/nv-nb-regs.h65
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/include/nv-priv.h357
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/include/nv-reg.h1137
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/include/nv-unix-nvos-params-wrappers.h49
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/include/nv.h1367
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/include/nv_escape.h55
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/include/os-interface.h298
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/include/os_custom.h60
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/include/osapi.h203
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/include/rmobjexportimport.h40
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/include/x86emu/debug.h211
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/include/x86emu/decode.h88
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/include/x86emu/fpu.h61
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/include/x86emu/fpu_regs.h119
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/include/x86emu/ops.h45
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/include/x86emu/prim_ops.h141
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/include/x86emu/regs.h340
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/include/x86emu/types.h93
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/include/x86emu/x86emu.h205
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/include/x86emu/x86emui.h113
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/src/asm/x86/nv_cpuid.c51
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/src/asm/x86/nv_rdcr.c37
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/src/dynamic-power.c3185
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/src/escape.c1017
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/src/exports-stubs.c30
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/src/gcc_helper.c35
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/src/os-hypervisor.c994
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/src/os.c6359
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/src/osapi.c6284
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/src/osinit.c2768
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/src/osmemdesc.c1325
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/src/osnvlink.c783
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/src/osunix.c42
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/src/power-management-tegra.c100
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/src/registry.c712
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/src/rm-gpu-ops.c1079
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/src/rmobjexportimport.c650
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/src/subdevice_ctrl_os_unix.c97
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/src/unix_console.c412
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/src/unix_intr.c1050
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/src/vbioscall.c457
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/x86emu/debug.c547
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/x86emu/decode.c1094
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/x86emu/fpu.c965
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/x86emu/ops.c11761
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/x86emu/ops2.c2877
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/x86emu/prim_ops.c2655
-rw-r--r--userspace/sdks/nv570/nvalloc/unix/x86emu/sys.c663
99 files changed, 64184 insertions, 0 deletions
diff --git a/userspace/sdks/nv570/nvalloc/common/inc/conf_compute/cc_keyrotation.h b/userspace/sdks/nv570/nvalloc/common/inc/conf_compute/cc_keyrotation.h
new file mode 100644
index 0000000..473f294
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/common/inc/conf_compute/cc_keyrotation.h
@@ -0,0 +1,34 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef CC_KEYROTATION_H
+#define CC_KEYROTATION_H
+
+//
+// Default threshold value derived from SECURITY_POLICY_ATTACKER_ADVANTAGE_DEFAULT
+// Minimum threshold defined based on minimum in confComputeSetKeyRotation.
+//
+#define KEY_ROTATION_MINIMUM_INTERNAL_THRESHOLD (134217727u)
+#define KEY_ROTATION_DEFAULT_INTERNAL_THRESHOLD (24296003999ull)
+
+#endif // CC_KEYROTATION_H
diff --git a/userspace/sdks/nv570/nvalloc/common/inc/conf_compute/cc_keystore.h b/userspace/sdks/nv570/nvalloc/common/inc/conf_compute/cc_keystore.h
new file mode 100644
index 0000000..c629050
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/common/inc/conf_compute/cc_keystore.h
@@ -0,0 +1,487 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef CC_KEYSTORE_H
+#define CC_KEYSTORE_H
+
+//
+// Keys are typically grouped in two's so that the first key is used for CPU-to-GPU encryption
+// and the second key is used for GPU-to-CPU encryption.
+//
+
+// Keyspace identifiers.
+enum
+{
+ CC_KEYSPACE_GSP,
+ CC_KEYSPACE_SEC2,
+ CC_KEYSPACE_LCE0,
+ CC_KEYSPACE_LCE1,
+ CC_KEYSPACE_LCE2,
+ CC_KEYSPACE_LCE3,
+ CC_KEYSPACE_LCE4,
+ CC_KEYSPACE_LCE5,
+ CC_KEYSPACE_LCE6,
+ CC_KEYSPACE_LCE7,
+ CC_KEYSPACE_LCE10,
+ CC_KEYSPACE_LCE11,
+ CC_KEYSPACE_LCE12,
+ CC_KEYSPACE_LCE13,
+ CC_KEYSPACE_LCE14,
+ CC_KEYSPACE_LCE15,
+ CC_KEYSPACE_LCE16,
+ CC_KEYSPACE_LCE17,
+ CC_KEYSPACE_SIZE // This is always the last element.
+};
+
+#define CC_KEYSPACE_SIZE_GH100 (CC_KEYSPACE_LCE7 + 1)
+
+enum
+{
+ CC_LKEYID_CPU_GSP_LOCKED_RPC,
+ CC_LKEYID_GSP_CPU_LOCKED_RPC,
+ CC_LKEYID_CPU_GSP_DMA,
+ CC_LKEYID_GSP_CPU_DMA,
+ CC_LKEYID_CPU_GSP_RESERVED1,
+ CC_LKEYID_GSP_CPU_REPLAYABLE_FAULT,
+ CC_LKEYID_CPU_GSP_RESERVED2,
+ CC_LKEYID_GSP_CPU_NON_REPLAYABLE_FAULT,
+ CC_LKEYID_SEC2_GSP_LOCKED_RPC,
+ CC_LKEYID_GSP_SEC2_LOCKED_RPC,
+ CC_LKEYID_CPU_GSP_NVLE_P2P_WRAPPING,
+ CC_LKEYID_GSP_CPU_RESERVED_1,
+ CC_KEYSPACE_GSP_SIZE // This is always the last element.
+};
+// The fault buffers only support GPU-to-CPU encryption, so the CPU-to-GPU encryption slot
+// is left reserved.
+
+#define CC_LKEYID_GSP_CPU_LOCKED_RPC_STR "gsp_cpu_locked_rpc"
+#define CC_LKEYID_CPU_GSP_LOCKED_RPC_STR "cpu_gsp_locked_rpc"
+#define CC_LKEYID_GSP_CPU_DMA_STR "gsp_cpu_dma"
+#define CC_LKEYID_CPU_GSP_DMA_STR "cpu_gsp_dma"
+#define CC_LKEYID_GSP_CPU_REPLAYABLE_FAULT_STR "gsp_cpu_replayable_fault"
+#define CC_LKEYID_GSP_CPU_NON_REPLAYABLE_FAULT_STR "gsp_cpu_non_replayable_fault"
+#define CC_LKEYID_CPU_GSP_NVLE_P2P_WRAPPING_STR "cpu_gsp_nvle_p2p_wrapping"
+
+enum
+{
+ CC_LKEYID_CPU_SEC2_DATA_USER,
+ CC_LKEYID_CPU_SEC2_HMAC_USER,
+ CC_LKEYID_CPU_SEC2_DATA_KERN,
+ CC_LKEYID_CPU_SEC2_HMAC_KERN,
+ CC_LKEYID_CPU_SEC2_DATA_SCRUBBER,
+ CC_LKEYID_CPU_SEC2_HMAC_SCRUBBER,
+ CC_KEYSPACE_SEC2_SIZE // This is always the last element.
+};
+
+#define CC_LKEYID_CPU_SEC2_DATA_USER_STR "cpu_sec2_data_user"
+#define CC_LKEYID_CPU_SEC2_HMAC_USER_STR "cpu_sec2_hmac_user"
+#define CC_LKEYID_CPU_SEC2_DATA_KERN_STR "cpu_sec2_data_kernel"
+#define CC_LKEYID_CPU_SEC2_HMAC_KERN_STR "cpu_sec2_hmac_kernel"
+#define CC_LKEYID_CPU_SEC2_DATA_SCRUBBER_STR "cpu_sec2_data_scrubber"
+#define CC_LKEYID_CPU_SEC2_HMAC_SCRUBBER_STR "cpu_sec2_hmac_scrubber"
+
+enum
+{
+ CC_LKEYID_LCE_H2D_USER,
+ CC_LKEYID_LCE_D2H_USER,
+ CC_LKEYID_LCE_H2D_KERN,
+ CC_LKEYID_LCE_D2H_KERN,
+ CC_LKEYID_LCE_H2D_P2P,
+ CC_LKEYID_LCE_D2H_P2P,
+ CC_KEYSPACE_LCE_SIZE // This is always the last element.
+};
+
+
+#define CC_KEYSPACE_TOTAL_SIZE (CC_KEYSPACE_GSP_SIZE + CC_KEYSPACE_SEC2_SIZE + (16 * CC_KEYSPACE_LCE_SIZE))
+#define CC_LKEYID_LCE0_H2D_USER_STR "Lce00_h2d_user"
+#define CC_LKEYID_LCE0_D2H_USER_STR "Lce00_d2h_user"
+#define CC_LKEYID_LCE0_H2D_KERN_STR "Lce00_h2d_kernel"
+#define CC_LKEYID_LCE0_D2H_KERN_STR "Lce00_d2h_kernel"
+#define CC_LKEYID_LCE0_H2D_P2P_STR "Lce00_h2d_p2p"
+#define CC_LKEYID_LCE0_D2H_P2P_STR "Lce00_d2h_p2p"
+
+#define CC_LKEYID_LCE1_H2D_USER_STR "Lce01_h2d_user"
+#define CC_LKEYID_LCE1_D2H_USER_STR "Lce01_d2h_user"
+#define CC_LKEYID_LCE1_H2D_KERN_STR "Lce01_h2d_kernel"
+#define CC_LKEYID_LCE1_D2H_KERN_STR "Lce01_d2h_kernel"
+#define CC_LKEYID_LCE1_H2D_P2P_STR "Lce01_h2d_p2p"
+#define CC_LKEYID_LCE1_D2H_P2P_STR "Lce01_d2h_p2p"
+
+#define CC_LKEYID_LCE2_H2D_USER_STR "Lce02_h2d_user"
+#define CC_LKEYID_LCE2_D2H_USER_STR "Lce02_d2h_user"
+#define CC_LKEYID_LCE2_H2D_KERN_STR "Lce02_h2d_kernel"
+#define CC_LKEYID_LCE2_D2H_KERN_STR "Lce02_d2h_kernel"
+#define CC_LKEYID_LCE2_H2D_P2P_STR "Lce02_h2d_p2p"
+#define CC_LKEYID_LCE2_D2H_P2P_STR "Lce02_d2h_p2p"
+
+#define CC_LKEYID_LCE3_H2D_USER_STR "Lce03_h2d_user"
+#define CC_LKEYID_LCE3_D2H_USER_STR "Lce03_d2h_user"
+#define CC_LKEYID_LCE3_H2D_KERN_STR "Lce03_h2d_kernel"
+#define CC_LKEYID_LCE3_D2H_KERN_STR "Lce03_d2h_kernel"
+#define CC_LKEYID_LCE3_H2D_P2P_STR "Lce03_h2d_p2p"
+#define CC_LKEYID_LCE3_D2H_P2P_STR "Lce03_d2h_p2p"
+
+#define CC_LKEYID_LCE4_H2D_USER_STR "Lce04_h2d_user"
+#define CC_LKEYID_LCE4_D2H_USER_STR "Lce04_d2h_user"
+#define CC_LKEYID_LCE4_H2D_KERN_STR "Lce04_h2d_kernel"
+#define CC_LKEYID_LCE4_D2H_KERN_STR "Lce04_d2h_kernel"
+#define CC_LKEYID_LCE4_H2D_P2P_STR "Lce04_h2d_p2p"
+#define CC_LKEYID_LCE4_D2H_P2P_STR "Lce04_d2h_p2p"
+
+#define CC_LKEYID_LCE5_H2D_USER_STR "Lce05_h2d_user"
+#define CC_LKEYID_LCE5_D2H_USER_STR "Lce05_d2h_user"
+#define CC_LKEYID_LCE5_H2D_KERN_STR "Lce05_h2d_kernel"
+#define CC_LKEYID_LCE5_D2H_KERN_STR "Lce05_d2h_kernel"
+#define CC_LKEYID_LCE5_H2D_P2P_STR "Lce05_h2d_p2p"
+#define CC_LKEYID_LCE5_D2H_P2P_STR "Lce05_d2h_p2p"
+
+#define CC_LKEYID_LCE6_H2D_USER_STR "Lce06_h2d_user"
+#define CC_LKEYID_LCE6_D2H_USER_STR "Lce06_d2h_user"
+#define CC_LKEYID_LCE6_H2D_KERN_STR "Lce06_h2d_kernel"
+#define CC_LKEYID_LCE6_D2H_KERN_STR "Lce06_d2h_kernel"
+#define CC_LKEYID_LCE6_H2D_P2P_STR "Lce06_h2d_p2p"
+#define CC_LKEYID_LCE6_D2H_P2P_STR "Lce06_d2h_p2p"
+
+#define CC_LKEYID_LCE7_H2D_USER_STR "Lce07_h2d_user"
+#define CC_LKEYID_LCE7_D2H_USER_STR "Lce07_d2h_user"
+#define CC_LKEYID_LCE7_H2D_KERN_STR "Lce07_h2d_kernel"
+#define CC_LKEYID_LCE7_D2H_KERN_STR "Lce07_d2h_kernel"
+#define CC_LKEYID_LCE7_H2D_P2P_STR "Lce07_h2d_p2p"
+#define CC_LKEYID_LCE7_D2H_P2P_STR "Lce07_d2h_p2p"
+
+#define CC_LKEYID_LCE10_H2D_USER_STR "Lce10_h2d_user"
+#define CC_LKEYID_LCE10_D2H_USER_STR "Lce10_d2h_user"
+#define CC_LKEYID_LCE10_H2D_KERN_STR "Lce10_h2d_kernel"
+#define CC_LKEYID_LCE10_D2H_KERN_STR "Lce10_d2h_kernel"
+#define CC_LKEYID_LCE10_H2D_P2P_STR "Lce10_h2d_p2p"
+#define CC_LKEYID_LCE10_D2H_P2P_STR "Lce10_d2h_p2p"
+
+#define CC_LKEYID_LCE11_H2D_USER_STR "Lce11_h2d_user"
+#define CC_LKEYID_LCE11_D2H_USER_STR "Lce11_d2h_user"
+#define CC_LKEYID_LCE11_H2D_KERN_STR "Lce11_h2d_kernel"
+#define CC_LKEYID_LCE11_D2H_KERN_STR "Lce11_d2h_kernel"
+#define CC_LKEYID_LCE11_H2D_P2P_STR "Lce11_h2d_p2p"
+#define CC_LKEYID_LCE11_D2H_P2P_STR "Lce11_d2h_p2p"
+
+#define CC_LKEYID_LCE12_H2D_USER_STR "Lce12_h2d_user"
+#define CC_LKEYID_LCE12_D2H_USER_STR "Lce12_d2h_user"
+#define CC_LKEYID_LCE12_H2D_KERN_STR "Lce12_h2d_kernel"
+#define CC_LKEYID_LCE12_D2H_KERN_STR "Lce12_d2h_kernel"
+#define CC_LKEYID_LCE12_H2D_P2P_STR "Lce12_h2d_p2p"
+#define CC_LKEYID_LCE12_D2H_P2P_STR "Lce12_d2h_p2p"
+
+#define CC_LKEYID_LCE13_H2D_USER_STR "Lce13_h2d_user"
+#define CC_LKEYID_LCE13_D2H_USER_STR "Lce13_d2h_user"
+#define CC_LKEYID_LCE13_H2D_KERN_STR "Lce13_h2d_kernel"
+#define CC_LKEYID_LCE13_D2H_KERN_STR "Lce13_d2h_kernel"
+#define CC_LKEYID_LCE13_H2D_P2P_STR "Lce13_h2d_p2p"
+#define CC_LKEYID_LCE13_D2H_P2P_STR "Lce13_d2h_p2p"
+
+#define CC_LKEYID_LCE14_H2D_USER_STR "Lce14_h2d_user"
+#define CC_LKEYID_LCE14_D2H_USER_STR "Lce14_d2h_user"
+#define CC_LKEYID_LCE14_H2D_KERN_STR "Lce14_h2d_kernel"
+#define CC_LKEYID_LCE14_D2H_KERN_STR "Lce14_d2h_kernel"
+#define CC_LKEYID_LCE14_H2D_P2P_STR "Lce14_h2d_p2p"
+#define CC_LKEYID_LCE14_D2H_P2P_STR "Lce14_d2h_p2p"
+
+#define CC_LKEYID_LCE15_H2D_USER_STR "Lce15_h2d_user"
+#define CC_LKEYID_LCE15_D2H_USER_STR "Lce15_d2h_user"
+#define CC_LKEYID_LCE15_H2D_KERN_STR "Lce15_h2d_kernel"
+#define CC_LKEYID_LCE15_D2H_KERN_STR "Lce15_d2h_kernel"
+#define CC_LKEYID_LCE15_H2D_P2P_STR "Lce15_h2d_p2p"
+#define CC_LKEYID_LCE15_D2H_P2P_STR "Lce15_d2h_p2p"
+
+#define CC_LKEYID_LCE16_H2D_USER_STR "Lce16_h2d_user"
+#define CC_LKEYID_LCE16_D2H_USER_STR "Lce16_d2h_user"
+#define CC_LKEYID_LCE16_H2D_KERN_STR "Lce16_h2d_kernel"
+#define CC_LKEYID_LCE16_D2H_KERN_STR "Lce16_d2h_kernel"
+#define CC_LKEYID_LCE16_H2D_P2P_STR "Lce16_h2d_p2p"
+#define CC_LKEYID_LCE16_D2H_P2P_STR "Lce16_d2h_p2p"
+
+#define CC_LKEYID_LCE17_H2D_USER_STR "Lce17_h2d_user"
+#define CC_LKEYID_LCE17_D2H_USER_STR "Lce17_d2h_user"
+#define CC_LKEYID_LCE17_H2D_KERN_STR "Lce17_h2d_kernel"
+#define CC_LKEYID_LCE17_D2H_KERN_STR "Lce17_d2h_kernel"
+#define CC_LKEYID_LCE17_H2D_P2P_STR "Lce17_h2d_p2p"
+#define CC_LKEYID_LCE17_D2H_P2P_STR "Lce17_d2h_p2p"
+
+// Generate a global key ID from a keyspace (a) and local key ID (b).
+#define CC_GKEYID_GEN(a, b) (NvU32)(((a) << 16) | (b))
+
+// Get the keyspace component from a global key ID.
+#define CC_GKEYID_GET_KEYSPACE(a) (NvU16)((a) >> 16)
+
+// Get the local key ID from a global key ID.
+#define CC_GKEYID_GET_LKEYID(a) (NvU16)((a) & 0xffff)
+
+// Decrement/increment the local key ID portion of a global key ID.
+#define CC_GKEYID_DEC_LKEYID(a) CC_GKEYID_GEN(CC_GKEYID_GET_KEYSPACE((a)), CC_GKEYID_GET_LKEYID((a)) - 1)
+#define CC_GKEYID_INC_LKEYID(a) CC_GKEYID_GEN(CC_GKEYID_GET_KEYSPACE((a)), CC_GKEYID_GET_LKEYID((a)) + 1)
+
+// Get the unqiue string from a global key ID.
+#define CC_GKEYID_GET_STR(a) \
+ (CC_GKEYID_GET_KEYSPACE(a) == CC_KEYSPACE_GSP) ? \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_GSP_CPU_LOCKED_RPC) ? \
+ CC_LKEYID_GSP_CPU_LOCKED_RPC_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_CPU_GSP_LOCKED_RPC) ? \
+ CC_LKEYID_CPU_GSP_LOCKED_RPC_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_GSP_CPU_DMA) ? \
+ CC_LKEYID_GSP_CPU_DMA_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_CPU_GSP_DMA) ? \
+ CC_LKEYID_CPU_GSP_DMA_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_GSP_CPU_REPLAYABLE_FAULT) ? \
+ CC_LKEYID_GSP_CPU_REPLAYABLE_FAULT_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_GSP_CPU_NON_REPLAYABLE_FAULT) ? \
+ CC_LKEYID_GSP_CPU_NON_REPLAYABLE_FAULT_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_CPU_GSP_NVLE_P2P_WRAPPING) ? \
+ CC_LKEYID_CPU_GSP_NVLE_P2P_WRAPPING_STR : NULL : \
+ (CC_GKEYID_GET_KEYSPACE(a) == CC_KEYSPACE_SEC2) ? \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_CPU_SEC2_DATA_USER) ? \
+ CC_LKEYID_CPU_SEC2_DATA_USER_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_CPU_SEC2_HMAC_USER) ? \
+ CC_LKEYID_CPU_SEC2_HMAC_USER_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_CPU_SEC2_DATA_KERN) ? \
+ CC_LKEYID_CPU_SEC2_DATA_KERN_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_CPU_SEC2_HMAC_KERN) ? \
+ CC_LKEYID_CPU_SEC2_HMAC_KERN_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_CPU_SEC2_DATA_SCRUBBER) ? \
+ CC_LKEYID_CPU_SEC2_DATA_SCRUBBER_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_CPU_SEC2_HMAC_SCRUBBER) ? \
+ CC_LKEYID_CPU_SEC2_HMAC_SCRUBBER_STR : NULL : \
+ (CC_GKEYID_GET_KEYSPACE(a) == CC_KEYSPACE_LCE0) ? \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_H2D_USER) ? \
+ CC_LKEYID_LCE0_H2D_USER_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_D2H_USER) ? \
+ CC_LKEYID_LCE0_D2H_USER_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_H2D_KERN) ? \
+ CC_LKEYID_LCE0_H2D_KERN_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_D2H_KERN) ? \
+ CC_LKEYID_LCE0_D2H_KERN_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_H2D_P2P) ? \
+ CC_LKEYID_LCE0_H2D_P2P_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_D2H_P2P) ? \
+ CC_LKEYID_LCE0_D2H_P2P_STR : NULL : \
+ (CC_GKEYID_GET_KEYSPACE(a) == CC_KEYSPACE_LCE1) ? \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_H2D_USER) ? \
+ CC_LKEYID_LCE1_H2D_USER_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_D2H_USER) ? \
+ CC_LKEYID_LCE1_D2H_USER_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_H2D_KERN) ? \
+ CC_LKEYID_LCE1_H2D_KERN_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_D2H_KERN) ? \
+ CC_LKEYID_LCE1_D2H_KERN_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_H2D_P2P) ? \
+ CC_LKEYID_LCE1_H2D_P2P_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_D2H_P2P) ? \
+ CC_LKEYID_LCE1_D2H_P2P_STR : NULL : \
+ (CC_GKEYID_GET_KEYSPACE(a) == CC_KEYSPACE_LCE2) ? \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_H2D_USER) ? \
+ CC_LKEYID_LCE2_H2D_USER_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_D2H_USER) ? \
+ CC_LKEYID_LCE2_D2H_USER_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_H2D_KERN) ? \
+ CC_LKEYID_LCE2_H2D_KERN_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_D2H_KERN) ? \
+ CC_LKEYID_LCE2_D2H_KERN_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_H2D_P2P) ? \
+ CC_LKEYID_LCE2_H2D_P2P_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_D2H_P2P) ? \
+ CC_LKEYID_LCE2_D2H_P2P_STR : NULL : \
+ (CC_GKEYID_GET_KEYSPACE(a) == CC_KEYSPACE_LCE3) ? \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_H2D_USER) ? \
+ CC_LKEYID_LCE3_H2D_USER_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_D2H_USER) ? \
+ CC_LKEYID_LCE3_D2H_USER_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_H2D_KERN) ? \
+ CC_LKEYID_LCE3_H2D_KERN_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_D2H_KERN) ? \
+ CC_LKEYID_LCE3_D2H_KERN_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_H2D_P2P) ? \
+ CC_LKEYID_LCE3_H2D_P2P_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_D2H_P2P) ? \
+ CC_LKEYID_LCE3_D2H_P2P_STR : NULL : \
+ (CC_GKEYID_GET_KEYSPACE(a) == CC_KEYSPACE_LCE4) ? \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_H2D_USER) ? \
+ CC_LKEYID_LCE4_H2D_USER_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_D2H_USER) ? \
+ CC_LKEYID_LCE4_D2H_USER_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_H2D_KERN) ? \
+ CC_LKEYID_LCE4_H2D_KERN_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_D2H_KERN) ? \
+ CC_LKEYID_LCE4_D2H_KERN_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_H2D_P2P) ? \
+ CC_LKEYID_LCE4_H2D_P2P_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_D2H_P2P) ? \
+ CC_LKEYID_LCE4_D2H_P2P_STR : NULL : \
+ (CC_GKEYID_GET_KEYSPACE(a) == CC_KEYSPACE_LCE5) ? \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_H2D_USER) ? \
+ CC_LKEYID_LCE5_H2D_USER_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_D2H_USER) ? \
+ CC_LKEYID_LCE5_D2H_USER_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_H2D_KERN) ? \
+ CC_LKEYID_LCE5_H2D_KERN_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_D2H_KERN) ? \
+ CC_LKEYID_LCE5_D2H_KERN_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_H2D_P2P) ? \
+ CC_LKEYID_LCE5_H2D_P2P_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_D2H_P2P) ? \
+ CC_LKEYID_LCE5_D2H_P2P_STR : NULL : \
+ (CC_GKEYID_GET_KEYSPACE(a) == CC_KEYSPACE_LCE6) ? \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_H2D_USER) ? \
+ CC_LKEYID_LCE6_H2D_USER_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_D2H_USER) ? \
+ CC_LKEYID_LCE6_D2H_USER_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_H2D_KERN) ? \
+ CC_LKEYID_LCE6_H2D_KERN_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_D2H_KERN) ? \
+ CC_LKEYID_LCE6_D2H_KERN_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_H2D_P2P) ? \
+ CC_LKEYID_LCE6_H2D_P2P_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_D2H_P2P) ? \
+ CC_LKEYID_LCE6_D2H_P2P_STR : NULL : \
+ (CC_GKEYID_GET_KEYSPACE(a) == CC_KEYSPACE_LCE7) ? \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_H2D_USER) ? \
+ CC_LKEYID_LCE7_H2D_USER_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_D2H_USER) ? \
+ CC_LKEYID_LCE7_D2H_USER_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_H2D_KERN) ? \
+ CC_LKEYID_LCE7_H2D_KERN_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_D2H_KERN) ? \
+ CC_LKEYID_LCE7_D2H_KERN_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_H2D_P2P) ? \
+ CC_LKEYID_LCE7_H2D_P2P_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_D2H_P2P) ? \
+ CC_LKEYID_LCE7_D2H_P2P_STR : NULL : \
+ (CC_GKEYID_GET_KEYSPACE(a) == CC_KEYSPACE_LCE10) ? \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_H2D_USER) ? \
+ CC_LKEYID_LCE10_H2D_USER_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_D2H_USER) ? \
+ CC_LKEYID_LCE10_D2H_USER_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_H2D_KERN) ? \
+ CC_LKEYID_LCE10_H2D_KERN_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_D2H_KERN) ? \
+ CC_LKEYID_LCE10_D2H_KERN_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_H2D_P2P) ? \
+ CC_LKEYID_LCE10_H2D_P2P_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_D2H_P2P) ? \
+ CC_LKEYID_LCE10_D2H_P2P_STR : NULL : \
+ (CC_GKEYID_GET_KEYSPACE(a) == CC_KEYSPACE_LCE11) ? \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_H2D_USER) ? \
+ CC_LKEYID_LCE11_H2D_USER_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_D2H_USER) ? \
+ CC_LKEYID_LCE11_D2H_USER_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_H2D_KERN) ? \
+ CC_LKEYID_LCE11_H2D_KERN_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_D2H_KERN) ? \
+ CC_LKEYID_LCE11_D2H_KERN_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_H2D_P2P) ? \
+ CC_LKEYID_LCE11_H2D_P2P_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_D2H_P2P) ? \
+ CC_LKEYID_LCE11_D2H_P2P_STR : NULL : \
+ (CC_GKEYID_GET_KEYSPACE(a) == CC_KEYSPACE_LCE12) ? \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_H2D_USER) ? \
+ CC_LKEYID_LCE12_H2D_USER_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_D2H_USER) ? \
+ CC_LKEYID_LCE12_D2H_USER_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_H2D_KERN) ? \
+ CC_LKEYID_LCE12_H2D_KERN_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_D2H_KERN) ? \
+ CC_LKEYID_LCE12_D2H_KERN_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_H2D_P2P) ? \
+ CC_LKEYID_LCE12_H2D_P2P_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_D2H_P2P) ? \
+ CC_LKEYID_LCE12_D2H_P2P_STR : NULL : \
+ (CC_GKEYID_GET_KEYSPACE(a) == CC_KEYSPACE_LCE13) ? \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_H2D_USER) ? \
+ CC_LKEYID_LCE13_H2D_USER_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_D2H_USER) ? \
+ CC_LKEYID_LCE13_D2H_USER_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_H2D_KERN) ? \
+ CC_LKEYID_LCE13_H2D_KERN_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_D2H_KERN) ? \
+ CC_LKEYID_LCE13_D2H_KERN_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_H2D_P2P) ? \
+ CC_LKEYID_LCE13_H2D_P2P_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_D2H_P2P) ? \
+ CC_LKEYID_LCE13_D2H_P2P_STR : NULL : \
+ (CC_GKEYID_GET_KEYSPACE(a) == CC_KEYSPACE_LCE14) ? \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_H2D_USER) ? \
+ CC_LKEYID_LCE14_H2D_USER_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_D2H_USER) ? \
+ CC_LKEYID_LCE14_D2H_USER_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_H2D_KERN) ? \
+ CC_LKEYID_LCE14_H2D_KERN_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_D2H_KERN) ? \
+ CC_LKEYID_LCE14_D2H_KERN_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_H2D_P2P) ? \
+ CC_LKEYID_LCE14_H2D_P2P_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_D2H_P2P) ? \
+ CC_LKEYID_LCE14_D2H_P2P_STR : NULL : \
+ (CC_GKEYID_GET_KEYSPACE(a) == CC_KEYSPACE_LCE15) ? \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_H2D_USER) ? \
+ CC_LKEYID_LCE15_H2D_USER_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_D2H_USER) ? \
+ CC_LKEYID_LCE15_D2H_USER_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_H2D_KERN) ? \
+ CC_LKEYID_LCE15_H2D_KERN_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_D2H_KERN) ? \
+ CC_LKEYID_LCE15_D2H_KERN_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_H2D_P2P) ? \
+ CC_LKEYID_LCE15_H2D_P2P_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_D2H_P2P) ? \
+ CC_LKEYID_LCE15_D2H_P2P_STR : NULL : \
+ (CC_GKEYID_GET_KEYSPACE(a) == CC_KEYSPACE_LCE16) ? \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_H2D_USER) ? \
+ CC_LKEYID_LCE16_H2D_USER_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_D2H_USER) ? \
+ CC_LKEYID_LCE16_D2H_USER_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_H2D_KERN) ? \
+ CC_LKEYID_LCE16_H2D_KERN_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_D2H_KERN) ? \
+ CC_LKEYID_LCE16_D2H_KERN_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_H2D_P2P) ? \
+ CC_LKEYID_LCE16_H2D_P2P_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_D2H_P2P) ? \
+ CC_LKEYID_LCE16_D2H_P2P_STR : NULL : \
+ (CC_GKEYID_GET_KEYSPACE(a) == CC_KEYSPACE_LCE17) ? \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_H2D_USER) ? \
+ CC_LKEYID_LCE17_H2D_USER_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_D2H_USER) ? \
+ CC_LKEYID_LCE17_D2H_USER_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_H2D_KERN) ? \
+ CC_LKEYID_LCE17_H2D_KERN_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_D2H_KERN) ? \
+ CC_LKEYID_LCE17_D2H_KERN_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_H2D_P2P) ? \
+ CC_LKEYID_LCE17_H2D_P2P_STR : \
+ (CC_GKEYID_GET_LKEYID(a) == CC_LKEYID_LCE_D2H_P2P) ? \
+ CC_LKEYID_LCE17_D2H_P2P_STR : NULL : NULL
+
+#define CC_EXPORT_MASTER_KEY_SIZE_BYTES 32
+
+#define CC_KEYID_PERCHANNEL_INITIAL_KEYSEED "ce_channel"
+#define CC_KEYID_PERCHANNEL_UPDATE_KEYSEED "update_keyseeed"
+#define CC_KEYID_PERCHANNEL_CPU_GPU_UPDATE_KEY "update_key1"
+#define CC_KEYID_PERCHANNEL_GPU_CPU_UPDATE_KEY "update_key2"
+
+#endif // CC_KEYSTORE_H
diff --git a/userspace/sdks/nv570/nvalloc/common/inc/dev_ctrl_defines.h b/userspace/sdks/nv570/nvalloc/common/inc/dev_ctrl_defines.h
new file mode 100644
index 0000000..fa06bcf
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/common/inc/dev_ctrl_defines.h
@@ -0,0 +1,87 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2021-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/*!
+ * @brief Defines for simplifying SW accesses to the dev_ctrl interrupt tree.
+ * These are generic defines ued in addition to architecure-specific
+ * defines in dev_vm_addendum.h
+ *
+ */
+
+//
+// Notes on the terms used below:
+// Subtree: The HW tree is a 64-way tree that consists of 2 TOP level interrupt
+// registers, 32 bits each. Each of these 64 is referred to as a subtree.
+// Leaf: Each of these 64 subtrees are associated with a pair of LEAF registers
+// giving us a total of 128 LEAF registers.
+// GPU vector: The 128 LEAF registers give us a total of (128*32) GPU vectors
+// giving us a total of 4096 GPU vectors
+//
+
+//
+// Given a subtree index, the below macros give us the index of the TOP level
+// register and the bit within the TOP level register to program for that
+// subtree.
+//
+#define NV_CTRL_INTR_SUBTREE_TO_TOP_IDX(i) (((NvU32)(i)) / 32)
+#define NV_CTRL_INTR_SUBTREE_TO_TOP_BIT(i) (((NvU32)(i)) % 32)
+
+//
+// Given a subtree index, the below macros give us the two LEAF register indices
+// that correspond to that subtree.
+//
+#define NV_CTRL_INTR_SUBTREE_TO_LEAF_IDX_START(i) (((NvU32)(i)) * 2)
+#define NV_CTRL_INTR_SUBTREE_TO_LEAF_IDX_END(i) ((((NvU32)(i)) * 2) + 1)
+
+#define NV_CTRL_INTR_LEAF_IDX_TO_SUBTREE(i) (((NvU32)(i)) / 2)
+
+//
+// Given a LEAF register index, the below macros give us the range of GPU
+// interrupt vectors that correspond to those leafs.
+//
+#define NV_CTRL_INTR_LEAF_IDX_TO_GPU_VECTOR_START(i) (((NvU32)(i)) * 32)
+#define NV_CTRL_INTR_LEAF_IDX_TO_GPU_VECTOR_END(i) ((((NvU32)(i)) * 32) + 31)
+
+//
+// Given a GPU interrupt vector, the below macros give us the index of the
+// LEAF register and the bit within the LEAF register to program for that
+// GPU interrupt vector.
+//
+#define NV_CTRL_INTR_GPU_VECTOR_TO_LEAF_REG(i) (((NvU32)(i)) / 32)
+#define NV_CTRL_INTR_GPU_VECTOR_TO_LEAF_BIT(i) (((NvU32)(i)) % 32)
+
+//
+// Given a GPU interrupt vector, the below macro gives us the subtree in which
+// it belongs.
+//
+#define NV_CTRL_INTR_GPU_VECTOR_TO_SUBTREE(i) \
+ ((NV_CTRL_INTR_GPU_VECTOR_TO_LEAF_REG(i)) / 2)
+
+// First index of doorbell which is controlled by VF
+#define NV_CTRL_INTR_GPU_DOORBELL_INDEX_VF_START 2048
+
+// The max number of leaf registers we expect
+#define NV_MAX_INTR_LEAVES 16
+
+// In SW, this specifies an invalid interrupt vector
+#define NV_INTR_VECTOR_INVALID (NV_U32_MAX)
diff --git a/userspace/sdks/nv570/nvalloc/common/inc/flcnifcmn.h b/userspace/sdks/nv570/nvalloc/common/inc/flcnifcmn.h
new file mode 100644
index 0000000..df4ba6c
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/common/inc/flcnifcmn.h
@@ -0,0 +1,141 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2014-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/*!
+ * flcn Command/Message Interfaces - Common
+ */
+
+#ifndef FLCNIFCMN_H
+#define FLCNIFCMN_H
+
+#include "nvtypes.h"
+#include "flcnretval.h"
+
+/*!
+ * @ref NvU64_ALIGN32 , NvU64_ALIGN32_PACK, NvU64_ALIGN32_UNPACK
+ * TODO: Use NV types directly
+ */
+typedef NvU64_ALIGN32 RM_FLCN_U64;
+typedef NvU64_ALIGN32 *PRM_FLCN_U64;
+
+#define RM_FLCN_U64_IS_ZERO NvU64_ALIGN32_IS_ZERO
+#define RM_FLCN_U64_PACK NvU64_ALIGN32_PACK
+#define RM_FLCN_U64_UNPACK NvU64_ALIGN32_UNPACK
+
+/*!
+ * @brief Header preceding each CMD/MSG exchanged through falcon's queues.
+ *
+ * @note Data package sent to falcon are referred as CMDs (commands).
+ * Data package sent by falcon are referred as MSGs (messages).
+ */
+typedef struct
+{
+ /*!
+ * Unit ID identifies falcon's task/unit receiving/issuing this message.
+ */
+ NvU8 unitId;
+ /*!
+ * Total CMD/MSG size (including header).
+ */
+ NvU8 size;
+ /*!
+ * Flags identifying state of CMD/MSG.
+ */
+ NvU8 ctrlFlags;
+ /*!
+ * Sequence # ID to track each request sent to falcon (where applicable).
+ */
+ NvU8 seqNumId;
+} RM_FLCN_QUEUE_HDR,
+*PRM_FLCN_QUEUE_HDR;
+
+/*!
+ * Convenience macro for determining the size of the falcon's queue header:
+ */
+#define RM_FLCN_QUEUE_HDR_SIZE sizeof(RM_FLCN_QUEUE_HDR)
+
+/*!
+ * Generic Falcon rewind unit ID.
+ */
+#define RM_FLCN_UNIT_ID_REWIND (0x00U)
+
+/*!
+ * Generic CMD structure to hold the header.
+ */
+typedef struct
+{
+ RM_FLCN_QUEUE_HDR hdr;
+ NvU32 cmd;
+} RM_FLCN_CMD_GEN;
+
+/*!
+ * Generic MSG structure to hold the header.
+ */
+typedef struct
+{
+ RM_FLCN_QUEUE_HDR hdr;
+ NvU32 msg;
+} RM_FLCN_MSG_GEN;
+
+/*!
+ * Convenience macros for determining the size of body for a command or message:
+ */
+#define RM_FLCN_CMD_BODY_SIZE(u,t) sizeof(RM_FLCN_##u##_CMD_##t)
+#define RM_FLCN_MSG_BODY_SIZE(u,t) sizeof(RM_FLCN_##u##_MSG_##t)
+
+/*!
+ * Convenience macros for determining the size of a command or message:
+ */
+#define RM_FLCN_CMD_SIZE(u,t) \
+ (RM_FLCN_QUEUE_HDR_SIZE + RM_FLCN_CMD_BODY_SIZE(u,t))
+
+#define RM_FLCN_MSG_SIZE(u,t) \
+ (RM_FLCN_QUEUE_HDR_SIZE + RM_FLCN_MSG_BODY_SIZE(u,t))
+
+/*!
+ * Convenience macros for determining the type of a command or message
+ * (intended to be used symmetrically with the CMD and MSG _SIZE macros):
+ */
+#define RM_FLCN_CMD_TYPE(u,t) RM_FLCN_##u##_CMD_ID_##t
+#define RM_FLCN_MSG_TYPE(u,t) RM_FLCN_##u##_MSG_ID_##t
+
+/*!
+ * @brief Falcons' queue header flags (@ref RM_FLCN_QUEUE_HDR::ctrlFlags).
+ *
+ * RM_FLCN_QUEUE_FLAGS_STATUS
+ * Set by command's sender to request back message confirming the completion of
+ * command's execution. In RM->FLCN communication response is required to free
+ * command related data tracked within RM (***_SEQ_INFO).
+ *
+ * RM_FLCN_QUEUE_HDR_FLAGS_EVENT
+ * Set by the falcon to distinguish messages sent to RM from command responses.
+ *
+ * RM_FLCN_QUEUE_HDR_FLAGS_UNIT_ACK
+ * Used internally within the falcon to track completed commands when updating
+ * get (tail) command queue pointers.
+ */
+#define RM_FLCN_QUEUE_HDR_FLAGS_STATUS NVBIT(0)
+#define RM_FLCN_QUEUE_HDR_FLAGS_EVENT NVBIT(2)
+#define RM_FLCN_QUEUE_HDR_FLAGS_UNIT_ACK NVBIT(5)
+
+#endif // FLCNIFCMN_H
diff --git a/userspace/sdks/nv570/nvalloc/common/inc/flcnretval.h b/userspace/sdks/nv570/nvalloc/common/inc/flcnretval.h
new file mode 100644
index 0000000..0e1efe5
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/common/inc/flcnretval.h
@@ -0,0 +1,305 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2008-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/*!
+ * @file flcnretval.h
+ * @brief Defines various status codes that are convenient to relay status
+ * information in functions.
+ */
+
+#ifndef FLCNRETVAL_H
+#define FLCNRETVAL_H
+
+#include "nvtypes.h"
+/*!
+ * Defines a generic type that may be used to convey status information. This
+ * is very similar to the RM_STATUS type but smaller in width to save DMEM and
+ * stack space.
+ */
+typedef NvU8 FLCN_STATUS;
+
+#define FLCN_OK (0x00U)
+#define FLCN_ERR_BINARY_NOT_STARTED (0xFEU)
+#define FLCN_ERROR (0xFFU)
+
+#define FLCN_ERR_NOT_SUPPORTED (0x01U)
+#define FLCN_ERR_INVALID_ARGUMENT (0x02U)
+#define FLCN_ERR_ILLEGAL_OPERATION (0x03U)
+#define FLCN_ERR_TIMEOUT (0x04U)
+#define FLCN_ERR_NO_FREE_MEM (0x05U)
+#define FLCN_ERR_HDCP_INVALID_SRM (0x06U)
+#define FLCN_ERR_HDCP_RECV_REVOKED (0x07U)
+#define FLCN_ERR_RPC_INVALID_INPUT (0x08U)
+#define FLCN_ERR_DMA_SUSPENDED (0x09U)
+#define FLCN_ERR_MUTEX_ACQUIRED (0x10U)
+#define FLCN_ERR_MUTEX_ID_NOT_AVAILABLE (0x11U)
+#define FLCN_ERR_OBJECT_NOT_FOUND (0x12U)
+#define FLCN_ERR_MSGBOX_TIMEOUT (0x13U)
+#define FLCN_ERR_INVALID_INDEX (0x14U)
+#define FLCN_ERR_INVALID_FUNCTION (0x15U)
+#define FLCN_ERR_INSUFFICIENT_PMB_PLM_PROTECTION (0x16U)
+#define FLCN_ERR_DMA_NACK (0x17U)
+#define FLCN_ERR_CHIP_NOT_SUPPORTED_FOR_PR (0x18U)
+#define FLCN_ERR_BAR0_PRIV_READ_ERROR (0x19U)
+#define FLCN_ERR_BAR0_PRIV_WRITE_ERROR (0x1AU)
+#define FLCN_ERR_HDCP22_ABORT_AUTHENTICATION (0x1BU)
+#define FLCN_ERR_DPU_IS_BUSY (0x1CU)
+#define FLCN_ERR_DPU_TIMEOUT_FOR_HDCP_TYPE1_LOCK_REQUEST (0x1DU)
+#define FLCN_ERR_HDCP_TYPE1_LOCK_FAILED (0x1EU)
+#define FLCN_ERR_HDCP_TYPE1_LOCK_UNKNOWN (0x1FU)
+#define FLCN_ERR_WAIT_FOR_BAR0_IDLE_FAILED (0x20U)
+#define FLCN_ERR_CSB_PRIV_READ_ERROR (0x21U)
+#define FLCN_ERR_CSB_PRIV_WRITE_ERROR (0x22U)
+#define FLCN_ERR_DMA_UNEXPECTED_DMAIDX (0x23U)
+#define FLCN_ERR_PRIV_SEC_VIOLATION (0x24U)
+#define FLCN_ERR_INVALID_VERSION (0x25U)
+#define FLCN_ERR_PR_SHARED_STRUCT_INIT_FAILED (0x26U)
+#define FLCN_ERR_GPU_IN_DEBUG_MODE (0x27U)
+#define FLCN_ERR_HPD_UNPLUG (0x28U)
+#define FLCN_ERR_HDCP22_DELAY_ABORT_AUTHENTICATION (0x29U)
+#define FLCN_ERR_SECUREBUS_REGISTER_READ_ERROR (0x2AU)
+#define FLCN_ERR_SECUREBUS_REGISTER_WRITE_ERROR (0x2BU)
+#define FLCN_ERR_HDCP22_FLUSH_TYPE_LOCK_ACTIVE (0x2CU)
+#define FLCN_ERR_HDCP22_FLUSH_TYPE_IN_PROGRESS (0x2DU)
+#define FLCN_ERR_FEATURE_NOT_ENABLED (0x2EU)
+#define FLCN_ERR_OUT_OF_RANGE (0x2FU)
+
+// I2C Errors
+#define FLCN_ERR_I2C_BUSY (0x30U)
+#define FLCN_ERR_I2C_NACK_ADDRESS (0x31U)
+#define FLCN_ERR_I2C_NACK_BYTE (0x32U)
+#define FLCN_ERR_I2C_SIZE (0x33U)
+#define FLCN_ERR_I2C_BUS_INVALID (0x34U)
+
+#define FLCN_ERR_INVALID_STATE (0x35U)
+#define FLCN_ERR_RECURSION_LIMIT_EXCEEDED (0x36U)
+#define FLCN_ERR_INVALID_CAST (0x37U)
+
+// AUX Errors
+#define FLCN_ERR_AUX_ERROR (0x3AU)
+#define FLCN_ERR_AUX_SEMA_ACQUIRED (0x3BU)
+#define FLCN_ERR_AUX_SEMA_INVALID_RELEASE (0x3CU)
+#define FLCN_ERR_AUX_DEFER_TIMEOUT (0x3DU)
+#define FLCN_ERR_MORE_PROCESSING_REQUIRED (0x3EU)
+#define FLCN_ERR_DMA_ALIGN (0x3FU)
+
+// Power-Device Errors
+#define FLCN_ERR_PWR_DEVICE_TAMPERED (0x40U)
+
+#define FLCN_ERR_ITERATION_END (0x41U)
+
+// Perf change sequence Errors
+#define FLCN_ERR_LOCK_NOT_AVAILABLE (0x42U)
+
+#define FLCN_ERR_STATE_RESET_NEEDED (0x43U)
+#define FLCN_ERR_DMA_GENERIC (0x44U)
+#define FLCN_ERR_LS_CHK_UCODE_REVOKED (0x45U)
+#define FLCN_ERR_ACC_SEQ_MISMATCH (0x46U)
+#define FLCN_ERR_SSP_STACK_CHECK_FAILED (0x47U)
+#define FLCN_ERR_SE_TRNG_FAILED (0x48U)
+#define FLCN_ERR_PROD_MODE_NOT_YET_SUPPORTED (0x49U)
+
+// SHA HW errors
+#define FLCN_ERR_SHA_HW_CHECK_INT_STATUS (0x4AU)
+#define FLCN_ERR_SHA_HW_SOFTRESET_REQUIRED (0x4BU)
+#define FLCN_ERR_SHA_HW_SOFTRESET_FAILED (0x4CU)
+#define FLCN_ERR_SHA_HW_BUSY (0x4DU)
+
+//
+// Add new generic error codes here, do not changes values of exiting error codes,
+// because that will affect other binaries and their signatures
+//
+#define FLCN_ERR_CTXSW_ERROR (0x4EU)
+#define FLCN_ERR_SE_SNPKA_HW_CRYPTO_OPERATION_FAILED (0x4FU)
+
+// VPR SEC2 task errors
+#define FLCN_ERR_VPR_APP_INVALID_REQUEST_END_ADDR (0x51U)
+#define FLCN_ERR_VPR_APP_INVALID_REQUEST_START_ADDR (0x52U)
+#define FLCN_ERR_VPR_APP_SCRUB_VERIF_FAILED (0x53U)
+#define FLCN_ERR_VPR_APP_MEMLOCK_ALREADY_SET (0x54U)
+#define FLCN_ERR_VPR_APP_INVALID_INDEX (0x55U)
+#define FLCN_ERR_VPR_APP_UNEXPECTED_VPR_HANDOFF_FROM_SCRUBBER (0x56U)
+#define FLCN_ERR_VPR_APP_CBC_RANGE_CLASH (0x57U)
+#define FLCN_ERR_VPR_APP_NOT_SUPPORTED_BY_HW (0x58U)
+#define FLCN_ERR_VPR_APP_NOT_SUPPORTED_BY_SW (0x59U)
+#define FLCN_ERR_VPR_APP_DISPLAY_VERSION_NOT_SUPPORTED (0x5AU)
+#define FLCN_ERR_VPR_APP_VPR_WPR_WRITE_FAILED (0x5BU)
+#define FLCN_ERR_VPR_APP_NOTHING_TO_DO (0x5CU)
+#define FLCN_ERR_VPR_APP_DISPLAY_NOT_PRESENT (0x5DU)
+#define FLCN_ERR_VPR_APP_PREVIOUS_CMD_FAILED_AS_MAX_VPR_IS_0 (0x5EU)
+#define FLCN_ERR_VPR_APP_PLM_PROTECTION_NOT_RAISED (0x5FU)
+#define FLCN_ERR_VPR_APP_PLM_PROTECTION_ALREADY_RAISED (0x60U)
+#define FLCN_ERR_VPR_APP_DISP_FALCON_IS_NOT_IN_LS_MODE (0x61U)
+#define FLCN_ERR_VPR_APP_VPR_IS_ALREADY_ENABLED (0x62U)
+#define FLCN_ERR_VPR_APP_UNEXPECTEDLY_RUNNING_ON_RISCV (0x63U)
+#define FLCN_ERR_INVALID_SR_CONFIGURATION (0x64U)
+#define FLCN_ERR_VPR_CMD_NOT_SUPPORTED (0x65U)
+
+// Clocks Errors
+#define FLCN_ERR_CYCLE_DETECTED (0x70U)
+#define FLCN_ERR_INVALID_PATH (0x71U)
+#define FLCN_ERR_MISMATCHED_TARGET (0x72U)
+#define FLCN_ERR_FREQ_NOT_SUPPORTED (0x73U)
+#define FLCN_ERR_INVALID_SOURCE (0x74U)
+#define FLCN_ERR_NOT_INITIALIZED (0x75U)
+#define FLCN_ERR_CLOCK_NOT_SETTLED (0x76U)
+
+// HDCP2.2 Errors
+#define FLCN_ERR_HDCP22_GETDKEY_FAILED (0x80U)
+#define FLCN_ERR_HDCP22_H_PRIME (0x81U)
+#define FLCN_ERR_HDCP22_CERT_RX (0x82U)
+#define FLCN_ERR_HDCP22_PAIRING (0x83U)
+#define FLCN_ERR_HDCP22_L_PRIME (0x84U)
+#define FLCN_ERR_HDCP22_V_PRIME (0x85U)
+#define FLCN_ERR_HDCP22_INVALID_RXIDLIST (0x86U)
+#define FLCN_ERR_HDCP22_M_PRIME (0x87U)
+#define FLCN_ERR_HDCP22_SEQ_ROLLOVER (0x88U)
+#define FLCN_ERR_HDCP22_RSA_HW (0x89U)
+#define FLCN_ERR_HDCP22_ECF_TIMESLOT_MISMATCH (0x90U)
+
+// LibCCC Errors
+#define FLCN_ERR_INIT_CRYPTO_DEVICE_FAILED (0x91U)
+#define FLCN_ERR_NVPKA_SELECT_ENGINE_FAILED (0x92U)
+#define FLCN_ERR_NVPKA_ACQUIRE_MUTEX_FAILED (0x93U)
+#define FLCN_ERR_NVPKA_MODULAR_EXP_LOCK_FAILED (0x94U)
+#define FLCN_ERR_NVRNG_INIT_CRYPTO_DEVICE_FAILED (0x95U)
+#define FLCN_ERR_NVRNG_SELECT_ENGINE_FAILED (0x96U)
+#define FLCN_ERR_NVRNG_GENERATE_FAILED (0x97U)
+#define FLCN_ERR_NVPKA_ECDSA_INIT_FAILED (0x98U)
+#define FLCN_ERR_NVPKA_ECDSA_SIGN_FAILED (0x99U)
+#define FLCN_ERR_NVPKA_GET_ECC_KEY_PAIR_FAILED (0x9AU)
+
+// Heavy Secure Errors
+#define FLCN_ERR_HS_CHK_INVALID_INPUT (0xA0U)
+#define FLCN_ERR_HS_CHK_CHIP_NOT_SUPPORTED (0xA1U)
+#define FLCN_ERR_HS_CHK_UCODE_REVOKED (0xA2U)
+#define FLCN_ERR_HS_CHK_NOT_IN_LSMODE (0xA3U)
+#define FLCN_ERR_HS_CHK_INVALID_LS_PRIV_LEVEL (0xA4U)
+#define FLCN_ERR_HS_CHK_INVALID_REGIONCFG (0xA5U)
+#define FLCN_ERR_HS_CHK_PRIV_SEC_DISABLED_ON_PROD (0xA6U)
+#define FLCN_ERR_HS_CHK_SW_FUSING_ALLOWED_ON_PROD (0xA7U)
+#define FLCN_ERR_HS_CHK_INTERNAL_SKU_ON_PROD (0xA8U)
+#define FLCN_ERR_HS_CHK_DEVID_OVERRIDE_ENABLED_ON_PROD (0xA9U)
+#define FLCN_ERR_HS_CHK_INCONSISTENT_PROD_MODES (0xAAU)
+#define FLCN_ERR_HS_CHK_HUB_ENCRPTION_DISABLED (0xABU)
+#define FLCN_ERR_HS_PR_ILLEGAL_LASSAHS_STATE_AT_HS_ENTRY (0xACU)
+#define FLCN_ERR_HS_PR_ILLEGAL_LASSAHS_STATE_AT_MPK_DECRYPT (0xADU)
+#define FLCN_ERR_HS_PR_ILLEGAL_LASSAHS_STATE_AT_HS_EXIT (0xAEU)
+#define FLCN_ERR_HS_PROD_MODE_NOT_YET_SUPPORTED (0xAFU)
+#define FLCN_ERR_HS_DEV_VERSION_ON_PROD (0xB0U)
+#define FLCN_ERR_HS_PR_LASSAHS_LS_SIG_GRP_MISMATCH (0xB1U)
+#define FLCN_ERR_HS_PR_LASSAHS_LS_SIG_GRP_OVERLAYS_CNT (0xB2U)
+#define FLCN_ERR_HS_PR_LASSAHS_LS_SIG_GRP_INVALID_VA (0xB3U)
+#define FLCN_ERR_HS_MUTEX_ACQUIRE_FAILED (0xB4U)
+#define FLCN_ERR_HS_MUTEX_RELEASE_FAILED (0xB5U)
+#define FLCN_ERR_HS_PR_MPK_DEC_NEEDS_NEWER_ACR_UDE_SCRUBBER (0xB6U)
+#define FLCN_ERR_HS_CHK_ENGID_MISMATCH (0xB7U)
+#define FLCN_ERR_HS_OPT_INTERNAL_SKU_CHECK_FAILED (0xB8U)
+#define FLCN_ERR_HS_CHK_BOARD_MISMATCH (0xB9U)
+#define FLCN_ERR_HS_CHK_DISP_ENG_DISABLED (0xBAU)
+#define FLCN_ERR_HS_GEN_RANDOM (0xBBU)
+#define FLCN_ERR_HS_CHK_IMPROPERLY_FUSED_BOARD (0xBCU)
+#define FLCN_ERR_HS_CHK_HDCP_DISABLED (0xBDU)
+#define FLCN_ERR_HS_CHK_HDCP_BLACKLISTED_SKU (0XBEU)
+#define FLCN_ERR_HS_SECURE_ACTION_ARG_CHECK_FAILED (0xBFU)
+#define FLCN_ERR_HS_CHK_RETURN_PC_AT_HS_ENTRY_IS_OF_HS (0xC0U)
+#define FLCN_ERR_HS_CHK_HS_LIB_ENTRY_CALLED_BY_NON_HS (0xC1U)
+#define FLCN_ERR_HS_DECODE_TRAP_ALREADY_IN_USE (0xC2U)
+#define FLCN_ERR_HS_REGISTER_READ_WRITE_ERROR (0xC3U)
+#define FLCN_ERR_HS_CHK_CPUCTL_ALIAS_FALSE (0xC4U)
+#define FLCN_ERR_HS_UPDATE_RESET_PLM_ERROR (0xC5U)
+#define FLCN_ERR_HS_RNG_CONFIG_ERROR (0xC6U)
+#define FLCN_ERR_HS_CHK_NOT_IN_HSMODE (0xC7U)
+#define FLCN_ERR_HS_CHK_GFW_CHAIN_OF_TRUST_BROKEN (0xC8U)
+#define FLCN_ERR_HS_HDCP22_WRONG_SEQUENCE (0xC9U)
+#define FLCN_ERR_HS_HDCP22_INTEGRITY_ERROR (0xCAU)
+#define FLCN_ERR_HS_HDCP22_WRONG_TYPE (0xCBU)
+#define FLCN_ERR_HS_APM_NOT_ENABLED (0xCCU)
+#define FLCN_ERR_HS_APM_SMC_ENABLED (0xCDU)
+#define FLCN_ERR_HS_APM_FECS_NOT_HALTED (0xCEU)
+#define FLCN_ERR_HS_APM_SCRATCH_PLM_INVALID (0xCFU)
+#define FLCN_ERR_HS_APM_SCRATCH_INIT_INVALID (0xD0U)
+#define FLCN_ERR_HS_INVALID_KEY (0xD1U)
+#define FLCN_ERR_HS_SWKG_INVALID_SIGNATURE (0xD2U)
+#define FLCN_ERR_HS_SCP_LIB_DMHASH_FAILED (0xD3U)
+#define FLCN_ERR_HS_SCP_LIB_AESKDF_FAILED (0xD4U)
+#define FLCN_ERR_INSUFFICIENT_NOPS (0xD5U)
+
+//
+// BAR0/CSB Priv Read/Write Error Handling Defines
+// These need to be defined by HW - NV Bug 200198584
+//
+#define FLCN_BAR0_PRIV_PRI_ERROR_MASK 0xFFF00000U
+#define FLCN_BAR0_PRIV_PRI_ERROR_CODE 0xBAD00000U
+#define FLCN_BAR0_PRIV_PRI_RETURN_VAL 0x00BADBADU
+
+#define FLCN_CSB_PRIV_PRI_ERROR_MASK 0xFFFF0000U
+#define FLCN_CSB_PRIV_PRI_ERROR_CODE 0xBADF0000U
+
+//
+// Macro to check FALCON return status
+//
+#define CHECK_FLCN_STATUS(expr) do { \
+ flcnStatus = (expr); \
+ if (flcnStatus != FLCN_OK) \
+ { \
+ goto ErrorExit; \
+ } \
+ } while (NV_FALSE)
+
+// Warnings.
+#define FLCN_WARN_NOTHING_TO_DO (0xD0U)
+#define FLCN_WARN_NOT_QUERIED (0xD1U)
+#define FLCN_WARN_DATA_NOT_AVAILABLE (0xD2U)
+
+// Queue handling Errors
+#define FLCN_ERR_QUEUE_MGMT_INVALID_UNIT_ID (0xE0U)
+#define FLCN_ERR_QUEUE_MGMT_HEAP_MIRROR_ERR (0xE1U)
+#define FLCN_ERR_QUEUE_TASK_INVALID_EVENT_TYPE (0xE2U)
+#define FLCN_ERR_QUEUE_TASK_INVALID_UNIT_ID (0xE3U)
+#define FLCN_ERR_QUEUE_TASK_INVALID_CMD_TYPE (0xE4U)
+#define FLCN_ERR_QUEUE_TASK_SLOT_NOT_AVAILABLE (0xE5U)
+
+// Posted write errors
+#define FLCN_ERR_POSTED_WRITE_FAILURE (0xF0U)
+#define FLCN_ERR_POSTED_WRITE_INTERRUPTS_ENABLED (0xF1U)
+#define FLCN_ERR_POSTED_WRITE_PRI_CLUSTER_COUNT_MISMATCH (0xF2U)
+#define FLCN_ERR_POSTED_WRITE_INCORRECT_PARAMS (0xF3U)
+
+// Lane Margining errors
+#define FLCN_ERR_LM_INVALID_RECEIVER_NUMBER (0xF5U)
+
+// APM errors
+#define FLCN_ERR_APM_NOT_FUSED_FOR_EK (0xF6U)
+#define FLCN_ERR_APM_BROM_SIGN_FAIL (0xF7U)
+// Booter Reload on SEC2-RTOS errors
+#define FLCN_ERR_AUTH_GSP_RM_HANDOFF_FAILED (0xF8U)
+#define FLCN_ERR_INVALID_WPRMETA_MAGIC_OR_REVISION (0xF9U)
+
+// Arithmetic errors
+#define FLCN_ERR_ARITHMETIC_OVERFLOW (0xFAU)
+
+// Pri errros
+#define FLCN_ERR_OUTSTANDING_PRI_ERROR (0xFBU)
+
+#endif // FLCNRETVAL_H
diff --git a/userspace/sdks/nv570/nvalloc/common/inc/fsp/fsp_caps_query_rpc.h b/userspace/sdks/nv570/nvalloc/common/inc/fsp/fsp_caps_query_rpc.h
new file mode 100644
index 0000000..dc4f887
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/common/inc/fsp/fsp_caps_query_rpc.h
@@ -0,0 +1,51 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef FSP_CAPS_QUERY_RPC_H
+#define FSP_CAPS_QUERY_RPC_H
+
+#include "fsp/nvdm_payload_cmd_response.h"
+
+#pragma pack(1)
+
+ /*!
+ * @biief Capability query payload command to FSP
+ */
+typedef struct
+{
+ NvU8 subMessageId;
+} FSP_CAPS_QUERY_RPC_PAYLOAD_PARAMS;
+
+/*!
+ * @brief Capability query response payload for FSP capability query
+ */
+typedef struct
+{
+ NvU8 nvdmType;
+ NVDM_PAYLOAD_COMMAND_RESPONSE cmdResponse;
+ NvU8 rspPayload[4];
+} FSP_CAPS_QUERY_RESPONSE_PAYLOAD_PARAMS;
+
+#pragma pack()
+
+#endif // FSP_CAPS_QUERY_RPC_H
diff --git a/userspace/sdks/nv570/nvalloc/common/inc/fsp/fsp_clock_boost_rpc.h b/userspace/sdks/nv570/nvalloc/common/inc/fsp/fsp_clock_boost_rpc.h
new file mode 100644
index 0000000..7564fb6
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/common/inc/fsp/fsp_clock_boost_rpc.h
@@ -0,0 +1,44 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef FSP_CLOCK_BOOST_RPC_H
+#define FSP_CLOCK_BOOST_RPC_H
+
+
+#define FSP_CLOCK_BOOST_FEATURE_DISABLE_SUBMESSAGE_ID 0x0
+#define FSP_CLOCK_BOOST_FEATURE_ENABLE_SUBMESSAGE_ID 0x1
+#define FSP_CLOCK_BOOST_TRIGGER_RESTORE_SUBMESSAGE_ID 0x2
+
+#pragma pack(1)
+
+ /*!
+ * @brief Clock Boost payload command to FSP
+ */
+typedef struct
+{
+ NvU8 subMessageId;
+} FSP_CLOCK_BOOST_RPC_PAYLOAD_PARAMS;
+
+#pragma pack()
+
+#endif // FSP_CLOCK_BOOST_RPC_H
diff --git a/userspace/sdks/nv570/nvalloc/common/inc/fsp/fsp_emem_channels.h b/userspace/sdks/nv570/nvalloc/common/inc/fsp/fsp_emem_channels.h
new file mode 100644
index 0000000..912eeae
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/common/inc/fsp/fsp_emem_channels.h
@@ -0,0 +1,39 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _FSP_EMEM_CHANNELS_H_
+#define _FSP_EMEM_CHANNELS_H_
+
+//
+// NVDM (NVIDIA Data Model) overlayed on MCTP (Management Component Transport
+// Protocol) and sent over EMEM is the communication mechanism used between FSP
+// management partition and CPU-RM/other uprocs.
+//
+
+// RM uses channel 0 for FSP EMEM.
+#define FSP_EMEM_CHANNEL_RM 0x0
+
+// EMEM channel 0 (RM) is allocated 1K bytes.
+#define FSP_EMEM_CHANNEL_RM_SIZE 1024
+
+#endif // _FSP_EMEM_CHANNELS_H_
diff --git a/userspace/sdks/nv570/nvalloc/common/inc/fsp/fsp_tnvl_rpc.h b/userspace/sdks/nv570/nvalloc/common/inc/fsp/fsp_tnvl_rpc.h
new file mode 100644
index 0000000..73e3034
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/common/inc/fsp/fsp_tnvl_rpc.h
@@ -0,0 +1,137 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _FSP_TNVL_RPC_H_
+#define _FSP_TNVL_RPC_H_
+
+#define TNVL_CAPS_SUBMESSAGE_ID 0xFF
+#define TNVL_GET_ATT_CERTS_SUBMESSAGE_ID 0x0
+#define TNVL_GET_ATT_REPORT_SUBMESSAGE_ID 0x1
+#define TNVL_LOCK_CONFIG_SUBMESSAGE_ID 0x2
+
+#define NVSWITCH_IK_HASH_LENGTH (48)
+#define NVSWITCH_ATT_CERT_SIZE_FIELD_LENGTH (2)
+#define NVSWITCH_ATT_RSVD1_FIELD_LENGTH (2)
+
+#pragma pack(1)
+
+ /*!
+ * @brief TNVL payload to query FSP capabilities
+ */
+typedef struct
+{
+ NvU8 subMessageId;
+} TNVL_RPC_CAPS_PAYLOAD;
+
+/*!
+ * @brief TNVL response payload for FSP capability query
+ */
+typedef struct
+{
+ NvU8 nvdmType;
+ NVDM_PAYLOAD_COMMAND_RESPONSE cmdResponse;
+ NvU8 rspPayload[40];
+} TNVL_RPC_CAPS_RSP_PAYLOAD;
+
+ /*!
+ * @brief TNVL payload to query attestation cert chain
+ */
+typedef struct
+{
+ NvU8 subMessageId;
+ NvU8 rsvd;
+ NvU8 minorVersion;
+ NvU8 majorVersion;
+} TNVL_GET_ATT_CERTS_CMD_PAYLOAD;
+
+/*!
+ * @brief TNVL response payload for attestation cert chain
+ */
+typedef struct
+{
+ NvU8 nvdmType;
+ NVDM_PAYLOAD_COMMAND_RESPONSE cmdResponse;
+ NvU8 subMessageId;
+ NvU8 rsvd0;
+ NvU8 minorVersion;
+ NvU8 majorVersion;
+ NvU16 certChainLength;
+ NvU16 rsvd1;
+ NvU8 devIkHash[NVSWITCH_IK_HASH_LENGTH];
+ NvU8 certChain[NVSWITCH_ATTESTATION_CERT_CHAIN_MAX_SIZE];
+} TNVL_GET_ATT_CERTS_RSP_PAYLOAD;
+
+ /*!
+ * @brief TNVL payload to query attestation report
+ */
+typedef struct
+{
+ NvU8 subMessageId;
+ NvU8 rsvd;
+ NvU8 minorVersion;
+ NvU8 majorVersion;
+ NvU8 nonce[NVSWITCH_NONCE_SIZE];
+} TNVL_GET_ATT_REPORT_CMD_PAYLOAD;
+
+/*!
+ * @brief TNVL response payload for attestation report
+ */
+typedef struct
+{
+ NvU8 nvdmType;
+ NVDM_PAYLOAD_COMMAND_RESPONSE cmdResponse;
+ NvU8 subMessageId;
+ NvU8 rsvd0;
+ NvU8 minorVersion;
+ NvU8 majorVersion;
+ NvU32 measurementSize;
+ NvU8 measurementBuffer[NVSWITCH_ATTESTATION_REPORT_MAX_SIZE];
+} TNVL_GET_ATT_REPORT_RSP_PAYLOAD;
+
+/*!
+ * @brief TNVL payload to send lock config
+ */
+typedef struct
+{
+ NvU8 subMessageId;
+ NvU8 rsvd;
+ NvU8 minorVersion;
+ NvU8 majorVersion;
+} TNVL_LOCK_CONFIG_CMD_PAYLOAD;
+
+/*!
+ * @brief TNVL response payload for lock config
+ */
+typedef struct
+{
+ NvU8 nvdmType;
+ NVDM_PAYLOAD_COMMAND_RESPONSE cmdResponse;
+ NvU8 subMessageId;
+ NvU8 rsvd0;
+ NvU8 minorVersion;
+ NvU8 majorVersion;
+} TNVL_LOCK_CONFIG_RSP_PAYLOAD;
+
+#pragma pack()
+
+#endif // _FSP_TNVL_RPC_H_
diff --git a/userspace/sdks/nv570/nvalloc/common/inc/fsp/nvdm_payload_cmd_response.h b/userspace/sdks/nv570/nvalloc/common/inc/fsp/nvdm_payload_cmd_response.h
new file mode 100644
index 0000000..fa117aa
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/common/inc/fsp/nvdm_payload_cmd_response.h
@@ -0,0 +1,44 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/*
+ * @file nvdm_payload_cmd_response.h
+ * @brief Header file containing the definition for the
+ * NVDM_PAYLOAD_COMMAND_RESPONSE structure, which
+ * is required for SMBPBI-specific payloads and needs
+ * to be visible by bothe the PMU and the driver sides.
+ */
+
+#ifndef _NVDM_PAYLOAD_CMD_RESPONSE_H
+#define _NVDM_PAYLOAD_CMD_RESPONSE_H
+
+#pragma pack(1)
+typedef struct
+{
+ NvU32 taskId;
+ NvU32 commandNvdmType;
+ NvU32 errorCode;
+} NVDM_PAYLOAD_COMMAND_RESPONSE;
+#pragma pack()
+
+#endif // _NVDM_PAYLOAD_CMD_RESPONSE_H
diff --git a/userspace/sdks/nv570/nvalloc/common/inc/gsp/gsp_fmc_error_code_formatting.h b/userspace/sdks/nv570/nvalloc/common/inc/gsp/gsp_fmc_error_code_formatting.h
new file mode 100644
index 0000000..2f0a51b
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/common/inc/gsp/gsp_fmc_error_code_formatting.h
@@ -0,0 +1,79 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef GSP_FMC_ERROR_CODES_FORMATTING_H
+#define GSP_FMC_ERROR_CODES_FORMATTING_H
+
+//================================================================================
+// DRF Field Definitions for NV_PBUS_SW_SCRATCH_GSP_FMC_ERROR
+// These define the bit ranges for the register fields.
+//================================================================================
+
+// Error code layout
+#define NV_PBUS_SW_SCRATCH_GSP_FMC_ERROR_VARIANT 31:28
+#define NV_PBUS_SW_SCRATCH_GSP_FMC_ERROR_PARTITION 27:24
+#define NV_PBUS_SW_SCRATCH_GSP_FMC_ERROR_PAYLOAD 23:0
+
+// Fields within the PAYLOAD for Variant 0 (SK)
+#define NV_PBUS_SW_SCRATCH_GSP_FMC_ERROR_SK_ERROR 15:8
+#define NV_PBUS_SW_SCRATCH_GSP_FMC_ERROR_SK_PHASE 7:0
+
+// Fields within the PAYLOAD for Variant 1 (Generic)
+#define NV_PBUS_SW_SCRATCH_GSP_FMC_ERROR_GENERIC_ADDITIONAL_INFO 23:16
+#define NV_PBUS_SW_SCRATCH_GSP_FMC_ERROR_GENERIC_ERROR_CODE 15:0
+
+// Error code layout for safety
+#define NV_PBUS_SW_SCRATCH_GSP_FMC_ERROR_VARIANT_XMSB 31
+#define NV_PBUS_SW_SCRATCH_GSP_FMC_ERROR_VARIANT_XLSB 28
+#define NV_PBUS_SW_SCRATCH_GSP_FMC_ERROR_PARTITION_XMSB 27
+#define NV_PBUS_SW_SCRATCH_GSP_FMC_ERROR_PARTITION_XLSB 24
+#define NV_PBUS_SW_SCRATCH_GSP_FMC_ERROR_PAYLOAD_XMSB 23
+#define NV_PBUS_SW_SCRATCH_GSP_FMC_ERROR_PAYLOAD_XLSB 0
+
+// Fields within the PAYLOAD for Variant 0 (SK) for safety
+#define NV_PBUS_SW_SCRATCH_GSP_FMC_ERROR_SK_ERROR_XMSB 15
+#define NV_PBUS_SW_SCRATCH_GSP_FMC_ERROR_SK_ERROR_XLSB 8
+
+#define NV_PBUS_SW_SCRATCH_GSP_FMC_ERROR_SK_PHASE_XMSB 7
+#define NV_PBUS_SW_SCRATCH_GSP_FMC_ERROR_SK_PHASE_XLSB 0
+
+// Fields within the PAYLOAD for Variant 1 (Generic) for safety
+#define NV_PBUS_SW_SCRATCH_GSP_FMC_ERROR_GENERIC_ADDITIONAL_INFO_XMSB 23
+#define NV_PBUS_SW_SCRATCH_GSP_FMC_ERROR_GENERIC_ADDITIONAL_INFO_XLSB 16
+
+#define NV_PBUS_SW_SCRATCH_GSP_FMC_ERROR_GENERIC_ERROR_CODE_XMSB 15
+#define NV_PBUS_SW_SCRATCH_GSP_FMC_ERROR_GENERIC_ERROR_CODE_XLSB 0
+
+//================================================================================
+// Constant Values
+//================================================================================
+
+// Partition ID Encoding Logic
+#define GSP_FMC_PARTITION_ID_MASK 0xFU
+#define GSP_FMC_PARTITION_ID_OFFSET 1U
+
+// Error Variants / Versions
+#define GSP_FMC_ERROR_VARIANT_SK 0U
+#define GSP_FMC_ERROR_VARIANT_GENERIC 1U
+
+#endif /* GSP_FMC_ERROR_CODES_FORMATTING_H */
diff --git a/userspace/sdks/nv570/nvalloc/common/inc/gsp/gsp_fw_sr_meta.h b/userspace/sdks/nv570/nvalloc/common/inc/gsp/gsp_fw_sr_meta.h
new file mode 100644
index 0000000..22a0ef7
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/common/inc/gsp/gsp_fw_sr_meta.h
@@ -0,0 +1,74 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#pragma once
+
+#ifndef GSP_FW_SR_META_H_
+#define GSP_FW_SR_META_H_
+
+#define GSP_FW_SR_META_MAGIC 0x8a3bb9e6c6c39d93ULL
+#define GSP_FW_SR_META_REVISION 2
+
+#define GSP_FW_SR_META_INTERNAL_SIZE 128
+
+/*!
+ * GSP firmware SR metadata
+ *
+ * Initialized by CPU-RM and kept in Sysmem.
+ * Consumed by secure ucode (Booter or ACR_RISCV).
+ */
+typedef struct
+{
+ // Magic for verification by secure ucode
+ NvU64 magic; // = GSP_FW_SR_META_MAGIC;
+
+ //
+ // Revision number
+ // Bumped up when we change this interface so it is not backward compatible.
+ //
+ NvU64 revision; // = GSP_FW_SR_META_MAGIC_REVISION;
+
+ // Members regarding data in SYSMEM
+ NvU64 sysmemAddrOfSuspendResumeData;
+ NvU64 sizeOfSuspendResumeData;
+
+ //
+ // Internal members for use by secure ucode
+ // Must be exactly GSP_FW_SR_META_INTERNAL_SIZE bytes.
+ //
+ NvU32 internal[32];
+
+ // Same as flags of GspFwWprMeta
+ NvU32 flags;
+
+ // Subrevision number used by secure ucode
+ NvU32 subrevision;
+
+ //
+ // Pad structure to exactly 256 bytes (1 DMA chunk).
+ // Padding initialized to zero.
+ //
+ NvU32 padding[22];
+} GspFwSRMeta;
+
+#endif // GSP_FW_SR_META_H_
diff --git a/userspace/sdks/nv570/nvalloc/common/inc/gsp/gsp_fw_wpr_meta.h b/userspace/sdks/nv570/nvalloc/common/inc/gsp/gsp_fw_wpr_meta.h
new file mode 100644
index 0000000..35293d1
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/common/inc/gsp/gsp_fw_wpr_meta.h
@@ -0,0 +1,242 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2021-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#pragma once
+
+#ifndef GSP_FW_WPR_META_H_
+#define GSP_FW_WPR_META_H_
+
+/*!
+ * GSP firmware WPR metadata
+ *
+ * Initialized by CPU-RM and DMA'd to FB, at the end of what will be WPR2.
+ * Verified, and locked in WPR2 by Booter.
+ *
+ * Firmware scrubs the last 256mb of FB, no memory outside of this region
+ * may be used until the FW RM has scrubbed the remainder of memory.
+ *
+ * ---------------------------- <- fbSize (end of FB, 1M aligned)
+ * | VGA WORKSPACE |
+ * ---------------------------- <- vbiosReservedOffset (64K? aligned)
+ * | (potential align. gap) |
+ * ---------------------------- <- gspFwWprEnd + frtsSize + pmuReservedSize
+ * | PMU mem reservation |
+ * ---------------------------- <- gspFwWprEnd (128K aligned) + frtsSize
+ * | FRTS data | (frtsSize is 0 on GA100)
+ * | ------------------------ | <- frtsOffset
+ * | BOOT BIN (e.g. SK + BL) |
+ * ---------------------------- <- bootBinOffset
+ * | GSP FW ELF |
+ * ---------------------------- <- gspFwOffset
+ * | GSP FW (WPR) HEAP |
+ * ---------------------------- <- gspFwHeapOffset
+ * | Booter-placed metadata |
+ * | (struct GspFwWprMeta) |
+ * ---------------------------- <- gspFwWprStart (128K aligned)
+ * | GSP FW (non-WPR) HEAP |
+ * ---------------------------- <- nonWprHeapOffset, gspFwRsvdStart
+ * (GSP_CARVEOUT_SIZE bytes from end of FB)
+ */
+typedef struct
+{
+ // Magic
+ // BL to use for verification (i.e. Booter locked it in WPR2)
+ NvU64 magic; // = 0xdc3aae21371a60b3;
+
+ // Revision number of Booter-BL-Sequencer handoff interface
+ // Bumped up when we change this interface so it is not backward compatible.
+ // Bumped up when we revoke GSP-RM ucode
+ NvU64 revision; // = 1;
+
+ // ---- Members regarding data in SYSMEM ----------------------------
+ // Consumed by Booter for DMA
+
+ NvU64 sysmemAddrOfRadix3Elf;
+ NvU64 sizeOfRadix3Elf;
+
+ NvU64 sysmemAddrOfBootloader;
+ NvU64 sizeOfBootloader;
+
+ // Offsets inside bootloader image needed by Booter
+ NvU64 bootloaderCodeOffset;
+ NvU64 bootloaderDataOffset;
+ NvU64 bootloaderManifestOffset;
+
+ union
+ {
+ // Used only at initial boot
+ struct
+ {
+ NvU64 sysmemAddrOfSignature;
+ NvU64 sizeOfSignature;
+ };
+
+ //
+ // Used at suspend/resume to read GspFwHeapFreeList
+ // Offset relative to GspFwWprMeta FBMEM PA (gspFwWprStart)
+ //
+ struct
+ {
+ NvU32 gspFwHeapFreeListWprOffset;
+ NvU32 unused0;
+ NvU64 unused1;
+ };
+ };
+
+ // ---- Members describing FB layout --------------------------------
+ NvU64 gspFwRsvdStart;
+
+ NvU64 nonWprHeapOffset;
+ NvU64 nonWprHeapSize;
+
+ NvU64 gspFwWprStart;
+
+ // GSP-RM to use to setup heap.
+ NvU64 gspFwHeapOffset;
+ NvU64 gspFwHeapSize;
+
+ // BL to use to find ELF for jump
+ NvU64 gspFwOffset;
+ // Size is sizeOfRadix3Elf above.
+
+ NvU64 bootBinOffset;
+ // Size is sizeOfBootloader above.
+
+ NvU64 frtsOffset;
+ NvU64 frtsSize;
+
+ NvU64 gspFwWprEnd;
+
+ // GSP-RM to use for fbRegionInfo?
+ NvU64 fbSize;
+
+ // ---- Other members -----------------------------------------------
+
+ // GSP-RM to use for fbRegionInfo?
+ NvU64 vgaWorkspaceOffset;
+ NvU64 vgaWorkspaceSize;
+
+ // Boot count. Used to determine whether to load the firmware image.
+ NvU64 bootCount;
+
+ // This union is organized the way it is to start at an 8-byte boundary and achieve natural
+ // packing of the internal struct fields.
+ union
+ {
+ struct
+ {
+ // TODO: the partitionRpc* fields below do not really belong in this
+ // structure. The values are patched in by the partition bootstrapper
+ // when GSP-RM is booted in a partition, and this structure was a
+ // convenient place for the bootstrapper to access them. These should
+ // be moved to a different comm. mechanism between the bootstrapper
+ // and the GSP-RM tasks.
+
+ // Shared partition RPC memory (physical address)
+ NvU64 partitionRpcAddr;
+
+ // Offsets relative to partitionRpcAddr
+ NvU16 partitionRpcRequestOffset;
+ NvU16 partitionRpcReplyOffset;
+
+ // Code section and dataSection offset and size.
+ NvU32 elfCodeOffset;
+ NvU32 elfDataOffset;
+ NvU32 elfCodeSize;
+ NvU32 elfDataSize;
+
+ // Used during GSP-RM resume to check for revocation
+ NvU32 lsUcodeVersion;
+ };
+
+ struct
+ {
+ // Pad for the partitionRpc* fields, plus 4 bytes
+ NvU32 partitionRpcPadding[4];
+
+ // CrashCat (contiguous) buffer size/location - occupies same bytes as the
+ // elf(Code|Data)(Offset|Size) fields above.
+ // TODO: move to GSP_FMC_INIT_PARAMS
+ NvU64 sysmemAddrOfCrashReportQueue;
+ NvU32 sizeOfCrashReportQueue;
+
+ // Pad for the lsUcodeVersion field
+ NvU32 lsUcodeVersionPadding[1];
+ };
+ };
+
+ // Number of VF partitions allocating sub-heaps from the WPR heap
+ // Used during boot to ensure the heap is adequately sized
+ NvU8 gspFwHeapVfPartitionCount;
+
+ // Flags to help decide GSP-FW flow.
+ NvU8 flags;
+
+ // Pad structure to exactly 256 bytes. Can replace padding with additional
+ // fields without incrementing revision. Padding initialized to 0.
+ NvU8 padding[2];
+
+ //
+ // Starts at gspFwWprEnd+frtsSize b/c FRTS is positioned
+ // to end where this allocation starts (when RM requests FSP to create
+ // FRTS).
+ //
+ NvU32 pmuReservedSize;
+
+ // BL to use for verification (i.e. Booter says OK to boot)
+ NvU64 verified; // 0x0 -> unverified, 0xa0a0a0a0a0a0a0a0 -> verified
+} GspFwWprMeta;
+
+#define GSP_FW_WPR_META_VERIFIED 0xa0a0a0a0a0a0a0a0ULL
+#define GSP_FW_WPR_META_REVISION 1
+#define GSP_FW_WPR_META_MAGIC 0xdc3aae21371a60b3ULL
+
+#define GSP_FW_WPR_HEAP_FREE_REGION_COUNT 128
+
+typedef struct
+{
+ //
+ // offset relative to GspFwWprMeta FBMEM PA
+ // describes a region at [offs, offs + length)
+ //
+ NvU32 offs; // start, inclusive
+ NvU32 length;
+} GspFwHeapFreeRegion;
+
+typedef struct
+{
+ NvU64 magic;
+ NvU32 nregions;
+ GspFwHeapFreeRegion regions[GSP_FW_WPR_HEAP_FREE_REGION_COUNT];
+} GspFwHeapFreeList;
+
+#define GSP_FW_HEAP_FREE_LIST_MAGIC 0x4845415046524545ULL
+
+#define GSP_FW_FLAGS 8:0
+#define GSP_FW_FLAGS_CLOCK_BOOST NVBIT(0)
+#define GSP_FW_FLAGS_RECOVERY_MARGIN_PRESENT NVBIT(1)
+#define GSP_FW_FLAGS_PPCIE_ENABLED NVBIT(2)
+#define GSP_FW_FLAGS_MULTI_GPU_NVLE_ENABLED NVBIT(3)
+#define GSP_FW_FLAGS_SCAN_RECOVERY_MARGIN NVBIT(4)
+
+#endif // GSP_FW_WPR_META_H_
diff --git a/userspace/sdks/nv570/nvalloc/common/inc/gsp/gsp_proxy_reg.h b/userspace/sdks/nv570/nvalloc/common/inc/gsp/gsp_proxy_reg.h
new file mode 100644
index 0000000..28aad84
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/common/inc/gsp/gsp_proxy_reg.h
@@ -0,0 +1,83 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2021-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef NVGSP_PROXY_REG_H
+#define NVGSP_PROXY_REG_H
+
+#if !defined(NVRISCV_LIBFSP_BUILD) || !NVRISCV_LIBFSP_BUILD
+
+#define NVGSP_PROXY_REG_CONFIDENTIAL_COMPUTE 0:0
+#define NVGSP_PROXY_REG_CONFIDENTIAL_COMPUTE_DISABLE 0x00000000
+#define NVGSP_PROXY_REG_CONFIDENTIAL_COMPUTE_ENABLE 0x00000001
+
+#define NVGSP_PROXY_REG_CONF_COMPUTE_EARLY_INIT 1:1
+#define NVGSP_PROXY_REG_CONF_COMPUTE_EARLY_INIT_DISABLE 0x00000000
+#define NVGSP_PROXY_REG_CONF_COMPUTE_EARLY_INIT_ENABLE 0x00000001
+
+#define NVGSP_PROXY_REG_CONF_COMPUTE_DEV_MODE 2:2
+#define NVGSP_PROXY_REG_CONF_COMPUTE_DEV_MODE_DISABLE 0x00000000
+#define NVGSP_PROXY_REG_CONF_COMPUTE_DEV_MODE_ENABLE 0x00000001
+
+#define NVGSP_PROXY_REG_CONF_COMPUTE_MULTI_GPU_MODE 5:3
+#define NVGSP_PROXY_REG_CONF_COMPUTE_MULTI_GPU_MODE_NONE 0x00000000
+#define NVGSP_PROXY_REG_CONF_COMPUTE_MULTI_GPU_MODE_PROTECTED_PCIE 0x00000001
+#define NVGSP_PROXY_REG_CONF_COMPUTE_MULTI_GPU_MODE_NVLE 0x00000002
+
+#define NVGSP_PROXY_REG_NVLINK_ENCRYPTION 6:6
+#define NVGSP_PROXY_REG_NVLINK_ENCRYPTION_DISABLE 0x00000000
+#define NVGSP_PROXY_REG_NVLINK_ENCRYPTION_ENABLE 0x00000001
+
+#else
+#define NVGSP_PROXY_REG_CONFIDENTIAL_COMPUTE 0U:0U
+#define NVGSP_PROXY_REG_CONFIDENTIAL_COMPUTE_XLSB 0U
+#define NVGSP_PROXY_REG_CONFIDENTIAL_COMPUTE_XMSB 0U
+#define NVGSP_PROXY_REG_CONFIDENTIAL_COMPUTE_DISABLE 0x00000000U
+#define NVGSP_PROXY_REG_CONFIDENTIAL_COMPUTE_ENABLE 0x00000001U
+
+#define NVGSP_PROXY_REG_CONF_COMPUTE_EARLY_INIT 1U:1U
+#define NVGSP_PROXY_REG_CONF_COMPUTE_EARLY_INIT_XLSB 1U
+#define NVGSP_PROXY_REG_CONF_COMPUTE_EARLY_INIT_XMSB 1U
+#define NVGSP_PROXY_REG_CONF_COMPUTE_EARLY_INIT_DISABLE 0x00000000U
+#define NVGSP_PROXY_REG_CONF_COMPUTE_EARLY_INIT_ENABLE 0x00000001U
+
+#define NVGSP_PROXY_REG_CONF_COMPUTE_DEV_MODE 2U:2U
+#define NVGSP_PROXY_REG_CONF_COMPUTE_DEV_MODE_XLSB 2U
+#define NVGSP_PROXY_REG_CONF_COMPUTE_DEV_MODE_XMSB 2U
+#define NVGSP_PROXY_REG_CONF_COMPUTE_DEV_MODE_DISABLE 0x00000000U
+#define NVGSP_PROXY_REG_CONF_COMPUTE_DEV_MODE_ENABLE 0x00000001U
+
+#define NVGSP_PROXY_REG_CONF_COMPUTE_MULTI_GPU_MODE 5U:3U
+#define NVGSP_PROXY_REG_CONF_COMPUTE_MULTI_GPU_MODE_XLSB 3U
+#define NVGSP_PROXY_REG_CONF_COMPUTE_MULTI_GPU_MODE_XMSB 5U
+#define NVGSP_PROXY_REG_CONF_COMPUTE_MULTI_GPU_MODE_NONE 0x00000000U
+#define NVGSP_PROXY_REG_CONF_COMPUTE_MULTI_GPU_MODE_PROTECTED_PCIE 0x00000001U
+#define NVGSP_PROXY_REG_CONF_COMPUTE_MULTI_GPU_MODE_NVLE 0x00000002U
+
+#define NVGSP_PROXY_REG_NVLINK_ENCRYPTION 6U:6U
+#define NVGSP_PROXY_REG_NVLINK_ENCRYPTION_XLSB 6U
+#define NVGSP_PROXY_REG_NVLINK_ENCRYPTION_XMSB 6U
+#define NVGSP_PROXY_REG_NVLINK_ENCRYPTION_DISABLE 0x00000000U
+#define NVGSP_PROXY_REG_NVLINK_ENCRYPTION_ENABLE 0x00000001U
+
+#endif // !defined(NVRISCV_LIBFSP_BUILD) || !NVRISCV_LIBFSP_BUILD
+#endif // NVGSP_PROXY_REG_H
diff --git a/userspace/sdks/nv570/nvalloc/common/inc/gsp/gspifpub.h b/userspace/sdks/nv570/nvalloc/common/inc/gsp/gspifpub.h
new file mode 100644
index 0000000..b366a9d
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/common/inc/gsp/gspifpub.h
@@ -0,0 +1,181 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2021-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef GSPIFPUB_H
+#define GSPIFPUB_H
+
+#include <nvtypes.h>
+
+/*!
+ * @file gspifpub.h
+ * @brief GSP Command/Message Interfaces - Published
+ */
+
+/*!
+ * Target physical memory apertures supported for DMA
+ */
+typedef enum {
+ GSP_DMA_TARGET_LOCAL_FB,
+ GSP_DMA_TARGET_COHERENT_SYSTEM,
+ GSP_DMA_TARGET_NONCOHERENT_SYSTEM,
+ GSP_DMA_TARGET_COUNT
+} GSP_DMA_TARGET;
+
+/*!
+ * @brief GSP-CC Microcode Initialization Parameters
+ */
+typedef struct GSP_FMC_INIT_PARAMS
+{
+ // CC initialization "registry keys"
+ NvU32 regkeys;
+} GSP_FMC_INIT_PARAMS;
+
+/*!
+ * @brief GSP-ACR BOOT_GSP_RM Command Parameters
+ *
+ * The wprCarveout fields have no effect in environments where the WPR can be allocated
+ * implicitly by ACR.
+ */
+typedef struct GSP_ACR_BOOT_GSP_RM_PARAMS
+{
+ // Physical memory aperture through which gspRmDescPa is accessed
+ GSP_DMA_TARGET target;
+ // Size in bytes of the GSP-RM descriptor structure
+ NvU32 gspRmDescSize;
+ // Physical offset in the target aperture of the GSP-RM descriptor structure
+ NvU64 gspRmDescOffset;
+ // Physical offset in FB to set the start of the WPR containing GSP-RM
+ NvU64 wprCarveoutOffset;
+ // Size in bytes of the WPR containing GSP-RM
+ NvU32 wprCarveoutSize;
+ // Whether to boot GSP-RM or GSP-Proxy through ACR
+ NvBool bIsGspRmBoot;
+ // Whether inst-in-sys mode is enabled or not
+ NvBool bInstInSysMode;
+} GSP_ACR_BOOT_GSP_RM_PARAMS;
+
+/*!
+ * @brief GSP-RM Parameters
+ */
+typedef struct GSP_RM_PARAMS
+{
+ // Physical memory aperture through which bootArgsOffset is accessed
+ GSP_DMA_TARGET target;
+ // Physical offset in the memory aperture that will be passed to GSP-RM
+ NvU64 bootArgsOffset;
+} GSP_RM_PARAMS;
+
+/*!
+ * @brief GSP-SPDM Parameters
+ *
+ * Parameters required to set up a communication mechanism between Kernel-RM
+ * and SPDM partition inside GSP.
+ */
+typedef struct GSP_SPDM_PARAMS
+{
+ // Physical Memory Aperture through which all addresses are accessed
+ GSP_DMA_TARGET target;
+
+ // Physical offset in the memory aperture where SPDM payload is stored
+ NvU64 payloadBufferOffset;
+
+ // Size of the above payload buffer
+ NvU32 payloadBufferSize;
+} GSP_SPDM_PARAMS;
+
+typedef struct GSP_RM_MEM_PARAMS
+{
+ NvU32 flushSysmemAddrValLo;
+ NvU32 flushSysmemAddrValHi;
+} GSP_RM_MEM_PARAMS;
+
+/*!
+ * @brief GSP-CC Microcode Parameters for Boot Partitions
+ */
+typedef struct GSP_FMC_BOOT_PARAMS
+{
+ GSP_FMC_INIT_PARAMS initParams;
+ GSP_ACR_BOOT_GSP_RM_PARAMS bootGspRmParams;
+ GSP_RM_PARAMS gspRmParams;
+ GSP_SPDM_PARAMS gspSpdmParams;
+ GSP_RM_MEM_PARAMS gspRmMemParams;
+} GSP_FMC_BOOT_PARAMS;
+
+/*!
+ * @brief Inform KeyMgr about which slots needs to be refreshed
+ */
+typedef enum {
+ //
+ // KeyMgr will program the received rotated session key in spare (the once which is not being used for
+ // current crypto flow) Rx key slot of all ports
+ //
+ refreshRxKeySlot,
+ //
+ // KeyMgr will program the received rotated session key in Tx key slot of all ports and flip the epoch
+ // to start using new session key for crypto flow
+ //
+ refreshTxKeySlot
+} sessionKeyRefreshStage;
+
+/*!
+ * @brief Definitions for messages to GSP which will convey NVLE programming keys
+ */
+#define RM_GSP_NVLE_CMD_ID_UPDATE_SESSION_KEYS (0x80)
+#define RM_GSP_NVLE_CMD_ID_REFRESH_SESSION_KEYS (0x81)
+#define RM_GSP_NVLE_SESSION_KEY_ENTRY_SET_COUNT (1)
+#define RM_GSP_NVLE_AES_256_GCM_KEY_SIZE_BYTES (32)
+#define RM_GSP_NVLE_AES_256_GCM_KEY_SIZE_DWORDS (RM_GSP_NVLE_AES_256_GCM_KEY_SIZE_BYTES / sizeof(NvU32))
+#define RM_GSP_NVLE_CMD_TAG_SIZE_BYTES (16)
+#define RM_GSP_NVLE_CMD_TAG_SIZE_DWORDS (RM_GSP_NVLE_CMD_TAG_SIZE_BYTES / sizeof(NvU32))
+
+typedef struct
+{
+ NvU32 remoteGpuClid;
+ NvU32 remoteGpuAlid;
+ NvU32 key[RM_GSP_NVLE_AES_256_GCM_KEY_SIZE_DWORDS];
+ //
+ // Epoch will inform which keyslot<0,1> is spare in case of refreshRxKeySlot stage and the epoch to which
+ // the Tx key slot needs to switch to in case of refreshTxKeySlot stage. Epoch is provided only when
+ // keyslot needs to be refreshed and keymgr will implicitly use epoch = 0 during setup stage
+ //
+ NvU8 epoch;
+ NvBool bValid;
+} RM_GSP_NVLE_SESSION_KEY_ENTRY;
+
+typedef struct
+{
+ NvU32 cmdId;
+ NvBool bForKeyRotation; // To be deprecated
+ RM_GSP_NVLE_SESSION_KEY_ENTRY wrappedKeyEntries[RM_GSP_NVLE_SESSION_KEY_ENTRY_SET_COUNT];
+ NvU32 keyEntriesTag[RM_GSP_NVLE_CMD_TAG_SIZE_DWORDS];
+} RM_GSP_NVLE_UPDATE_SESSION_KEYS;
+
+typedef struct
+{
+ NvU32 cmdId;
+ sessionKeyRefreshStage stage; // Inform KeyMgr about which slots needs to be programmmed
+ RM_GSP_NVLE_SESSION_KEY_ENTRY wrappedKeyEntries[RM_GSP_NVLE_SESSION_KEY_ENTRY_SET_COUNT];
+ NvU32 keyEntriesTag[RM_GSP_NVLE_CMD_TAG_SIZE_DWORDS];
+} RM_GSP_NVLE_REFRESH_SESSION_KEYS;
+
+#endif // GSPIFPUB_H
diff --git a/userspace/sdks/nv570/nvalloc/common/inc/inforom/ifrdem.h b/userspace/sdks/nv570/nvalloc/common/inc/inforom/ifrdem.h
new file mode 100644
index 0000000..26395e8
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/common/inc/inforom/ifrdem.h
@@ -0,0 +1,43 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) <year> NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _IFR_DEM_H_
+#define _IFR_DEM_H_
+
+#define INFOROM_DEM_OBJECT_V1_00_PACKED_SIZE 4144
+#define INFOROM_DEM_OBJECT_V1_00_FIFO_SIZE 4096
+
+struct INFOROM_DEM_OBJECT_V1_00
+{
+ INFOROM_OBJECT_HEADER_V1_00 header;
+ inforom_U032 seqNumber;
+ inforom_U016 writeOffset;
+ inforom_U016 readOffset;
+ inforom_X008 fifoBuffer[INFOROM_DEM_OBJECT_V1_00_FIFO_SIZE];
+ inforom_U032 reserved[8];
+};
+
+#define INFOROM_DEM_OBJECT_V1_00_FMT INFOROM_OBJECT_HEADER_V1_00_FMT "d2w4096x8d"
+typedef struct INFOROM_DEM_OBJECT_V1_00 INFOROM_DEM_OBJECT_V1_00;
+
+#endif // _IFR_DEM_H_
diff --git a/userspace/sdks/nv570/nvalloc/common/inc/inforom/ifrecc.h b/userspace/sdks/nv570/nvalloc/common/inc/inforom/ifrecc.h
new file mode 100644
index 0000000..309b47a
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/common/inc/inforom/ifrecc.h
@@ -0,0 +1,119 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2017-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _IFRECC_H_
+#define _IFRECC_H_
+
+#include "nvtypes.h"
+#include "inforom/types.h"
+
+// NVSwitch ECC v6 object definition
+#define INFOROM_ECC_OBJECT_V6_S0_PACKED_SIZE 3808
+
+//Used to determine if the entry is empty or not
+#define NV_INFOROM_ECC_OBJECT_V6_S0_ERROR_COUNTER_HEADER_VALID 0:0
+#define NV_INFOROM_ECC_OBJECT_V6_S0_ERROR_COUNTER_HEADER_VALID_FALSE 0
+#define NV_INFOROM_ECC_OBJECT_V6_S0_ERROR_COUNTER_HEADER_VALID_TRUE 1
+#define NV_INFOROM_ECC_OBJECT_V6_S0_ERROR_COUNTER_HEADER_CORRUPT_TIMEDATA 1:1
+#define NV_INFOROM_ECC_OBJECT_V6_S0_ERROR_COUNTER_HEADER_CORRUPT_TIMEDATA_FALSE 0
+#define NV_INFOROM_ECC_OBJECT_V6_S0_ERROR_COUNTER_HEADER_CORRUPT_TIMEDATA_TRUE 1
+#define NV_INFOROM_ECC_OBJECT_V6_S0_ERROR_COUNTER_HEADER_ADDR_VALID 2:2
+#define NV_INFOROM_ECC_OBJECT_V6_S0_ERROR_COUNTER_HEADER_ADDR_VALID_FALSE 0
+#define NV_INFOROM_ECC_OBJECT_V6_S0_ERROR_COUNTER_HEADER_ADDR_VALID_TRUE 1
+
+#define NV_INFOROM_ECC_OBJECT_V6_S0_ERROR_COUNTER_LOCATION_LINK_ID 7:0
+
+typedef struct INFOROM_ECC_OBJECT_V6_S0_ERROR_COUNTER
+{
+ inforom_U008 header;
+ inforom_U032 errId;
+ inforom_U032 lastErrorTimestamp;
+ inforom_U032 averageEventDelta;
+ inforom_U016 location;
+ inforom_U016 sublocation;
+ inforom_U032 correctedCount;
+ inforom_U032 uncorrectedCount;
+ inforom_U032 address;
+
+} INFOROM_ECC_OBJECT_V6_S0_ERROR_COUNTER;
+
+#define INFOROM_ECC_OBJECT_V6_S0_ERROR_COUNTER_MAX_COUNT 128
+
+typedef struct INFOROM_ECC_OBJECT_V6_S0
+{
+ INFOROM_OBJECT_HEADER_V1_00 header;
+
+ NvU64_ALIGN32 uncorrectedTotal;
+ NvU64_ALIGN32 correctedTotal;
+ inforom_U032 lastClearedTimestamp;
+
+ INFOROM_ECC_OBJECT_V6_S0_ERROR_COUNTER errorEntries[INFOROM_ECC_OBJECT_V6_S0_ERROR_COUNTER_MAX_COUNT];
+
+ inforom_U008 padding[68];
+} INFOROM_ECC_OBJECT_V6_S0;
+
+#define INFOROM_ECC_OBJECT_V6_S0_HEADER_FMT INFOROM_OBJECT_HEADER_V1_00_FMT
+
+#define INFOROM_ECC_OBJECT_V6_S0_ERROR_COUNTER_FMT "b3d2w3d"
+
+#define INFOROM_ECC_OBJECT_V6_S0_ERROR_COUNTER_ARRAY_FMT \
+ INFOROM_FMT_REP128(INFOROM_ECC_OBJECT_V6_S0_ERROR_COUNTER_FMT)
+
+#define INFOROM_ECC_OBJECT_V6_S0_PADDING_FMT "68b"
+
+#define INFOROM_ECC_OBJECT_V6_S0_FMT INFOROM_ECC_OBJECT_V6_S0_HEADER_FMT "qqd" \
+ INFOROM_ECC_OBJECT_V6_S0_ERROR_COUNTER_ARRAY_FMT \
+ INFOROM_ECC_OBJECT_V6_S0_PADDING_FMT
+
+// Error event structure for NVSwitch ECC errors
+typedef struct
+{
+ NvU32 sxid;
+ NvU32 linkId;
+ NvBool bAddressValid;
+ NvU32 address;
+
+ // The timestamp is filled in by the inforom ECC error logging API
+ NvU32 timestamp;
+
+ NvBool bUncErr;
+ NvU32 errorCount;
+} INFOROM_NVS_ECC_ERROR_EVENT;
+
+typedef union
+{
+ INFOROM_OBJECT_HEADER_V1_00 header;
+ INFOROM_ECC_OBJECT_V6_S0 v6s;
+} INFOROM_ECC_OBJECT;
+
+typedef struct
+{
+ const char *pFmt;
+ NvU8 *pPackedObject;
+ INFOROM_ECC_OBJECT *pEcc;
+
+ // Signals if there are pending updates to be flushed to InfoROM
+ NvBool bDirty;
+} INFOROM_ECC_STATE, *PINFOROM_ECC_STATE;
+
+#endif // _IFRECC_H_
diff --git a/userspace/sdks/nv570/nvalloc/common/inc/inforom/ifrnvl.h b/userspace/sdks/nv570/nvalloc/common/inc/inforom/ifrnvl.h
new file mode 100644
index 0000000..f09740d
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/common/inc/inforom/ifrnvl.h
@@ -0,0 +1,1561 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2017-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _IFRNVL_H_
+#define _IFRNVL_H_
+
+//
+// NVL - NVLINK Configuration and Error Data
+//
+
+// Link Remote Endpoint Type
+typedef enum
+{
+ INFOROM_NVLINK_REMOTE_TYPE_UNSUPPORTED = -1,
+ INFOROM_NVLINK_REMOTE_TYPE_NONE = 0,
+ INFOROM_NVLINK_REMOTE_TYPE_PEER = 1,
+ INFOROM_NVLINK_REMOTE_TYPE_SYSTEM = 2,
+ INFOROM_NVLINK_REMOTE_TYPE_SWITCH = 3,
+ INFOROM_NVLINK_REMOTE_TYPE_MAX = 3,
+ INFOROM_NVLINK_NUM_REMOTE_TYPES = 4
+} INFOROM_NVLINK_REMOTE_TYPE;
+
+// Fatal Errors
+typedef enum
+{
+ INFOROM_NVLINK_FATAL_ERR_TYPE_UNSUPPORTED = -1,
+
+ //
+ // NVLink 1.0
+ //
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TL_RX_DL_DATA_PARITY = 0,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TL_RX_DL_CTRL_PARITY = 1,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TL_RX_PROTOCOL = 2,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TL_RX_OVERFLOW = 3,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TL_RX_RAM_DATA_PARITY = 4,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TL_RX_RAM_HDR_PARITY = 5,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TL_RX_RESP = 6,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TL_RX_POISON = 7,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TL_TX_RAM_DATA_PARITY = 8,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TL_TX_RAM_HDR_PARITY = 9,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TL_TX_CREDIT = 10,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TL_DL_FLOW_CTRL_PARITY = 11,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TL_DL_HDR_PARITY = 12,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_DL_TX_RECOVERY_LONG = 13,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_DL_TX_FAULT_RAM = 14,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_DL_TX_FAULT_INTERFACE = 15,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_DL_TX_FAULT_SUBLINK_CHANGE = 16,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_DL_RX_FAULT_SUBLINK_CHANGE = 17,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_DL_RX_FAULT_DL_PROTOCOL = 18,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_DL_LTSSM_FAULT = 19,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_MAX_V1 = 19,
+ INFOROM_NVLINK_NUM_V1_FATAL_ERR_TYPES = 20,
+
+ //
+ // NVLink 2.0
+ //
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_DL_DATA_PARITY = 0,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_DL_CTRL_PARITY = 1,
+ // No direct equivalent to: _TL_RX_PROTOCOL = 2,
+ // No direct equivalent to: _TL_RX_OVERFLOW = 3,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_RAM_DATA_PARITY = 4,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_RAM_HDR_PARITY = 5,
+ // No direct equivalent to: _TL_RX_RESP = 6,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_DATA_POISONED_PKT_RCVD = 7,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_TX_RAM_DATA_PARITY = 8,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_TX_RAM_HDR_PARITY = 9,
+ // No direct equivalent to: _TL_TX_CREDIT = 10,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_TX_DL_FLOW_CONTROL_PARITY = 11,
+ // No direct equivalent to: _TL_DL_HDR_PARITY = 12,
+ // Identical to NVLink 1.0: _DL_TX_RECOVERY_LONG = 13,
+ // Identical to NVLink 1.0: _DL_TX_FAULT_RAM = 14,
+ // Identical to NVLink 1.0: _DL_TX_FAULT_INTERFACE = 15,
+ // Identical to NVLink 1.0: _DL_TX_FAULT_SUBLINK_CHANGE = 16,
+ // Identical to NVLink 1.0: _DL_RX_FAULT_SUBLINK_CHANGE = 17,
+ // Identical to NVLink 1.0: _DL_RX_FAULT_DL_PROTOCOL = 18,
+ // Identical to NVLink 1.0: _DL_LTSSM_FAULT = 19,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_DL_HDR_PARITY = 20,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_INVALID_AE_FLIT_RCVD = 21,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_INVALID_BE_FLIT_RCVD = 22,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_INVALID_ADDR_ALIGN = 23,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_PKT_LEN = 24,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_RSVD_CMD_ENC = 25,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_RSVD_DAT_LEN_ENC = 26,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_RSVD_ADDR_TYPE = 27,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_RSVD_RSP_STATUS = 28,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_RSVD_PKT_STATUS = 29,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_RSVD_CACHE_ATTR_ENC_IN_PROBE_REQ = 30,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_RSVD_CACHE_ATTR_ENC_IN_PROBE_RESP = 31,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_DAT_LEN_GT_ATOMIC_REQ_MAX_SIZE = 32,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_DAT_LEN_GT_RMW_REQ_MAX_SIZE = 33,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_DAT_LEN_LT_ATR_RESP_MIN_SIZE = 34,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_INVALID_PO_FOR_CACHE_ATTR = 35,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_INVALID_COMPRESSED_RESP = 36,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_RESP_STATUS_TARGET = 37,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_RESP_STATUS_UNSUPPORTED_REQUEST = 38,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_HDR_OVERFLOW = 39,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_DATA_OVERFLOW = 40,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_STOMPED_PKT_RCVD = 41,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_CORRECTABLE_INTERNAL = 42,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_UNSUPPORTED_VC_OVERFLOW = 43,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_UNSUPPORTED_NVLINK_CREDIT_RELEASE = 44,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_UNSUPPORTED_NCISOC_CREDIT_RELEASE = 45,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_TX_HDR_CREDIT_OVERFLOW = 46,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_TX_DATA_CREDIT_OVERFLOW = 47,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_TX_DL_REPLAY_CREDIT_OVERFLOW = 48,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_TX_UNSUPPORTED_VC_OVERFLOW = 49,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_TX_STOMPED_PKT_SENT = 50,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_TX_DATA_POISONED_PKT_SENT = 51,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_TX_RESP_STATUS_TARGET = 52,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_TX_RESP_STATUS_UNSUPPORTED_REQUEST = 53,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_MIF_RX_RAM_DATA_PARITY = 54,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_MIF_RX_RAM_HDR_PARITY = 55,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_MIF_TX_RAM_DATA_PARITY = 56,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_MIF_TX_RAM_HDR_PARITY = 57,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_MAX_V2 = 57,
+ INFOROM_NVLINK_NUM_V2_FATAL_ERR_TYPES = 58,
+
+ // NVLink 3.0
+
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_INVALID_COLLAPSED_RESPONSE = 58,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_TX_NCISOC_HDR_ECC_DBE = 59,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_TX_NCISOC_PARITY = 60,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_DL_LTSSM_FAULT_UP = 61,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_DL_LTSSM_FAULT_DOWN = 62,
+ INFOROM_NVLINK_FATAL_ERR_TYPE_MAX_V3 = 62,
+ INFOROM_NVLINK_NUM_V3_FATAL_ERR_TYPES = 63,
+
+ INFOROM_NVLINK_FATAL_ERR_TYPE_MAX = 62,
+ INFOROM_NVLINK_NUM_FATAL_ERR_TYPES = 63,
+} INFOROM_NVLINK_FATAL_ERR_TYPE;
+
+typedef enum
+{
+ // DL RX -----------------------------------------
+ // Fatal Counts
+ INFOROM_NVLINK_DL_RX_FAULT_DL_PROTOCOL_FATAL = 0,
+ INFOROM_NVLINK_DL_RX_FAULT_SUBLINK_CHANGE_FATAL,
+
+ // Correctable Accumulated Counts
+ INFOROM_NVLINK_DL_RX_FLIT_CRC_CORR,
+ INFOROM_NVLINK_DL_RX_LANE0_CRC_CORR,
+ INFOROM_NVLINK_DL_RX_LANE1_CRC_CORR,
+ INFOROM_NVLINK_DL_RX_LANE2_CRC_CORR,
+ INFOROM_NVLINK_DL_RX_LANE3_CRC_CORR,
+ INFOROM_NVLINK_DL_RX_LINK_REPLAY_EVENTS_CORR,
+
+ // DL TX -----------------------------------------
+ // Fatal Counts
+ INFOROM_NVLINK_DL_TX_FAULT_RAM_FATAL,
+ INFOROM_NVLINK_DL_TX_FAULT_INTERFACE_FATAL,
+ INFOROM_NVLINK_DL_TX_FAULT_SUBLINK_CHANGE_FATAL,
+
+ // Correctable Accumulated Counts
+ INFOROM_NVLINK_DL_TX_LINK_REPLAY_EVENTS_CORR,
+
+ // DL Disassociated ------------------------------
+ // Fatal Counts
+ INFOROM_NVLINK_DL_LTSSM_FAULT_UP_FATAL,
+ INFOROM_NVLINK_DL_LTSSM_FAULT_DOWN_FATAL,
+
+ // Correctable Accumulated Counts
+ INFOROM_NVLINK_DL_LINK_RECOVERY_EVENTS_CORR,
+
+ // TLC RX ----------------------------------------
+ // Fatal Counts
+ INFOROM_NVLINK_TLC_RX_DL_HDR_PARITY_ERR_FATAL,
+ INFOROM_NVLINK_TLC_RX_DL_DATA_PARITY_ERR_FATAL,
+ INFOROM_NVLINK_TLC_RX_DL_CTRL_PARITY_ERR_FATAL,
+ INFOROM_NVLINK_TLC_RX_INVALID_AE_FATAL,
+ INFOROM_NVLINK_TLC_RX_INVALID_BE_FATAL,
+ INFOROM_NVLINK_TLC_RX_INVALID_ADDR_ALIGN_FATAL,
+ INFOROM_NVLINK_TLC_RX_PKTLEN_ERR_FATAL,
+ INFOROM_NVLINK_TLC_RX_RSVD_PACKET_STATUS_ERR_FATAL,
+ INFOROM_NVLINK_TLC_RX_RSVD_CACHE_ATTR_PROBE_REQ_ERR_FATAL,
+ INFOROM_NVLINK_TLC_RX_RSVD_CACHE_ATTR_PROBE_RSP_ERR_FATAL,
+ INFOROM_NVLINK_TLC_RX_DATLEN_GT_RMW_REQ_MAX_ERR_FATAL,
+ INFOROM_NVLINK_TLC_RX_DATLEN_LT_ATR_RSP_MIN_ERR_FATAL,
+ INFOROM_NVLINK_TLC_RX_INVALID_CR_FATAL,
+ INFOROM_NVLINK_TLC_RX_INVALID_COLLAPSED_RESPONSE_FATAL,
+ INFOROM_NVLINK_TLC_RX_HDR_OVERFLOW_FATAL,
+ INFOROM_NVLINK_TLC_RX_DATA_OVERFLOW_FATAL,
+ INFOROM_NVLINK_TLC_RX_STOMP_DETECTED_FATAL,
+ INFOROM_NVLINK_TLC_RX_RSVD_CMD_ENC_FATAL,
+ INFOROM_NVLINK_TLC_RX_RSVD_DAT_LEN_ENC_FATAL,
+ INFOROM_NVLINK_TLC_RX_INVALID_PO_FOR_CACHE_ATTR_FATAL,
+ // This is only needed for NCISOC support (not used outside SoC?)
+ // TLC_RX_NCISOC_CREDIT_PARITY_ERR_FATAL_COUNT,
+
+ // Non-Fatal Counts
+ INFOROM_NVLINK_TLC_RX_RSP_STATUS_HW_ERR_NONFATAL,
+ INFOROM_NVLINK_TLC_RX_RSP_STATUS_UR_ERR_NONFATAL,
+ INFOROM_NVLINK_TLC_RX_RSP_STATUS_PRIV_ERR_NONFATAL,
+ INFOROM_NVLINK_TLC_RX_POISON_NONFATAL,
+ INFOROM_NVLINK_TLC_RX_AN1_HEARTBEAT_TIMEOUT_NONFATAL,
+ INFOROM_NVLINK_TLC_RX_ILLEGAL_PRI_WRITE_NONFATAL,
+
+ // Correctable Accumulated Counts
+ // These should be logged in the ECC object instead
+ // TLC_RX_HDR_RAM_ECC_SBE_ACCUM,
+ // TLC_RX_DAT0_RAM_ECC_SBE_ACCUM,
+ // TLC_RX_DAT1_RAM_ECC_SBE_ACCUM,
+
+ // TLC TX ----------------------------------------
+ // Fatal Counts
+ INFOROM_NVLINK_TLC_TX_DL_CREDIT_PARITY_ERR_FATAL,
+ // These should be logged in the ECC object instead
+ // TLC_TX_CREQ_HDR_RAM_ECC_DBE_FATAL_COUNT,
+ // TLC_TX_RSP_HDR_RAM_ECC_DBE_FATAL_COUNT,
+ // TLC_TX_RSP1_HDR_RAM_ECC_DBE_FATAL_COUNT,
+ // TLC_TX_COM_HDR_RAM_ECC_DBE_FATAL_COUNT,
+ INFOROM_NVLINK_TLC_TX_NCISOC_HDR_ECC_DBE_FATAL,
+ INFOROM_NVLINK_TLC_TX_NCISOC_PARITY_ERR_FATAL,
+
+ // Non-Fatal Counts
+ // This is only needed for NCISOC support (not used outside SoC?)
+ // TLC_TX_NCISOC_DAT_ECC_DBE_NONFATAL_COUNT,
+ INFOROM_NVLINK_TLC_TX_ILLEGAL_PRI_WRITE_NONFATAL,
+ INFOROM_NVLINK_TLC_TX_AN1_TIMEOUT_VC0_NONFATAL,
+ INFOROM_NVLINK_TLC_TX_AN1_TIMEOUT_VC1_NONFATAL,
+ INFOROM_NVLINK_TLC_TX_AN1_TIMEOUT_VC2_NONFATAL,
+ INFOROM_NVLINK_TLC_TX_AN1_TIMEOUT_VC3_NONFATAL,
+ INFOROM_NVLINK_TLC_TX_AN1_TIMEOUT_VC4_NONFATAL,
+ INFOROM_NVLINK_TLC_TX_AN1_TIMEOUT_VC5_NONFATAL,
+ INFOROM_NVLINK_TLC_TX_AN1_TIMEOUT_VC6_NONFATAL,
+ INFOROM_NVLINK_TLC_TX_AN1_TIMEOUT_VC7_NONFATAL,
+ INFOROM_NVLINK_TLC_TX_POISON_NONFATAL,
+ INFOROM_NVLINK_TLC_TX_RSP_STATUS_HW_ERR_NONFATAL,
+ INFOROM_NVLINK_TLC_TX_RSP_STATUS_UR_ERR_NONFATAL,
+ INFOROM_NVLINK_TLC_TX_RSP_STATUS_PRIV_ERR_NONFATAL,
+
+ // Correctable Counts
+ // These should be logged in the ECC object instead
+ // TLC_TX_CREQ_RAMS_ECC_SBE_CORR_ACCUM,
+ // TLC_TX_RSP_RAMS_ECC_SBE_CORR_ACCUM,
+ // TLC_TX_RSP1_RAMS_ECC_SBE_CORR_ACCUM,
+ // TLC_TX_COM_RAMS_ECC_SBE_CORR_ACCUM,
+ // This is only needed for NCISOC support (not used outside SoC?)
+ // TLC_TX_NCISOC_ECC_LIMIT_ERR_CORR_ACCUM,
+
+ // NVLIPT Disassociated --------------------------
+ // Fatal Counts
+ INFOROM_NVLINK_NVLIPT_SLEEP_WHILE_ACTIVE_LINK_FATAL,
+ INFOROM_NVLINK_NVLIPT_RSTSEQ_PHYCTL_TIMEOUT_FATAL,
+ INFOROM_NVLINK_NVLIPT_RSTSEQ_CLKCTL_TIMEOUT_FATAL,
+ INFOROM_NVLINK_NVLIPT_CLKCTL_ILLEGAL_REQUEST_FATAL,
+ INFOROM_NVLINK_NVLIPT_RSTSEQ_PLL_TIMEOUT_FATAL,
+ INFOROM_NVLINK_NVLIPT_RSTSEQ_PHYARB_TIMEOUT_FATAL,
+
+ // Non-Fatal Counts
+ INFOROM_NVLINK_NVLIPT_ILLEGAL_LINK_STATE_REQUEST_NONFATAL,
+ INFOROM_NVLINK_NVLIPT_FAILED_MINION_REQUEST_NONFATAL,
+ INFOROM_NVLINK_NVLIPT_RESERVED_REQUEST_VALUE_NONFATAL,
+ INFOROM_NVLINK_NVLIPT_LINK_STATE_WRITE_WHILE_BUSY_NONFATAL,
+ INFOROM_NVLINK_NVLIPT_WRITE_TO_LOCKED_SYSTEM_REG_NONFATAL,
+ INFOROM_NVLINK_NVLIPT_LINK_STATE_REQUEST_TIMEOUT_NONFATAL,
+
+ // TODO 3014908 log these in the NVL object until we have ECC object support
+ INFOROM_NVLINK_TLC_RX_HDR_RAM_ECC_DBE_FATAL,
+ INFOROM_NVLINK_TLC_RX_DAT0_RAM_ECC_DBE_FATAL,
+ INFOROM_NVLINK_TLC_RX_DAT1_RAM_ECC_DBE_FATAL,
+ INFOROM_NVLINK_TLC_TX_CREQ_DAT_RAM_ECC_DBE_NONFATAL,
+ INFOROM_NVLINK_TLC_TX_RSP_DAT_RAM_ECC_DBE_NONFATAL,
+ INFOROM_NVLINK_TLC_TX_COM_DAT_RAM_ECC_DBE_NONFATAL,
+ INFOROM_NVLINK_TLC_TX_RSP1_DAT_RAM_ECC_DBE_FATAL,
+
+ // DL Interrupts -----------------------------------------
+ // Fatal Counts
+ INFOROM_NVLINK_DL_PHY_A_FATAL,
+ INFOROM_NVLINK_DL_RX_CRC_COUNTER_FATAL,
+ INFOROM_NVLINK_DL_TX_PL_ERROR_FATAL,
+ INFOROM_NVLINK_DL_RX_PL_ERROR_FATAL,
+
+ INFOROM_NVLINK_MAX_ERROR_TYPE
+} INFOROM_NVLINK_ERROR_TYPES;
+
+#define INFOROM_NVLINK_V1_FATAL_ERR_TYPES \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TL_RX_DL_DATA_PARITY) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TL_RX_DL_CTRL_PARITY) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TL_RX_PROTOCOL) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TL_RX_OVERFLOW) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TL_RX_RAM_DATA_PARITY) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TL_RX_RAM_HDR_PARITY) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TL_RX_RESP) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TL_RX_POISON) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TL_TX_RAM_DATA_PARITY) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TL_TX_RAM_HDR_PARITY) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TL_TX_CREDIT) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TL_DL_FLOW_CTRL_PARITY) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TL_DL_HDR_PARITY) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_DL_TX_RECOVERY_LONG) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_DL_TX_FAULT_RAM) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_DL_TX_FAULT_INTERFACE) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_DL_TX_FAULT_SUBLINK_CHANGE) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_DL_RX_FAULT_SUBLINK_CHANGE) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_DL_RX_FAULT_DL_PROTOCOL) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_DL_LTSSM_FAULT)
+
+#define INFOROM_NVLINK_V2_FATAL_ERR_TYPES \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_DL_DATA_PARITY) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_DL_CTRL_PARITY) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_RAM_DATA_PARITY) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_RAM_HDR_PARITY) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_DATA_POISONED_PKT_RCVD) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_TX_RAM_DATA_PARITY) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_TX_RAM_HDR_PARITY) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_TX_DL_FLOW_CONTROL_PARITY) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_DL_TX_RECOVERY_LONG) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_DL_TX_FAULT_RAM) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_DL_TX_FAULT_INTERFACE) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_DL_TX_FAULT_SUBLINK_CHANGE) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_DL_RX_FAULT_SUBLINK_CHANGE) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_DL_RX_FAULT_DL_PROTOCOL) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_DL_LTSSM_FAULT) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_DL_HDR_PARITY) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_INVALID_AE_FLIT_RCVD) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_INVALID_BE_FLIT_RCVD) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_INVALID_ADDR_ALIGN) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_PKT_LEN) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_RSVD_CMD_ENC) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_RSVD_DAT_LEN_ENC) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_RSVD_ADDR_TYPE) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_RSVD_RSP_STATUS) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_RSVD_PKT_STATUS) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_RSVD_CACHE_ATTR_ENC_IN_PROBE_REQ) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_RSVD_CACHE_ATTR_ENC_IN_PROBE_RESP) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_DAT_LEN_GT_ATOMIC_REQ_MAX_SIZE) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_DAT_LEN_GT_RMW_REQ_MAX_SIZE) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_DAT_LEN_LT_ATR_RESP_MIN_SIZE) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_INVALID_PO_FOR_CACHE_ATTR) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_INVALID_COMPRESSED_RESP) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_RESP_STATUS_TARGET) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_RESP_STATUS_UNSUPPORTED_REQUEST) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_HDR_OVERFLOW) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_DATA_OVERFLOW) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_STOMPED_PKT_RCVD) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_CORRECTABLE_INTERNAL) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_UNSUPPORTED_VC_OVERFLOW) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_UNSUPPORTED_NVLINK_CREDIT_RELEASE) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_UNSUPPORTED_NCISOC_CREDIT_RELEASE) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_TX_HDR_CREDIT_OVERFLOW) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_TX_DATA_CREDIT_OVERFLOW) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_TX_DL_REPLAY_CREDIT_OVERFLOW) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_TX_UNSUPPORTED_VC_OVERFLOW) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_TX_STOMPED_PKT_SENT) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_TX_DATA_POISONED_PKT_SENT) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_TX_RESP_STATUS_TARGET) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_TX_RESP_STATUS_UNSUPPORTED_REQUEST) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_MIF_RX_RAM_DATA_PARITY) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_MIF_RX_RAM_HDR_PARITY) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_MIF_TX_RAM_DATA_PARITY) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_MIF_TX_RAM_HDR_PARITY)
+
+#define INFOROM_NVLINK_V3_FATAL_ERR_TYPES \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_DL_DATA_PARITY) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_DL_CTRL_PARITY) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_TX_DL_FLOW_CONTROL_PARITY) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_DL_TX_FAULT_RAM) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_DL_TX_FAULT_INTERFACE) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_DL_TX_FAULT_SUBLINK_CHANGE) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_DL_RX_FAULT_SUBLINK_CHANGE) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_DL_RX_FAULT_DL_PROTOCOL) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_DL_HDR_PARITY) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_INVALID_AE_FLIT_RCVD) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_INVALID_BE_FLIT_RCVD) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_INVALID_ADDR_ALIGN) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_PKT_LEN) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_RSVD_CMD_ENC) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_RSVD_DAT_LEN_ENC) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_RSVD_PKT_STATUS) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_RSVD_CACHE_ATTR_ENC_IN_PROBE_REQ) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_RSVD_CACHE_ATTR_ENC_IN_PROBE_RESP) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_DAT_LEN_GT_RMW_REQ_MAX_SIZE) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_DAT_LEN_LT_ATR_RESP_MIN_SIZE) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_INVALID_PO_FOR_CACHE_ATTR) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_INVALID_COMPRESSED_RESP) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_HDR_OVERFLOW) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_DATA_OVERFLOW) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_STOMPED_PKT_RCVD) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_RX_INVALID_COLLAPSED_RESPONSE) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_TX_NCISOC_HDR_ECC_DBE) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_TLC_TX_NCISOC_PARITY) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_DL_LTSSM_FAULT_UP) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_DL_LTSSM_FAULT_DOWN)
+
+#define INFOROM_NVLINK_V4_FATAL_ERR_TYPES \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_DL_PHY_A) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_DL_RX_CRC_COUNTER) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_DL_TX_PL_ERROR) | \
+ NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_DL_RX_PL_ERROR)
+
+#define INFOROM_ADD_NVLINK_FATAL_ERR_TYPE(mask, type) \
+ mask |= NVBIT64(INFOROM_NVLINK_FATAL_ERR_TYPE_##type)
+
+typedef struct
+{
+ NvU32 errorsPerMinute;
+ NvU32 timestamp;
+} INFOROM_NVLINK_ERROR_RATE;
+
+#define INFOROM_NVLINK_NUM_LINKS 6
+
+typedef union INFOROM_NVL_OBJECT INFOROM_NVL_OBJECT, *PINFOROM_NVL_OBJECT;
+
+// Version 1.0 ----------------------------------------------------------------
+
+// Link Remote Endpoint Type
+typedef enum
+{
+ INFOROM_NVL_OBJECT_V1_REMOTE_TYPE_UNSUPPORTED = -1,
+ INFOROM_NVL_OBJECT_V1_REMOTE_TYPE_NONE = 0,
+ INFOROM_NVL_OBJECT_V1_REMOTE_TYPE_PEER = 1,
+ INFOROM_NVL_OBJECT_V1_REMOTE_TYPE_SYSTEM = 2,
+ INFOROM_NVL_OBJECT_V1_REMOTE_TYPE_SWITCH = 3,
+ INFOROM_NVL_OBJECT_V1_REMOTE_TYPE_MAX = 3,
+ INFOROM_NVL_OBJECT_V1_NUM_REMOTE_TYPES = 4,
+} INFOROM_NVL_OBJECT_V1_REMOTE_TYPE;
+
+// Fatal Errors
+typedef enum
+{
+ INFOROM_NVL_OBJECT_V1_FATAL_ERR_INDEX_UNSUPPORTED = -1,
+ INFOROM_NVL_OBJECT_V1_FATAL_ERR_INDEX_TL_RX_DL_DATA_PARITY = 0,
+ INFOROM_NVL_OBJECT_V1_FATAL_ERR_INDEX_TL_RX_DL_CTRL_PARITY = 1,
+ INFOROM_NVL_OBJECT_V1_FATAL_ERR_INDEX_TL_RX_PROTOCOL = 2,
+ INFOROM_NVL_OBJECT_V1_FATAL_ERR_INDEX_TL_RX_OVERFLOW = 3,
+ INFOROM_NVL_OBJECT_V1_FATAL_ERR_INDEX_TL_RX_RAM_DATA_PARITY = 4,
+ INFOROM_NVL_OBJECT_V1_FATAL_ERR_INDEX_TL_RX_RAM_HDR_PARITY = 5,
+ INFOROM_NVL_OBJECT_V1_FATAL_ERR_INDEX_TL_RX_RESP = 6,
+ INFOROM_NVL_OBJECT_V1_FATAL_ERR_INDEX_TL_RX_POISON = 7,
+ INFOROM_NVL_OBJECT_V1_FATAL_ERR_INDEX_TL_TX_RAM_DATA_PARITY = 8,
+ INFOROM_NVL_OBJECT_V1_FATAL_ERR_INDEX_TL_TX_RAM_HDR_PARITY = 9,
+ INFOROM_NVL_OBJECT_V1_FATAL_ERR_INDEX_TL_TX_CREDIT = 10,
+ INFOROM_NVL_OBJECT_V1_FATAL_ERR_INDEX_TL_DL_FLOW_CTRL_PARITY = 11,
+ INFOROM_NVL_OBJECT_V1_FATAL_ERR_INDEX_TL_DL_HDR_PARITY = 12,
+ INFOROM_NVL_OBJECT_V1_FATAL_ERR_INDEX_DL_TX_RECOVERY_LONG = 13,
+ INFOROM_NVL_OBJECT_V1_FATAL_ERR_INDEX_DL_TX_FAULT_RAM = 14,
+ INFOROM_NVL_OBJECT_V1_FATAL_ERR_INDEX_DL_TX_FAULT_INTERFACE = 15,
+ INFOROM_NVL_OBJECT_V1_FATAL_ERR_INDEX_DL_TX_FAULT_SUBLINK_CHANGE = 16,
+ INFOROM_NVL_OBJECT_V1_FATAL_ERR_INDEX_DL_RX_FAULT_SUBLINK_CHANGE = 17,
+ INFOROM_NVL_OBJECT_V1_FATAL_ERR_INDEX_DL_RX_FAULT_DL_PROTOCOL = 18,
+ INFOROM_NVL_OBJECT_V1_FATAL_ERR_INDEX_DL_LTSSM_FAULT = 19,
+ INFOROM_NVL_OBJECT_V1_FATAL_ERR_INDEX_MAX = 19,
+ INFOROM_NVL_OBJECT_V1_NUM_FATAL_ERR_INDICES = 20,
+} INFOROM_NVL_OBJECT_V1_FATAL_ERR_INDEX;
+
+typedef struct INFOROM_NVL_OBJECT_V1_FATAL_ERR_DATA
+{
+ inforom_U008 counts[INFOROM_NVL_OBJECT_V1_NUM_FATAL_ERR_INDICES];
+ inforom_U008 reserved[25];
+} INFOROM_NVL_OBJECT_V1_FATAL_ERR_DATA;
+
+#define INFOROM_NVL_OBJECT_V1_FATAL_ERR_DATA_FMT "45b"
+
+// Non-Fatal Errors
+typedef struct INFOROM_NVL_OBJECT_V1_NONFATAL_ERR_RATE_ENTRY
+{
+ inforom_U024 errRate;
+ inforom_U032 timestamp;
+} INFOROM_NVL_OBJECT_V1_NONFATAL_ERR_RATE_ENTRY;
+
+#define INFOROM_NVL_OBJECT_V1_NONFATAL_ERR_RATE_FMT "td"
+
+#define INFOROM_NVL_OBJECT_V1_NONFATAL_ERR_RATE_DAY_ENTRIES 5
+#define INFOROM_NVL_OBJECT_V1_NONFATAL_ERR_RATE_DAY_INTERVAL (60*60*24)
+#define INFOROM_NVL_OBJECT_V1_NONFATAL_ERR_RATE_MONTH_ENTRIES 3
+#define INFOROM_NVL_OBJECT_V1_NONFATAL_ERR_RATE_MONTH_INTERVAL (60*60*24*30)
+
+typedef struct INFOROM_NVL_OBJECT_V1_NONFATAL_ERR_DATA
+{
+ INFOROM_NVL_OBJECT_V1_NONFATAL_ERR_RATE_ENTRY maxNDaysAgo[
+ INFOROM_NVL_OBJECT_V1_NONFATAL_ERR_RATE_DAY_ENTRIES];
+ INFOROM_NVL_OBJECT_V1_NONFATAL_ERR_RATE_ENTRY maxNMonthsAgo[
+ INFOROM_NVL_OBJECT_V1_NONFATAL_ERR_RATE_MONTH_ENTRIES];
+} INFOROM_NVL_OBJECT_V1_NONFATAL_ERR_DATA;
+
+#define INFOROM_NVL_OBJECT_V1_NONFATAL_ERR_DATA_FMT \
+ INFOROM_FMT_REP08(INFOROM_NVL_OBJECT_V1_NONFATAL_ERR_RATE_FMT)
+
+typedef struct INFOROM_NVL_OBJECT_V1_ERR_DATA
+{
+ INFOROM_NVL_OBJECT_V1_FATAL_ERR_DATA fatal;
+ INFOROM_NVL_OBJECT_V1_NONFATAL_ERR_DATA nonfatal;
+} INFOROM_NVL_OBJECT_V1_ERR_DATA;
+
+#define INFOROM_NVL_OBJECT_V1_ERR_DATA_FMT \
+ INFOROM_NVL_OBJECT_V1_FATAL_ERR_DATA_FMT \
+ INFOROM_NVL_OBJECT_V1_NONFATAL_ERR_DATA_FMT
+
+#define INFOROM_NVL_OBJECT_V1_NUM_LINKS 6
+
+typedef struct INFOROM_NVL_OBJECT_V1
+{
+ INFOROM_OBJECT_HEADER_V1_00 header;
+ inforom_U004 lastErrorRemoteType[
+ INFOROM_NVL_OBJECT_V1_NUM_LINKS];
+ inforom_U008 reserved1[1];
+ INFOROM_NVL_OBJECT_V1_ERR_DATA errData[INFOROM_NVL_OBJECT_V1_NUM_LINKS];
+ inforom_U016 padding[1];
+ inforom_U032 reserved2[13];
+} INFOROM_NVL_OBJECT_V1;
+
+#define INFOROM_NVL_OBJECT_V1_FMT \
+ INFOROM_OBJECT_HEADER_V1_00_FMT \
+ "6n" /* lastRemoteType */ \
+ "b" /* reserved1 */ \
+ INFOROM_FMT_REP04(INFOROM_NVL_OBJECT_V1_ERR_DATA_FMT) \
+ INFOROM_FMT_REP02(INFOROM_NVL_OBJECT_V1_ERR_DATA_FMT) \
+ "w" /* padding */ \
+ "13d" /* reserved2 */
+
+#define INFOROM_NVL_OBJECT_V1_PACKED_SIZE 672
+
+// Version 2.0 ----------------------------------------------------------------
+
+// Link Remote Endpoint Type
+typedef enum
+{
+ INFOROM_NVL_OBJECT_V2_REMOTE_TYPE_UNSUPPORTED = -1,
+ INFOROM_NVL_OBJECT_V2_REMOTE_TYPE_NONE = 0,
+ INFOROM_NVL_OBJECT_V2_REMOTE_TYPE_PEER = 1,
+ INFOROM_NVL_OBJECT_V2_REMOTE_TYPE_SYSTEM = 2,
+ INFOROM_NVL_OBJECT_V2_REMOTE_TYPE_SWITCH = 3,
+ INFOROM_NVL_OBJECT_V2_REMOTE_TYPE_MAX = 3,
+ INFOROM_NVL_OBJECT_V2_NUM_REMOTE_TYPES = 4,
+} INFOROM_NVL_OBJECT_V2_REMOTE_TYPE;
+
+// Fatal Errors
+typedef enum
+{
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_UNSUPPORTED = -1,
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_TLC_RX_DL_HDR_PARITY = 0,
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_TLC_RX_DL_DATA_PARITY = 1,
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_TLC_RX_DL_CTRL_PARITY = 2,
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_TLC_RX_RAM_DATA_PARITY = 3,
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_TLC_RX_RAM_HDR_PARITY = 4,
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_TLC_RX_INVALID_AE_FLIT_RCVD = 5,
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_TLC_RX_INVALID_BE_FLIT_RCVD = 6,
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_TLC_RX_INVALID_ADDR_ALIGN = 7,
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_TLC_RX_PKT_LEN = 8,
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_TLC_RX_RSVD_CMD_ENC = 9,
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_TLC_RX_RSVD_DAT_LEN_ENC = 10,
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_TLC_RX_RSVD_ADDR_TYPE = 11,
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_TLC_RX_RSVD_RSP_STATUS = 12,
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_TLC_RX_RSVD_PKT_STATUS = 13,
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_TLC_RX_RSVD_CACHE_ATTR_ENC_IN_PROBE_REQ = 14,
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_TLC_RX_RSVD_CACHE_ATTR_ENC_IN_PROBE_RESP = 15,
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_TLC_RX_DAT_LEN_GT_ATOMIC_REQ_MAX_SIZE = 16,
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_TLC_RX_DAT_LEN_GT_RMW_REQ_MAX_SIZE = 17,
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_TLC_RX_DAT_LEN_LT_ATR_RESP_MIN_SIZE = 18,
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_TLC_RX_INVALID_PO_FOR_CACHE_ATTR = 19,
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_TLC_RX_INVALID_COMPRESSED_RESP = 20,
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_TLC_RX_RESP_STATUS_TARGET = 21,
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_TLC_RX_RESP_STATUS_UNSUPPORTED_REQUEST = 22,
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_TLC_RX_HDR_OVERFLOW = 23,
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_TLC_RX_DATA_OVERFLOW = 24,
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_TLC_RX_STOMPED_PKT_RCVD = 25,
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_TLC_RX_DATA_POISONED_PKT_RCVD = 26,
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_TLC_RX_CORRECTABLE_INTERNAL = 27,
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_TLC_RX_UNSUPPORTED_VC_OVERFLOW = 28,
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_TLC_RX_UNSUPPORTED_NVLINK_CREDIT_RELEASE = 29,
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_TLC_RX_UNSUPPORTED_NCISOC_CREDIT_RELEASE = 30,
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_TLC_TX_HDR_CREDIT_OVERFLOW = 31,
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_TLC_TX_DATA_CREDIT_OVERFLOW = 32,
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_TLC_TX_DL_REPLAY_CREDIT_OVERFLOW = 33,
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_TLC_TX_DL_FLOW_CONTROL_PARITY = 34,
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_TLC_TX_RAM_HDR_PARITY = 35,
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_TLC_TX_RAM_DATA_PARITY = 36,
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_TLC_TX_UNSUPPORTED_VC_OVERFLOW = 37,
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_TLC_TX_STOMPED_PKT_SENT = 38,
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_TLC_TX_DATA_POISONED_PKT_SENT = 39,
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_TLC_TX_RESP_STATUS_TARGET = 40,
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_TLC_TX_RESP_STATUS_UNSUPPORTED_REQUEST = 41,
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_MIF_RX_RAM_DATA_PARITY = 42,
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_MIF_RX_RAM_HDR_PARITY = 43,
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_MIF_TX_RAM_DATA_PARITY = 44,
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_MIF_TX_RAM_HDR_PARITY = 45,
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_DL_TX_RECOVERY_LONG = 46,
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_DL_TX_FAULT_RAM = 47,
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_DL_TX_FAULT_INTERFACE = 48,
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_DL_TX_FAULT_SUBLINK_CHANGE = 49,
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_DL_RX_FAULT_SUBLINK_CHANGE = 50,
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_DL_RX_FAULT_DL_PROTOCOL = 51,
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_DL_LTSSM_FAULT = 52,
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX_MAX = 52,
+ INFOROM_NVL_OBJECT_V2_NUM_FATAL_ERR_INDICES = 53,
+} INFOROM_NVL_OBJECT_V2_FATAL_ERR_INDEX;
+
+typedef struct INFOROM_NVL_OBJECT_V2_FATAL_ERR_DATA
+{
+ inforom_U008 counts[INFOROM_NVL_OBJECT_V2_NUM_FATAL_ERR_INDICES];
+} INFOROM_NVL_OBJECT_V2_FATAL_ERR_DATA;
+
+#define INFOROM_NVL_OBJECT_V2_FATAL_ERR_DATA_FMT "53b"
+
+// Non-Fatal Errors
+typedef INFOROM_NVL_OBJECT_V1_NONFATAL_ERR_RATE_ENTRY
+ INFOROM_NVL_OBJECT_V2_NONFATAL_ERR_RATE_ENTRY;
+
+#define INFOROM_NVL_OBJECT_V2_NONFATAL_ERR_RATE_FMT \
+ INFOROM_NVL_OBJECT_V1_NONFATAL_ERR_RATE_FMT
+
+#define INFOROM_NVL_OBJECT_V2_NONFATAL_ERR_RATE_DAY_ENTRIES \
+ INFOROM_NVL_OBJECT_V1_NONFATAL_ERR_RATE_DAY_ENTRIES
+#define INFOROM_NVL_OBJECT_V2_NONFATAL_ERR_RATE_DAY_INTERVAL \
+ INFOROM_NVL_OBJECT_V1_NONFATAL_ERR_RATE_DAY_INTERVAL
+#define INFOROM_NVL_OBJECT_V2_NONFATAL_ERR_RATE_MONTH_ENTRIES \
+ INFOROM_NVL_OBJECT_V1_NONFATAL_ERR_RATE_MONTH_ENTRIES
+#define INFOROM_NVL_OBJECT_V2_NONFATAL_ERR_RATE_MONTH_INTERVAL \
+ INFOROM_NVL_OBJECT_V1_NONFATAL_ERR_RATE_MONTH_INTERVAL
+
+typedef INFOROM_NVL_OBJECT_V1_NONFATAL_ERR_DATA
+ INFOROM_NVL_OBJECT_V2_NONFATAL_ERR_DATA;
+
+#define INFOROM_NVL_OBJECT_V2_NONFATAL_ERR_DATA_FMT \
+ INFOROM_NVL_OBJECT_V1_NONFATAL_ERR_DATA_FMT
+
+typedef struct INFOROM_NVL_OBJECT_V2_ERR_DATA
+{
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_DATA fatal;
+ INFOROM_NVL_OBJECT_V2_NONFATAL_ERR_DATA nonfatal;
+} INFOROM_NVL_OBJECT_V2_ERR_DATA;
+
+#define INFOROM_NVL_OBJECT_V2_ERR_DATA_FMT \
+ INFOROM_NVL_OBJECT_V2_FATAL_ERR_DATA_FMT \
+ INFOROM_NVL_OBJECT_V2_NONFATAL_ERR_DATA_FMT
+
+#define INFOROM_NVL_OBJECT_V2_NUM_LINKS INFOROM_NVL_OBJECT_V1_NUM_LINKS
+
+typedef struct INFOROM_NVL_OBJECT_V2
+{
+ INFOROM_OBJECT_HEADER_V1_00 header;
+ inforom_U004 lastErrorRemoteType[
+ INFOROM_NVL_OBJECT_V2_NUM_LINKS];
+ inforom_U008 reserved1[1];
+ INFOROM_NVL_OBJECT_V2_ERR_DATA errData[INFOROM_NVL_OBJECT_V2_NUM_LINKS];
+ inforom_U016 padding[1];
+ inforom_U032 reserved2[1];
+} INFOROM_NVL_OBJECT_V2;
+
+#define INFOROM_NVL_OBJECT_V2_FMT \
+ INFOROM_OBJECT_HEADER_V1_00_FMT \
+ "6n" /* lastRemoteType */ \
+ "b" /* reserved1 */ \
+ INFOROM_FMT_REP04(INFOROM_NVL_OBJECT_V2_ERR_DATA_FMT) \
+ INFOROM_FMT_REP02(INFOROM_NVL_OBJECT_V2_ERR_DATA_FMT) \
+ "w" /* padding */ \
+ "d" /* reserved2 */
+
+#define INFOROM_NVL_OBJECT_V2_PACKED_SIZE 672
+
+// Version 3.G0 ---------------------------------------------------------------
+
+#define INFOROM_NVL_OBJECT_V3G_NUM_LINKS 12
+#define INFOROM_NVL_OBJECT_V3G_MAX_SEED_BUFFER_SIZE 7
+
+typedef INFOROM_NVL_OBJECT_V2_REMOTE_TYPE INFOROM_NVL_OBJECT_V3_REMOTE_TYPE;
+
+typedef struct INFOROM_NVL_OBJECT_V3_REMOTE_DEVICE_INFO
+{
+ inforom_U032 lastUpdated;
+ NvU64_ALIGN32 remoteDeviceSID;
+ inforom_U008 remoteDeviceType;
+ inforom_U008 remoteDeviceLink;
+} INFOROM_NVL_OBJECT_V3_REMOTE_DEVICE_INFO;
+
+#define INFOROM_NVL_OBJECT_V3_REMOTE_DEVICE_INFO_FMT "dq2b"
+
+typedef struct INFOROM_NVL_OBJECT_V3_MINION_DATA
+{
+ inforom_U032 lastUpdated;
+ inforom_U032 data[INFOROM_NVL_OBJECT_V3G_MAX_SEED_BUFFER_SIZE];
+} INFOROM_NVL_OBJECT_V3_MINION_DATA;
+
+#define INFOROM_NVL_OBJECT_V3_MINION_DATA_FMT "8d"
+
+typedef struct INFOROM_NVL_OBJECT_V3_CORRECTABLE_ERROR_RATE
+{
+ inforom_U032 lastUpdated;
+ inforom_U032 flitCrcErrorsPerMinute;
+ inforom_U016 laneCrcErrorsPerMinute[4];
+} INFOROM_NVL_OBJECT_V3_CORRECTABLE_ERROR_RATE;
+
+#define INFOROM_NVL_OBJECT_V3_CORRECTABLE_ERROR_RATE_FMT "2d4w"
+
+typedef INFOROM_NVL_OBJECT_V3_CORRECTABLE_ERROR_RATE
+ INFOROM_NVL_OBJECT_V3G_CORRECTABLE_ERROR_RATE_ARRAY[INFOROM_NVL_OBJECT_V3G_NUM_LINKS];
+
+#define INFOROM_NVL_OBJECT_V3G_CORRECTABLE_ERROR_RATE_ARRAY_FMT \
+ INFOROM_FMT_REP08(INFOROM_NVL_OBJECT_V3_CORRECTABLE_ERROR_RATE_FMT) \
+ INFOROM_FMT_REP04(INFOROM_NVL_OBJECT_V3_CORRECTABLE_ERROR_RATE_FMT)
+
+typedef struct INFOROM_NVL_OBJECT_V3G_MAX_CORRECTABLE_ERROR_RATES
+{
+ INFOROM_NVL_OBJECT_V3G_CORRECTABLE_ERROR_RATE_ARRAY dailyMaxCorrectableErrorRates[5];
+ INFOROM_NVL_OBJECT_V3G_CORRECTABLE_ERROR_RATE_ARRAY monthlyMaxCorrectableErrorRates[3];
+} INFOROM_NVL_OBJECT_V3G_MAX_CORRECTABLE_ERROR_RATES;
+
+#define INFOROM_NVL_OBJECT_V3G_MAX_CORRECTABLE_ERROR_RATES_FMT \
+ INFOROM_FMT_REP08(INFOROM_NVL_OBJECT_V3G_CORRECTABLE_ERROR_RATE_ARRAY_FMT)
+
+#define NV_INFOROM_NVL_OBJECT_V3_ERROR_METADATA_NVLIPT_INSTANCE_ID 3:0
+#define NV_INFOROM_NVL_OBJECT_V3_ERROR_METADATA_BLOCK_ID 7:4
+#define NV_INFOROM_NVL_OBJECT_V3_ERROR_METADATA_BLOCK_ID_DL0 0
+#define NV_INFOROM_NVL_OBJECT_V3_ERROR_METADATA_BLOCK_ID_DL1 1
+#define NV_INFOROM_NVL_OBJECT_V3_ERROR_METADATA_BLOCK_ID_DL2 2
+#define NV_INFOROM_NVL_OBJECT_V3_ERROR_METADATA_BLOCK_ID_DL3 3
+#define NV_INFOROM_NVL_OBJECT_V3_ERROR_METADATA_BLOCK_ID_DL4 4
+#define NV_INFOROM_NVL_OBJECT_V3_ERROR_METADATA_BLOCK_ID_DL5 5
+#define NV_INFOROM_NVL_OBJECT_V3_ERROR_METADATA_BLOCK_ID_DL(n) \
+ (NV_INFOROM_NVL_OBJECT_V3_ERROR_METADATA_BLOCK_ID_DL0+(n))
+#define NV_INFOROM_NVL_OBJECT_V3_ERROR_METADATA_BLOCK_ID_TLC0 6
+#define NV_INFOROM_NVL_OBJECT_V3_ERROR_METADATA_BLOCK_ID_TLC1 7
+#define NV_INFOROM_NVL_OBJECT_V3_ERROR_METADATA_BLOCK_ID_TLC2 8
+#define NV_INFOROM_NVL_OBJECT_V3_ERROR_METADATA_BLOCK_ID_TLC3 9
+#define NV_INFOROM_NVL_OBJECT_V3_ERROR_METADATA_BLOCK_ID_TLC4 10
+#define NV_INFOROM_NVL_OBJECT_V3_ERROR_METADATA_BLOCK_ID_TLC5 11
+#define NV_INFOROM_NVL_OBJECT_V3_ERROR_METADATA_BLOCK_ID_TLC(n) \
+ (NV_INFOROM_NVL_OBJECT_V3_ERROR_METADATA_BLOCK_ID_TLC0+(n))
+#define NV_INFOROM_NVL_OBJECT_V3_ERROR_METADATA_BLOCK_ID_MINION 12
+#define NV_INFOROM_NVL_OBJECT_V3_ERROR_METADATA_BLOCK_ID_NVLIPT 13
+#define NV_INFOROM_NVL_OBJECT_V3_ERROR_METADATA_DIRECTION 9:8
+#define NV_INFOROM_NVL_OBJECT_V3_ERROR_METADATA_DIRECTION_NA 1
+#define NV_INFOROM_NVL_OBJECT_V3_ERROR_METADATA_DIRECTION_RX 2
+#define NV_INFOROM_NVL_OBJECT_V3_ERROR_METADATA_DIRECTION_TX 3
+#define NV_INFOROM_NVL_OBJECT_V3_ERROR_METADATA_SEVERITY 11:10
+#define NV_INFOROM_NVL_OBJECT_V3_ERROR_METADATA_SEVERITY_CORRECTABLE 1
+#define NV_INFOROM_NVL_OBJECT_V3_ERROR_METADATA_SEVERITY_UNCORRECTABLE_NONFATAL 2
+#define NV_INFOROM_NVL_OBJECT_V3_ERROR_METADATA_SEVERITY_UNCORRECTABLE_FATAL 3
+
+#define INFOROM_NVL_OBJECT_V3_NVLIPT_INSTANCE_MAX 15
+#define INFOROM_NVL_OBJECT_V3_BLOCK_ID_MAX 15
+
+#define NV_INFOROM_NVL_OBJECT_V3_NVLIPT_ERROR_SUBTYPE 4:0
+#define NV_INFOROM_NVL_OBJECT_V3_NVLIPT_ERROR_LINK_ID 7:5
+#define NV_INFOROM_NVL_OBJECT_V3_NVLIPT_ERROR_LINK_ID_COMMON 7
+
+// Format is <BLOCK>_<DIRECTION>_<SUBTYPE>_<SEVERITY>_<TYPE>
+// Each <BLOCK>_<DIRECTION> has its own subtype space.
+typedef enum
+{
+ // DL RX -----------------------------------------
+ // Fatal Counts
+ DL_RX_FAULT_DL_PROTOCOL_FATAL_COUNT = 0,
+ DL_RX_FAULT_SUBLINK_CHANGE_FATAL_COUNT,
+
+ // Correctable Accumulated Counts
+ DL_RX_FLIT_CRC_CORR_ACCUM,
+ DL_RX_LANE0_CRC_CORR_ACCUM,
+ DL_RX_LANE1_CRC_CORR_ACCUM,
+ DL_RX_LANE2_CRC_CORR_ACCUM,
+ DL_RX_LANE3_CRC_CORR_ACCUM,
+ DL_RX_LINK_REPLAY_EVENTS_CORR_ACCUM,
+
+ // DL TX -----------------------------------------
+ // Fatal Counts
+ DL_TX_FAULT_RAM_FATAL_COUNT = 0,
+ DL_TX_FAULT_INTERFACE_FATAL_COUNT,
+ DL_TX_FAULT_SUBLINK_CHANGE_FATAL_COUNT,
+
+ // Correctable Accumulated Counts
+ DL_TX_LINK_REPLAY_EVENTS_CORR_ACCUM,
+
+ // DL Disassociated ------------------------------
+ // Fatal Counts
+ DL_NA_LTSSM_FAULT_UP_FATAL_COUNT = 0,
+ DL_NA_LTSSM_FAULT_DOWN_FATAL_COUNT,
+
+ // Correctable Accumulated Counts
+ DL_NA_LINK_RECOVERY_EVENTS_CORR_ACCUM,
+
+ DL_NA_PHY_A_FATAL_COUNT,
+ DL_RX_CRC_COUNTER_FATAL_COUNT,
+ DL_TX_PL_ERROR_FATAL_COUNT,
+ DL_RX_PL_ERROR_FATAL_COUNT,
+
+ // TLC RX ----------------------------------------
+ // Fatal Counts
+ TLC_RX_DL_HDR_PARITY_ERR_FATAL_COUNT = 0,
+ TLC_RX_DL_DATA_PARITY_ERR_FATAL_COUNT,
+ TLC_RX_DL_CTRL_PARITY_ERR_FATAL_COUNT,
+ TLC_RX_INVALID_AE_FATAL_COUNT,
+ TLC_RX_INVALID_BE_FATAL_COUNT,
+ TLC_RX_INVALID_ADDR_ALIGN_FATAL_COUNT,
+ TLC_RX_PKTLEN_ERR_FATAL_COUNT,
+ TLC_RX_RSVD_PACKET_STATUS_ERR_FATAL_COUNT,
+ TLC_RX_RSVD_CACHE_ATTR_PROBE_REQ_ERR_FATAL_COUNT,
+ TLC_RX_RSVD_CACHE_ATTR_PROBE_RSP_ERR_FATAL_COUNT,
+ TLC_RX_DATLEN_GT_RMW_REQ_MAX_ERR_FATAL_COUNT,
+ TLC_RX_DATLEN_LT_ATR_RSP_MIN_ERR_FATAL_COUNT,
+ TLC_RX_INVALID_CR_FATAL_COUNT,
+ TLC_RX_INVALID_COLLAPSED_RESPONSE_FATAL_COUNT,
+ TLC_RX_HDR_OVERFLOW_FATAL_COUNT,
+ TLC_RX_DATA_OVERFLOW_FATAL_COUNT,
+ TLC_RX_STOMP_DETECTED_FATAL_COUNT,
+ TLC_RX_RSVD_CMD_ENC_FATAL_COUNT,
+ TLC_RX_RSVD_DAT_LEN_ENC_FATAL_COUNT,
+ TLC_RX_INVALID_PO_FOR_CACHE_ATTR_FATAL_COUNT,
+ // This is only needed for NCISOC support (not used outside SoC?)
+ // TLC_RX_NCISOC_CREDIT_PARITY_ERR_FATAL_COUNT,
+
+ // Non-Fatal Counts
+ TLC_RX_RSP_STATUS_HW_ERR_NONFATAL_COUNT,
+ TLC_RX_RSP_STATUS_UR_ERR_NONFATAL_COUNT,
+ TLC_RX_RSP_STATUS_PRIV_ERR_NONFATAL_COUNT,
+ TLC_RX_POISON_NONFATAL_COUNT,
+ TLC_RX_AN1_HEARTBEAT_TIMEOUT_NONFATAL_COUNT,
+ TLC_RX_ILLEGAL_PRI_WRITE_NONFATAL_COUNT,
+
+ // Fatal Counts addendum
+ TLC_RX_HDR_RAM_ECC_DBE_FATAL_COUNT,
+ TLC_RX_DAT0_RAM_ECC_DBE_FATAL_COUNT,
+ TLC_RX_DAT1_RAM_ECC_DBE_FATAL_COUNT,
+
+ // Correctable Accumulated Counts
+ // These should be logged in the ECC object instead
+ // TLC_RX_HDR_RAM_ECC_SBE_ACCUM,
+ // TLC_RX_DAT0_RAM_ECC_SBE_ACCUM,
+ // TLC_RX_DAT1_RAM_ECC_SBE_ACCUM,
+
+ // TLC TX ----------------------------------------
+ // Fatal Counts
+ TLC_TX_DL_CREDIT_PARITY_ERR_FATAL_COUNT = 0,
+ // These should be logged in the ECC object instead
+ // TLC_TX_CREQ_HDR_RAM_ECC_DBE_FATAL_COUNT,
+ // TLC_TX_RSP_HDR_RAM_ECC_DBE_FATAL_COUNT,
+ // TLC_TX_RSP1_HDR_RAM_ECC_DBE_FATAL_COUNT,
+ // TLC_TX_COM_HDR_RAM_ECC_DBE_FATAL_COUNT,
+ TLC_TX_NCISOC_HDR_ECC_DBE_FATAL_COUNT,
+ TLC_TX_NCISOC_PARITY_ERR_FATAL_COUNT,
+
+ // Non-Fatal Counts
+ // This is only needed for NCISOC support (not used outside SoC?)
+ // TLC_TX_NCISOC_DAT_ECC_DBE_NONFATAL_COUNT,
+ TLC_TX_ILLEGAL_PRI_WRITE_NONFATAL_COUNT,
+ TLC_TX_AN1_TIMEOUT_VC0_NONFATAL_COUNT,
+ TLC_TX_AN1_TIMEOUT_VC1_NONFATAL_COUNT,
+ TLC_TX_AN1_TIMEOUT_VC2_NONFATAL_COUNT,
+ TLC_TX_AN1_TIMEOUT_VC3_NONFATAL_COUNT,
+ TLC_TX_AN1_TIMEOUT_VC4_NONFATAL_COUNT,
+ TLC_TX_AN1_TIMEOUT_VC5_NONFATAL_COUNT,
+ TLC_TX_AN1_TIMEOUT_VC6_NONFATAL_COUNT,
+ TLC_TX_AN1_TIMEOUT_VC7_NONFATAL_COUNT,
+ TLC_TX_POISON_NONFATAL_COUNT,
+ TLC_TX_RSP_STATUS_HW_ERR_NONFATAL_COUNT,
+ TLC_TX_RSP_STATUS_UR_ERR_NONFATAL_COUNT,
+ TLC_TX_RSP_STATUS_PRIV_ERR_NONFATAL_COUNT,
+ TLC_TX_CREQ_DAT_RAM_ECC_DBE_NONFATAL_COUNT,
+ TLC_TX_RSP_DAT_RAM_ECC_DBE_NONFATAL_COUNT,
+ TLC_TX_COM_DAT_RAM_ECC_DBE_NONFATAL_COUNT,
+
+ // Correctable Counts
+ // These should be logged in the ECC object instead
+ // TLC_TX_CREQ_RAMS_ECC_SBE_CORR_ACCUM,
+ // TLC_TX_RSP_RAMS_ECC_SBE_CORR_ACCUM,
+ // TLC_TX_RSP1_RAMS_ECC_SBE_CORR_ACCUM,
+ // TLC_TX_COM_RAMS_ECC_SBE_CORR_ACCUM,
+ // This is only needed for NCISOC support (not used outside SoC?)
+ // TLC_TX_NCISOC_ECC_LIMIT_ERR_CORR_ACCUM,
+
+ // TLC TX Fatal addendum
+ TLC_TX_RSP1_DAT_RAM_ECC_DBE_FATAL_COUNT,
+
+ // NVLIPT Disassociated --------------------------
+ // Fatal Counts
+ NVLIPT_NA_SLEEP_WHILE_ACTIVE_LINK_FATAL_COUNT = 0,
+ NVLIPT_NA_RSTSEQ_PHYCTL_TIMEOUT_FATAL_COUNT,
+ NVLIPT_NA_RSTSEQ_CLKCTL_TIMEOUT_FATAL_COUNT,
+ NVLIPT_NA_CLKCTL_ILLEGAL_REQUEST_FATAL_COUNT,
+ NVLIPT_NA_RSTSEQ_PLL_TIMEOUT_FATAL_COUNT,
+ NVLIPT_NA_RSTSEQ_PHYARB_TIMEOUT_FATAL_COUNT,
+
+ // Non-Fatal Counts
+ NVLIPT_NA_ILLEGAL_LINK_STATE_REQUEST_NONFATAL_COUNT,
+ NVLIPT_NA_FAILED_MINION_REQUEST_NONFATAL_COUNT,
+ NVLIPT_NA_RESERVED_REQUEST_VALUE_NONFATAL_COUNT,
+ NVLIPT_NA_LINK_STATE_WRITE_WHILE_BUSY_NONFATAL_COUNT,
+ NVLIPT_NA_WRITE_TO_LOCKED_SYSTEM_REG_NONFATAL_COUNT,
+ NVLIPT_NA_LINK_STATE_REQUEST_TIMEOUT_NONFATAL_COUNT
+} INFOROM_NVL_OBJECT_V3_ERROR_ENTRY_SUBTYPE;
+
+#define INFOROM_NVL_OBJECT_V3_FATAL_ERR_INDEX_UNSUPPORTED ((NvU8) NV_U8_MAX)
+
+typedef enum
+{
+ INFOROM_NVL_ERROR_TYPE_INVALID = 0,
+ INFOROM_NVL_ERROR_TYPE_COUNT,
+ INFOROM_NVL_ERROR_TYPE_ACCUM
+} INFOROM_NVL_OBJECT_V3_ERROR_TYPE;
+
+typedef enum
+{
+ INFOROM_NVL_ERROR_BLOCK_TYPE_DL = 0,
+ INFOROM_NVL_ERROR_BLOCK_TYPE_TLC,
+ INFOROM_NVL_ERROR_BLOCK_TYPE_NVLIPT
+} INFOROM_NVL_ERROR_BLOCK_TYPE;
+
+typedef struct
+{
+ NvU8 nvliptInstance;
+ NvU8 localLinkIdx;
+ INFOROM_NVLINK_ERROR_TYPES error;
+ NvU32 count; // count is used only for correctable errors
+} INFOROM_NVLINK_ERROR_EVENT;
+
+#define INFOROM_NVL_OBJECT_MAX_SUBLINK_WIDTH 8
+typedef struct
+{
+ NvU16 flitCrc;
+ NvU8 laneCrc[INFOROM_NVL_OBJECT_MAX_SUBLINK_WIDTH];
+ NvU16 rxLinkReplay;
+ NvU16 txLinkReplay;
+ NvU16 linkRecovery;
+} INFOROM_NVLINK_CORRECTABLE_ERROR_COUNTS;
+
+typedef struct INFOROM_NVL_OBJECT_V3_ERROR_ENTRY
+{
+ inforom_U008 header;
+ inforom_U016 metadata;
+ inforom_U008 errorSubtype;
+ union
+ {
+ struct
+ {
+ inforom_U032 lastError;
+ inforom_U032 avgEventDelta;
+ inforom_U032 totalCount;
+ } event;
+ struct
+ {
+ inforom_U032 lastUpdated;
+ NvU64_ALIGN32 totalCount;
+ } accum;
+ } data;
+} INFOROM_NVL_OBJECT_V3_ERROR_ENTRY;
+
+#define INFOROM_NVL_OBJECT_V3_ERROR_ENTRY_FMT "bwb3d"
+
+#define INFOROM_NVL_OBJECT_V3G_NUM_ERROR_ENTRIES 240
+
+typedef struct INFOROM_NVL_OBJECT_V3G
+{
+ INFOROM_OBJECT_HEADER_V1_00 header;
+ INFOROM_NVL_OBJECT_V3_REMOTE_DEVICE_INFO remoteDeviceInfo[INFOROM_NVL_OBJECT_V3G_NUM_LINKS];
+ INFOROM_NVL_OBJECT_V3_MINION_DATA minionData[INFOROM_NVL_OBJECT_V3G_NUM_LINKS];
+ INFOROM_NVL_OBJECT_V3G_MAX_CORRECTABLE_ERROR_RATES maxCorrectableErrorRates;
+ INFOROM_NVL_OBJECT_V3_ERROR_ENTRY errorLog[INFOROM_NVL_OBJECT_V3G_NUM_ERROR_ENTRIES];
+} INFOROM_NVL_OBJECT_V3G;
+
+#define INFOROM_NVL_OBJECT_V3G_REMOTE_DEVICE_INFO_ARRAY_FMT \
+ INFOROM_FMT_REP08(INFOROM_NVL_OBJECT_V3_REMOTE_DEVICE_INFO_FMT) \
+ INFOROM_FMT_REP04(INFOROM_NVL_OBJECT_V3_REMOTE_DEVICE_INFO_FMT)
+
+#define INFOROM_NVL_OBJECT_V3G_MINION_DATA_ARRAY_FMT \
+ INFOROM_FMT_REP08(INFOROM_NVL_OBJECT_V3_MINION_DATA_FMT) \
+ INFOROM_FMT_REP04(INFOROM_NVL_OBJECT_V3_MINION_DATA_FMT)
+
+#define INFOROM_NVL_OBJECT_V3G_ERROR_LOG_FMT \
+ INFOROM_FMT_REP128(INFOROM_NVL_OBJECT_V3_ERROR_ENTRY_FMT) \
+ INFOROM_FMT_REP64(INFOROM_NVL_OBJECT_V3_ERROR_ENTRY_FMT) \
+ INFOROM_FMT_REP32(INFOROM_NVL_OBJECT_V3_ERROR_ENTRY_FMT) \
+ INFOROM_FMT_REP16(INFOROM_NVL_OBJECT_V3_ERROR_ENTRY_FMT)
+
+#define INFOROM_NVL_OBJECT_V3G_FMT \
+ INFOROM_OBJECT_HEADER_V1_00_FMT \
+ INFOROM_NVL_OBJECT_V3G_REMOTE_DEVICE_INFO_ARRAY_FMT \
+ INFOROM_NVL_OBJECT_V3G_MINION_DATA_ARRAY_FMT \
+ INFOROM_NVL_OBJECT_V3G_MAX_CORRECTABLE_ERROR_RATES_FMT \
+ INFOROM_NVL_OBJECT_V3G_ERROR_LOG_FMT
+
+#define INFOROM_NVL_OBJECT_V3G_PACKED_SIZE 5936
+
+// Version 3.S0 ---------------------------------------------------------------
+#define INFOROM_NVL_OBJECT_V3S_NUM_LINKS 36
+#define INFOROM_NVL_OBJECT_V3S_NUM_ERROR_ENTRIES 721
+
+typedef INFOROM_NVL_OBJECT_V3_CORRECTABLE_ERROR_RATE
+ INFOROM_NVL_OBJECT_V3S_CORRECTABLE_ERROR_RATE_ARRAY[INFOROM_NVL_OBJECT_V3S_NUM_LINKS];
+
+#define INFOROM_NVL_OBJECT_V3S_CORRECTABLE_ERROR_RATE_ARRAY_FMT \
+ INFOROM_FMT_REP32(INFOROM_NVL_OBJECT_V3_CORRECTABLE_ERROR_RATE_FMT) \
+ INFOROM_FMT_REP04(INFOROM_NVL_OBJECT_V3_CORRECTABLE_ERROR_RATE_FMT)
+
+typedef struct INFOROM_NVL_OBJECT_V3S_MAX_CORRECTABLE_ERROR_RATES
+{
+ INFOROM_NVL_OBJECT_V3S_CORRECTABLE_ERROR_RATE_ARRAY dailyMaxCorrectableErrorRates[5];
+ INFOROM_NVL_OBJECT_V3S_CORRECTABLE_ERROR_RATE_ARRAY monthlyMaxCorrectableErrorRates[3];
+} INFOROM_NVL_OBJECT_V3S_MAX_CORRECTABLE_ERROR_RATES;
+
+#define INFOROM_NVL_OBJECT_V3S_MAX_CORRECTABLE_ERROR_RATES_FMT \
+ INFOROM_FMT_REP08(INFOROM_NVL_OBJECT_V3S_CORRECTABLE_ERROR_RATE_ARRAY_FMT)
+
+typedef struct INFOROM_NVL_OBJECT_V3S
+{
+ INFOROM_OBJECT_HEADER_V1_00 header;
+ INFOROM_NVL_OBJECT_V3_REMOTE_DEVICE_INFO remoteDeviceInfo[INFOROM_NVL_OBJECT_V3S_NUM_LINKS];
+ INFOROM_NVL_OBJECT_V3_MINION_DATA minionData[INFOROM_NVL_OBJECT_V3S_NUM_LINKS];
+ INFOROM_NVL_OBJECT_V3S_MAX_CORRECTABLE_ERROR_RATES maxCorrectableErrorRates;
+ INFOROM_NVL_OBJECT_V3_ERROR_ENTRY errorLog[INFOROM_NVL_OBJECT_V3S_NUM_ERROR_ENTRIES];
+} INFOROM_NVL_OBJECT_V3S;
+
+#define INFOROM_NVL_OBJECT_V3S_REMOTE_DEVICE_INFO_ARRAY_FMT \
+ INFOROM_FMT_REP32(INFOROM_NVL_OBJECT_V3_REMOTE_DEVICE_INFO_FMT) \
+ INFOROM_FMT_REP04(INFOROM_NVL_OBJECT_V3_REMOTE_DEVICE_INFO_FMT)
+
+#define INFOROM_NVL_OBJECT_V3S_MINION_DATA_ARRAY_FMT \
+ INFOROM_FMT_REP32(INFOROM_NVL_OBJECT_V3_MINION_DATA_FMT) \
+ INFOROM_FMT_REP04(INFOROM_NVL_OBJECT_V3_MINION_DATA_FMT)
+
+#define INFOROM_NVL_OBJECT_V3S_ERROR_LOG_FMT \
+ INFOROM_FMT_REP512(INFOROM_NVL_OBJECT_V3_ERROR_ENTRY_FMT) \
+ INFOROM_FMT_REP128(INFOROM_NVL_OBJECT_V3_ERROR_ENTRY_FMT) \
+ INFOROM_FMT_REP64(INFOROM_NVL_OBJECT_V3_ERROR_ENTRY_FMT) \
+ INFOROM_FMT_REP16(INFOROM_NVL_OBJECT_V3_ERROR_ENTRY_FMT) \
+ INFOROM_NVL_OBJECT_V3_ERROR_ENTRY_FMT
+
+#define INFOROM_NVL_OBJECT_V3S_FMT \
+ INFOROM_OBJECT_HEADER_V1_00_FMT \
+ INFOROM_NVL_OBJECT_V3S_REMOTE_DEVICE_INFO_ARRAY_FMT \
+ INFOROM_NVL_OBJECT_V3S_MINION_DATA_ARRAY_FMT \
+ INFOROM_NVL_OBJECT_V3S_MAX_CORRECTABLE_ERROR_RATES_FMT \
+ INFOROM_NVL_OBJECT_V3S_ERROR_LOG_FMT
+
+#define INFOROM_NVL_OBJECT_V3S_PACKED_SIZE 17808
+
+// Version 4.G0 ---------------------------------------------------------------
+
+#define INFOROM_NVL_OBJECT_V4G_NUM_LINKS 18
+
+typedef struct INFOROM_NVL_OBJECT_V4_L1_THRESHOLD_DATA
+{
+ inforom_U032 word1;
+ inforom_U032 word2;
+} INFOROM_NVL_OBJECT_V4_L1_THRESHOLD_DATA;
+
+#define INFOROM_NVL_OBJECT_V4_L1_THRESHOLD_DATA_FMT "2d"
+
+typedef INFOROM_NVL_OBJECT_V3_CORRECTABLE_ERROR_RATE
+ INFOROM_NVL_OBJECT_V4G_CORRECTABLE_ERROR_RATE_ARRAY[INFOROM_NVL_OBJECT_V4G_NUM_LINKS];
+
+#define INFOROM_NVL_OBJECT_V4G_CORRECTABLE_ERROR_RATE_ARRAY_FMT \
+ INFOROM_FMT_REP16(INFOROM_NVL_OBJECT_V3_CORRECTABLE_ERROR_RATE_FMT) \
+ INFOROM_FMT_REP02(INFOROM_NVL_OBJECT_V3_CORRECTABLE_ERROR_RATE_FMT)
+
+typedef struct INFOROM_NVL_OBJECT_V4G_MAX_CORRECTABLE_ERROR_RATES
+{
+ INFOROM_NVL_OBJECT_V4G_CORRECTABLE_ERROR_RATE_ARRAY dailyMaxCorrectableErrorRates[5];
+ INFOROM_NVL_OBJECT_V4G_CORRECTABLE_ERROR_RATE_ARRAY monthlyMaxCorrectableErrorRates[3];
+} INFOROM_NVL_OBJECT_V4G_MAX_CORRECTABLE_ERROR_RATES;
+
+#define INFOROM_NVL_OBJECT_V4G_MAX_CORRECTABLE_ERROR_RATES_FMT \
+ INFOROM_FMT_REP08(INFOROM_NVL_OBJECT_V4G_CORRECTABLE_ERROR_RATE_ARRAY_FMT)
+
+typedef struct INFOROM_NVL_OBJECT_V4G_RESERVED
+{
+ inforom_U032 reserved;
+} INFOROM_NVL_OBJECT_V4G_RESERVED;
+
+#define INFOROM_NVL_OBJECT_V4G_RESERVED_FMT "d"
+
+#define INFOROM_NVL_OBJECT_V4G_NUM_ERROR_ENTRIES 364
+
+typedef struct INFOROM_NVL_OBJECT_V4G
+{
+ INFOROM_OBJECT_HEADER_V1_00 header;
+ INFOROM_NVL_OBJECT_V4_L1_THRESHOLD_DATA l1ThresholdData;
+ INFOROM_NVL_OBJECT_V3_REMOTE_DEVICE_INFO remoteDeviceInfo[INFOROM_NVL_OBJECT_V4G_NUM_LINKS];
+ INFOROM_NVL_OBJECT_V4G_MAX_CORRECTABLE_ERROR_RATES maxCorrectableErrorRates;
+ INFOROM_NVL_OBJECT_V3_ERROR_ENTRY errorLog[INFOROM_NVL_OBJECT_V4G_NUM_ERROR_ENTRIES];
+ INFOROM_NVL_OBJECT_V4G_RESERVED reserved;
+} INFOROM_NVL_OBJECT_V4G;
+
+#define INFOROM_NVL_OBJECT_V4G_REMOTE_DEVICE_INFO_ARRAY_FMT \
+ INFOROM_FMT_REP16(INFOROM_NVL_OBJECT_V3_REMOTE_DEVICE_INFO_FMT) \
+ INFOROM_FMT_REP02(INFOROM_NVL_OBJECT_V3_REMOTE_DEVICE_INFO_FMT)
+
+#define INFOROM_NVL_OBJECT_V4G_ERROR_LOG_FMT \
+ INFOROM_FMT_REP128(INFOROM_NVL_OBJECT_V3_ERROR_ENTRY_FMT) \
+ INFOROM_FMT_REP128(INFOROM_NVL_OBJECT_V3_ERROR_ENTRY_FMT) \
+ INFOROM_FMT_REP64(INFOROM_NVL_OBJECT_V3_ERROR_ENTRY_FMT) \
+ INFOROM_FMT_REP32(INFOROM_NVL_OBJECT_V3_ERROR_ENTRY_FMT) \
+ INFOROM_FMT_REP08(INFOROM_NVL_OBJECT_V3_ERROR_ENTRY_FMT) \
+ INFOROM_FMT_REP04(INFOROM_NVL_OBJECT_V3_ERROR_ENTRY_FMT)
+
+#define INFOROM_NVL_OBJECT_V4G_FMT \
+ INFOROM_OBJECT_HEADER_V1_00_FMT \
+ INFOROM_NVL_OBJECT_V4G_REMOTE_DEVICE_INFO_ARRAY_FMT \
+ INFOROM_NVL_OBJECT_V4_L1_THRESHOLD_DATA_FMT \
+ INFOROM_NVL_OBJECT_V4G_MAX_CORRECTABLE_ERROR_RATES_FMT \
+ INFOROM_NVL_OBJECT_V4G_ERROR_LOG_FMT \
+ INFOROM_NVL_OBJECT_V4G_RESERVED_FMT
+
+#define INFOROM_NVL_OBJECT_V4G_PACKED_SIZE 8400
+
+// Version 4.S0 ---------------------------------------------------------------
+#define INFOROM_NVL_OBJECT_V4S_NUM_LINKS 64
+#define INFOROM_NVL_OBJECT_V4S_NUM_ERROR_ENTRIES 1286
+
+typedef INFOROM_NVL_OBJECT_V3_CORRECTABLE_ERROR_RATE
+ INFOROM_NVL_OBJECT_V4S_CORRECTABLE_ERROR_RATE_ARRAY[INFOROM_NVL_OBJECT_V4S_NUM_LINKS];
+
+#define INFOROM_NVL_OBJECT_V4S_CORRECTABLE_ERROR_RATE_ARRAY_FMT \
+ INFOROM_FMT_REP64(INFOROM_NVL_OBJECT_V3_CORRECTABLE_ERROR_RATE_FMT)
+
+typedef struct INFOROM_NVL_OBJECT_V4S_MAX_CORRECTABLE_ERROR_RATES
+{
+ INFOROM_NVL_OBJECT_V4S_CORRECTABLE_ERROR_RATE_ARRAY dailyMaxCorrectableErrorRates[5];
+ INFOROM_NVL_OBJECT_V4S_CORRECTABLE_ERROR_RATE_ARRAY monthlyMaxCorrectableErrorRates[3];
+} INFOROM_NVL_OBJECT_V4S_MAX_CORRECTABLE_ERROR_RATES;
+
+#define INFOROM_NVL_OBJECT_V4S_MAX_CORRECTABLE_ERROR_RATES_FMT \
+ INFOROM_FMT_REP08(INFOROM_NVL_OBJECT_V4S_CORRECTABLE_ERROR_RATE_ARRAY_FMT)
+
+typedef struct INFOROM_NVL_OBJECT_V4S
+{
+ INFOROM_OBJECT_HEADER_V1_00 header;
+ INFOROM_NVL_OBJECT_V4_L1_THRESHOLD_DATA l1ThresholdData;
+ INFOROM_NVL_OBJECT_V3_REMOTE_DEVICE_INFO remoteDeviceInfo[INFOROM_NVL_OBJECT_V4S_NUM_LINKS];
+ INFOROM_NVL_OBJECT_V4S_MAX_CORRECTABLE_ERROR_RATES maxCorrectableErrorRates;
+ INFOROM_NVL_OBJECT_V3_ERROR_ENTRY errorLog[INFOROM_NVL_OBJECT_V4S_NUM_ERROR_ENTRIES];
+} INFOROM_NVL_OBJECT_V4S;
+
+#define INFOROM_NVL_OBJECT_V4S_REMOTE_DEVICE_INFO_ARRAY_FMT \
+ INFOROM_FMT_REP64(INFOROM_NVL_OBJECT_V3_REMOTE_DEVICE_INFO_FMT)
+
+#define INFOROM_NVL_OBJECT_V4S_ERROR_LOG_FMT \
+ INFOROM_FMT_REP512(INFOROM_NVL_OBJECT_V3_ERROR_ENTRY_FMT) \
+ INFOROM_FMT_REP512(INFOROM_NVL_OBJECT_V3_ERROR_ENTRY_FMT) \
+ INFOROM_FMT_REP256(INFOROM_NVL_OBJECT_V3_ERROR_ENTRY_FMT) \
+ INFOROM_FMT_REP04(INFOROM_NVL_OBJECT_V3_ERROR_ENTRY_FMT) \
+ INFOROM_FMT_REP02(INFOROM_NVL_OBJECT_V3_ERROR_ENTRY_FMT)
+
+#define INFOROM_NVL_OBJECT_V4S_FMT \
+ INFOROM_OBJECT_HEADER_V1_00_FMT \
+ INFOROM_NVL_OBJECT_V4S_REMOTE_DEVICE_INFO_ARRAY_FMT \
+ INFOROM_NVL_OBJECT_V4_L1_THRESHOLD_DATA_FMT \
+ INFOROM_NVL_OBJECT_V4S_MAX_CORRECTABLE_ERROR_RATES_FMT \
+ INFOROM_NVL_OBJECT_V4S_ERROR_LOG_FMT
+
+#define INFOROM_NVL_OBJECT_V4S_PACKED_SIZE 29680
+
+#define INFOROM_NVL_OBJECT_V5_MAX_NUM_LINKS 18
+#define INFOROM_NVL_OBJECT_V5_MAX_NUM_LANES_PER_LINK 2
+
+#define INFOROM_NVL_OBJECT_V5_RECORD_METRIC_LINK_DATA_UPTIME_FMT "d"
+#define INFOROM_NVL_OBJECT_V5_RECORD_METRIC_LINK_DATA_LOCAL_MAX_RAW_BER_FMT "b"
+#define INFOROM_NVL_OBJECT_V5_RECORD_METRIC_LINK_DATA_LOCAL_MAX_EFF_BER_FMT "b"
+#define INFOROM_NVL_OBJECT_V5_RECORD_METRIC_LINK_DATA_CURR_EFF_MONITOR_FMT "w"
+#define INFOROM_NVL_OBJECT_V5_RECORD_METRIC_LINK_DATA_PLR_XMIT_RETRY_FMT "d"
+#define INFOROM_NVL_OBJECT_V5_RECORD_METRIC_LINK_DATA_TOTAL_RECOVERY_FMT "d"
+
+#define INFOROM_NVL_OBJECT_V5_RECORD_METRIC_LINK_DATA_FMT \
+ INFOROM_NVL_OBJECT_V5_RECORD_METRIC_LINK_DATA_UPTIME_FMT \
+ INFOROM_NVL_OBJECT_V5_RECORD_METRIC_LINK_DATA_LOCAL_MAX_RAW_BER_FMT \
+ INFOROM_NVL_OBJECT_V5_RECORD_METRIC_LINK_DATA_LOCAL_MAX_EFF_BER_FMT \
+ INFOROM_NVL_OBJECT_V5_RECORD_METRIC_LINK_DATA_CURR_EFF_MONITOR_FMT \
+ INFOROM_NVL_OBJECT_V5_RECORD_METRIC_LINK_DATA_PLR_XMIT_RETRY_FMT \
+ INFOROM_NVL_OBJECT_V5_RECORD_METRIC_LINK_DATA_TOTAL_RECOVERY_FMT
+
+typedef struct INFOROM_NVL_OBJECT_V5_RECORD_METRIC_LINK_DATA // u8[16]
+{
+ inforom_U032 uptime; // u8[4]
+ inforom_U008 localMaxRawBERExp; // u8[1]
+ inforom_U008 localMaxEffBERExp; // u8[1]
+ inforom_U016 currEffBERMonitor; // u8[2]
+ inforom_U032 plrXmitRetryWithinTSecMaxLo; // u8[4]
+ inforom_U032 totalSuccessfulRecoveryEvents; // u8[4]
+} INFOROM_NVL_OBJECT_V5_RECORD_METRIC_LINK_DATA;
+
+#define INFOROM_NVL_OBJECT_V5_RECORD_METRIC_MFDE_FMT "43d"
+
+typedef struct INFOROM_NVL_OBJECT_V5_RECORD_METRIC_MFDE // u8[172]
+{
+ inforom_U032 data[43]; // u8[172]
+} INFOROM_NVL_OBJECT_V5_RECORD_METRIC_MFDE;
+
+#define INFOROM_NVL_OBJECT_V5_RECORD_METRIC_DATA_INITIAL_RAW_BER_FMT "18b"
+#define INFOROM_NVL_OBJECT_V5_RECORD_METRIC_DATA_INITIAL_EFF_BER_FMT "18b"
+#define INFOROM_NVL_OBJECT_V5_RECORD_METRIC_DATA_LAST_DOWN_REASON_FMT "18b"
+#define INFOROM_NVL_OBJECT_V5_RECORD_METRIC_DATA_PADDING_FMT "82b"
+
+#define INFOROM_NVL_OBJECT_V5_RECORD_METRIC_DATA_FMT \
+ INFOROM_NVL_OBJECT_V5_RECORD_METRIC_MFDE_FMT \
+ INFOROM_FMT_REP16(INFOROM_NVL_OBJECT_V5_RECORD_METRIC_LINK_DATA_FMT) \
+ INFOROM_FMT_REP02(INFOROM_NVL_OBJECT_V5_RECORD_METRIC_LINK_DATA_FMT) \
+ INFOROM_NVL_OBJECT_V5_RECORD_METRIC_DATA_INITIAL_RAW_BER_FMT \
+ INFOROM_NVL_OBJECT_V5_RECORD_METRIC_DATA_INITIAL_EFF_BER_FMT \
+ INFOROM_NVL_OBJECT_V5_RECORD_METRIC_DATA_LAST_DOWN_REASON_FMT \
+ INFOROM_NVL_OBJECT_V5_RECORD_METRIC_DATA_PADDING_FMT
+
+typedef struct INFOROM_NVL_OBJECT_V5_RECORD_METRIC_DATA // u8[596]
+{
+ INFOROM_NVL_OBJECT_V5_RECORD_METRIC_MFDE mfdeEvent; // u8[172]
+ INFOROM_NVL_OBJECT_V5_RECORD_METRIC_LINK_DATA link[INFOROM_NVL_OBJECT_V5_MAX_NUM_LINKS]; // u8[288]
+ inforom_U008 initialRawBERExp[INFOROM_NVL_OBJECT_V5_MAX_NUM_LINKS]; // u8[18]
+ inforom_U008 initialEffBERExp[INFOROM_NVL_OBJECT_V5_MAX_NUM_LINKS]; // u8[18]
+ inforom_U008 lastDownReason[INFOROM_NVL_OBJECT_V5_MAX_NUM_LINKS]; // u8[18]
+ inforom_U008 padding[82]; // u8[82]
+} INFOROM_NVL_OBJECT_V5_RECORD_METRIC_DATA;
+
+#define INFOROM_NVL_OBJECT_V5_ACCUMULATIVE_METRIC_HISTOGRAM_FMT "12b"
+
+typedef struct INFOROM_NVL_OBJECT_V5_ACCUMULATIVE_METRIC_HISTOGRAM // u8[12]
+{
+ inforom_U008 fixedPoint[12]; // u8[12]
+} INFOROM_NVL_OBJECT_V5_ACCUMULATIVE_METRIC_HISTOGRAM;
+
+#define INFOROM_NVL_OBJECT_V5_ACCUMULATIVE_METRIC_LINK_DATA_LINK_DOWN_COUNT_FMT "d"
+
+#define INFOROM_NVL_OBJECT_V5_ACCUMULATIVE_METRIC_LINK_DATA_FMT \
+ "4b" \
+ INFOROM_NVL_OBJECT_V5_ACCUMULATIVE_METRIC_LINK_DATA_LINK_DOWN_COUNT_FMT \
+ INFOROM_NVL_OBJECT_V5_ACCUMULATIVE_METRIC_HISTOGRAM_FMT
+
+typedef struct INFOROM_NVL_OBJECT_V5_ACCUMULATIVE_METRIC_LINK_DATA // u8[20]
+{
+ inforom_U008 reserved[4]; // u8[4]
+ inforom_U032 linkDownCount; // u8[4]
+ INFOROM_NVL_OBJECT_V5_ACCUMULATIVE_METRIC_HISTOGRAM downReasonHistogram; // u8[12]
+} INFOROM_NVL_OBJECT_V5_ACCUMULATIVE_METRIC_LINK_DATA;
+
+#define INFOROM_NVL_OBJECT_V5_ACCUMULATIVE_METRIC_DATA_GLOBAL_MAX_RAW_BER_FMT "18b"
+#define INFOROM_NVL_OBJECT_V5_ACCUMULATIVE_METRIC_DATA_GLOBAL_MAX_EFF_BER_FMT "18b"
+
+#define INFOROM_NVL_OBJECT_V5_ACCUMULATIVE_METRIC_DATA_FMT \
+ INFOROM_FMT_REP16(INFOROM_NVL_OBJECT_V5_ACCUMULATIVE_METRIC_LINK_DATA_FMT) \
+ INFOROM_FMT_REP02(INFOROM_NVL_OBJECT_V5_ACCUMULATIVE_METRIC_LINK_DATA_FMT) \
+ INFOROM_NVL_OBJECT_V5_ACCUMULATIVE_METRIC_DATA_GLOBAL_MAX_RAW_BER_FMT \
+ INFOROM_NVL_OBJECT_V5_ACCUMULATIVE_METRIC_DATA_GLOBAL_MAX_EFF_BER_FMT
+
+typedef struct INFOROM_NVL_OBJECT_V5_ACCUMULATIVE_METRIC_DATA // u8[396]
+{
+ INFOROM_NVL_OBJECT_V5_ACCUMULATIVE_METRIC_LINK_DATA link[INFOROM_NVL_OBJECT_V5_MAX_NUM_LINKS]; // u8[360]
+ inforom_U008 globalMaxRawBERExp[INFOROM_NVL_OBJECT_V5_MAX_NUM_LINKS]; // u8[18]
+ inforom_U008 globalMaxEffBERExp[INFOROM_NVL_OBJECT_V5_MAX_NUM_LINKS]; // u8[18]
+} INFOROM_NVL_OBJECT_V5_ACCUMULATIVE_METRIC_DATA;
+
+#define INFOROM_NVL_OBJECT_V5_RESERVED_FMT "8b"
+
+#define INFOROM_NVL_OBJECT_V5_FMT \
+ INFOROM_OBJECT_HEADER_V1_00_FMT \
+ INFOROM_NVL_OBJECT_V5_ACCUMULATIVE_METRIC_DATA_FMT \
+ INFOROM_NVL_OBJECT_V5_RECORD_METRIC_DATA_FMT \
+ INFOROM_NVL_OBJECT_V5_RESERVED_FMT
+
+#define INFOROM_NVL_OBJECT_V5_PACKED_SIZE 1008
+
+typedef struct INFOROM_NVL_OBJECT_V5 // u8[1008]
+{
+ INFOROM_OBJECT_HEADER_V1_00 header; // u8[8]
+ INFOROM_NVL_OBJECT_V5_ACCUMULATIVE_METRIC_DATA accumulative; // u8[396]
+ INFOROM_NVL_OBJECT_V5_RECORD_METRIC_DATA record; // u8[596]
+ inforom_U008 reserved[8]; // u8[8]
+} INFOROM_NVL_OBJECT_V5;
+
+#define INFOROM_NVL_OBJECT_FLUSH_INTERVAL (60 * 10)
+
+typedef struct
+{
+ struct
+ {
+ NvU32 flitCrc;
+ NvU32 laneCrc[4];
+ } errorsPerMinute[INFOROM_NVL_OBJECT_V3G_NUM_LINKS];
+
+ struct
+ {
+ NvU32 flitCrc;
+ NvU32 laneCrc[4];
+ NvU32 rxLinkReplay;
+ NvU32 txLinkReplay;
+ NvU32 linkRecovery;
+ } lastRead[INFOROM_NVL_OBJECT_V3G_NUM_LINKS];
+} INFOROM_NVL_CORRECTABLE_ERROR_RATE_STATE_V3G;
+
+typedef struct
+{
+ struct
+ {
+ NvU32 flitCrc;
+ NvU32 laneCrc[4];
+ } errorsPerMinute[INFOROM_NVL_OBJECT_V3S_NUM_LINKS];
+
+ struct
+ {
+ NvU32 flitCrc;
+ NvU32 laneCrc[4];
+ NvU32 rxLinkReplay;
+ NvU32 txLinkReplay;
+ NvU32 linkRecovery;
+ } lastRead[INFOROM_NVL_OBJECT_V3S_NUM_LINKS];
+} INFOROM_NVL_CORRECTABLE_ERROR_RATE_STATE_V3S;
+
+typedef struct
+{
+ struct
+ {
+ NvU32 flitCrc;
+ NvU32 laneCrc[4];
+ } errorsPerMinute[INFOROM_NVL_OBJECT_V4G_NUM_LINKS];
+
+ struct
+ {
+ NvU32 flitCrc;
+ NvU32 laneCrc[4];
+ NvU32 rxLinkReplay;
+ NvU32 txLinkReplay;
+ NvU32 linkRecovery;
+ } lastRead[INFOROM_NVL_OBJECT_V4G_NUM_LINKS];
+} INFOROM_NVL_CORRECTABLE_ERROR_RATE_STATE_V4G;
+
+typedef struct
+{
+ struct
+ {
+ NvU32 flitCrc;
+ NvU32 laneCrc[4];
+ } errorsPerMinute[INFOROM_NVL_OBJECT_V4S_NUM_LINKS];
+
+ struct
+ {
+ NvU32 flitCrc;
+ NvU32 laneCrc[4];
+ NvU32 rxLinkReplay;
+ NvU32 txLinkReplay;
+ NvU32 linkRecovery;
+ } lastRead[INFOROM_NVL_OBJECT_V4S_NUM_LINKS];
+} INFOROM_NVL_CORRECTABLE_ERROR_RATE_STATE_V4S;
+
+typedef struct INFOROM_NVL_CORRECTABLE_ERROR_RATE_STATE_V5
+{
+ struct
+ {
+ void *pParams;
+ void *pAsyncHandle;
+ } request[2];
+ NvU8 head;
+} INFOROM_NVL_CORRECTABLE_ERROR_RATE_STATE_V5, INFOROM_NVL_CORRECTABLE_ERROR_RATE_STATE_V6;
+
+typedef union
+{
+ INFOROM_NVL_CORRECTABLE_ERROR_RATE_STATE_V3G v3g;
+ INFOROM_NVL_CORRECTABLE_ERROR_RATE_STATE_V3S v3s;
+ INFOROM_NVL_CORRECTABLE_ERROR_RATE_STATE_V4G v4g;
+ INFOROM_NVL_CORRECTABLE_ERROR_RATE_STATE_V4S v4s;
+ INFOROM_NVL_CORRECTABLE_ERROR_RATE_STATE_V5 v5;
+ INFOROM_NVL_CORRECTABLE_ERROR_RATE_STATE_V6 v6;
+} INFOROM_NVL_CORRECTABLE_ERROR_RATE_STATE;
+
+typedef struct
+{
+ const char *pFmt;
+ NvU8 *pPackedObject;
+ INFOROM_NVL_OBJECT *pNvl;
+
+ NvBool bDirty;
+ NvBool bDisableFatalErrorLogging;
+ NvBool bDisableCorrectableErrorLogging;
+ NvBool bCallbackPending;
+
+ NvU32 timeSinceLastFlush;
+
+ INFOROM_NVL_CORRECTABLE_ERROR_RATE_STATE correctableErrorRateState;
+} INFOROM_NVLINK_STATE, *PINFOROM_NVLINK_STATE;
+
+// Version 6.0 -------------------------------------------------------------
+#define INFOROM_NVL_OBJECT_V6_MAX_NUM_LINKS 36
+#define INFOROM_NVL_OBJECT_V6_MAX_NUM_LANES_PER_LINK 2
+
+#define INFOROM_NVL_OBJECT_V6_RECORD_METRIC_LINK_DATA_PLR_TX_BW_LOSS_LOW_FREQUENCY_FMT "6w"
+typedef struct INFOROM_NVL_OBJECT_V6_RECORD_METRIC_LINK_DATA_PLR_TX_BW_LOSS_LOW_FREQUENCY // u16[6]
+{
+ inforom_U016 lastPlrTxBwLossLf; // u16
+ inforom_U016 meanPlrTxBwLossLf; // u16
+ inforom_U016 maxPlrTxBwLossLf; // u16
+ inforom_U016 consBelowPlrTxBwLossLfThreshold; // u16
+ inforom_U016 numOfPlrTxBwLossLfWarnings; // u16
+ inforom_U016 numOfPlrTxBwLossLfAlarms; // u16
+} INFOROM_NVL_OBJECT_V6_RECORD_METRIC_LINK_DATA_PLR_TX_BW_LOSS_LOW_FREQUENCY;
+
+#define INFOROM_NVL_OBJECT_V6_RECORD_METRIC_LINK_DATA_RECOVERY_BW_LOSS_LOW_FREQUENCY_FMT "6w"
+typedef struct INFOROM_NVL_OBJECT_V6_RECORD_METRIC_LINK_DATA_RECOVERY_BW_LOSS_LOW_FREQUENCY // u16[6]
+{
+ inforom_U016 lastRecoveryBwLossLf; // u16
+ inforom_U016 meanRecoveryBwLossLf; // u16
+ inforom_U016 maxRecoveryBwLossLf; // u16
+ inforom_U016 consBelowRecoveryBwLossLfThreshold; // u16
+ inforom_U016 numOfRecoveryBwLossLfWarnings; // u16
+ inforom_U016 numOfRecoveryBwLossLfAlarms; // u16
+} INFOROM_NVL_OBJECT_V6_RECORD_METRIC_LINK_DATA_RECOVERY_BW_LOSS_LOW_FREQUENCY;
+
+#define INFOROM_NVL_OBJECT_V6_RECORD_METRIC_LINK_DATA_EFFECTIVE_BER_LOW_FREQUENCY_FMT "3w3b6n"
+typedef struct INFOROM_NVL_OBJECT_V6_RECORD_METRIC_LINK_DATA_EFFECTIVE_BER_LOW_FREQUENCY // u8[12]
+{
+ inforom_U016 consBelowEffBerLfThreshold; // u16
+ inforom_U016 numOfEffBerLfWarnings; // u16
+ inforom_U016 numOfEffBERLfAlarms; // u16
+ inforom_U008 meanEffBerLfMagnitue; // u8
+ inforom_U008 lastEffBerLfMagnitue; // u8
+ inforom_U008 maxEffBerLfMagnitue; // u8
+ inforom_U004 lastEffBerLfCoef; // u4
+ inforom_U004 meanEffBerLfCoef; // u4
+ inforom_U004 maxEffBerLfCoef; // u4
+ inforom_U004 padding[3]; // u4[3]
+} INFOROM_NVL_OBJECT_V6_RECORD_METRIC_LINK_DATA_EFFECTIVE_BER_LOW_FREQUENCY;
+
+#define INFOROM_NVL_OBJECT_V6_RECORD_METRIC_LINK_DATA_UPTIME_FMT "d"
+#define INFOROM_NVL_OBJECT_V6_RECORD_METRIC_LINK_DATA_TOTAL_RECOVERY_FMT "d"
+
+#define INFOROM_NVL_OBJECT_V6_RECORD_METRIC_LINK_DATA_FMT \
+ INFOROM_NVL_OBJECT_V6_RECORD_METRIC_LINK_DATA_UPTIME_FMT \
+ INFOROM_NVL_OBJECT_V6_RECORD_METRIC_LINK_DATA_PLR_TX_BW_LOSS_LOW_FREQUENCY_FMT \
+ INFOROM_NVL_OBJECT_V6_RECORD_METRIC_LINK_DATA_RECOVERY_BW_LOSS_LOW_FREQUENCY_FMT \
+ INFOROM_NVL_OBJECT_V6_RECORD_METRIC_LINK_DATA_EFFECTIVE_BER_LOW_FREQUENCY_FMT \
+ INFOROM_NVL_OBJECT_V6_RECORD_METRIC_LINK_DATA_TOTAL_RECOVERY_FMT
+
+typedef struct INFOROM_NVL_OBJECT_V6_RECORD_METRIC_LINK_DATA // u8[44]
+{
+ inforom_U032 uptime; // u8[4]
+ INFOROM_NVL_OBJECT_V6_RECORD_METRIC_LINK_DATA_PLR_TX_BW_LOSS_LOW_FREQUENCY plrTxBwLossLf; // u16[6]
+ INFOROM_NVL_OBJECT_V6_RECORD_METRIC_LINK_DATA_RECOVERY_BW_LOSS_LOW_FREQUENCY recoveryBwLossLf; // u16[6]
+ INFOROM_NVL_OBJECT_V6_RECORD_METRIC_LINK_DATA_EFFECTIVE_BER_LOW_FREQUENCY effBerLf; // u8[12]
+ inforom_U032 totalSuccessfulRecoveryEvents; // u8[4]
+} INFOROM_NVL_OBJECT_V6_RECORD_METRIC_LINK_DATA;
+
+#define INFOROM_NVL_OBJECT_V6_RECORD_METRIC_MFDE_FMT "43w"
+
+typedef struct INFOROM_NVL_OBJECT_V6_RECORD_METRIC_MFDE // u8[172]
+{
+ inforom_U032 data[43]; // u8[172]
+} INFOROM_NVL_OBJECT_V6_RECORD_METRIC_MFDE;
+
+#define INFOROM_NVL_OBJECT_V6_RECORD_METRIC_DATA_INITIAL_RAW_BER_FMT "36b"
+#define INFOROM_NVL_OBJECT_V6_RECORD_METRIC_DATA_INITIAL_EFF_BER_FMT "36b"
+#define INFOROM_NVL_OBJECT_V6_RECORD_METRIC_DATA_LAST_DOWN_REASON_FMT "36b"
+#define INFOROM_NVL_OBJECT_V6_RECORD_METRIC_DATA_LAST_DOWN_ADVANCED_REASON_FMT "36w"
+
+#define INFOROM_NVL_OBJECT_V6_RECORD_METRIC_DATA_FMT \
+ INFOROM_NVL_OBJECT_V6_RECORD_METRIC_MFDE_FMT \
+ INFOROM_FMT_REP32(INFOROM_NVL_OBJECT_V6_RECORD_METRIC_LINK_DATA_FMT) \
+ INFOROM_FMT_REP04(INFOROM_NVL_OBJECT_V6_RECORD_METRIC_LINK_DATA_FMT) \
+ INFOROM_NVL_OBJECT_V6_RECORD_METRIC_DATA_INITIAL_RAW_BER_FMT \
+ INFOROM_NVL_OBJECT_V6_RECORD_METRIC_DATA_INITIAL_EFF_BER_FMT \
+ INFOROM_NVL_OBJECT_V6_RECORD_METRIC_DATA_LAST_DOWN_REASON_FMT \
+ INFOROM_NVL_OBJECT_V6_RECORD_METRIC_DATA_LAST_DOWN_ADVANCED_REASON_FMT
+
+typedef struct INFOROM_NVL_OBJECT_V6_RECORD_METRIC_DATA // u8[1936]
+{
+ INFOROM_NVL_OBJECT_V6_RECORD_METRIC_MFDE mfdeEvent; // u8[172]
+ INFOROM_NVL_OBJECT_V6_RECORD_METRIC_LINK_DATA link[INFOROM_NVL_OBJECT_V6_MAX_NUM_LINKS]; // u8[1584]
+ inforom_U008 initialRawBERExp[INFOROM_NVL_OBJECT_V6_MAX_NUM_LINKS]; // u8[36]
+ inforom_U008 initialEffBERExp[INFOROM_NVL_OBJECT_V6_MAX_NUM_LINKS]; // u8[36]
+ inforom_U008 lastDownReason[INFOROM_NVL_OBJECT_V6_MAX_NUM_LINKS]; // u8[36]
+ inforom_U016 lastDownAdvancedReason[INFOROM_NVL_OBJECT_V6_MAX_NUM_LINKS]; // u8[72]
+} INFOROM_NVL_OBJECT_V6_RECORD_METRIC_DATA;
+
+#define INFOROM_NVL_OBJECT_V6_ACCUMULATIVE_METRIC_HISTOGRAM_FMT "16b"
+
+typedef struct INFOROM_NVL_OBJECT_V6_ACCUMULATIVE_METRIC_HISTOGRAM // u8[24]
+{
+ inforom_U008 fixedPoint[24]; // u8[24]
+} INFOROM_NVL_OBJECT_V6_ACCUMULATIVE_METRIC_HISTOGRAM;
+
+#define INFOROM_NVL_OBJECT_V6_ACCUMULATIVE_METRIC_HISTOGRAM_XID_LINK_FMT "5b"
+
+typedef struct INFOROM_NVL_OBJECT_V6_ACCUMULATIVE_METRIC_HISTOGRAM_XID_LINK // u8[5]
+{
+ inforom_U008 fixedPoint[5];
+} INFOROM_NVL_OBJECT_V6_ACCUMULATIVE_METRIC_HISTOGRAM_XID_LINK;
+
+#define INFOROM_NVL_OBJECT_V6_ACCUMULATIVE_METRIC_HISTOGRAM_XID_GPU_FMT "d3b"
+
+typedef struct INFOROM_NVL_OBJECT_V6_ACCUMULATIVE_METRIC_HISTOGRAM_XID_GPU // u8[7]
+{
+ inforom_U032 xidCount; // u8[4]
+ inforom_U008 fixedPoint[3]; // u8[3] 3 per GPU XIDs
+} INFOROM_NVL_OBJECT_V6_ACCUMULATIVE_METRIC_HISTOGRAM_XID_GPU;
+
+#define INFOROM_NVL_OBJECT_V6_ACCUMULATIVE_METRIC_LINK_DATA_LINK_DOWN_COUNT_FMT "d"
+#define INFOROM_NVL_OBJECT_V6_ACCUMULATIVE_METRIC_LINK_DATA_PADDING_FMT "3b"
+
+#define INFOROM_NVL_OBJECT_V6_ACCUMULATIVE_METRIC_LINK_DATA_FMT \
+ INFOROM_NVL_OBJECT_V6_ACCUMULATIVE_METRIC_LINK_DATA_LINK_DOWN_COUNT_FMT \
+ INFOROM_NVL_OBJECT_V6_ACCUMULATIVE_METRIC_HISTOGRAM_FMT \
+ INFOROM_NVL_OBJECT_V6_ACCUMULATIVE_METRIC_HISTOGRAM_XID_LINK_FMT \
+ INFOROM_NVL_OBJECT_V6_ACCUMULATIVE_METRIC_LINK_DATA_PADDING_FMT
+
+typedef struct INFOROM_NVL_OBJECT_V6_ACCUMULATIVE_METRIC_LINK_DATA // u8[36]
+{
+ inforom_U032 linkDownCount; // u8[4]
+ INFOROM_NVL_OBJECT_V6_ACCUMULATIVE_METRIC_HISTOGRAM downReasonHistogram; // u8[24]
+ INFOROM_NVL_OBJECT_V6_ACCUMULATIVE_METRIC_HISTOGRAM_XID_LINK xidHistogram; // u8[5]
+ inforom_U008 padding[3]; // u8[3]
+} INFOROM_NVL_OBJECT_V6_ACCUMULATIVE_METRIC_LINK_DATA;
+
+#define INFOROM_NVL_OBJECT_V6_ACCUMULATIVE_METRIC_DATA_PADDING_FMT "b"
+
+#define INFOROM_NVL_OBJECT_V6_ACCUMULATIVE_METRIC_DATA_FMT \
+ INFOROM_FMT_REP32(INFOROM_NVL_OBJECT_V6_ACCUMULATIVE_METRIC_LINK_DATA_FMT) \
+ INFOROM_FMT_REP04(INFOROM_NVL_OBJECT_V6_ACCUMULATIVE_METRIC_LINK_DATA_FMT) \
+ INFOROM_NVL_OBJECT_V6_ACCUMULATIVE_METRIC_HISTOGRAM_XID_GPU_FMT \
+ INFOROM_NVL_OBJECT_V6_ACCUMULATIVE_METRIC_DATA_PADDING_FMT
+
+typedef struct INFOROM_NVL_OBJECT_V6_ACCUMULATIVE_METRIC_DATA // u8[1304]
+{
+ INFOROM_NVL_OBJECT_V6_ACCUMULATIVE_METRIC_LINK_DATA link[INFOROM_NVL_OBJECT_V6_MAX_NUM_LINKS]; // u8[1296]
+ INFOROM_NVL_OBJECT_V6_ACCUMULATIVE_METRIC_HISTOGRAM_XID_GPU xidHistogram; // u8[7]
+ inforom_U008 padding; // u8
+} INFOROM_NVL_OBJECT_V6_ACCUMULATIVE_METRIC_DATA;
+
+#define INFOROM_NVL_OBJECT_V6_RESERVED_FMT "784b"
+
+#define INFOROM_NVL_OBJECT_V6_FMT \
+ INFOROM_OBJECT_HEADER_V1_00_FMT \
+ INFOROM_NVL_OBJECT_V6_ACCUMULATIVE_METRIC_DATA_FMT \
+ INFOROM_NVL_OBJECT_V6_RECORD_METRIC_DATA_FMT \
+ INFOROM_NVL_OBJECT_V6_RESERVED_FMT
+
+#define INFOROM_NVL_OBJECT_V6_PACKED_SIZE 4032
+
+typedef struct INFOROM_NVL_OBJECT_V6 // u8[]
+{
+ INFOROM_OBJECT_HEADER_V1_00 header; // u8[8]
+ INFOROM_NVL_OBJECT_V6_ACCUMULATIVE_METRIC_DATA accumulative; // u8[1304]
+ INFOROM_NVL_OBJECT_V6_RECORD_METRIC_DATA record; // u8[1936]
+ inforom_U008 reserved[784]; // u8[784]
+} INFOROM_NVL_OBJECT_V6;
+
+union INFOROM_NVL_OBJECT
+{
+ INFOROM_OBJECT_HEADER_V1_00 header;
+ INFOROM_NVL_OBJECT_V1 v1;
+ INFOROM_NVL_OBJECT_V2 v2;
+ INFOROM_NVL_OBJECT_V3G v3g;
+ INFOROM_NVL_OBJECT_V3S v3s;
+ INFOROM_NVL_OBJECT_V4G v4g;
+ INFOROM_NVL_OBJECT_V4S v4s;
+ INFOROM_NVL_OBJECT_V5 v5;
+ INFOROM_NVL_OBJECT_V6 v6;
+};
+
+#endif /* _IFRNVL_H_ */
diff --git a/userspace/sdks/nv570/nvalloc/common/inc/inforom/ifrstruct.h b/userspace/sdks/nv570/nvalloc/common/inc/inforom/ifrstruct.h
new file mode 100644
index 0000000..5c1caed
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/common/inc/inforom/ifrstruct.h
@@ -0,0 +1,110 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 1999-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _IFRSTRUCT_H_
+#define _IFRSTRUCT_H_
+
+#include "inforom/types.h"
+
+#include "inforom/ifrnvl.h"
+#include "inforom/ifrecc.h"
+#include "inforom/ifrdem.h"
+#include "inforom/omsdef.h"
+
+#define INFOROM_OBD_OBJECT_V1_XX_PACKED_SIZE 128
+
+struct INFOROM_OBD_OBJECT_V1_XX
+{
+ INFOROM_OBJECT_HEADER_V1_00 header;
+ inforom_U032 buildDate;
+ inforom_U008 marketingName[24];
+ inforom_U008 serialNumber[16];
+ inforom_U008 memoryManufacturer;
+ inforom_U008 memoryPartID[20];
+ inforom_U008 memoryDateCode[6];
+ inforom_U008 productPartNumber[20];
+ inforom_U008 boardRevision[3];
+ inforom_U008 boardType;
+ inforom_U008 board699PartNumber[20];
+ inforom_U008 reserved[5];
+};
+#define INFOROM_OBD_OBJECT_V1_XX_FMT INFOROM_OBJECT_HEADER_V1_00_FMT "d116b"
+typedef struct INFOROM_OBD_OBJECT_V1_XX INFOROM_OBD_OBJECT_V1_XX;
+
+#define INFOROM_OBD_OBJECT_V2_XX_PACKED_SIZE 224
+
+struct INFOROM_OBD_OBJECT_V2_XX
+{
+ INFOROM_OBJECT_HEADER_V1_00 header;
+ inforom_U032 buildDate;
+ inforom_U008 marketingName[24];
+ inforom_U008 serialNumber[16];
+ inforom_U008 memoryManufacturer;
+ inforom_U008 memoryPartID[20];
+ inforom_U008 memoryDateCode[6];
+ inforom_U008 productPartNumber[20];
+ inforom_U008 boardRevision[3];
+ inforom_U008 boardType;
+ inforom_U008 board699PartNumber[20];
+ inforom_U032 productLength;
+ inforom_U032 productWidth;
+ inforom_U032 productHeight;
+ inforom_U008 vbiosFactoryVersion[5];
+ inforom_U008 board965PartNumber[20];
+ inforom_U008 reserved[64];
+};
+#define INFOROM_OBD_OBJECT_V2_XX_FMT INFOROM_OBJECT_HEADER_V1_00_FMT "d111b3d89b"
+typedef struct INFOROM_OBD_OBJECT_V2_XX INFOROM_OBD_OBJECT_V2_XX;
+
+//
+// OEM 1.0
+//
+
+#define INFOROM_OEM_OBJECT_V1_00_PACKED_SIZE 512
+#define INFOROM_OEM_OBJECT_HEADER_VERSION 1
+
+struct INFOROM_OEM_OBJECT_V1_00
+{
+ INFOROM_OBJECT_HEADER_V1_00 header;
+ inforom_U008 oemInfo[504];
+};
+#define INFOROM_OEM_OBJECT_V1_00_FMT INFOROM_OBJECT_HEADER_V1_00_FMT "504b"
+typedef struct INFOROM_OEM_OBJECT_V1_00 INFOROM_OEM_OBJECT_V1_00;
+
+#define INFOROM_IMG_OBJECT_V1_00_PACKED_SIZE 64
+#define INFOROM_IMG_OBJECT_V1_00_VERSION_LENGTH 16
+
+struct INFOROM_IMG_OBJECT_V1_00
+{
+ INFOROM_OBJECT_HEADER_V1_00 header;
+ inforom_U008 version[INFOROM_IMG_OBJECT_V1_00_VERSION_LENGTH];
+ inforom_U016 pciDeviceId;
+ inforom_U016 pciVendorId;
+ inforom_U016 pciSubsystemId;
+ inforom_U016 pciSubsystemVendorId;
+ inforom_U008 reserved[32];
+};
+#define INFOROM_IMG_OBJECT_V1_00_FMT INFOROM_OBJECT_HEADER_V1_00_FMT "16b4w32b"
+typedef struct INFOROM_IMG_OBJECT_V1_00 INFOROM_IMG_OBJECT_V1_00;
+
+#endif // _IFRSTRUCT_H_
diff --git a/userspace/sdks/nv570/nvalloc/common/inc/inforom/omsdef.h b/userspace/sdks/nv570/nvalloc/common/inc/inforom/omsdef.h
new file mode 100644
index 0000000..9509a7b
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/common/inc/inforom/omsdef.h
@@ -0,0 +1,116 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2020-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _INFOROM_OMSDEF_H_
+#define _INFOROM_OMSDEF_H_
+
+#include "inforom/types.h"
+
+#define INFOROM_OMS_OBJECT_V1_PACKED_SIZE 112
+
+#define INFOROM_OMS_OBJECT_V1_SETTINGS_ENTRY_DATA_ENTRY_AVAILABLE 0:0
+#define INFOROM_OMS_OBJECT_V1_SETTINGS_ENTRY_DATA_ENTRY_AVAILABLE_NO 0
+#define INFOROM_OMS_OBJECT_V1_SETTINGS_ENTRY_DATA_ENTRY_AVAILABLE_YES 1
+#define INFOROM_OMS_OBJECT_V1_SETTINGS_ENTRY_DATA_FORCE_DEVICE_DISABLE 1:1
+#define INFOROM_OMS_OBJECT_V1_SETTINGS_ENTRY_DATA_FORCE_DEVICE_DISABLE_NO 0
+#define INFOROM_OMS_OBJECT_V1_SETTINGS_ENTRY_DATA_FORCE_DEVICE_DISABLE_YES 1
+
+#define INFOROM_OMS_OBJECT_V1G_SETTINGS_ENTRY_DATA_RESERVED 23:2
+#define INFOROM_OMS_OBJECT_V1G_SETTINGS_ENTRY_DATA_ENTRY_CHECKSUM 31:24
+
+typedef struct INFOROM_OMS_OBJECT_V1G_SETTINGS_ENTRY
+{
+ inforom_U032 data;
+ inforom_U032 clockLimitMin;
+ inforom_U032 clockLimitMax;
+} INFOROM_OMS_OBJECT_V1G_SETTINGS_ENTRY;
+
+#define INFOROM_OMS_OBJECT_V1G_NUM_SETTINGS_ENTRIES 8
+
+typedef struct INFOROM_OMS_OBJECT_V1G
+{
+ INFOROM_OBJECT_HEADER_V1_00 header;
+ inforom_U032 lifetimeRefreshCount;
+ INFOROM_OMS_OBJECT_V1G_SETTINGS_ENTRY settings[
+ INFOROM_OMS_OBJECT_V1G_NUM_SETTINGS_ENTRIES];
+ inforom_U032 reserved;
+} INFOROM_OMS_OBJECT_V1G;
+
+#define INFOROM_OMS_OBJECT_V1G_FMT INFOROM_OBJECT_HEADER_V1_00_FMT "26d"
+
+#define INFOROM_OMS_OBJECT_V1S_SETTINGS_ENTRY_DATA_RESERVED 7:2
+#define INFOROM_OMS_OBJECT_V1S_SETTINGS_ENTRY_DATA_ENTRY_CHECKSUM 15:8
+
+typedef struct INFOROM_OMS_OBJECT_V1S_SETTINGS_ENTRY
+{
+ inforom_U016 data;
+} INFOROM_OMS_OBJECT_V1S_SETTINGS_ENTRY;
+
+#define INFOROM_OMS_OBJECT_V1S_NUM_SETTINGS_ENTRIES 50
+
+typedef struct INFOROM_OMS_OBJECT_V1S
+{
+ INFOROM_OBJECT_HEADER_V1_00 header;
+ inforom_U032 lifetimeRefreshCount;
+ INFOROM_OMS_OBJECT_V1S_SETTINGS_ENTRY settings[
+ INFOROM_OMS_OBJECT_V1S_NUM_SETTINGS_ENTRIES];
+} INFOROM_OMS_OBJECT_V1S;
+
+#define INFOROM_OMS_OBJECT_V1S_FMT INFOROM_OBJECT_HEADER_V1_00_FMT "d50w"
+
+typedef struct INFOROM_OMS_V1S_DATA
+{
+ INFOROM_OMS_OBJECT_V1S_SETTINGS_ENTRY *pIter;
+ INFOROM_OMS_OBJECT_V1S_SETTINGS_ENTRY prev;
+ INFOROM_OMS_OBJECT_V1S_SETTINGS_ENTRY *pNext;
+} INFOROM_OMS_V1S_DATA;
+
+typedef struct INFOROM_OMS_V1G_DATA
+{
+ INFOROM_OMS_OBJECT_V1G_SETTINGS_ENTRY *pIter;
+ INFOROM_OMS_OBJECT_V1G_SETTINGS_ENTRY prev;
+ INFOROM_OMS_OBJECT_V1G_SETTINGS_ENTRY *pNext;
+} INFOROM_OMS_V1G_DATA;
+
+typedef union
+{
+ INFOROM_OBJECT_HEADER_V1_00 header;
+ INFOROM_OMS_OBJECT_V1S v1s;
+ INFOROM_OMS_OBJECT_V1G v1g;
+} INFOROM_OMS_OBJECT;
+
+typedef union
+{
+ INFOROM_OMS_V1S_DATA v1s;
+ INFOROM_OMS_V1G_DATA v1g;
+} INFOROM_OMS_DATA;
+
+typedef struct
+{
+ const char *pFmt;
+ NvU8 *pPackedObject;
+ INFOROM_OMS_OBJECT *pOms;
+ INFOROM_OMS_DATA omsData;
+} INFOROM_OMS_STATE;
+
+#endif /* _INFOROM_OMSDEF_H_ */
diff --git a/userspace/sdks/nv570/nvalloc/common/inc/inforom/types.h b/userspace/sdks/nv570/nvalloc/common/inc/inforom/types.h
new file mode 100644
index 0000000..c062cb0
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/common/inc/inforom/types.h
@@ -0,0 +1,79 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2020-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _INFOROM_TYPES_H_
+#define _INFOROM_TYPES_H_
+
+/*!
+ * @file types.h
+ * @brief Common types and definitions used by InfoROM objects
+ */
+
+typedef NvS32 inforom_S008;
+typedef NvU32 inforom_U004;
+typedef NvU32 inforom_U008;
+typedef NvU32 inforom_U016;
+typedef NvU32 inforom_U024;
+typedef NvU32 inforom_U032;
+typedef NvU64 inforom_U064;
+typedef NvU8 inforom_X008;
+
+#define INFOROM_FMT_S08 's'
+#define INFOROM_FMT_U04 'n'
+#define INFOROM_FMT_U08 'b'
+#define INFOROM_FMT_U16 'w'
+#define INFOROM_FMT_U24 't'
+#define INFOROM_FMT_U32 'd'
+#define INFOROM_FMT_U64 'q'
+#define INFOROM_FMT_BINARY 'x'
+
+// Helper macros for generating repeating format sequences
+#define INFOROM_FMT_REP02(fmt) fmt fmt
+#define INFOROM_FMT_REP04(fmt) INFOROM_FMT_REP02(fmt) INFOROM_FMT_REP02(fmt)
+#define INFOROM_FMT_REP08(fmt) INFOROM_FMT_REP04(fmt) INFOROM_FMT_REP04(fmt)
+#define INFOROM_FMT_REP16(fmt) INFOROM_FMT_REP08(fmt) INFOROM_FMT_REP08(fmt)
+#define INFOROM_FMT_REP32(fmt) INFOROM_FMT_REP16(fmt) INFOROM_FMT_REP16(fmt)
+#define INFOROM_FMT_REP64(fmt) INFOROM_FMT_REP32(fmt) INFOROM_FMT_REP32(fmt)
+#define INFOROM_FMT_REP128(fmt) INFOROM_FMT_REP64(fmt) INFOROM_FMT_REP64(fmt)
+#define INFOROM_FMT_REP256(fmt) INFOROM_FMT_REP128(fmt) INFOROM_FMT_REP128(fmt)
+#define INFOROM_FMT_REP512(fmt) INFOROM_FMT_REP256(fmt) INFOROM_FMT_REP256(fmt)
+
+#define INFOROM_OBJECT_SUBVERSION_SUPPORTS_NVSWITCH(sv) \
+ ((((sv) & 0xF0) == 0) || (((sv) & 0xF0) == 0x20))
+
+#define INFOROM_OBJECT_HEADER_V1_00_SIZE_OFFSET 0x05
+#define INFOROM_OBJECT_HEADER_V1_00_CHECKSUM_OFFSET 0x07
+#define INFOROM_OBJECT_HEADER_V1_00_PACKED_SIZE 8
+
+typedef struct INFOROM_OBJECT_HEADER_V1_00
+{
+ inforom_S008 type[3];
+ inforom_U008 version;
+ inforom_U008 subversion;
+ inforom_U016 size;
+ inforom_U008 checksum;
+} INFOROM_OBJECT_HEADER_V1_00;
+
+#define INFOROM_OBJECT_HEADER_V1_00_FMT "3s2bwb"
+
+#endif // _INFOROM_TYPES_H_
diff --git a/userspace/sdks/nv570/nvalloc/common/inc/mctp_format.h b/userspace/sdks/nv570/nvalloc/common/inc/mctp_format.h
new file mode 100644
index 0000000..dd2052a
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/common/inc/mctp_format.h
@@ -0,0 +1,120 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef MCTP_FORMAT_H
+#define MCTP_FORMAT_H
+
+/**
+ * MCTP (Management Component Transport Protocol) format definitions
+ *
+ * Based on DMTF DSP0236 - MCTP Base Specification.
+ * This is a common header that will be used across multiple RM subsystems
+ * like FSP, GSP, SEC2, etc. for standardized inter-processor communication.
+ *
+ * MCTP provides a transport-agnostic protocol for message exchange between
+ * platform management components. RM uses MCTP's basic transport header
+ * with vendor-defined message types (NVDM) for internal communication.
+ */
+
+// MCTP Transport Header Fields (First DWORD)
+#define MCTP_HEADER_VERSION 3:0
+#define MCTP_HEADER_RSVD 7:4
+#define MCTP_HEADER_DEID 15:8
+#define MCTP_HEADER_SEID 23:16
+#define MCTP_HEADER_TAG 26:24
+#define MCTP_HEADER_TO 27:27
+#define MCTP_HEADER_SEQ 29:28
+#define MCTP_HEADER_EOM 30:30
+#define MCTP_HEADER_SOM 31:31
+
+// MCTP Message Header Fields (Second DWORD)
+#define MCTP_MSG_HEADER_TYPE 6:0
+#define MCTP_MSG_HEADER_IC 7:7
+#define MCTP_MSG_HEADER_VENDOR_ID 23:8
+#define MCTP_MSG_HEADER_NVDM_TYPE 31:24
+
+// MCTP Constants from specification
+#define MCTP_MSG_HEADER_TYPE_VENDOR_PCI 0x7e
+#define MCTP_MSG_HEADER_VENDOR_ID_NV 0x10de
+
+/**
+ * @brief Create MCTP transport header
+ *
+ * Generic helper function to construct the MCTP transport header (first DWORD).
+ * Can be used by any subsystem (FSP, GSP, SEC2, etc.).
+ *
+ * Note: TAG and TO fields are set to 0. These are only needed for complex
+ * scenarios with concurrent interleaved messages or request/response correlation,
+ * which are not currently used. Header version is hard-coded to 0x1 (MCTP 1.0).
+ *
+ * @param[in] som Start of Message flag (1 for first packet)
+ * @param[in] eom End of Message flag (1 for last packet)
+ * @param[in] seid Source Endpoint ID
+ * @param[in] deid Destination Endpoint ID
+ * @param[in] seq Packet sequence number (0-3, modulo 4)
+ *
+ * @return Constructed MCTP transport header (32-bit DWORD)
+ */
+static NV_INLINE NvU32
+mctpCreateTransportHeader
+(
+ NvU8 som,
+ NvU8 eom,
+ NvU8 seid,
+ NvU8 deid,
+ NvU8 seq
+)
+{
+ return REF_NUM(MCTP_HEADER_VERSION, 0x1) |
+ REF_NUM(MCTP_HEADER_SEID, seid) |
+ REF_NUM(MCTP_HEADER_DEID, deid) |
+ REF_NUM(MCTP_HEADER_SEQ, seq) |
+ REF_NUM(MCTP_HEADER_EOM, eom) |
+ REF_NUM(MCTP_HEADER_SOM, som);
+}
+
+/**
+ * @brief Create NVDM over MCTP header
+ *
+ * Generic helper function to construct the NVDM message header (second DWORD).
+ * Sets the MCTP message type to Vendor Defined PCI (0x7E) and includes
+ * NVIDIA's vendor ID (0x10DE) along with the subsystem-specific NVDM type.
+ * Can be used by any subsystem (FSP, GSP, SEC2, etc.).
+ *
+ * @param[in] nvdmType NVDM message type (subsystem/communication-path specific)
+ *
+ * @return Constructed NVDM header (32-bit DWORD)
+ */
+static NV_INLINE NvU32
+mctpCreateNvdmHeader
+(
+ NvU8 nvdmType
+)
+{
+ return REF_DEF(MCTP_MSG_HEADER_TYPE, _VENDOR_PCI) |
+ REF_NUM(MCTP_MSG_HEADER_IC, 0) |
+ REF_DEF(MCTP_MSG_HEADER_VENDOR_ID, _NV) |
+ REF_NUM(MCTP_MSG_HEADER_NVDM_TYPE, nvdmType);
+}
+
+#endif // MCTP_FORMAT_H
diff --git a/userspace/sdks/nv570/nvalloc/common/inc/nv-firmware-chip-family-select.h b/userspace/sdks/nv570/nvalloc/common/inc/nv-firmware-chip-family-select.h
new file mode 100644
index 0000000..962776a
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/common/inc/nv-firmware-chip-family-select.h
@@ -0,0 +1,230 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2022-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef NV_FIRMWARE_CHIP_FAMILY_SELECT_H
+#define NV_FIRMWARE_CHIP_FAMILY_SELECT_H
+
+
+
+#include <published/nv_arch.h>
+#include <nv-firmware.h>
+#include <nvctassert.h>
+
+static inline nv_firmware_chip_family_t nv_firmware_get_chip_family(
+ NvU32 gpuArch,
+ NvU32 gpuImpl
+)
+{
+ switch (gpuArch)
+ {
+ case GPU_ARCHITECTURE_TURING:
+ if (gpuImpl <= GPU_IMPLEMENTATION_TU106)
+ return NV_FIRMWARE_CHIP_FAMILY_TU10X;
+ else
+ return NV_FIRMWARE_CHIP_FAMILY_TU11X;
+
+ case GPU_ARCHITECTURE_AMPERE:
+ if (gpuImpl == GPU_IMPLEMENTATION_GA100)
+ return NV_FIRMWARE_CHIP_FAMILY_GA100;
+ else
+ return NV_FIRMWARE_CHIP_FAMILY_GA10X;
+
+ case GPU_ARCHITECTURE_ADA:
+ return NV_FIRMWARE_CHIP_FAMILY_AD10X;
+
+ case GPU_ARCHITECTURE_HOPPER:
+ return NV_FIRMWARE_CHIP_FAMILY_GH100;
+
+ case GPU_ARCHITECTURE_BLACKWELL_GB1XX:
+ if (gpuImpl == GPU_IMPLEMENTATION_GB10B)
+ return NV_FIRMWARE_CHIP_FAMILY_GB10Y;
+ else
+ return NV_FIRMWARE_CHIP_FAMILY_GB10X;
+
+ case GPU_ARCHITECTURE_BLACKWELL_GB2XX:
+ if (gpuImpl >= GPU_IMPLEMENTATION_GB20B)
+ return NV_FIRMWARE_CHIP_FAMILY_GB20Y;
+ else
+ return NV_FIRMWARE_CHIP_FAMILY_GB20X;
+
+ case GPU_ARCHITECTURE_RUBIN_GR1XX:
+ return NV_FIRMWARE_CHIP_FAMILY_GR10X;
+ }
+
+ return NV_FIRMWARE_CHIP_FAMILY_NULL;
+}
+
+typedef enum
+{
+ NV_FIRMWARE_TASK_INIT,
+ NV_FIRMWARE_TASK_RM,
+ NV_FIRMWARE_TASK_INTR,
+ NV_FIRMWARE_TASK_VGPU,
+ NV_FIRMWARE_TASK_MNOC,
+ NV_FIRMWARE_TASK_DEBUG,
+ NV_FIRMWARE_TASK_ROOT,
+ NV_FIRMWARE_TASK_RM_STATE_MONITOR,
+
+ NV_FIRMWARE_TASK_COUNT
+} nv_firmware_task_t;
+
+typedef enum {
+ NV_FIRMWARE_LIBOS_NONE_SUPPORTED = 0x0,
+ NV_FIRMWARE_LIBOS2_SUPPORTED = 0x1,
+ NV_FIRMWARE_LIBOS3_SUPPORTED = 0x2,
+} libosMappingType;
+
+typedef struct
+{
+ const char *memory_id;
+ const char *prefix;
+ const char *elf_section_name;
+ const NvU8 supported_os; // bitmask
+} nv_firmware_task_log_info_t;
+
+static inline
+const nv_firmware_task_log_info_t *nv_firmware_get_task_log_infos(unsigned *num_infos)
+{
+ const static nv_firmware_task_log_info_t infos[] =
+ {
+ {"LOGINIT", "INIT", ".fwlogging_init", NV_FIRMWARE_LIBOS2_SUPPORTED | NV_FIRMWARE_LIBOS3_SUPPORTED},
+ {"LOGRM", "RM", ".fwlogging_rm", NV_FIRMWARE_LIBOS2_SUPPORTED | NV_FIRMWARE_LIBOS3_SUPPORTED},
+ {"LOGINTR", "INTR", ".fwlogging_rm", NV_FIRMWARE_LIBOS3_SUPPORTED},
+ {"LOGVGPU", "VGPU", ".fwlogging_vgpu", NV_FIRMWARE_LIBOS2_SUPPORTED | NV_FIRMWARE_LIBOS3_SUPPORTED},
+ {"LOGMNOC", "MNOC", ".fwlogging_mnoc", NV_FIRMWARE_LIBOS3_SUPPORTED},
+ {"LOGDBG", "DBG", ".fwlogging_debug", NV_FIRMWARE_LIBOS3_SUPPORTED},
+ {"LOGROOT", "ROOT", ".fwlogging_start", NV_FIRMWARE_LIBOS3_SUPPORTED},
+ {"LOGRMON", "RMON", ".fwlogging_rm", NV_FIRMWARE_LIBOS3_SUPPORTED},
+ };
+
+ *num_infos = NV_ARRAY_ELEMENTS(infos);
+ ct_assert(NV_ARRAY_ELEMENTS(infos) == NV_FIRMWARE_TASK_COUNT);
+
+ return infos;
+}
+
+static inline
+const nv_firmware_task_log_info_t* nv_firmware_log_info_for_task(nv_firmware_task_t task_id)
+{
+ unsigned num_infos = 0;
+ const nv_firmware_task_log_info_t* infos = nv_firmware_get_task_log_infos(&num_infos);
+
+ if ((unsigned)task_id >= num_infos)
+ {
+ return NULL;
+ }
+
+ return &infos[task_id];
+}
+
+typedef struct
+{
+ const char *elf_section_name;
+
+ struct
+ {
+ NvU32 lo, hi;
+ } gpuArch;
+
+ struct
+ {
+ NvU32 lo, hi;
+ } gpuImpl;
+} nv_firmware_kernel_log_info_t;
+
+#define NV_FIRMWARE_KERNEL_LOG_MEMORY_ID "LOGKRNL"
+#define NV_FIRMWARE_KERNEL_LOG_PREFIX "KRNL"
+#define NV_FIRMWARE_GPU_ARCH_SHIFT 0x4
+
+//
+// HAL for selecting .fwlogging section. Chip ID is checked to fall within {gpuArch, gpuImpl}::{lo, hi}
+// ranges. Optional gpuImpl range can be used to specify sub-range of an architecture.
+// If `hi` is not set, the range is treated as open. Ranges are checked in order of specification.
+// Range overlaps are allowed and resolved by the order.
+//
+static inline
+const nv_firmware_kernel_log_info_t *nv_firmware_get_kernel_log_infos(unsigned *num_infos)
+{
+ const static nv_firmware_kernel_log_info_t infos[] =
+ {
+ {".fwlogging_kernel_gr10x",
+ {GPU_ARCHITECTURE_RUBIN_GR1XX}, // gr10x...
+ },
+ {".fwlogging_kernel_gb20y",
+ {GPU_ARCHITECTURE_BLACKWELL_GB2XX, GPU_ARCHITECTURE_BLACKWELL_GB2XX}, // gb20y
+ {GPU_IMPLEMENTATION_GB20B, 0}
+ },
+ {".fwlogging_kernel_gb20x",
+ {GPU_ARCHITECTURE_BLACKWELL_GB2XX}, // gb20x...
+ },
+ {".fwlogging_kernel_gb10y",
+ {GPU_ARCHITECTURE_BLACKWELL_GB1XX, GPU_ARCHITECTURE_BLACKWELL_GB1XX}, // gb10y
+ {GPU_IMPLEMENTATION_GB10B, 0}
+ },
+
+ {".fwlogging_kernel_gb10x",
+ {GPU_ARCHITECTURE_BLACKWELL_GB1XX}, // gb10x...
+ },
+
+ {".fwlogging_kernel_gh100",
+ {GPU_ARCHITECTURE_HOPPER, GPU_ARCHITECTURE_HOPPER}, // gh100
+ },
+
+ {".fwlogging_kernel_ga10x",
+ {GPU_ARCHITECTURE_AMPERE, GPU_ARCHITECTURE_ADA}, // ga10x...ad10x
+ },
+ };
+
+ *num_infos = NV_ARRAY_ELEMENTS(infos);
+
+ return infos;
+}
+
+static inline
+const nv_firmware_kernel_log_info_t *nv_firmware_kernel_log_info_for_gpu(NvU32 gpuArch, NvU32 gpuImpl)
+{
+ unsigned num_infos = 0;
+ const nv_firmware_kernel_log_info_t* infos = nv_firmware_get_kernel_log_infos(&num_infos);
+
+ for (unsigned i = 0; i < num_infos; i++)
+ {
+ const nv_firmware_kernel_log_info_t* info = &infos[i];
+
+ NvBool bMatchingArch = info->gpuArch.lo <= gpuArch;
+ if (info->gpuArch.hi != 0)
+ bMatchingArch &= gpuArch <= info->gpuArch.hi;
+
+ NvBool bMatchingImpl = info->gpuImpl.lo <= gpuImpl;
+ if (info->gpuImpl.hi != 0)
+ bMatchingImpl &= gpuImpl <= info->gpuImpl.hi;
+
+ if (bMatchingArch && bMatchingImpl)
+ {
+ return info;
+ }
+ }
+
+ return NULL;
+}
+
+#endif // NV_FIRMWARE_CHIP_FAMILY_SELECT_H
diff --git a/userspace/sdks/nv570/nvalloc/common/inc/nv-firmware.h b/userspace/sdks/nv570/nvalloc/common/inc/nv-firmware.h
new file mode 100644
index 0000000..000aa38
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/common/inc/nv-firmware.h
@@ -0,0 +1,145 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2022-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef NV_FIRMWARE_H
+#define NV_FIRMWARE_H
+
+
+
+#include <nvtypes.h>
+#include <nvmisc.h>
+
+typedef enum
+{
+ NV_FIRMWARE_TYPE_GSP,
+ NV_FIRMWARE_TYPE_GSP_LOG,
+ NV_FIRMWARE_TYPE_UCODES
+} nv_firmware_type_t;
+
+typedef enum
+{
+ NV_FIRMWARE_CHIP_FAMILY_NULL = 0,
+ NV_FIRMWARE_CHIP_FAMILY_TU10X = 1,
+ NV_FIRMWARE_CHIP_FAMILY_TU11X = 2,
+ NV_FIRMWARE_CHIP_FAMILY_GA100 = 3,
+ NV_FIRMWARE_CHIP_FAMILY_GA10X = 4,
+ NV_FIRMWARE_CHIP_FAMILY_AD10X = 5,
+ NV_FIRMWARE_CHIP_FAMILY_GH100 = 6,
+ NV_FIRMWARE_CHIP_FAMILY_GB10X = 8,
+ NV_FIRMWARE_CHIP_FAMILY_GB20X = 9,
+ NV_FIRMWARE_CHIP_FAMILY_GR10X = 10,
+ NV_FIRMWARE_CHIP_FAMILY_GB10Y = 11,
+ NV_FIRMWARE_CHIP_FAMILY_GB20Y = 12,
+ NV_FIRMWARE_CHIP_FAMILY_END,
+} nv_firmware_chip_family_t;
+
+static inline const char *nv_firmware_chip_family_to_string(
+ nv_firmware_chip_family_t fw_chip_family
+)
+{
+ switch (fw_chip_family) {
+ case NV_FIRMWARE_CHIP_FAMILY_GR10X: return "gr10x";
+ case NV_FIRMWARE_CHIP_FAMILY_GB10X: return "gb10x";
+ case NV_FIRMWARE_CHIP_FAMILY_GB10Y: return "gb10y";
+ case NV_FIRMWARE_CHIP_FAMILY_GB20Y: return "gb20y";
+ case NV_FIRMWARE_CHIP_FAMILY_GB20X: return "gb20x";
+ case NV_FIRMWARE_CHIP_FAMILY_GH100: return "gh100";
+ case NV_FIRMWARE_CHIP_FAMILY_AD10X: return "ad10x";
+ case NV_FIRMWARE_CHIP_FAMILY_GA10X: return "ga10x";
+ case NV_FIRMWARE_CHIP_FAMILY_GA100: return "ga100";
+ case NV_FIRMWARE_CHIP_FAMILY_TU11X: return "tu11x";
+ case NV_FIRMWARE_CHIP_FAMILY_TU10X: return "tu10x";
+
+ case NV_FIRMWARE_CHIP_FAMILY_END: // fall through
+ case NV_FIRMWARE_CHIP_FAMILY_NULL:
+ return "";
+ }
+ return "";
+}
+
+// The includer may optionally define
+// NV_FIRMWARE_FOR_NAME(name)
+// to return a platform-defined string for a given a firmware base name.
+//
+// The function nv_firmware_for_chip_family will then be available.
+#if defined(NV_FIRMWARE_FOR_NAME)
+static inline const char *nv_firmware_for_chip_family(
+ nv_firmware_type_t fw_type,
+ nv_firmware_chip_family_t fw_chip_family
+)
+{
+ switch (fw_chip_family)
+ {
+ case NV_FIRMWARE_CHIP_FAMILY_GR10X: // fall through
+ case NV_FIRMWARE_CHIP_FAMILY_GB10X: // fall through
+ case NV_FIRMWARE_CHIP_FAMILY_GB10Y: // fall through
+ case NV_FIRMWARE_CHIP_FAMILY_GB20Y: // fall through
+ case NV_FIRMWARE_CHIP_FAMILY_GB20X: // fall through
+ case NV_FIRMWARE_CHIP_FAMILY_GH100: // fall through
+ case NV_FIRMWARE_CHIP_FAMILY_AD10X: // fall through
+ case NV_FIRMWARE_CHIP_FAMILY_GA10X:
+ {
+ switch (fw_type)
+ {
+ case NV_FIRMWARE_TYPE_GSP: return NV_FIRMWARE_FOR_NAME("gsp_ga10x");
+ case NV_FIRMWARE_TYPE_GSP_LOG: return NV_FIRMWARE_FOR_NAME("gsp_log_ga10x");
+ case NV_FIRMWARE_TYPE_UCODES: return NV_FIRMWARE_FOR_NAME("ucodes_ga10x");
+ }
+ return "";
+ }
+
+ case NV_FIRMWARE_CHIP_FAMILY_GA100: // fall through
+ case NV_FIRMWARE_CHIP_FAMILY_TU11X: // fall through
+ case NV_FIRMWARE_CHIP_FAMILY_TU10X:
+ {
+ switch (fw_type)
+ {
+ case NV_FIRMWARE_TYPE_GSP: return NV_FIRMWARE_FOR_NAME("gsp_tu10x");
+ case NV_FIRMWARE_TYPE_GSP_LOG: return NV_FIRMWARE_FOR_NAME("gsp_log_tu10x");
+ case NV_FIRMWARE_TYPE_UCODES: return NV_FIRMWARE_FOR_NAME("ucodes_tu10x");
+ }
+ return "";
+ }
+
+ case NV_FIRMWARE_CHIP_FAMILY_END: // fall through
+ case NV_FIRMWARE_CHIP_FAMILY_NULL:
+ return "";
+ }
+
+ return "";
+}
+#endif // defined(NV_FIRMWARE_FOR_NAME)
+
+// The includer may optionally define
+// NV_FIRMWARE_DECLARE_GSP(name)
+// which will then be invoked (at the top-level) for each
+// gsp_* and ucodes_* (but not gsp_log_*)
+#if defined(NV_FIRMWARE_DECLARE_GSP)
+NV_FIRMWARE_DECLARE_GSP("gsp_ga10x")
+NV_FIRMWARE_DECLARE_GSP("gsp_tu10x")
+NV_FIRMWARE_DECLARE_GSP("ucodes_ga10x")
+NV_FIRMWARE_DECLARE_GSP("ucodes_tu10x")
+#endif // defined(NV_FIRMWARE_DECLARE_GSP)
+
+#endif // NV_FIRMWARE_DECLARE_GSP
+
diff --git a/userspace/sdks/nv570/nvalloc/common/inc/nvcst.h b/userspace/sdks/nv570/nvalloc/common/inc/nvcst.h
new file mode 100644
index 0000000..1b7239a
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/common/inc/nvcst.h
@@ -0,0 +1,460 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2004-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef NVCST_H
+#define NVCST_H
+
+#include <platform/chipset/chipset.h>
+#include <platform/chipset/chipset_info.h>
+#include <nvpcie.h>
+#include <nvdevid.h>
+
+#define CHIPSET_SETUP_FUNC(name) static NV_STATUS name(OBJCL *pCl);
+
+CHIPSET_SETUP_FUNC(Intel_25XX_setupFunc)
+CHIPSET_SETUP_FUNC(Intel_27XX_setupFunc)
+CHIPSET_SETUP_FUNC(Intel_2A40_setupFunc)
+CHIPSET_SETUP_FUNC(Intel_0040_setupFunc)
+CHIPSET_SETUP_FUNC(Intel_2E00_setupFunc)
+CHIPSET_SETUP_FUNC(Intel_25E0_setupFunc)
+CHIPSET_SETUP_FUNC(Intel_29XX_setupFunc)
+CHIPSET_SETUP_FUNC(Intel_29X0_setupFunc)
+CHIPSET_SETUP_FUNC(Intel_29E0_setupFunc)
+CHIPSET_SETUP_FUNC(Intel_359E_setupFunc)
+CHIPSET_SETUP_FUNC(Intel_4000_setupFunc)
+CHIPSET_SETUP_FUNC(Intel_4003_setupFunc)
+CHIPSET_SETUP_FUNC(Intel_3400_setupFunc)
+CHIPSET_SETUP_FUNC(Intel_3B42_setupFunc)
+CHIPSET_SETUP_FUNC(Intel_1C46_setupFunc)
+CHIPSET_SETUP_FUNC(Intel_1C10_setupFunc)
+CHIPSET_SETUP_FUNC(Intel_1C4B_setupFunc)
+CHIPSET_SETUP_FUNC(Intel_1C49_setupFunc)
+CHIPSET_SETUP_FUNC(Intel_1D40_setupFunc)
+CHIPSET_SETUP_FUNC(Intel_8D47_setupFunc)
+CHIPSET_SETUP_FUNC(Intel_8D44_setupFunc)
+CHIPSET_SETUP_FUNC(Intel_1E10_setupFunc)
+CHIPSET_SETUP_FUNC(Intel_8C4B_setupFunc)
+CHIPSET_SETUP_FUNC(Intel_8CC4_setupFunc)
+CHIPSET_SETUP_FUNC(Intel_A145_setupFunc)
+CHIPSET_SETUP_FUNC(Intel_A2C5_setupFunc)
+CHIPSET_SETUP_FUNC(Intel_A242_setupFunc)
+CHIPSET_SETUP_FUNC(Intel_A2D2_setupFunc)
+CHIPSET_SETUP_FUNC(Intel_A2C9_setupFunc)
+CHIPSET_SETUP_FUNC(Intel_A301_setupFunc)
+CHIPSET_SETUP_FUNC(Intel_0685_setupFunc)
+CHIPSET_SETUP_FUNC(Intel_4381_setupFunc)
+CHIPSET_SETUP_FUNC(Intel_7A82_setupFunc)
+CHIPSET_SETUP_FUNC(Intel_7A04_setupFunc)
+CHIPSET_SETUP_FUNC(Intel_7D06_setupFunc)
+CHIPSET_SETUP_FUNC(SiS_656_setupFunc)
+CHIPSET_SETUP_FUNC(ATI_RS400_setupFunc)
+CHIPSET_SETUP_FUNC(ATI_RS480_setupFunc)
+CHIPSET_SETUP_FUNC(ATI_RD870_setupFunc)
+CHIPSET_SETUP_FUNC(ATI_RD890_setupFunc)
+CHIPSET_SETUP_FUNC(ATI_RX780_setupFunc)
+CHIPSET_SETUP_FUNC(ATI_FX990_setupFunc)
+CHIPSET_SETUP_FUNC(AMD_RS780_setupFunc)
+CHIPSET_SETUP_FUNC(AMD_FX790_setupFunc)
+CHIPSET_SETUP_FUNC(AMD_FX890_setupFunc)
+CHIPSET_SETUP_FUNC(AMD_X370_setupFunc)
+CHIPSET_SETUP_FUNC(VIA_VX900_setupFunc)
+CHIPSET_SETUP_FUNC(APM_Storm_setupFunc)
+CHIPSET_SETUP_FUNC(ARMV8_generic_setupFunc)
+CHIPSET_SETUP_FUNC(Marvell_ThunderX2_setupFunc)
+CHIPSET_SETUP_FUNC(QEMU_setupFunc)
+CHIPSET_SETUP_FUNC(Ampere_eMag_setupFunc)
+CHIPSET_SETUP_FUNC(Huawei_Kunpeng920_setupFunc)
+CHIPSET_SETUP_FUNC(Mellanox_BlueField_setupFunc)
+CHIPSET_SETUP_FUNC(Mellanox_BlueField3_setupFunc)
+CHIPSET_SETUP_FUNC(Amazon_Gravitron2_setupFunc)
+CHIPSET_SETUP_FUNC(Fujitsu_A64FX_setupFunc)
+CHIPSET_SETUP_FUNC(Ampere_Altra_setupFunc)
+CHIPSET_SETUP_FUNC(Arm_NeoverseN1_setupFunc)
+CHIPSET_SETUP_FUNC(Ampere_AmpereOne_setupFunc)
+CHIPSET_SETUP_FUNC(Qualcomm_Snapdragon_setupFunc)
+CHIPSET_SETUP_FUNC(Nvidia_T210_setupFunc)
+CHIPSET_SETUP_FUNC(Nvidia_T194_setupFunc)
+CHIPSET_SETUP_FUNC(Nvidia_TH500_setupFunc)
+CHIPSET_SETUP_FUNC(PLDA_XpressRichAXI_setupFunc)
+CHIPSET_SETUP_FUNC(Riscv_generic_setupFunc)
+CHIPSET_SETUP_FUNC(Intel_A70D_setupFunc)
+CHIPSET_SETUP_FUNC(AMD_14D8_setupFunc)
+CHIPSET_SETUP_FUNC(Nvidia_TB500_setupFunc)
+
+
+// Keep string length <=32 (including termination) to avoid string copy overflow
+CSINFO chipsetInfo[] =
+{
+ // PCI Express chipset
+
+ {PCI_VENDOR_ID_INTEL, 0x2580, CS_INTEL_2580, "Grantsdale", Intel_25XX_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x2584, CS_INTEL_2584, "Alderwood", Intel_25XX_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x2588, CS_INTEL_2588, "Intel2588", Intel_25XX_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x2590, CS_INTEL_2590, "Alviso", Intel_25XX_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x25C0, CS_INTEL_25E0, "Greencreek", Intel_25E0_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x25E0, CS_INTEL_25E0, "Greencreek", Intel_25E0_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x29B0, CS_INTEL_29X0, "IntelQ35", Intel_29X0_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x29C0, CS_INTEL_29X0, "BearlakeB", Intel_29X0_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x29D0, CS_INTEL_29X0, "IntelQ33", Intel_29X0_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x29E0, CS_INTEL_29E0, "BearlakeX", Intel_29E0_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x359E, CS_INTEL_359E, "Tumwater", Intel_359E_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x4000, CS_INTEL_4000, "Stoakley", Intel_4000_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x4003, CS_INTEL_4003, "SkullTrail", Intel_4003_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x3400, CS_INTEL_3400, "IntelX58", Intel_3400_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x3403, CS_INTEL_3400, "IntelX58", Intel_3400_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x3405, CS_INTEL_3400, "IntelX58", Intel_3400_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x3406, CS_INTEL_3400, "Tylersburg", Intel_3400_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x2770, CS_INTEL_2770, "Lakeport", Intel_25XX_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x2774, CS_INTEL_2774, "Glenwood", Intel_27XX_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x277C, CS_INTEL_277C, "Glenwood", Intel_27XX_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x2A40, CS_INTEL_2A40, "Montevina", Intel_2A40_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x2E00, CS_INTEL_2E00, "Eaglelake", Intel_2E00_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x2E10, CS_INTEL_2E00, "Eaglelake", Intel_2E00_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x2E20, CS_INTEL_2E00, "Eaglelake", Intel_2E00_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x2E30, CS_INTEL_2E00, "Eaglelake", Intel_2E00_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x0044, CS_INTEL_0040, "Arrandale/Auburndale", Intel_0040_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x0062, CS_INTEL_0040, "Arrandale/Auburndale", Intel_0040_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0xD130, CS_INTEL_3B42, "Clarksfield", Intel_3B42_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0xD132, CS_INTEL_3B42, "Clarksfield", Intel_3B42_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x3B42, CS_INTEL_3B42, "P55/PM55/H57", Intel_3B42_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x1C46, CS_INTEL_1C46, "IntelP67-CougarPoint", Intel_1C46_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x1C4B, CS_INTEL_1C46, "HuronRiver-HM67", Intel_1C4B_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x1C4F, CS_INTEL_1C46, "HuronRiver-QM67", Intel_1C4B_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x1C49, CS_INTEL_1C49, "HuronRiver-HM65", Intel_1C49_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x1C44, CS_INTEL_1C46, "IntelZ68", Intel_1C46_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x1C10, CS_INTEL_1C10, "IntelP67", Intel_1C10_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x1D40, CS_INTEL_1D40, "IntelX79", Intel_1D40_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x1D41, CS_INTEL_1D40, "IntelX79", Intel_1D40_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x1E10, CS_INTEL_1E10, "IntelZ75", Intel_1E10_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x0150, CS_INTEL_1E10, "IntelZ77A-GD55", Intel_1E10_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x0151, CS_INTEL_1E10, "IntelZ77A-GD55", Intel_1E10_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x0100, CS_INTEL_1E10, "IntelZ77A-GD55", Intel_1E10_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x8C4B, CS_INTEL_8C4B, "SharkBay-HM87", Intel_8C4B_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x8C44, CS_INTEL_8C4B, "SharkBay-Z87", Intel_8C4B_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x8C41, CS_INTEL_8C4B, "SharkBay-H8x/P8x", Intel_8C4B_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x8C49, CS_INTEL_8C4B, "SharkBay-HM86", Intel_8C4B_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x8C52, CS_INTEL_8C4B, "SharkBay-E3", Intel_8C4B_setupFunc}, // Does not support SLI
+ {PCI_VENDOR_ID_INTEL, 0x8CC4, CS_INTEL_8CC4, "IntelZ97", Intel_8CC4_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x8CC3, CS_INTEL_8CC4, "IntelHM97", Intel_8CC4_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0xA145, CS_INTEL_A145, "IntelZ170", Intel_A145_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0xA14E, CS_INTEL_A145, "IntelHM170", Intel_A145_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0xA150, CS_INTEL_A145, "IntelHM170", Intel_A145_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0xA149, CS_INTEL_A145, "SkyLake C236", Intel_A145_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0xA14A, CS_INTEL_A145, "SkyLake C232", Intel_A145_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0xA14D, CS_INTEL_A145, "SkyLake-H", Intel_A145_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0xA244, CS_INTEL_A145, "SkyLake C620", Intel_A145_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0xA1C8, CS_INTEL_A145, "SkyLake C620", Intel_A145_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x8D47, CS_INTEL_8D47, "IntelX99", Intel_8D47_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x8D44, CS_INTEL_8D47, "IntelC612", Intel_8D44_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0xA2C5, CS_INTEL_A2C5, "IntelZ270", Intel_A2C5_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0xA154, CS_INTEL_A2C5, "IntelZ270", Intel_A2C5_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0xA152, CS_INTEL_A2C5, "IntelRX9S", Intel_A2C5_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0xA242, CS_INTEL_A242, "IntelC422", Intel_A242_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0xA241, CS_INTEL_A242, "IntelC422", Intel_A242_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0xA243, CS_INTEL_A242, "IntelC422", Intel_A242_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0xA2D2, CS_INTEL_A2D2, "IntelX299", Intel_A2D2_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0xA2D3, CS_INTEL_A242, "IntelC422", Intel_A242_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0xA1C1, CS_INTEL_A242, "IntelC621", Intel_A242_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0xA1C2, CS_INTEL_A242, "IntelC622", Intel_A242_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0xA1C3, CS_INTEL_A242, "IntelC624", Intel_A242_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0xA1C4, CS_INTEL_A242, "IntelC625", Intel_A242_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0xA1C5, CS_INTEL_A242, "IntelC626", Intel_A242_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0xA1C6, CS_INTEL_A242, "IntelC627", Intel_A242_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0xA1C7, CS_INTEL_A242, "IntelC628", Intel_A242_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0xA2C9, CS_INTEL_A2C9, "IntelZ370", Intel_A2C9_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0xA310, CS_INTEL_A2C9, "IntelZ370", Intel_A2C9_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0xA30E, CS_INTEL_A2C9, "IntelZ370", Intel_A2C9_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0xA305, CS_INTEL_A2C9, "IntelZ390", Intel_A2C9_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0xA30D, CS_INTEL_A2C9, "IntelH370", Intel_A2C9_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0xA301, CS_INTEL_A301, "Intel-CannonLake", Intel_A301_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x0685, CS_INTEL_0685, "Intel-CometLake", Intel_0685_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0xA1CB, CS_INTEL_C620, "Intel-IceLake", NULL},
+ {PCI_VENDOR_ID_INTEL, 0x4381, CS_INTEL_4381, "Intel-RocketLake", Intel_4381_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x4385, CS_INTEL_4381, "Intel-RocketLake", Intel_4381_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x7A82, CS_INTEL_7A82, "Intel-AlderLake", Intel_7A82_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x7A84, CS_INTEL_7A82, "Intel-AlderLake", Intel_7A82_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x1B81, CS_INTEL_1B81, "Intel-SapphireRapids", NULL},
+ {PCI_VENDOR_ID_INTEL, 0x7A8A, CS_INTEL_1B81, "Intel-SapphireRapids", NULL},
+ {PCI_VENDOR_ID_INTEL, 0x18DC, CS_INTEL_18DC, "Intel-IceLake", NULL},
+ {PCI_VENDOR_ID_INTEL, 0x7A04, CS_INTEL_7A04, "Intel-RaptorLake", Intel_7A04_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x5795, CS_INTEL_5795, "Intel-GraniteRapids", NULL},
+ {PCI_VENDOR_ID_INTEL, 0xA70D, CS_INTEL_B660, "Intel-B660", Intel_A70D_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x7D06, CS_INTEL_7D06, "Intel-Arrowlake", Intel_7D06_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x7D1A, CS_INTEL_7D06, "Intel-Arrowlake", Intel_7D06_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x7D1B, CS_INTEL_7D06, "Intel-Arrowlake", Intel_7D06_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x7D1C, CS_INTEL_7D06, "Intel-Arrowlake", Intel_7D06_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x7D2A, CS_INTEL_7D06, "Intel-Arrowlake", Intel_7D06_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x7D2D, CS_INTEL_7D06, "Intel-Arrowlake", Intel_7D06_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x7D2E, CS_INTEL_7D06, "Intel-Arrowlake", Intel_7D06_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x7D2F, CS_INTEL_7D06, "Intel-Arrowlake", Intel_7D06_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x7D35, CS_INTEL_7D06, "Intel-Arrowlake", Intel_7D06_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x7D67, CS_INTEL_7D06, "Intel-Arrowlake", Intel_7D06_setupFunc},
+ {PCI_VENDOR_ID_INTEL, 0x7D30, CS_INTEL_7D06, "Intel-Arrowlake", Intel_7D06_setupFunc},
+
+ {PCI_VENDOR_ID_NVIDIA, 0x0FAE, CS_NVIDIA_T210, "T210", Nvidia_T210_setupFunc},
+ {PCI_VENDOR_ID_NVIDIA, 0x0FAF, CS_NVIDIA_T210, "T210", Nvidia_T210_setupFunc},
+ {PCI_VENDOR_ID_NVIDIA, 0x10E5, CS_NVIDIA_T186, "T186", Nvidia_T210_setupFunc},
+ {PCI_VENDOR_ID_NVIDIA, 0x10E6, CS_NVIDIA_T186, "T186", Nvidia_T210_setupFunc},
+ {PCI_VENDOR_ID_NVIDIA, 0x1AD0, CS_NVIDIA_T194, "T194", Nvidia_T194_setupFunc},
+ {PCI_VENDOR_ID_NVIDIA, 0x1AD1, CS_NVIDIA_T194, "T194", Nvidia_T194_setupFunc},
+ {PCI_VENDOR_ID_NVIDIA, 0x1AD2, CS_NVIDIA_T194, "T194", Nvidia_T194_setupFunc},
+ {PCI_VENDOR_ID_NVIDIA, 0x229A, CS_NVIDIA_T234, "T234", Nvidia_T194_setupFunc},
+ {PCI_VENDOR_ID_NVIDIA, 0x229C, CS_NVIDIA_T234, "T234", Nvidia_T194_setupFunc},
+ {PCI_VENDOR_ID_NVIDIA, 0x229E, CS_NVIDIA_T234, "T234", Nvidia_T194_setupFunc},
+ {PCI_VENDOR_ID_NVIDIA, 0x22C2, CS_NVIDIA_T23x, "T23x", Nvidia_T194_setupFunc},
+ {PCI_VENDOR_ID_NVIDIA, 0x22C3, CS_NVIDIA_T23x, "T23x", Nvidia_T194_setupFunc},
+ {PCI_VENDOR_ID_NVIDIA, 0x22B1, CS_NVIDIA_TH500, "TH500", Nvidia_TH500_setupFunc},
+ {PCI_VENDOR_ID_NVIDIA, 0x22B2, CS_NVIDIA_TH500, "TH500", Nvidia_TH500_setupFunc},
+ {PCI_VENDOR_ID_NVIDIA, 0x22B3, CS_NVIDIA_TH500, "TH500", Nvidia_TH500_setupFunc},
+ {PCI_VENDOR_ID_NVIDIA, 0x22B4, CS_NVIDIA_TH500, "TH500", Nvidia_TH500_setupFunc},
+ {PCI_VENDOR_ID_NVIDIA, 0x22B8, CS_NVIDIA_TH500, "TH500", Nvidia_TH500_setupFunc},
+ {PCI_VENDOR_ID_NVIDIA, 0x22B9, CS_NVIDIA_TH500, "TH500", Nvidia_TH500_setupFunc},
+ {PCI_VENDOR_ID_NVIDIA, 0x22D6, CS_NVIDIA_T264, "T264", Nvidia_T194_setupFunc},
+ {PCI_VENDOR_ID_NVIDIA, 0x22D8, CS_NVIDIA_T264, "T264", Nvidia_T194_setupFunc},
+ {PCI_VENDOR_ID_NVIDIA, 0x22DA, CS_NVIDIA_T264, "T264", Nvidia_T194_setupFunc},
+ {PCI_VENDOR_ID_NVIDIA, 0x2B00, CS_NVIDIA_T264, "T264", Nvidia_T194_setupFunc},
+ {PCI_VENDOR_ID_NVIDIA, 0x2F95, CS_NVIDIA_TB500, "TB500", Nvidia_TB500_setupFunc},
+ {PCI_VENDOR_ID_NVIDIA, 0x2F96, CS_NVIDIA_TB500, "TB500", Nvidia_TB500_setupFunc},
+ {PCI_VENDOR_ID_NVIDIA, 0x2F97, CS_NVIDIA_TB500, "TB500", Nvidia_TB500_setupFunc},
+ {PCI_VENDOR_ID_NVIDIA, 0x2F98, CS_NVIDIA_TB500, "TB500", Nvidia_TB500_setupFunc},
+ {PCI_VENDOR_ID_NVIDIA, 0x2F99, CS_NVIDIA_TB500, "TB500", Nvidia_TB500_setupFunc},
+
+ {PCI_VENDOR_ID_SIS, 0x0649, CS_SIS_649, "649", SiS_656_setupFunc},
+ {PCI_VENDOR_ID_SIS, 0x0656, CS_SIS_656, "656", SiS_656_setupFunc},
+
+ {PCI_VENDOR_ID_ATI, 0x5A31, CS_ATI_RS400, "RS400", ATI_RS400_setupFunc},
+ {PCI_VENDOR_ID_ATI, 0x5A33, CS_ATI_RS400, "RS400", ATI_RS400_setupFunc},
+ {PCI_VENDOR_ID_ATI, 0x5950, CS_ATI_RS480, "RS480", ATI_RS480_setupFunc},
+ {PCI_VENDOR_ID_ATI, 0x5951, CS_ATI_RS480, "RS480", ATI_RS480_setupFunc},
+ {PCI_VENDOR_ID_ATI, 0x5956, CS_ATI_FX790, "FX790" ,AMD_FX790_setupFunc},
+ {PCI_VENDOR_ID_ATI, 0x5A11, CS_ATI_FX890, "FX890" ,AMD_FX890_setupFunc},
+ {PCI_VENDOR_ID_ATI, 0x5a13, CS_ATI_RD850, "RD850" ,ATI_RD870_setupFunc},
+ {PCI_VENDOR_ID_ATI, 0x5a12, CS_ATI_RD870, "RD870" ,ATI_RD870_setupFunc},
+ {PCI_VENDOR_ID_ATI, 0x5a10, CS_ATI_RD890, "RD890" ,ATI_RD890_setupFunc},
+ {PCI_VENDOR_ID_ATI, 0x5957, CS_ATI_RX780, "RX780" ,ATI_RX780_setupFunc},
+ {PCI_VENDOR_ID_ATI, 0x5A14, CS_ATI_FX990, "FX990/X990/970",ATI_FX990_setupFunc},
+
+ {PCI_VENDOR_ID_AMD, 0x9601, CS_AMD_GX890, "GX890" ,AMD_FX890_setupFunc},
+ {PCI_VENDOR_ID_AMD, 0x9600, CS_AMD_RS780, "RS780" ,AMD_RS780_setupFunc},
+ {PCI_VENDOR_ID_AMD, 0x790e, CS_AMD_X370, "X370/X399/X470/ TRX40/X570/WRX80", AMD_X370_setupFunc },
+ {PCI_VENDOR_ID_AMD, 0x14d8, CS_AMD_RPH, "AMD-Raphael", AMD_14D8_setupFunc},
+
+ {PCI_VENDOR_ID_VIA, 0x0308, CS_VIA_VT8369B, "VT8369B", NULL},
+ {PCI_VENDOR_ID_VIA, 0x0410, CS_VIA_VX900, "VX900", VIA_VX900_setupFunc},
+ {PCI_VENDOR_ID_APM, 0xe004, CS_APM_STORM, "X-Gene Storm", APM_Storm_setupFunc},
+ {PCI_VENDOR_ID_IBM, 0x03DC, CS_IBM_VENICE, "Venice", NULL},
+ {PCI_VENDOR_ID_MARVELL, 0xAF00, CS_MARVELL_THUNDERX2, "Marvell ThunderX2", Marvell_ThunderX2_setupFunc},
+ {PCI_VENDOR_ID_REDHAT, 0x0008, CS_REDHAT_QEMU, "QEMU Redhat", QEMU_setupFunc},
+ {PCI_VENDOR_ID_AMPERE, 0xE005, CS_AMPERE_EMAG, "AMPERE eMag", Ampere_eMag_setupFunc},
+ {PCI_VENDOR_ID_AMPERE, 0xE006, CS_AMPERE_EMAG, "AMPERE eMag", Ampere_eMag_setupFunc},
+ {PCI_VENDOR_ID_AMPERE, 0xE007, CS_AMPERE_EMAG, "AMPERE eMag", Ampere_eMag_setupFunc},
+ {PCI_VENDOR_ID_AMPERE, 0xE008, CS_AMPERE_EMAG, "AMPERE eMag", Ampere_eMag_setupFunc},
+ {PCI_VENDOR_ID_AMPERE, 0xE009, CS_AMPERE_EMAG, "AMPERE eMag", Ampere_eMag_setupFunc},
+ {PCI_VENDOR_ID_AMPERE, 0xE00A, CS_AMPERE_EMAG, "AMPERE eMag", Ampere_eMag_setupFunc},
+ {PCI_VENDOR_ID_AMPERE, 0xE00B, CS_AMPERE_EMAG, "AMPERE eMag", Ampere_eMag_setupFunc},
+ {PCI_VENDOR_ID_AMPERE, 0xE00C, CS_AMPERE_EMAG, "AMPERE eMag", Ampere_eMag_setupFunc},
+ {PCI_VENDOR_ID_HUAWEI, 0xA120, CS_HUAWEI_KUNPENG920, "Huawei Kunpeng920", Huawei_Kunpeng920_setupFunc},
+ {PCI_VENDOR_ID_MELLANOX, 0xA2D0, CS_MELLANOX_BLUEFIELD, "Mellanox BlueField", Mellanox_BlueField_setupFunc},
+ {PCI_VENDOR_ID_MELLANOX, 0xA2D4, CS_MELLANOX_BLUEFIELD2, "Mellanox BlueField 2", NULL},
+ {PCI_VENDOR_ID_MELLANOX, 0xA2D5, CS_MELLANOX_BLUEFIELD2, "Mellanox BlueField 2 Crypto disabled", NULL},
+ {PCI_VENDOR_ID_MELLANOX, 0xA2DA, CS_MELLANOX_BLUEFIELD3, "Mellanox BlueField 3 Crypto enabled", Mellanox_BlueField3_setupFunc},
+ {PCI_VENDOR_ID_MELLANOX, 0xA2DB, CS_MELLANOX_BLUEFIELD3, "Mellanox BlueField 3 Crypto disabled", Mellanox_BlueField3_setupFunc},
+ {PCI_VENDOR_ID_AMAZON, 0x0200, CS_AMAZON_GRAVITRON2, "Amazon Gravitron2", Amazon_Gravitron2_setupFunc},
+ {PCI_VENDOR_ID_FUJITSU, 0x1952, CS_FUJITSU_A64FX, "Fujitsu A64FX", Fujitsu_A64FX_setupFunc},
+ {PCI_VENDOR_ID_CADENCE, 0xDC01, CS_PHYTIUM_S2500, "Phytium S2500", NULL},
+ {PCI_VENDOR_ID_CADENCE, 0xDC08, CS_PHYTIUM_S2500, "Phytium S2500", NULL},
+ {PCI_VENDOR_ID_CADENCE, 0xDC16, CS_PHYTIUM_S2500, "Phytium S2500", NULL},
+ {PCI_VENDOR_ID_CADENCE, 0xFC01, CS_PHYTIUM_S2500, "Phytium S2500", NULL},
+ {PCI_VENDOR_ID_CADENCE, 0xFC08, CS_PHYTIUM_S2500, "Phytium S2500", NULL},
+ {PCI_VENDOR_ID_CADENCE, 0xFC16, CS_PHYTIUM_S2500, "Phytium S2500", NULL},
+ {PCI_VENDOR_ID_AMPERE, 0xE000, CS_AMPERE_ALTRA, "Ampere Altra", Ampere_Altra_setupFunc},
+ {PCI_VENDOR_ID_AMPERE, 0xE00D, CS_AMPERE_ALTRA, "Ampere Altra", Ampere_Altra_setupFunc},
+ {PCI_VENDOR_ID_AMPERE, 0xE00E, CS_AMPERE_ALTRA, "Ampere Altra", Ampere_Altra_setupFunc},
+ {PCI_VENDOR_ID_AMPERE, 0xE010, CS_AMPERE_ALTRA, "Ampere Altra", Ampere_Altra_setupFunc},
+ {PCI_VENDOR_ID_AMPERE, 0xE100, CS_AMPERE_ALTRA, "Ampere Altra", Ampere_Altra_setupFunc},
+ {PCI_VENDOR_ID_AMPERE, 0xE110, CS_AMPERE_ALTRA, "Ampere Altra", Ampere_Altra_setupFunc},
+ {PCI_VENDOR_ID_ARM, 0x0100, CS_ARM_NEOVERSEN1, "Arm Neoverse N1", Arm_NeoverseN1_setupFunc},
+ {PCI_VENDOR_ID_HYGON, 0x790E, CS_HYGON_C86, "Hygon-C86-7151", NULL},
+ {PCI_VENDOR_ID_MARVELL, 0xA02D, CS_MARVELL_OCTEON_CN96XX, "Marvell Octeon CN96xx", ARMV8_generic_setupFunc},
+ {PCI_VENDOR_ID_MARVELL, 0xA02D, CS_MARVELL_OCTEON_CN98XX, "Marvell Octeon CN98xx", ARMV8_generic_setupFunc},
+ {PCI_VENDOR_ID_QUALCOMM, 0x010E, CS_SNAPDRAGON_8CX, "Qualcomm Snapdragon 8cx Gen3", Qualcomm_Snapdragon_setupFunc},
+ {PCI_VENDOR_ID_QUALCOMM, 0x0111, CS_SNAPDRAGON_8CX, "Qualcomm Snapdragon 8cx Gen4", Qualcomm_Snapdragon_setupFunc},
+ {PCI_VENDOR_ID_SIFIVE, 0x0000, CS_SIFIVE_FU740_C000, "SiFive FU740-000", Riscv_generic_setupFunc},
+ {PCI_VENDOR_ID_PLDA, 0x1111, CS_PLDA_XPRESSRICH_AXI_REF, "XpressRich-AXI Ref Design", PLDA_XpressRichAXI_setupFunc},
+ {PCI_VENDOR_ID_AMPERE, 0xE200, CS_AMPERE_AMPEREONE160, "Ampere AmpereOne-160", Ampere_AmpereOne_setupFunc},
+ {PCI_VENDOR_ID_AMPERE, 0xE201, CS_AMPERE_AMPEREONE160, "Ampere AmpereOne-160", Ampere_AmpereOne_setupFunc},
+ {PCI_VENDOR_ID_AMPERE, 0xE202, CS_AMPERE_AMPEREONE160, "Ampere AmpereOne-160", Ampere_AmpereOne_setupFunc},
+ {PCI_VENDOR_ID_AMPERE, 0xE203, CS_AMPERE_AMPEREONE160, "Ampere AmpereOne-160", Ampere_AmpereOne_setupFunc},
+ {PCI_VENDOR_ID_AMPERE, 0xE204, CS_AMPERE_AMPEREONE160, "Ampere AmpereOne-160", Ampere_AmpereOne_setupFunc},
+ {PCI_VENDOR_ID_AMPERE, 0xE205, CS_AMPERE_AMPEREONE160, "Ampere AmpereOne-160", Ampere_AmpereOne_setupFunc},
+ {PCI_VENDOR_ID_AMPERE, 0xE206, CS_AMPERE_AMPEREONE160, "Ampere AmpereOne-160", Ampere_AmpereOne_setupFunc},
+ {PCI_VENDOR_ID_AMPERE, 0xE207, CS_AMPERE_AMPEREONE160, "Ampere AmpereOne-160", Ampere_AmpereOne_setupFunc},
+ {PCI_VENDOR_ID_PHYTIUM, 0x5C16, CS_PHYTIUM_S5000, "Phytium S5000", NULL},
+ {PCI_VENDOR_ID_AMPERE, 0xE208, CS_AMPERE_AMPEREONE192, "Ampere AmpereOne-192", Ampere_AmpereOne_setupFunc},
+ {PCI_VENDOR_ID_AMPERE, 0xE209, CS_AMPERE_AMPEREONE192, "Ampere AmpereOne-192", Ampere_AmpereOne_setupFunc},
+ {PCI_VENDOR_ID_AMPERE, 0xE20A, CS_AMPERE_AMPEREONE192, "Ampere AmpereOne-192", Ampere_AmpereOne_setupFunc},
+ {PCI_VENDOR_ID_AMPERE, 0xE20B, CS_AMPERE_AMPEREONE192, "Ampere AmpereOne-192", Ampere_AmpereOne_setupFunc},
+ {PCI_VENDOR_ID_AMPERE, 0xE20C, CS_AMPERE_AMPEREONE192, "Ampere AmpereOne-192", Ampere_AmpereOne_setupFunc},
+ {PCI_VENDOR_ID_AMPERE, 0xE20D, CS_AMPERE_AMPEREONE192, "Ampere AmpereOne-192", Ampere_AmpereOne_setupFunc},
+ {PCI_VENDOR_ID_AMPERE, 0xE20E, CS_AMPERE_AMPEREONE192, "Ampere AmpereOne-192", Ampere_AmpereOne_setupFunc},
+ {PCI_VENDOR_ID_AMPERE, 0xE20F, CS_AMPERE_AMPEREONE192, "Ampere AmpereOne-192", Ampere_AmpereOne_setupFunc},
+ {PCI_VENDOR_ID_NVIDIA, 0x22D1, CS_NVIDIA_T254, "T254", Nvidia_T194_setupFunc},
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+ // last element must have chipset CS_UNKNOWN (zero)
+ {0, 0, CS_UNKNOWN, "Unknown", NULL}
+};
+
+
+VENDORNAME vendorName[] =
+{
+ {PCI_VENDOR_ID_NVIDIA, "NVIDIA"},
+ {PCI_VENDOR_ID_INTEL, "Intel"},
+ {PCI_VENDOR_ID_VIA, "VIA"},
+ {PCI_VENDOR_ID_RCC, "ServerWorks"},
+ {PCI_VENDOR_ID_MICRON_1, "Micron"},
+ {PCI_VENDOR_ID_MICRON_2, "Micron"},
+ {PCI_VENDOR_ID_APPLE, "Apple"},
+ {PCI_VENDOR_ID_SIS, "SiS"},
+ {PCI_VENDOR_ID_ATI, "ATI"},
+ {PCI_VENDOR_ID_TRANSMETA, "Transmeta"},
+ {PCI_VENDOR_ID_HP, "HP"},
+ {PCI_VENDOR_ID_AMD, "AMD"},
+ {PCI_VENDOR_ID_ALI, "ALi"},
+ {PCI_VENDOR_ID_APM, "AppliedMicro"},
+ {PCI_VENDOR_ID_IBM, "IBM"},
+ {PCI_VENDOR_ID_MARVELL, "MarvellThunderX2"},
+ {PCI_VENDOR_ID_REDHAT, "QemuRedhat"},
+ {PCI_VENDOR_ID_AMPERE, "AmpereComputing"},
+ {PCI_VENDOR_ID_HUAWEI, "Huawei"},
+ {PCI_VENDOR_ID_MELLANOX, "Mellanox"},
+ {PCI_VENDOR_ID_AMAZON, "Amazon"},
+ {PCI_VENDOR_ID_FUJITSU, "Fujitsu"},
+ {PCI_VENDOR_ID_CADENCE, "Cadence"},
+ {PCI_VENDOR_ID_ARM, "ARM"},
+ {PCI_VENDOR_ID_ALIBABA, "Alibaba"},
+ {PCI_VENDOR_ID_QUALCOMM, "Qualcomm"},
+ {PCI_VENDOR_ID_SIFIVE, "SiFive"},
+ {PCI_VENDOR_ID_PLDA, "PLDA"},
+ {PCI_VENDOR_ID_PHYTIUM, "Phytium"},
+ {0, "Unknown"} // Indicates end of the table
+};
+
+
+//
+// Allowlist all chipsets with which dGPU over PCIe is supported on ARM
+// (both v7 and v8) platforms. Also include IGPU specific chipsets.
+//
+ARMCSALLOWLISTINFO armChipsetAllowListInfo[] =
+{
+ {PCI_VENDOR_ID_NVIDIA, 0x0FAE, CS_NVIDIA_T210}, // NVIDIA Tegra X1 RP0
+ {PCI_VENDOR_ID_NVIDIA, 0x0FAF, CS_NVIDIA_T210}, // NVIDIA Tegra X1 RP1
+ {PCI_VENDOR_ID_NVIDIA, 0x10E5, CS_NVIDIA_T186}, // NVIDIA Tegra P1 RP0
+ {PCI_VENDOR_ID_NVIDIA, 0x10E6, CS_NVIDIA_T186}, // NVIDIA Tegra P1 RP1
+ {PCI_VENDOR_ID_NVIDIA, 0x1AD0, CS_NVIDIA_T194}, // NVIDIA Tegra V1 RP0
+ {PCI_VENDOR_ID_NVIDIA, 0x1AD1, CS_NVIDIA_T194}, // NVIDIA Tegra V1 RP1
+ {PCI_VENDOR_ID_NVIDIA, 0x1AD2, CS_NVIDIA_T194}, // NVIDIA Tegra V1 RP2
+ {PCI_VENDOR_ID_NVIDIA, 0x229A, CS_NVIDIA_T234}, // NVIDIA Tegra Orin RP0
+ {PCI_VENDOR_ID_NVIDIA, 0x229C, CS_NVIDIA_T234}, // NVIDIA Tegra Orin RP1
+ {PCI_VENDOR_ID_NVIDIA, 0x229E, CS_NVIDIA_T234}, // NVIDIA Tegra Orin RP2
+ {PCI_VENDOR_ID_NVIDIA, 0x22C2, CS_NVIDIA_T23x}, // NVIDIA Tegra RP0
+ {PCI_VENDOR_ID_NVIDIA, 0x22C3, CS_NVIDIA_T23x}, // NVIDIA Tegra RP1
+ {PCI_VENDOR_ID_NVIDIA, 0x22B1, CS_NVIDIA_TH500}, // NVIDIA TH500 RP for GH100 GPU in GH180.
+ {PCI_VENDOR_ID_NVIDIA, 0x22B2, CS_NVIDIA_TH500}, // NVIDIA TH500 RP x16
+ {PCI_VENDOR_ID_NVIDIA, 0x22B3, CS_NVIDIA_TH500}, // NVIDIA TH500 RP x4
+ {PCI_VENDOR_ID_NVIDIA, 0x22B4, CS_NVIDIA_TH500}, // NVIDIA TH500 RP x1
+ {PCI_VENDOR_ID_NVIDIA, 0x22B8, CS_NVIDIA_TH500}, // NVIDIA TH500 RP x8
+ {PCI_VENDOR_ID_NVIDIA, 0x22B9, CS_NVIDIA_TH500}, // NVIDIA TH500 RP x2
+ {PCI_VENDOR_ID_NVIDIA, 0x22D6, CS_NVIDIA_T264}, // NVIDIA Tegra RP x8
+ {PCI_VENDOR_ID_NVIDIA, 0x22D8, CS_NVIDIA_T264}, // NVIDIA Tegra RP x4
+ {PCI_VENDOR_ID_NVIDIA, 0x22DA, CS_NVIDIA_T264}, // NVIDIA Tegra RP x2
+ {PCI_VENDOR_ID_NVIDIA, 0x22E6, CS_NVIDIA_T264}, // NVIDIA Tegra iGPU RP
+ {PCI_VENDOR_ID_NVIDIA, 0x2B00, CS_NVIDIA_T264}, // NVIDIA Tegra iGPU
+ {PCI_VENDOR_ID_NVIDIA, 0x2F95, CS_NVIDIA_TB500}, // NVIDIA TB500 RP x16
+ {PCI_VENDOR_ID_NVIDIA, 0x2F96, CS_NVIDIA_TB500}, // NVIDIA TB500 RP x8
+ {PCI_VENDOR_ID_NVIDIA, 0x2F97, CS_NVIDIA_TB500}, // NVIDIA TB500 RP x4
+ {PCI_VENDOR_ID_NVIDIA, 0x2F98, CS_NVIDIA_TB500}, // NVIDIA TB500 RP x2
+ {PCI_VENDOR_ID_NVIDIA, 0x2F99, CS_NVIDIA_TB500}, // NVIDIA TB500 RP x1
+
+ {PCI_VENDOR_ID_APM, 0xe004, CS_APM_STORM}, // Applied Micro X-Gene "Storm"
+ {PCI_VENDOR_ID_MARVELL, 0xAF00, CS_MARVELL_THUNDERX2}, // Marvell ThunderX2
+ {PCI_VENDOR_ID_REDHAT, 0x0008, CS_REDHAT_QEMU}, // Redhat QEMU
+ {PCI_VENDOR_ID_AMPERE, 0xE005, CS_AMPERE_EMAG}, // Ampere eMag
+ {PCI_VENDOR_ID_AMPERE, 0xE006, CS_AMPERE_EMAG}, // Ampere eMag
+ {PCI_VENDOR_ID_AMPERE, 0xE007, CS_AMPERE_EMAG}, // Ampere eMag
+ {PCI_VENDOR_ID_AMPERE, 0xE008, CS_AMPERE_EMAG}, // Ampere eMag
+ {PCI_VENDOR_ID_AMPERE, 0xE009, CS_AMPERE_EMAG}, // Ampere eMag
+ {PCI_VENDOR_ID_AMPERE, 0xE00A, CS_AMPERE_EMAG}, // Ampere eMag
+ {PCI_VENDOR_ID_AMPERE, 0xE00B, CS_AMPERE_EMAG}, // Ampere eMag
+ {PCI_VENDOR_ID_AMPERE, 0xE00C, CS_AMPERE_EMAG}, // Ampere eMag
+ {PCI_VENDOR_ID_HUAWEI, 0xA120, CS_HUAWEI_KUNPENG920}, // Huawei Kunpeng 920
+ {PCI_VENDOR_ID_MELLANOX, 0xA2D0, CS_MELLANOX_BLUEFIELD}, // Mellanox BlueField
+ {PCI_VENDOR_ID_MELLANOX, 0xA2D4, CS_MELLANOX_BLUEFIELD2},// Mellanox BlueField 2
+ {PCI_VENDOR_ID_MELLANOX, 0xA2D5, CS_MELLANOX_BLUEFIELD2},// Mellanox BlueField 2 Crypto disabled
+ {PCI_VENDOR_ID_MELLANOX, 0xA2DB, CS_MELLANOX_BLUEFIELD3},// Mellanox BlueField 3 Crypto disabled
+ {PCI_VENDOR_ID_MELLANOX, 0xA2DA, CS_MELLANOX_BLUEFIELD3},// Mellanox BlueField 3 Crypto enabled
+ {PCI_VENDOR_ID_AMAZON, 0x0200, CS_AMAZON_GRAVITRON2}, // Amazon Gravitron2
+ {PCI_VENDOR_ID_FUJITSU, 0x1952, CS_FUJITSU_A64FX}, // Fujitsu A64FX
+ {PCI_VENDOR_ID_CADENCE, 0xDC01, CS_PHYTIUM_S2500}, // Phytium S2500
+ {PCI_VENDOR_ID_CADENCE, 0xDC08, CS_PHYTIUM_S2500}, // Phytium S2500
+ {PCI_VENDOR_ID_CADENCE, 0xDC16, CS_PHYTIUM_S2500}, // Phytium S2500
+ {PCI_VENDOR_ID_CADENCE, 0xFC01, CS_PHYTIUM_S2500}, // Phytium S2500
+ {PCI_VENDOR_ID_CADENCE, 0xFC08, CS_PHYTIUM_S2500}, // Phytium S2500
+ {PCI_VENDOR_ID_CADENCE, 0xFC16, CS_PHYTIUM_S2500}, // Phytium S2500
+ {PCI_VENDOR_ID_AMPERE, 0xE000, CS_AMPERE_ALTRA}, // Ampere Altra
+ {PCI_VENDOR_ID_AMPERE, 0xE00D, CS_AMPERE_ALTRA}, // Ampere Altra
+ {PCI_VENDOR_ID_AMPERE, 0xE00E, CS_AMPERE_ALTRA}, // Ampere Altra
+ {PCI_VENDOR_ID_AMPERE, 0xE010, CS_AMPERE_ALTRA}, // Ampere Altra
+ {PCI_VENDOR_ID_AMPERE, 0xE100, CS_AMPERE_ALTRA}, // Ampere Altra
+ {PCI_VENDOR_ID_AMPERE, 0xE110, CS_AMPERE_ALTRA}, // Ampere Altra
+ {PCI_VENDOR_ID_ARM, 0x0100, CS_ARM_NEOVERSEN1}, // Arm Neoverse N1
+ {PCI_VENDOR_ID_MARVELL, 0xA02D, CS_MARVELL_OCTEON_CN96XX}, // Marvell OCTEON CN96xx
+ {PCI_VENDOR_ID_MARVELL, 0xA02D, CS_MARVELL_OCTEON_CN98XX}, // Marvell OCTEON CN98xx
+ {PCI_VENDOR_ID_ALIBABA, 0x8000, CS_ALIBABA_YITIAN}, // Alibaba Yitian
+ {PCI_VENDOR_ID_QUALCOMM, 0x010E, CS_SNAPDRAGON_8CX}, // Qualcomm Snapdragon 8cx Gen3 - 8280 dev platform
+ {PCI_VENDOR_ID_QUALCOMM, 0x0111, CS_SNAPDRAGON_8CX}, // Qualcomm Snapdragon 8cx Gen4 - 8380 dev(?) platform
+ {PCI_VENDOR_ID_AMPERE, 0xE200, CS_AMPERE_AMPEREONE160}, // Ampere AmpereOne-160
+ {PCI_VENDOR_ID_AMPERE, 0xE201, CS_AMPERE_AMPEREONE160}, // Ampere AmpereOne-160
+ {PCI_VENDOR_ID_AMPERE, 0xE202, CS_AMPERE_AMPEREONE160}, // Ampere AmpereOne-160
+ {PCI_VENDOR_ID_AMPERE, 0xE203, CS_AMPERE_AMPEREONE160}, // Ampere AmpereOne-160
+ {PCI_VENDOR_ID_AMPERE, 0xE204, CS_AMPERE_AMPEREONE160}, // Ampere AmpereOne-160
+ {PCI_VENDOR_ID_AMPERE, 0xE205, CS_AMPERE_AMPEREONE160}, // Ampere AmpereOne-160
+ {PCI_VENDOR_ID_AMPERE, 0xE206, CS_AMPERE_AMPEREONE160}, // Ampere AmpereOne-160
+ {PCI_VENDOR_ID_AMPERE, 0xE207, CS_AMPERE_AMPEREONE160}, // Ampere AmpereOne-160
+ {PCI_VENDOR_ID_PHYTIUM, 0x5C16, CS_PHYTIUM_S5000}, // Phytium S5000
+ {PCI_VENDOR_ID_AMPERE, 0xE208, CS_AMPERE_AMPEREONE192}, // Ampere AmpereOne-192
+ {PCI_VENDOR_ID_AMPERE, 0xE209, CS_AMPERE_AMPEREONE192}, // Ampere AmpereOne-192
+ {PCI_VENDOR_ID_AMPERE, 0xE20A, CS_AMPERE_AMPEREONE192}, // Ampere AmpereOne-192
+ {PCI_VENDOR_ID_AMPERE, 0xE20B, CS_AMPERE_AMPEREONE192}, // Ampere AmpereOne-192
+ {PCI_VENDOR_ID_AMPERE, 0xE20C, CS_AMPERE_AMPEREONE192}, // Ampere AmpereOne-192
+ {PCI_VENDOR_ID_AMPERE, 0xE20D, CS_AMPERE_AMPEREONE192}, // Ampere AmpereOne-192
+ {PCI_VENDOR_ID_AMPERE, 0xE20E, CS_AMPERE_AMPEREONE192}, // Ampere AmpereOne-192
+ {PCI_VENDOR_ID_AMPERE, 0xE20F, CS_AMPERE_AMPEREONE192}, // Ampere AmpereOne-192
+ {PCI_VENDOR_ID_NVIDIA, 0x22D1, CS_NVIDIA_T254},
+
+ // last element must have chipset CS_UNKNOWN (zero)
+ {0, 0, CS_UNKNOWN}
+};
+
+#endif /* NVCST_H */
diff --git a/userspace/sdks/nv570/nvalloc/common/inc/nvdm_format.h b/userspace/sdks/nv570/nvalloc/common/inc/nvdm_format.h
new file mode 100644
index 0000000..db3baa0
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/common/inc/nvdm_format.h
@@ -0,0 +1,63 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef NVDM_FORMAT_H
+#define NVDM_FORMAT_H
+
+/**
+ * NVDM (NVIDIA Data Model) overlaid on MCTP (Management Component Transport
+ * Protocol) format definitions.
+ *
+ * This header consolidates NVDM type definitions from multiple RM subsystems
+ * including FSP, SEC2, GSP, and others. NVDM is a vendor-defined message layer
+ * overlaid on MCTP that provides a simple way for different subsystems to
+ * communicate.
+ */
+
+//
+// List of NVDM Message Types
+//
+// Values are allocated from a shared namespace across all subsystems.
+// Add new types here and update the NVDM Message Type allocation page.
+//
+#define NVDM_TYPE_RESET 0x4
+#define NVDM_TYPE_HULK 0x11
+#define NVDM_TYPE_FIRMWARE_UPDATE 0x12
+#define NVDM_TYPE_PRC 0x13
+#define NVDM_TYPE_COT 0x14
+#define NVDM_TYPE_FSP_RESPONSE 0x15
+#define NVDM_TYPE_SEC2_RESPONSE NVDM_TYPE_FSP_RESPONSE
+#define NVDM_TYPE_CAPS_QUERY 0x16
+#define NVDM_TYPE_INFOROM 0x17
+#define NVDM_TYPE_SMBPBI 0x18
+#define NVDM_TYPE_ROMREAD 0x1A
+#define NVDM_TYPE_UEFI_RM 0x1C
+#define NVDM_TYPE_UEFI_XTL_DEBUG_INTR 0x1D
+#define NVDM_TYPE_TNVL 0x1F
+#define NVDM_TYPE_CLOCK_BOOST 0x20
+#define NVDM_TYPE_FSP_GSP_COMM 0x21
+#define NVDM_TYPE_SEC2_GSP_COMM NVDM_TYPE_FSP_GSP_COMM
+
+#define NVDM_TYPE_RM_RPC 0x25 // GSP-RM RPC messages
+
+#endif // NVDM_FORMAT_H
diff --git a/userspace/sdks/nv570/nvalloc/common/inc/nvpcie.h b/userspace/sdks/nv570/nvalloc/common/inc/nvpcie.h
new file mode 100644
index 0000000..c4ee983
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/common/inc/nvpcie.h
@@ -0,0 +1,545 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2000-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef NVPCIE_H
+#define NVPCIE_H
+
+
+#include "nvtypes.h"
+
+/**************** Resource Manager Defines and Structures ******************\
+* *
+* Private PCI Express related defines and structures. *
+* *
+\***************************************************************************/
+
+typedef struct NBADDR
+{
+ NvU32 domain;
+ NvU8 bus;
+ NvU8 device;
+ NvU8 func;
+ NvU8 valid;
+ void *handle;
+} NBADDR;
+
+typedef struct PORTDATA
+{
+ NBADDR addr;
+ void *vAddr; // virtual address of the port, if it has been mapped . Not used starting with Win10 BuildXXXXX
+ NvU32 PCIECapPtr; // offset of the PCIE capptr in the NB
+ // Capability register set in enhanced configuration space
+ //
+ NvU32 PCIEErrorCapPtr; // offset of the Advanced Error Reporting Capability register set
+ NvU32 PCIEVCCapPtr; // offset of the Virtual Channel (VC) Capability register set
+ NvU32 PCIEL1SsCapPtr; // Offset of the L1 Substates Capabilities
+ NvU32 PCIEAcsCapPtr; // Offset of the ACS redirect Capabilities
+ NvU16 DeviceID, VendorID; // device and vendor ID for port
+} PORTDATA;
+
+#define PCI_VENDOR_ID 0x00
+#ifndef PCI_DEVICE_ID
+#define PCI_DEVICE_ID 0x02
+#endif
+#define PCI_BASE_ADDRESS_1 0x14 /* Aperture Base */
+#define PCI_BASE_ADDRESS_2 0x18 /* Aperture Base */
+#define PCI_CAPABILITY_LIST 0x34
+#define PCI_DEVICE_SPECIFIC 0x40
+
+#define NV_PCI_ID 0x0
+#define NV_PCI_ID_VENDOR 15:0
+#define NV_PCI_ID_VENDOR_NVIDIA 0x10DE
+#define NV_PCI_ID_DEVICE 31:16
+
+#define PCI_MAX_SLOTS 255
+#define PCI_MAX_LANE_WIDTH 32
+
+#define PCI_MAX_FUNCTION 8
+#define PCI_INVALID_VENDORID 0xFFFF
+#define PCI_INVALID_DEVICEID 0xFFFF
+#define PCI_INVALID_SUBVENDORID 0xFFFF
+#define PCI_INVALID_SUBDEVICEID 0xFFFF
+
+#define PCI_IS_VENDORID_VALID(id) (((id) != 0x0000) && ((id) != 0xFFFF))
+
+#define PCI_CLASS_BRIDGE_DEV 0x06
+#define PCI_SUBCLASS_BR_HOST 0x00
+#define PCI_MULTIFUNCTION 0x80
+
+// From PCI Local Bus Specification, Revision 3.0
+// and PCI Express Base Specification 6.0
+// numbers in comments to right of values indicate
+// the referenced section in the PCIE spec
+
+
+#define CAP_ID_MASK 0xFF
+
+#define CAP_ID_NULL 0x00 // 7.9.28.1
+#define CAP_ID_PMI 0x01 // 7.5.2.1
+#define CAP_ID_AGP 0x02
+#define CAP_ID_VPD 0x03 // 7.9.18.1
+#define CAP_ID_SLOT_ID 0x04
+#define CAP_ID_MSI 0x05 // 7.7.1.1
+#define CAP_ID_HOT_SWAP 0x06
+#define CAP_ID_PCI_X 0x07
+#define CAP_ID_HYPER_TRANSPORT 0x08
+#define CAP_ID_VENDOR_SPECIFIC 0x09
+#define CAP_ID_DEBUG_PORT 0x0A
+#define CAP_ID_CRC 0x0B
+#define CAP_ID_HOT_PLUG 0x0C
+#define CAP_ID_SUBSYSTEM_ID 0x0D // 7.9.23.1
+#define CAP_ID_AGP8X 0x0E
+#define CAP_ID_SECURE 0x0F
+#define CAP_ID_PCI_EXPRESS 0x10 // 7.5.3.1
+#define CAP_ID_MSI_X 0x11 // 7.7.2.1
+#define CAP_ID_ENHANCED_ALLOCATION 0x14 // 7.8.5.1
+#define CAP_ID_FPB 0x15 // 7.8.11.1
+#define CAP_ID_AF 0x13 // 7.9.21.1
+
+//
+// sizes for static PCI capabilities structure
+//
+#define CAP_NULL_SIZE 0x04 // 7.9.28
+#define CAP_PMI_SIZE 0x08 // 7.5.2
+#define CAP_VPD_SIZE 0x08 // 7.9.18
+#define CAP_PCI_X_SIZE 0x3C // 7.5.3
+#define CAP_PCI_EXPRESS_SIZE 0x3C // 7.5.3
+#define CAP_FPB_SIZE 0x08 // 7.8.11.1
+#define CAP_AF_SIZE 0x08 // 7.9.21
+#define CAP_SUBSYSTEM_ID_SIZE 0x08 // 7.9.23
+
+// MSI capability size related fields
+#define PCI_MSI_CONTROL 0x02 // 7.7.1.2
+#define PCI_MSI_CONTROL_64BIT_CAPABLE 7:7
+#define PCI_MSI_CONTROL_64BIT_CAPABLE_FALSE 0
+#define PCI_MSI_CONTROL_64BIT_CAPABLE_TRUE 1
+#define PCI_MSI_CONTROL_PVM_CAPABLE 8:8
+#define PCI_MSI_CONTROL_PVM_CAPABLE_FALSE 0
+#define PCI_MSI_CONTROL_PVM_CAPABLE_TRUE 1
+#define PCI_MSI_BASE_SIZE 0x0C // 7.7.1
+#define PCI_MSI_64BIT_ADDR_CAPABLE_ADJ_SIZE 0x04 // 7.7.1
+#define PCI_MSI_PVM_CAPABLE_ADJ_SIZE 0x08 // 7.7.1
+
+// MSI-X capability size related fields
+#define PCI_MSI_X_BASE_SIZE 0x0C // 7.7.2
+#define PCI_MSI_X_CONTROL 0x02 // 7.7.2.2
+#define PCI_MSI_X_CONTROL_TABLE_SIZE 10:0
+#define PCI_MSI_X_TABLE_OFFSET_BIR 0x04 // 7.7.2.3
+#define PCI_MSI_X_TABLE_OFFSET 31:3
+#define PCI_MSI_X_PBR_OFFSET_BIR 0x08 // 7.7.2.4
+#define PCI_MSI_X_PBR_OFFSET 31:3
+#define PCI_MSI_X_TABLE_ENTRY_SIZE 0x10 // 7.7.2
+#define PCI_MSI_X_PBR_ENTRY_SIZE 0x10 // 7.7.2
+
+// Enhanced Allocation Capability size related fields
+#define PCI_ENHANCED_ALLOCATION_FIRST_DW 0x00 // 7.8.5.1
+#define PCI_ENHANCED_ALLOCATION_FIRST_DW_NUM_ENTRIES 21:16
+#define PCI_ENHANCED_ALLOCATION_TYPE_0_BASE_SIZE 0x04 // 7.8.5.1
+#define PCI_ENHANCED_ALLOCATION_TYPE_1_BASE_SIZE 0x08 // 7.8.5.2
+#define PCI_ENHANCED_ALLOCATION_ENTRY_HEADER 0x00 // 7.8.5.3
+#define PCI_ENHANCED_ALLOCATION_ENTRY_HEADER_ENTRY_SIZE 2:0
+
+// PCI Vendor Specific Capability size related fields
+#define PCI_VENDOR_SPECIFIC_CAP_HEADER 0x00 // 7.9.4
+#define PCI_VENDOR_SPECIFIC_CAP_HEADER_LENGTH 23:16
+
+//
+// Extended config space size is 4096 bytes.
+//
+#define PCI_EXTENDED_CONFIG_SPACE_LENGTH 4096
+
+//
+// From PCI Local Bus Specification, Revision 3.0
+// HEADER TYPE0 Definitions - Byte offsets
+//
+#define PCI_HEADER_TYPE0_VENDOR_ID 0x00
+#define PCI_HEADER_TYPE0_DEVICE_ID 0x02
+#define PCI_HEADER_TYPE0_COMMAND 0x04
+#define PCI_HEADER_TYPE0_STATUS 0x06
+#define PCI_HEADER_TYPE0_REVISION_ID 0x08
+#define PCI_HEADER_TYPE0_PROGIF 0x09
+#define PCI_HEADER_TYPE0_SUBCLASS 0x0A
+#define PCI_HEADER_TYPE0_BASECLASS 0x0B
+#define PCI_HEADER_TYPE0_CACHE_LINE_SIZE 0x0C
+#define PCI_HEADER_TYPE0_LATENCY_TIMER 0x0D
+#define PCI_HEADER_TYPE0_HEADER_TYPE 0x0E
+#define PCI_HEADER_TYPE0_HEADER_TYPE_0 0
+#define PCI_HEADER_TYPE0_HEADER_TYPE_1 1
+#define PCI_HEADER_TYPE0_BIST 0x0F
+#define PCI_HEADER_TYPE0_BAR0 0x10
+#define PCI_HEADER_TYPE0_BAR1 0x14
+#define PCI_HEADER_TYPE0_BAR2 0x18
+#define PCI_HEADER_TYPE0_BAR3 0x1C
+#define PCI_HEADER_TYPE0_BAR4 0x20
+#define PCI_HEADER_TYPE0_BAR5 0x24
+#define PCI_HEADER_TYPE0_CBCIS_PTR 0x28
+#define PCI_HEADER_TYPE0_SUBSYS_VEN_ID 0x2C
+#define PCI_HEADER_TYPE0_SUBSYS_ID 0x2E
+#define PCI_HEADER_TYPE0_ROMBAR 0x30
+#define PCI_HEADER_TYPE0_CAP_PTR 0x34
+#define PCI_HEADER_TYPE0_INT_LINE 0x3C
+#define PCI_HEADER_TYPE0_INT_PIN 0x3D
+#define PCI_HEADER_TYPE0_MIN_GNT 0x3E
+#define PCI_HEADER_TYPE0_MAX_LAT 0x3F
+
+//
+// From PCI Express Base Specification Revision 2.0
+// HEADER TYPE1 Definitions
+#define PCI_HEADER_TYPE1_BRIDGE_CONTROL 0x3E
+#define PCI_HEADER_TYPE1_BRIDGE_CONTROL_VGA_EN 0x08
+
+#define PCIE_LINK_CAPABILITIES_2 0x000000A4 /* R--4R */
+#define PCIE_LINK_CAPABILITIES_2_RSVD 0:0 /* C--VF */
+#define PCIE_LINK_CAPABILITIES_2_RSVD_INIT 0x00000000 /* C---V */
+#define PCIE_LINK_CAPABILITIES_2_SUPPORTED_LINK_SPEED 7:1 /* R-EVF */
+#define PCIE_LINK_CAPABILITIES_2_SUPPORTED_LINK_SPEED_GEN1_GEN2_GEN3_GEN4_GEN5 0x0000001F /* R---V */
+#define PCIE_LINK_CAPABILITIES_2_SUPPORTED_LINK_SPEED_HIDDEN 0x00000000 /* R---V */
+#define PCIE_LINK_CAPABILITIES_2_SUPPORTED_LINK_SPEED_GEN1 0x00000001 /* R---V */
+#define PCIE_LINK_CAPABILITIES_2_SUPPORTED_LINK_SPEED_GEN1_GEN2 0x00000003 /* R---V */
+#define PCIE_LINK_CAPABILITIES_2_SUPPORTED_LINK_SPEED_GEN1_GEN2_GEN3 0x00000007 /* R-E-V */
+#define PCIE_LINK_CAPABILITIES_2_SUPPORTED_LINK_SPEED_GEN1_GEN2_GEN3_GEN4 0x0000000F /* R---V */
+#define PCIE_LINK_CAPABILITIES_2_CROSS_LINK_SUPPORT 8:8 /* C--VF */
+#define PCIE_LINK_CAPABILITIES_2_CROSS_LINK_SUPPORT_DISABLED 0x00000000 /* C---V */
+#define PCIE_LINK_CAPABILITIES_2_RET_PRESENCE_DET_SUPP 23:23 /* R-EVF */
+#define PCIE_LINK_CAPABILITIES_2_RET_PRESENCE_DET_SUPP_UNSET 0x00000000 /* R-E-V */
+#define PCIE_LINK_CAPABILITIES_2_2RET_PRESENCE_DET_SUPP 24:24 /* R-EVF */
+#define PCIE_LINK_CAPABILITIES_2_2RET_PRESENCE_DET_SUPP_UNSET 0x00000000 /* R-E-V */
+#define PCIE_LINK_CAPABILITIES_2_RSVD1 31:25 /* C--VF */
+#define PCIE_LINK_CAPABILITIES_2_RSVD1_INIT 0x00000000 /* C---V */
+
+//
+// PCI Express Virtual Peer-to-Peer Approval Definition
+//
+// These offsets are unused in hardware on existing chips and are reserved on
+// future chips. Software has defined a virtual PCI capability that may be
+// emulated by hypervisors at these offsets, and this capability is not tied
+// to any specific hardware.
+//
+//
+#define NV_PCI_VIRTUAL_P2P_APPROVAL_CAP_0 0x000000C8
+#define NV_PCI_VIRTUAL_P2P_APPROVAL_CAP_0_ID 7:0
+#define NV_PCI_VIRTUAL_P2P_APPROVAL_CAP_0_NEXT 15:8
+#define NV_PCI_VIRTUAL_P2P_APPROVAL_CAP_0_LENGTH 23:16
+#define NV_PCI_VIRTUAL_P2P_APPROVAL_CAP_0_SIG_LO 31:24
+#define NV_PCI_VIRTUAL_P2P_APPROVAL_CAP_1 0x000000CC
+#define NV_PCI_VIRTUAL_P2P_APPROVAL_CAP_1_SIG_HI 15:0
+#define NV_PCI_VIRTUAL_P2P_APPROVAL_CAP_1_VERSION 18:16
+#define NV_PCI_VIRTUAL_P2P_APPROVAL_CAP_1_PEER_CLIQUE_ID 22:19
+#define NV_PCI_VIRTUAL_P2P_APPROVAL_CAP_1_RSVD 31:23
+
+#define NV_PCI_VIRTUAL_P2P_APPROVAL_SIGNATURE 0x00503250
+
+#define NV_PCI_VIRTUAL_CONFIG_BITS_CAP_0 0x000000D4
+#define NV_PCI_VIRTUAL_CONFIG_BITS_CAP_0_ID 7:0
+#define NV_PCI_VIRTUAL_CONFIG_BITS_CAP_0_NEXT 15:8
+#define NV_PCI_VIRTUAL_CONFIG_BITS_CAP_0_LENGTH 23:16
+#define NV_PCI_VIRTUAL_CONFIG_BITS_CAP_0_SIG_LO 31:24
+#define NV_PCI_VIRTUAL_CONFIG_BITS_CAP_1 0x000000D8
+#define NV_PCI_VIRTUAL_CONFIG_BITS_CAP_1_SIG_HI 15:0
+#define NV_PCI_VIRTUAL_CONFIG_BITS_CAP_1_VALUE 31:16
+
+#define NV_PCI_VIRTUAL_CONFIG_BITS_SIGNATURE 0x00535442 //"BTS"
+
+// Allocation of _VALUE bits
+#define NV_PCI_VIRTUAL_CONFIG_BITS_PCI_EGRESS_POISON_ENABLE 0:0
+
+// Chipset-specific definitions.
+// Intel SantaRosa definitions
+#define INTEL_2A00_CONFIG_SPACE_BASE 0x60
+
+// Intel Montevina definitions
+#define INTEL_2A40_CONFIG_SPACE_BASE 0x60
+#define INTEL_2A40_ASLM_CAPABLE_REVID 0x05
+
+// Intel EagleLake definitions
+#define INTEL_2E00_CONFIG_SPACE_BASE 0x60
+
+// Intel Bearlake definitions
+#define INTEL_29XX_CONFIG_SPACE_BASE 0x60
+
+// Intel BroadWater definitions
+#define INTEL_29A0_CONFIG_SPACE_BASE 0x60
+
+// Intel Grantsdale definitions
+#define INTEL_25XX_CONFIG_SPACE_BASE 0x48
+
+// Intel Tumwater definitions
+#define INTEL_359E_CONFIG_SPACE_BASE 0xCC
+
+// Intel Greencreek definitions
+#define INTEL_25E0_CONFIG_SPACE_BASE_ADDRESS 0xE0000000
+
+// Intel Stoakley definitions
+#define INTEL_4000_CONFIG_SPACE_BASE_ADDRESS 0xE0000000
+
+// Intel SkullTrail definitions
+#define INTEL_4003_CONFIG_SPACE_BASE_ADDRESS_F 0xF0000000
+#define INTEL_4003_CONFIG_SPACE_BASE_ADDRESS_E 0xE0000000
+#define INTEL_4003_CONFIG_SPACE_BASE_ADDRESS INTEL_4003_CONFIG_SPACE_BASE_ADDRESS_F
+#define INTEL_4003_CONFIG_SPACE_BASE 0x64
+
+// SiS 656
+#define SIS_656_CONFIG_SPACE_BASE 0xE0
+#define SIS_656_CONFIG_SPACE_BASE_ADDRESS 3:0 // mapped to 31:28
+
+// PCI/PCIE definitions
+#define PCI_MAX_CAPS 20 // max caps to parse
+#define PCI_MAX_DEVICES 32 // max devices on bus
+#define PCI_MAX_FUNCTIONS 8 // max functions for a device
+#define PCI_CAP_HEADER_ID 7:0 // PCI cap header id
+#define PCI_CAP_HEADER_NEXT 15:8 // PCI cap header next
+#define PCI_COMMON_CLASS_SUBCLASS 0x0a // PCI class/subclass (word)
+#define PCI_COMMON_CLASS_SUBBASECLASS_HOST 0x0600 // Host bridge (connect PCI to CPU) [00] + Bridge Device [06]
+#define PCI_COMMON_CLASS_SUBBASECLASS_P2P 0x0604 // PCI-to-PCI bridge (connects PCI buses) [04] + Bridge Device [06]
+#define PCI_COMMON_CLASS_SUBBASECLASS_VGA 0x0300
+#define PCI_COMMON_CLASS_SUBBASECLASS_3DCTRL 0x0302
+#define PCI_COMMON_CAP_PTR 0x34 // PCI common cap ptr (byte)
+#define PCI_TYPE_1_SECONDARY_BUS_NUMBER 0x19 // PCI type 1 sec bus (byte)
+#define PCI_TYPE_1_SUBORDINATE_BUS_NUMBER 0x1a // PCI type 1 sub bus (byte)
+#define PCIE_CAP_HEADER_ID 15:0 // PCIE cap header id
+#define PCIE_CAP_HEADER_ID_INVALID 0xffff
+#define PCIE_CAP_HEADER_NEXT 31:20 // PCIE cap header next
+#define PCIE_BUS_SHIFT 20 // PCIE cfg space bus shift
+#define PCIE_DEVICE_SHIFT 15 // PCIE cfg space dev shift
+#define PCIE_FUNC_SHIFT 12 // PCIE cfg space func shift
+#define PCIE_CAP_VERSION 19:16 // PCIE cap version
+#define PCIE_CAP_VERSION_2P0 2 // PCIE 2.0 version
+#define PCIE_LINK_CNTRL_STATUS_2_OFFSET 0x30 // PCIE Link Control/Status 2 offset
+#define PCIE_LINK_STATUS_2 31:16 // PCIE Link Status 2 Register
+#define PCIE_LINK_STATUS_2_DE_EMPHASIS 0:0 // PCIE De-Emphasis Level
+#define PCI_COMMON_SUBSYSTEM_VENDOR_ID 0x2c // PCI subsystem Vendor Id
+#define PCI_COMMON_SUBSYSTEM_ID 0x2e // PCI subsystem Id
+#define PCIE_CAPABILITY_BASE 0x100 // 1st PCIE capability.
+
+// PCI Express Capability ID in the enhanced configuration space
+#define PCIE_CAP_ID_NULL 0x00 // 7.9.28.1
+#define PCIE_CAP_ID_ERROR 0x01 // 7.8.4.1
+#define PCIE_CAP_ID_VC 0x02 // 7.9.1.1
+#define PCIE_CAP_ID_SERIAL 0x03 // 7.9.3.1
+#define PCIE_CAP_ID_POWER 0x04 // 7.8.1.1
+#define PCIE_CAP_ID_ROOT_COMPLEX 0x05 // 7.9.8.1
+#define PCIE_CAP_ID_ROOT_COMPLEX_INTERNAL_LINK_CTRL 0x06 // 7.9.9.1
+#define PCIE_CAP_ID_ROOT_COMPLEX_EVENT_COLLECTOR_ENDPOINT 0x07 // 7.9.10.1
+#define PCIE_CAP_ID_PCIE_CAP_ID_MFVC 0x08 // 7.9.2.1
+#define PCIE_CAP_ID_RCRB 0x0A // 7.9.7.1
+#define PCIE_CAP_ID_ACS 0x0D // 7.7.11.1
+#define PCIE_CAP_ID_ARI 0x0E // 7.8.8.1
+#define PCIE_CAP_ID_MULTICAST 0x12 // 7.9.11.1
+#define PCIE_CAP_ID_RESIZABLE_BAR 0x15 // 7.8.6.1
+#define PCIE_CAP_ID_DYNAMIC_POWER_ALLOCATION 0x16 // 7.9.12.1
+#define PCIE_CAP_ID_TPH 0x17 // 7.9.13.1
+#define PCIE_CAP_ID_LATENCY_TOLERANCE 0x18 // 7.8.2.1
+#define PCIE_CAP_ID_SECONDARY_PCIE_CAPABILITY 0x19 // 7.7.3.1
+#define PCIE_CAP_ID_PASID 0x1B // 7.8.9.1
+#define PCIE_CAP_ID_DPC 0x1D // 7.9.14.1
+#define PCIE_CAP_ID_L1_PM_SUBSTATES 0x1E // 7.8.3.1
+#define PCIE_CAP_ID_PTM 0x1F // 7.9.15.1
+#define PCIE_CAP_ID_FRS_QUEUING 0x21 // 7.8.10.1
+#define PCIE_CAP_ID_READINESS_TIME_REPORTING 0x22 // 7.9.16.1
+#define PCIE_CAP_ID_VENDOR_SPECIFIC 0x23 // 7.9.6.1
+#define PCIE_CAP_ID_VF_RESIZABLE_BAR 0x24 // 7.8.7.1
+#define PCIE_CAP_ID_DATA_LINK 0x25 // 7.7.4.1
+#define PCIE_CAP_ID_PHYSLAYER_16_GT 0x26 // 7.7.5.1
+#define PCIE_CAP_ID_LANE_MARGINING_AT_RECEVER 0x27 // 7.7.10.1
+#define PCIE_CAP_ID_HIERARCHY_ID 0x28 // 7.9.17.1
+#define PCIE_CAP_ID_NPEM 0x29 // 7.9.19.1
+#define PCIE_CAP_ID_PHYSLAYER_32_GT 0x2A // 7.7.6.1
+#define PCIE_CAP_ID_ALTERNATE_PROTOCOL 0x2B // 7.9.20.1
+#define PCIE_CAP_ID_SFI 0x2C // 7.9.22.1
+#define PCIE_CAP_ID_SHADOW_FUNCTIONS 0x2D // 7.9.25.1
+#define PCIE_CAP_ID_DATA_OBJECT_EXCHANGE 0x2E // 7.9.24.1
+#define PCIE_CAP_ID_DEVICE_3 0x2F // 7.7.9.1
+#define PCIE_CAP_ID_IDE 0x30 // 7.9.26.1
+#define PCIE_CAP_ID_PHYSLAYER_64_GT 0x31 // 7.7.7.1
+#define PCIE_CAP_ID_FLT_LOGGING 0x32 // 7.7.8.1
+#define PCIE_CAP_ID_FLIT_PERF_MEASURMENT 0x33 // 7.8.12.1
+#define PCIE_CAP_ID_FLIT_ERROR_INJECTION 0x34 // 7.8.13.1
+
+// static sized structure sizes
+#define PCIE_CAP_HEADER_SIZE 0x04 // 7.6.3
+#define PCIE_CAP_NULL_SIZE 0x04 // 7.9.28
+#define PCIE_CAP_ERROR_SIZE 0x48 // 7.8.4
+#define PCIE_CAP_POWER_SIZE 0x10 // 7.8.1
+#define PCIE_CAP_ROOT_COMPLEX_INTERNAL_LINK_CTRL_SIZE 0x0C // 7.9.9
+#define PCIE_CAP_ROOT_COMPLEX_EVENT_COLLECTOR_ENDPOINT_SIZE 0x0C // 7.9.10
+#define PCIE_CAP_SECONDARY_PCIE_SIZE 0x4C // 7.7.3.1
+#define PCIE_CAP_DATA_LINK_SIZE 0x0C // 7.7.4
+#define PCIE_CAP_PHYSLAYER_16_GT_SIZE 0x40 // 7.7.5
+#define PCIE_CAP_PHYSLAYER_32_GT_SIZE 0x40 // 7.7.6
+#define PCIE_CAP_PHYSLAYER_64_GT_SIZE 0x20 // 7.7.7
+#define PCIE_CAP_FLT_LOGGING_SIZE 0x3C // 7.7.8
+#define PCIE_CAP_DEVICE_3_SIZE 0x10 // 7.7.9
+#define PCIE_CAP_LANE_MARGINING_AT_RECEVER_SIZE 0x88 // 7.7.10
+#define PCIE_CAP_ACS_SIZE 0x10 // 7.7.11
+#define PCIE_CAP_LATENCY_TOLERANCE_SIZE 0x08 // 7.8.2
+#define PCIE_CAP_L1_PM_SUBSTATE_SIZE 0x14 // 7.8.3
+#define PCIE_CAP_RESIZABLE_BAR_SIZE 0x34 // 7.8.6
+#define PCIE_CAP_VF_RESIZABLE_BAR_SIZE 0x34 // 7.8.7
+#define PCIE_CAP_ARI_SIZE 0x08 // 7.8.8
+#define PCIE_CAP_PASID_SIZE 0x08 // 7.8.9
+#define PCIE_CAP_FRS_QUEUING_SIZE 0x10 // 7.8.10
+#define PCIE_CAP_FPB_SIZE 0x24 // 7.8.11
+#define PCIE_CAP_FLIT_PERF_MEASURMENT_SIZE 0x24 // 7.8.12
+#define PCIE_CAP_FLIT_ERROR_INJECTION_SIZE 0x24 // 7.8.13
+#define PCIE_CAP_DEV_SERIAL_SIZE 0x0C // 7.9.3
+#define PCIE_CAP_RCRB_SIZE 0x14 // 7.9.7
+#define PCIE_CAP_MULTICAST_SIZE 0x30 // 7.9.11
+#define PCIE_CAP_DYNAMIC_POWER_ALLOCATION_SIZE 0x30 // 7.9.12
+#define PCIE_CAP_DPC_SIZE 0x5C // 7.9.14
+#define PCIE_CAP_PTM_SIZE 0x0C // 7.9.15
+#define PCIE_CAP_READINESS_TIME_REPORTING_SIZE 0x0C // 7.9.16
+#define PCIE_CAP_HIERARCHY_ID_SIZE 0x0C // 7.9.17
+#define PCIE_CAP_NPEM_SIZE 0x10 // 7.9.19
+#define PCIE_CAP_ALTERNATE_PROTOCOL_SIZE 0x14 // 7.9.20
+#define PCIE_CAP_SFI_SIZE 0x14 // 7.9.22
+#define PCIE_CAP_DATA_OBJECT_EXCHANGE_SIZE 0x18 // 7.9.24
+#define PCIE_CAP_SHADOW_FUNCTIONS_SIZE 0x1C // 7.9.25
+#define PCIE_CAP_IDE_SIZE 0x34 // 7.9.26
+
+// Virtual Channel Capability size related fields
+#define PCIE_VC_REGISTER_1 0x04 // 7.9.1.2
+#define PCIE_VC_REGISTER_1_EXTENDED_VC_COUNT 2:0
+#define PCIE_VIRTUAL_CHANNELS_BASE_SIZE 0x18 // 7.9.1
+#define PCIE_VIRTUAL_CHANNELS_EXTENDED_VC_ENTRY_SIZE 0x10 // 7.9.1
+
+// Multi Function Virtual Channel Capability size related fields
+#define PCIE_MFVC_REGISTER_1 0x04 // 7.9.2.2
+#define PCIE_MFVC_REGISTER_1_EXTENDED_VC_COUNT 2:0
+#define PCIE_PCIE_CAP_ID_MFVC_BASE_SIZE 0x18 // 7.9.2
+#define PCIE_PCIE_CAP_ID_MFVC_EXTENDED_VC_ENTRY_SIZE 0x10 // 7.9.2
+
+// Vendor Specific Capability size related fields
+#define PCIE_VENDOR_SPECIFIC_HEADER_1 0x04 // 7.9.6.2
+#define PCIE_VENDOR_SPECIFIC_HEADER_1_LENGTH 31:20
+
+// Root Complex Capability size related fields
+#define PCIE_ROOT_COMPLEX_SELF_DESC_REGISTER 0x04 // 7.9.8.2
+#define PCIE_ROOT_COMPLEX_SELF_DESC_REGISTER_NUM_LINK_ENTRIES 15:8
+#define PCIE_ROOT_COMPLEX_BASE_SIZE 0x0C // 7.9.8
+#define PCIE_ROOT_COMPLEX_LINK_ENTRY_SIZE 0x10 // 7.9.8.3
+
+// TPH capability size related fields
+#define PCIE_TPH_REQUESTOR_REGISTER 0x04 // 7.9.13.2
+#define PCIE_TPH_REQUESTOR_REGISTER_ST_TABLE_SIZE 26:16
+#define PCIE_TPH_BASE_SIZE 0x0C // 7.9.13
+#define PCIE_TPH_ST_ENTRY_SIZE 0x02 // 7.9.13.4
+
+// Intel CPU family.
+#define INTEL_CPU_FAMILY_06 0x06
+#define INTEL_CPU_FAMILY_15 0x0f
+#define INTEL_CPU_FAMILY_16 0x10
+#define INTEL_CPU_FAMILY_21 0x15
+
+// Intel CPU Model. Calculated as Model += (extModel << 4).
+#define INTEL_CPU_MODEL_2A 0x2a
+#define INTEL_CPU_MODEL_2D 0x2d
+#define INTEL_CPU_MODEL_3A 0x3a
+#define INTEL_CPU_MODEL_3F 0x3f
+
+// Symbolic defines for each possible virtual channel
+enum
+{
+ RM_PCIE_VIRTUAL_CHANNEL_0 = 0,
+ RM_PCIE_VIRTUAL_CHANNEL_1,
+ RM_PCIE_VIRTUAL_CHANNEL_2,
+ RM_PCIE_VIRTUAL_CHANNEL_3,
+ RM_PCIE_VIRTUAL_CHANNEL_4,
+ RM_PCIE_VIRTUAL_CHANNEL_5,
+ RM_PCIE_VIRTUAL_CHANNEL_6,
+ RM_PCIE_VIRTUAL_CHANNEL_7,
+ RM_PCIE_VIRTUAL_CHANNEL_INVALID
+};
+
+// Diagnostic collection actions.
+#define RM_PCIE_ACTION_NOP 0
+#define RM_PCIE_ACTION_COLLECT_CONFIG_SPACE 1
+#define RM_PCIE_ACTION_COLLECT_PCI_CAP_STRUCT 2
+#define RM_PCIE_ACTION_COLLECT_PCIE_CAP_STRUCT 3
+#define RM_PCIE_ACTION_COLLECT_ALL_PCI_CAPS 4
+#define RM_PCIE_ACTION_COLLECT_ALL_PCIE_CAPS 5
+#define RM_PCIE_ACTION_REPORT_PCI_CAPS_COUNT 6
+#define RM_PCIE_ACTION_REPORT_PCIE_CAPS_COUNT 7
+#define RM_PCIE_ACTION_EOS 0xff
+
+
+// Diagnostic collection device Type ids
+#define RM_PCIE_DEVICE_TYPE_NONE 0xff
+#define RM_PCIE_DEVICE_TYPE_GPU 0
+#define RM_PCIE_DEVICE_TYPE_UPSTREAM_BRIDGE 1
+#define RM_PCIE_DEVICE_COUNT 2
+
+// Diagnostic collection capability Type ids
+#define RM_PCIE_DC_CAP_TYPE_NONE 0xff
+#define RM_PCIE_DC_CAP_TYPE_PCI 0
+#define RM_PCIE_DC_CAP_TYPE_PCIE 1
+#define RM_PCIE_DC_CAP_TYPE_COUNT 2
+
+typedef struct _def_bif_dc_diagnostic_collection_command
+{
+ NvU8 action;
+ NvU8 deviceType;
+ NvU16 locator;
+ NvU16 length;
+} CL_PCIE_DC_DIAGNOSTIC_COLLECTION_ENTRY;
+
+typedef struct _def_cl_pcie_dc_capability_map_entry
+{
+ NvU16 id;
+ NvU16 blkOffset;
+} CL_PCIE_DC_CAPABILITY_MAP_ENTRY;
+typedef struct
+{
+ NvU16 count;
+ CL_PCIE_DC_CAPABILITY_MAP_ENTRY entries[PCI_MAX_CAPS];
+} CL_PCIE_DC_CAPABILITY_MAP;
+
+typedef struct OBJCL OBJCL;
+typedef struct OBJGPU OBJGPU;
+// root port setup functions
+NV_STATUS Broadcom_HT2100_setupFunc(OBJGPU *, OBJCL*);
+
+NV_STATUS Intel_RP25XX_setupFunc(OBJGPU *, OBJCL*);
+NV_STATUS Intel_RP81XX_setupFunc(OBJGPU *, OBJCL*);
+NV_STATUS Intel_RP3C0X_setupFunc(OBJGPU *, OBJCL*);
+NV_STATUS Intel_RP2F0X_setupFunc(OBJGPU *, OBJCL*);
+NV_STATUS Intel_RP0C0X_setupFunc(OBJGPU *, OBJCL*);
+NV_STATUS Intel_Broadwell_setupFunc(OBJGPU *, OBJCL*);
+NV_STATUS Intel_Skylake_setupFunc(OBJGPU *, OBJCL*);
+NV_STATUS Intel_Skylake_U_Pch_setupFunc(OBJGPU *, OBJCL*);
+NV_STATUS Intel_Skylake_H_Pch_setupFunc(OBJGPU *, OBJCL*);
+NV_STATUS Intel_Kabylake_Y_setupFunc(OBJGPU *, OBJCL*);
+
+NV_STATUS Nvidia_RPC19_setupFunc(OBJGPU *, OBJCL*);
+NV_STATUS Nvidia_RPC51_setupFunc(OBJGPU *, OBJCL*);
+NV_STATUS Nvidia_RPC55_setupFunc(OBJGPU *, OBJCL*);
+
+NV_STATUS AMD_RP1480_setupFunc(OBJGPU *, OBJCL*);
+NV_STATUS AMD_RP1630_setupFunc(OBJGPU *, OBJCL*);
+NV_STATUS AMD_RP1483_setupFunc(OBJGPU *, OBJCL*);
+
+NV_STATUS Qualcomm_Snapdragon8cx_RP_setupFunc(OBJGPU *, OBJCL*);
+
+// Determines if the GPU is in a multi-GPU board based on devid checks
+NvBool gpuIsMultiGpuBoard(OBJGPU *);
+
+#endif // NVPCIE_H
diff --git a/userspace/sdks/nv570/nvalloc/common/inc/nvrangetypes.h b/userspace/sdks/nv570/nvalloc/common/inc/nvrangetypes.h
new file mode 100644
index 0000000..1ff7df6
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/common/inc/nvrangetypes.h
@@ -0,0 +1,162 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2016-2017 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/*!
+ * @file nvrangetypes.h
+ * @brief Range types and operator macros
+ * @note #include a header to define NvUxx and NvSxx before sourcing this file.
+ */
+
+#ifndef _NVRANGETYPES_H_
+#define _NVRANGETYPES_H_
+
+
+//
+// Define range types by convention
+//
+#define __NV_DEFINE_RANGE_TYPE(T) \
+typedef struct NvRange ## T \
+{ \
+ Nv ## T min; \
+ Nv ## T max; \
+} NvRange ## T;
+
+
+__NV_DEFINE_RANGE_TYPE(U64) // NvRangeU64
+__NV_DEFINE_RANGE_TYPE(S64) // NvRangeS64
+__NV_DEFINE_RANGE_TYPE(U32) // NvRangeU32
+__NV_DEFINE_RANGE_TYPE(S32) // NvRangeS32
+__NV_DEFINE_RANGE_TYPE(U16) // NvRangeU16
+__NV_DEFINE_RANGE_TYPE(S16) // NvRangeS16
+__NV_DEFINE_RANGE_TYPE(U8) // NvRangeU8
+__NV_DEFINE_RANGE_TYPE(S8) // NvRangeS8
+
+
+//
+// Operator macros
+//
+// Macros are named xxx_RANGE (rather than xxx_RANGEU32, etc.) since they work
+// properly on ranges with any number of bits, signed or unsigned.
+//
+
+#define NV_EQUAL_RANGE(r1, r2) ((r1).min == (r2).min && (r1).max == (r2).max)
+#define NV_EMPTY_INCLUSIVE_RANGE(r) ((r).min > (r).max)
+#define NV_EMPTY_EXCLUSIVE_RANGE(r) ((r).min + 1 > (r).max - 1)
+#define NV_WITHIN_INCLUSIVE_RANGE(r, x) ((r).min <= (x) && (x) <= (r).max)
+#define NV_WITHIN_EXCLUSIVE_RANGE(r, x) ((r).min < (x) && (x) < (r).max)
+#define NV_IS_SUBSET_RANGE(r1, r2) ((r1).min >= (r2).min && (r2).max >= (r1).max)
+#define NV_IS_SUPERSET_RANGE(r1, r2) ((r1).min <= (r2).min && (r2).max <= (r1).max)
+#define NV_CENTER_OF_RANGE(r) ((r).min / 2 + ((r).max + 1) / 2) // Avoid overflow and rounding anomalies.
+#define NV_IS_OVERLAPPING_RANGE(r1, r2) \
+ (NV_WITHIN_INCLUSIVE_RANGE((r1), (r2).min) || \
+ NV_WITHIN_INCLUSIVE_RANGE((r1), (r2).max))
+
+#define NV_DISTANCE_FROM_RANGE(r, x) ((x) < (r).min? (r).min - (x): ((x) > (r).max? (x) - (r).max: 0))
+#define NV_VALUE_WITHIN_INCLUSIVE_RANGE(r, x) ((x) < (r).min? (r).min : ((x) > (r).max? (r).max : (x)))
+#define NV_VALUE_WITHIN_EXCLUSIVE_RANGE(r, x) ((x) <= (r).min? (r).min + 1 : ((x) >= (r).max? (r).max - 1 : (x)))
+
+#define NV_INIT_RANGE(r, x, y) \
+do \
+{ \
+ (r).min = (x); \
+ (r).max = (y); \
+} while(0)
+
+#define NV_ASSIGN_DELTA_RANGE(r, x, d) \
+do \
+{ \
+ (r).min = (x) - (d); \
+ (r).max = (x) + (d); \
+} while(0)
+
+#define NV_ASSIGN_INTERSECTION_RANGE(r1, r2) \
+do \
+{ \
+ if ((r1).min < (r2).min) \
+ (r1).min = (r2).min; \
+ if ((r1).max > (r2).max) \
+ (r1).max = (r2).max; \
+} while(0)
+
+#define NV_ASSIGN_UNION_RANGE(r1, r2) \
+do \
+{ \
+ if ((r1).min > (r2).min) \
+ (r1).min = (r2).min; \
+ if ((r1).max < (r2).max) \
+ (r1).max = (r2).max; \
+} while(0)
+
+#define NV_MULTIPLY_RANGE(r, x) \
+do \
+{ \
+ (r).min *= (x); \
+ (r).max *= (x); \
+} while(0)
+
+#define NV_DIVIDE_FLOOR_RANGE(r, x) \
+do \
+{ \
+ (r).min /= (x); \
+ (r).max /= (x); \
+} while(0)
+
+#define NV_DIVIDE_CEILING_RANGE(r, x) \
+do \
+{ \
+ (r).min = ((r).min + (x) - 1) / (x); \
+ (r).max = ((r).max + (x) - 1) / (x); \
+} while(0)
+
+#define NV_DIVIDE_ROUND_RANGE(r, x) \
+do \
+{ \
+ (r).min = ((r).min + (x) / 2) / (x); \
+ (r).max = ((r).max + (x) / 2) / (x); \
+} while(0)
+
+#define NV_DIVIDE_WIDE_RANGE(r, x) \
+do \
+{ \
+ (r).min /= (x); \
+ (r).max = ((r).max + (x) - 1) / (x); \
+} while(0)
+
+#define NV_DIVIDE_NARROW_RANGE(r, x) \
+do \
+{ \
+ (r).min = ((r).min + (x) - 1) / (x); \
+ (r).max /= (x); \
+} while(0)
+
+#define NV_VALUE_WITHIN_INCLUSIVE_RANGE(r, x) \
+ ((x) < (r).min? (r).min : ((x) > (r).max? (r).max : (x)))
+
+#define NV_WITHIN_INCLUSIVE_RANGE(r, x) \
+ ((r).min <= (x) && (x) <= (r).max)
+
+#define NV_DISTANCE_FROM_RANGE(r, x) \
+ ((x) < (r).min? (r).min - (x): ((x) > (r).max? (x) - (r).max: 0))
+
+#endif // _NVRANGETYPES_H_
+
diff --git a/userspace/sdks/nv570/nvalloc/common/inc/oob/smbpbi.h b/userspace/sdks/nv570/nvalloc/common/inc/oob/smbpbi.h
new file mode 100644
index 0000000..aefad5e
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/common/inc/oob/smbpbi.h
@@ -0,0 +1,2925 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2010-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _SMBPBI_H
+#define _SMBPBI_H
+
+#include "oob/smbpbi_impl.h"
+
+/*!
+ * This file contains definitions for SMBPBI - SMBUS Out-Of-Band (OOB) interface
+ */
+/*!
+ * NV_MSGBOX_CMD() macro below and its derivatives depend on DRF_DEF() and DRF_NUM()
+ * macros, that are defined in "nvdrf.h" header file, which is a part of
+ * smbus/msgbox SDK. That file needs to be #included before this (smbpbi.h)
+ * header file.
+ */
+
+/********************************************************************************
+ * *
+ * GPU COMMANDS *
+ * *
+ ********************************************************************************/
+
+//
+// Encoding:
+// 30 29 23 16 15 8 7 0
+// .-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-.
+// |I|C|R| STATUS | ARG2 | ARG1 | OPCODE | COMMAND
+// `-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-'
+// 31 28 24
+//
+
+#define NV_MSGBOX_CMD_OPCODE 7:0
+#define NV_MSGBOX_CMD_OPCODE_NULL_CMD 0x00000000
+#define NV_MSGBOX_CMD_OPCODE_GET_CAP_DWORD 0x00000001
+#define NV_MSGBOX_CMD_OPCODE_GET_TEMP 0x00000002
+#define NV_MSGBOX_CMD_OPCODE_GET_EXT_TEMP 0x00000003 /* With 8 fractional bits! */
+#define NV_MSGBOX_CMD_OPCODE_GET_POWER 0x00000004
+#define NV_MSGBOX_CMD_OPCODE_GET_SYS_ID_DATA 0x00000005
+#define NV_MSGBOX_CMD_OPCODE_GET_ECC_V1 0x00000006
+#define NV_MSGBOX_CMD_OPCODE_GET_ECC_V2 0x00000007
+#define NV_MSGBOX_CMD_OPCODE_GPU_PCONTROL 0x00000008
+#define NV_MSGBOX_CMD_OPCODE_GPU_SYSCONTROL 0x00000009
+#define NV_MSGBOX_CMD_OPCODE_SET_MASTER_CAPS 0x0000000a
+#define NV_MSGBOX_CMD_OPCODE_SET_PRIMARY_CAPS 0x0000000a // Duplicate value till bug 3190552 is addressed.
+#define NV_MSGBOX_CMD_OPCODE_GPU_REQUEST_CPL 0x0000000b
+#define NV_MSGBOX_CMD_OPCODE_GET_ECC_V3 0x0000000c
+#define NV_MSGBOX_CMD_OPCODE_SCRATCH_READ 0x0000000d
+#define NV_MSGBOX_CMD_OPCODE_SCRATCH_WRITE 0x0000000e
+#define NV_MSGBOX_CMD_OPCODE_SCRATCH_COPY 0x0000000f
+#define NV_MSGBOX_CMD_OPCODE_ASYNC_REQUEST 0x00000010
+#define NV_MSGBOX_CMD_OPCODE_REGISTER_ACCESS 0x00000011
+#define NV_MSGBOX_CMD_OPCODE_GET_POWER_CONNECTOR_STATE 0x00000012
+#define NV_MSGBOX_CMD_OPCODE_GET_PAGE_RETIREMENT_STATS 0x00000013
+#define NV_MSGBOX_CMD_OPCODE_GET_ECC_V4 0x00000014
+#define NV_MSGBOX_CMD_OPCODE_GET_THERM_PARAM 0x00000015
+#define NV_MSGBOX_CMD_OPCODE_GET_ECC_V5 0x00000016
+#define NV_MSGBOX_CMD_OPCODE_ACCESS_WP_MODE 0x00000017
+
+//
+// TODO: Get rid of MISC_GPU_FLAGS once all SMBPBI implementations have made
+// the switch to MISC_DEVICE_FLAGS.
+//
+#define NV_MSGBOX_CMD_OPCODE_GET_MISC_GPU_FLAGS 0x00000018
+#define NV_MSGBOX_CMD_OPCODE_GET_MISC_DEVICE_FLAGS 0x00000018
+#define NV_MSGBOX_CMD_OPCODE_GPU_UTIL_COUNTERS 0x00000019
+#define NV_MSGBOX_CMD_OPCODE_GET_NVLINK_INFO 0x0000001a
+#define NV_MSGBOX_CMD_OPCODE_GET_CLOCK_FREQ_INFO 0x0000001b
+#define NV_MSGBOX_CMD_OPCODE_BUNDLE_LAUNCH 0x0000001c
+#define NV_MSGBOX_CMD_OPCODE_GET_DRIVER_EVENT_MSG 0x0000001d
+#define NV_MSGBOX_CMD_OPCODE_GET_ECC_V6 0x0000001e
+#define NV_MSGBOX_CMD_OPCODE_REMAP_ROW_STATS 0x00000020
+#define NV_MSGBOX_CMD_OPCODE_GET_PCIE_LINK_INFO 0x00000021
+#define NV_MSGBOX_CMD_OPCODE_GET_ENERGY_COUNTER 0x00000022
+#define NV_MSGBOX_CMD_OPCODE_RESERVED_0 0x00000024
+#define NV_MSGBOX_CMD_OPCODE_RESERVED_1 0x00000025
+#define NV_MSGBOX_CMD_OPCODE_GET_POWER_HINT_INFO 0x00000026
+#define NV_MSGBOX_CMD_OPCODE_DYNAMIC_SYSTEM_INFORMATION 0x00000027
+#define NV_MSGBOX_CMD_OPCODE_GPU_PERFORMANCE_MONITORING 0x00000028
+
+#define NV_MSGBOX_CMD_ARG1 15:8
+#define NV_MSGBOX_CMD_ARG1_NULL 0x00000000
+#define NV_MSGBOX_CMD_ARG1_TEMP_GPU_0 0x00000000
+#define NV_MSGBOX_CMD_ARG1_TEMP_NVSWITCH_0 0x00000000
+#define NV_MSGBOX_CMD_ARG1_TEMP_GPU_1 0x00000001 /* For Gemini boards */
+#define NV_MSGBOX_CMD_ARG1_TEMP_BOARD 0x00000004
+#define NV_MSGBOX_CMD_ARG1_TEMP_MEMORY 0x00000005
+#define NV_MSGBOX_CMD_ARG1_TEMP_PWR_SUPPLY 0x00000006
+#define NV_MSGBOX_CMD_ARG1_TEMP_T_LIMIT 0x00000007
+#define NV_MSGBOX_CMD_ARG1_TEMP_NUM_SENSORS 8
+#define NV_MSGBOX_CMD_ARG1_POWER_TOTAL 0x00000000
+#define NV_MSGBOX_CMD_ARG1_SMBPBI_POWER 0x00000001
+#define NV_MSGBOX_CMD_ARG1_POWER_FB 0x00000002
+#define NV_MSGBOX_CMD_ARG1_POWER_MODULE 0x00000003
+/* SysId info type encodings for opcode NV_MSGBOX_CMD_OPCODE_GET_SYS_ID_DATA (0x05) */
+#define NV_MSGBOX_CMD_ARG1_BOARD_PART_NUM_V1 0x00000000
+#define NV_MSGBOX_CMD_ARG1_OEM_INFO_V1 0x00000001
+#define NV_MSGBOX_CMD_ARG1_SERIAL_NUM_V1 0x00000002
+#define NV_MSGBOX_CMD_ARG1_MARKETING_NAME_V1 0x00000003
+#define NV_MSGBOX_CMD_ARG1_GPU_PART_NUM_V1 0x00000004
+#define NV_MSGBOX_CMD_ARG1_MEMORY_VENDOR_V1 0x00000005
+#define NV_MSGBOX_CMD_ARG1_MEMORY_PART_NUM_V1 0x00000006
+#define NV_MSGBOX_CMD_ARG1_BUILD_DATE_V1 0x00000007
+#define NV_MSGBOX_CMD_ARG1_FIRMWARE_VER_V1 0x00000008
+#define NV_MSGBOX_CMD_ARG1_VENDOR_ID_V1 0x00000009
+#define NV_MSGBOX_CMD_ARG1_DEV_ID_V1 0x0000000a
+#define NV_MSGBOX_CMD_ARG1_SUB_VENDOR_ID_V1 0x0000000b
+#define NV_MSGBOX_CMD_ARG1_SUB_ID_V1 0x0000000c
+#define NV_MSGBOX_CMD_ARG1_GPU_GUID_V1 0x0000000d
+#define NV_MSGBOX_CMD_ARG1_INFOROM_VER_V1 0x0000000e
+#define NV_MSGBOX_CMD_ARG1_PRODUCT_LENGTH_V1 0x0000000f
+#define NV_MSGBOX_CMD_ARG1_PRODUCT_WIDTH_V1 0x00000010
+#define NV_MSGBOX_CMD_ARG1_PRODUCT_HEIGHT_V1 0x00000011
+#define NV_MSGBOX_CMD_ARG1_PCIE_SPEED_V1 0x00000012
+#define NV_MSGBOX_CMD_ARG1_PCIE_WIDTH_V1 0x00000013
+#define NV_MSGBOX_CMD_ARG1_TGP_LIMIT_V1 0x00000014
+#define NV_MSGBOX_CMD_ARG1_FRU_PART_NUMBER_V1 0x00000015
+#define NV_MSGBOX_CMD_ARG1_MODULE_POWER_LIMIT_V1 0x00000016
+#define NV_MSGBOX_CMD_ARG1_MAX_DRAM_CAPACITY_V1 0x00000017
+#define NV_MSGBOX_CMD_ARG1_SYS_ID_DATA_TYPE_MAX 0x00000017 /* Adjust, when adding new types */
+#define NV_MSGBOX_CMD_ARG1_REGISTER_ACCESS_WRITE 0x00000000
+#define NV_MSGBOX_CMD_ARG1_REGISTER_ACCESS_READ 0x00000001
+#define NV_MSGBOX_CMD_ARG1_THERM_PARAM_TEMP_TARGET 0x00000000
+#define NV_MSGBOX_CMD_ARG1_THERM_PARAM_TEMP_HW_SLOWDN 0x00000001
+#define NV_MSGBOX_CMD_ARG1_THERM_PARAM_TEMP_SHUTDN 0x00000002
+#define NV_MSGBOX_CMD_ARG1_THERM_PARAM_TEMP_HBM_SLOWDN 0x00000003
+#define NV_MSGBOX_CMD_ARG1_THERM_PARAM_TEMP_SW_SLOWDN 0x00000004
+#define NV_MSGBOX_CMD_ARG1_THERM_PARAM_TEMP_TARGET_TLIMIT 0x00000005
+#define NV_MSGBOX_CMD_ARG1_THERM_PARAM_TEMP_HW_SLOWDN_TLIMIT 0x00000006
+#define NV_MSGBOX_CMD_ARG1_THERM_PARAM_TEMP_SHUTDN_TLIMIT 0x00000007
+#define NV_MSGBOX_CMD_ARG1_THERM_PARAM_TEMP_HBM_SLOWDN_TLIMIT 0x00000008
+#define NV_MSGBOX_CMD_ARG1_THERM_PARAM_TEMP_SW_SLOWDN_TLIMIT 0x00000009
+#define NV_MSGBOX_CMD_ARG1_GET_MISC_ECC_ENABLED_STATE 0x00000000
+#define NV_MSGBOX_CMD_ARG1_GET_MISC_GPU_RESET_REQUIRED 0x00000001
+#define NV_MSGBOX_CMD_ARG1_GET_MISC_GPU_FLAGS_PAGE_0 0x00000000
+#define NV_MSGBOX_CMD_ARG1_GET_MISC_GPU_FLAGS_PAGE_1 0x00000001
+#define NV_MSGBOX_CMD_ARG1_GET_MISC_DEVICE_FLAGS_PAGE_0 0x00000000
+#define NV_MSGBOX_CMD_ARG1_GET_MISC_DEVICE_FLAGS_PAGE_1 0x00000001
+
+#define NV_MSGBOX_CMD_ARG1_GPU_UTIL_COUNTERS_CONTEXT_TIME 0x00000000
+#define NV_MSGBOX_CMD_ARG1_GPU_UTIL_COUNTERS_SM_TIME 0x00000001
+#define NV_MSGBOX_CMD_ARG1_GPU_UTIL_COUNTERS_RESET_COUNTERS 0x000000FF
+#define NV_MSGBOX_CMD_ARG1_GET_NVLINK_INFO_LINK_COUNT 0x00000000
+#define NV_MSGBOX_CMD_ARG1_GET_NVLINK_INFO_LINK_STATE_V1 0x00000001
+#define NV_MSGBOX_CMD_ARG1_GET_NVLINK_INFO_LINK_BANDWIDTH 0x00000002
+#define NV_MSGBOX_CMD_ARG1_GET_NVLINK_INFO_ERR_COUNTER_REPLAY 0x00000003
+#define NV_MSGBOX_CMD_ARG1_GET_NVLINK_INFO_ERR_COUNTER_RECOVERY 0x00000004
+#define NV_MSGBOX_CMD_ARG1_GET_NVLINK_INFO_ERR_COUNTER_FLIT_CRC 0x00000005
+#define NV_MSGBOX_CMD_ARG1_GET_NVLINK_INFO_ERR_COUNTER_DATA_CRC 0x00000006
+#define NV_MSGBOX_CMD_ARG1_GET_NVLINK_INFO_LINK_STATE_V2 0x00000007
+#define NV_MSGBOX_CMD_ARG1_GET_NVLINK_INFO_SUBLINK_WIDTH 0x00000008
+#define NV_MSGBOX_CMD_ARG1_GET_NVLINK_INFO_THROUGHPUT_DATA_TX 0x00000009
+#define NV_MSGBOX_CMD_ARG1_GET_NVLINK_INFO_THROUGHPUT_DATA_RX 0x0000000a
+#define NV_MSGBOX_CMD_ARG1_GET_NVLINK_INFO_THROUGHPUT_RAW_TX 0x0000000b
+#define NV_MSGBOX_CMD_ARG1_GET_NVLINK_INFO_THROUGHPUT_RAW_RX 0x0000000c
+#define NV_MSGBOX_CMD_ARG1_GET_NVLINK_INFO_TRAINING_ERROR_STATE 0x0000000d
+#define NV_MSGBOX_CMD_ARG1_GET_NVLINK_INFO_RUNTIME_ERROR_STATE 0x0000000e
+#define NV_MSGBOX_CMD_ARG1_GET_NVLINK_INFO_AVAILABILITY 0x0000000f
+#define NV_MSGBOX_CMD_ARG1_GET_CLOCK_FREQ_INFO_CURRENT 0x00000000
+#define NV_MSGBOX_CMD_ARG1_GET_CLOCK_FREQ_INFO_MIN 0x00000001
+#define NV_MSGBOX_CMD_ARG1_GET_CLOCK_FREQ_INFO_MAX 0x00000002
+#define NV_MSGBOX_CMD_ARG1_GET_CLOCK_FREQ_INFO_PAGE_3 0x00000003
+#define NV_MSGBOX_CMD_ARG1_GET_SUPPORTED_CLOCK_THROTTLE_REASONS 0x00000004
+#define NV_MSGBOX_CMD_ARG1_GET_CURRENT_CLOCK_THROTTLE_REASONS 0x00000005
+#define NV_MSGBOX_CMD_ARG1_REMAP_ROWS_RAW_COUNTS 0x00000000
+#define NV_MSGBOX_CMD_ARG1_REMAP_ROWS_STATE_FLAGS 0x00000001
+#define NV_MSGBOX_CMD_ARG1_REMAP_ROWS_HISTOGRAM 0x00000002
+#define NV_MSGBOX_CMD_ARG1_GET_PCIE_LINK_INFO_PAGE_0 0x00000000
+#define NV_MSGBOX_CMD_ARG1_GET_PCIE_LINK_INFO_PAGE_1 0x00000001
+#define NV_MSGBOX_CMD_ARG1_GET_PCIE_LINK_INFO_PAGE_2 0x00000002
+#define NV_MSGBOX_CMD_ARG1_GET_PCIE_LINK_INFO_PAGE_3 0x00000003
+#define NV_MSGBOX_CMD_ARG1_GET_PCIE_LINK_INFO_PAGE_4 0x00000004
+#define NV_MSGBOX_CMD_ARG1_GET_PCIE_LINK_INFO_PAGE_6 0x00000006
+#define NV_MSGBOX_CMD_ARG1_GET_PCIE_LINK_INFO_PAGE_8 0x00000008
+#define NV_MSGBOX_CMD_ARG1_GET_PCIE_LINK_INFO_PAGE_9 0x00000009
+
+/* Async requests */
+#define NV_MSGBOX_CMD_ARG1_ASYNC_REQUEST_PMGR_PWR_TGP_LIMIT_CONTROL_GET \
+ 0x00000000
+#define NV_MSGBOX_CMD_ARG1_ASYNC_REQUEST_PMGR_PWR_TGP_LIMIT_CONTROL_SET \
+ 0x00000001
+#define NV_MSGBOX_CMD_ARG1_ASYNC_REQUEST_PMGR_PWR_TGP_LIMIT_INFO_GET \
+ 0x00000002
+#define NV_MSGBOX_CMD_ARG1_ASYNC_REQUEST_THERMAL_FAN_V1_COUNT_GET \
+ 0x00000003
+#define NV_MSGBOX_CMD_ARG1_ASYNC_REQUEST_THERMAL_FAN_V1_INFO_GET \
+ 0x00000004
+#define NV_MSGBOX_CMD_ARG1_ASYNC_REQUEST_THERMAL_FAN_V1_STATUS_GET \
+ 0x00000005
+#define NV_MSGBOX_CMD_ARG1_ASYNC_REQUEST_OVERCLOCKING_LIMIT_CONTROL_GET \
+ 0x00000006
+#define NV_MSGBOX_CMD_ARG1_ASYNC_REQUEST_OVERCLOCKING_LIMIT_CONTROL_SET \
+ 0x00000007
+#define NV_MSGBOX_CMD_ARG1_ASYNC_REQUEST_ENERGY_COUNTER_STATUS_GET \
+ 0x00000008
+#define NV_MSGBOX_CMD_ARG1_ASYNC_REQUEST_VIOLATION_COUNTERS_STATUS_GET \
+ 0x00000009
+#define NV_MSGBOX_CMD_ARG1_ASYNC_REQUEST_UTILIZATION_RATE_GET \
+ 0x0000000a
+#define NV_MSGBOX_CMD_ARG1_ASYNC_REQUEST_OOB_CLOCK_LIMIT_SET \
+ 0x0000000b
+#define NV_MSGBOX_CMD_ARG1_ASYNC_REQUEST_DEVICE_MODE_CONTROL \
+ 0x0000000c
+#define NV_MSGBOX_CMD_ARG1_ASYNC_REQUEST_TEST_MESSAGE_SEND \
+ 0x0000000e
+#define NV_MSGBOX_CMD_ARG1_ASYNC_REQUEST_CLOCK_LIMIT_GET \
+ 0x0000000d
+#define NV_MSGBOX_CMD_ARG1_ASYNC_REQUEST_FAN_CURVE_POINTS_GET_SET \
+ 0x0000000f
+#define NV_MSGBOX_CMD_ARG1_ASYNC_REQUEST_POWER_HINT_GET \
+ 0x00000010
+#define NV_MSGBOX_CMD_ARG1_ASYNC_REQUEST_CONFIGURE_PROGRAMMABLE_EDPP \
+ 0x00000011
+#define NV_MSGBOX_CMD_ARG1_ASYNC_REQUEST_PMGR_PWR_MODULE_LIMIT_CONTROL_GET \
+ 0x00000012
+#define NV_MSGBOX_CMD_ARG1_ASYNC_REQUEST_PMGR_PWR_MODULE_LIMIT_CONTROL_SET \
+ 0x00000013
+#define NV_MSGBOX_CMD_ARG1_ASYNC_REQUEST_PMGR_PWR_MODULE_LIMIT_INFO_GET \
+ 0x00000014
+#define NV_MSGBOX_CMD_ARG1_ASYNC_REQUEST_MEMORY_CAPACITY_UTILIZATION_GET \
+ 0x00000015
+#define NV_MSGBOX_CMD_ARG1_ASYNC_REQUEST_POLL 0x000000ff
+
+
+#define NV_MSGBOX_CMD_ARG1_ECC_V2_SEL 15:14
+#define NV_MSGBOX_CMD_ARG1_ECC_V2_SEL_CNT 0x00000000 /* counters */
+#define NV_MSGBOX_CMD_ARG1_ECC_V2_SEL_FBA 0x00000001 /* FB addresses */
+/* Counters */
+#define NV_MSGBOX_CMD_ARG1_ECC_V2_CNT_DEV 13:12
+#define NV_MSGBOX_CMD_ARG1_ECC_V2_CNT_DEV_FB 0x00000000
+#define NV_MSGBOX_CMD_ARG1_ECC_V2_CNT_DEV_GR 0x00000001
+#define NV_MSGBOX_CMD_ARG1_ECC_V2_CNT_FB_SRC 11:10
+#define NV_MSGBOX_CMD_ARG1_ECC_V2_CNT_FB_SRC_LTC 0x00000000
+#define NV_MSGBOX_CMD_ARG1_ECC_V2_CNT_FB_SRC_FB 0x00000001
+#define NV_MSGBOX_CMD_ARG1_ECC_V2_CNT_GR_SRC 11:10
+#define NV_MSGBOX_CMD_ARG1_ECC_V2_CNT_GR_SRC_L1 0x00000000
+#define NV_MSGBOX_CMD_ARG1_ECC_V2_CNT_GR_SRC_RF 0x00000001
+#define NV_MSGBOX_CMD_ARG1_ECC_V2_CNT_TYPE 9:8
+#define NV_MSGBOX_CMD_ARG1_ECC_V2_CNT_TYPE_SBE 0x00000000
+#define NV_MSGBOX_CMD_ARG1_ECC_V2_CNT_TYPE_DBE 0x00000001
+/* FB addresses */
+#define NV_MSGBOX_CMD_ARG1_ECC_V2_FBA_SC 13:13 /* scope */
+#define NV_MSGBOX_CMD_ARG1_ECC_V2_FBA_SC_IND 0x00000000 /* individual addresses */
+#define NV_MSGBOX_CMD_ARG1_ECC_V2_FBA_SC_CUMUL 0x00000001 /* cumulative counters */
+#define NV_MSGBOX_CMD_ARG1_ECC_V2_FBA_IND_FLD 12:12 /* field */
+#define NV_MSGBOX_CMD_ARG1_ECC_V2_FBA_IND_FLD_CTRS 0x00000000 /* counters: sbe, dbe */
+#define NV_MSGBOX_CMD_ARG1_ECC_V2_FBA_IND_FLD_ADDR 0x00000001 /* address value */
+#define NV_MSGBOX_CMD_ARG1_ECC_V2_FBA_IND_INDEX 11:8 /* address array index: 0-13 */
+
+#define NV_MSGBOX_CMD_ARG1_ECC_V3_SEL 15:14
+#define NV_MSGBOX_CMD_ARG1_ECC_V3_SEL_CNT 0x00000000 /* counters */
+#define NV_MSGBOX_CMD_ARG1_ECC_V3_SEL_FBA 0x00000001 /* FB addresses */
+/* Counters */
+#define NV_MSGBOX_CMD_ARG1_ECC_V3_CNT_DEV 13:12
+#define NV_MSGBOX_CMD_ARG1_ECC_V3_CNT_DEV_FB 0x00000000
+#define NV_MSGBOX_CMD_ARG1_ECC_V3_CNT_DEV_GR 0x00000001
+#define NV_MSGBOX_CMD_ARG1_ECC_V3_CNT_FB_SRC 11:10
+#define NV_MSGBOX_CMD_ARG1_ECC_V3_CNT_FB_SRC_LTC 0x00000000
+#define NV_MSGBOX_CMD_ARG1_ECC_V3_CNT_FB_SRC_FB 0x00000001
+#define NV_MSGBOX_CMD_ARG1_ECC_V3_CNT_GR_SRC 11:10
+#define NV_MSGBOX_CMD_ARG1_ECC_V3_CNT_GR_SRC_L1 0x00000000
+#define NV_MSGBOX_CMD_ARG1_ECC_V3_CNT_GR_SRC_RF 0x00000001
+#define NV_MSGBOX_CMD_ARG1_ECC_V3_CNT_GR_SRC_TEX 0x00000002
+#define NV_MSGBOX_CMD_ARG1_ECC_V3_CNT_TYPE 9:8
+#define NV_MSGBOX_CMD_ARG1_ECC_V3_CNT_TYPE_SBE 0x00000000
+#define NV_MSGBOX_CMD_ARG1_ECC_V3_CNT_TYPE_DBE 0x00000001
+/* FB addresses */
+#define NV_MSGBOX_CMD_ARG1_ECC_V3_FBA_SC 13:13 /* scope */
+#define NV_MSGBOX_CMD_ARG1_ECC_V3_FBA_SC_IND 0x00000000 /* individual addresses */
+// These are not present in V3
+//#define NV_MSGBOX_CMD_ARG1_ECC_V3_FBA_SC_CUMUL 0x00000001 /* cumulative counters */
+#define NV_MSGBOX_CMD_ARG1_ECC_V3_FBA_IND_FLD 12:12 /* field */
+#define NV_MSGBOX_CMD_ARG1_ECC_V3_FBA_IND_FLD_CTRS 0x00000000 /* counters: sbe, dbe */
+#define NV_MSGBOX_CMD_ARG1_ECC_V3_FBA_IND_FLD_ADDR 0x00000001 /* address value */
+#define NV_MSGBOX_CMD_ARG1_ECC_V3_FBA_IND_INDEX 11:8 /* address array index: 0-13 */
+
+#define NV_MSGBOX_CMD_ARG1_ECC_V4_SEL 15:14
+#define NV_MSGBOX_CMD_ARG1_ECC_V4_SEL_CNT 0x00000000 /* counters */
+#define NV_MSGBOX_CMD_ARG1_ECC_V4_SEL_FBA 0x00000001 /* FB addresses */
+/* Counters */
+#define NV_MSGBOX_CMD_ARG1_ECC_V4_CNT_DEV 13:12
+#define NV_MSGBOX_CMD_ARG1_ECC_V4_CNT_DEV_FB 0x00000000
+#define NV_MSGBOX_CMD_ARG1_ECC_V4_CNT_DEV_GR 0x00000001
+#define NV_MSGBOX_CMD_ARG1_ECC_V4_CNT_FB_SRC 11:10
+#define NV_MSGBOX_CMD_ARG1_ECC_V4_CNT_FB_SRC_LTC 0x00000000
+#define NV_MSGBOX_CMD_ARG1_ECC_V4_CNT_FB_SRC_FB 0x00000001
+#define NV_MSGBOX_CMD_ARG1_ECC_V4_CNT_GR_SRC 11:10
+#define NV_MSGBOX_CMD_ARG1_ECC_V4_CNT_GR_SRC_SHM 0x00000000
+#define NV_MSGBOX_CMD_ARG1_ECC_V4_CNT_GR_SRC_RF 0x00000001
+#define NV_MSGBOX_CMD_ARG1_ECC_V4_CNT_GR_SRC_TEX 0x00000002
+#define NV_MSGBOX_CMD_ARG1_ECC_V4_CNT_TYPE 9:8
+#define NV_MSGBOX_CMD_ARG1_ECC_V4_CNT_TYPE_SBE 0x00000000
+#define NV_MSGBOX_CMD_ARG1_ECC_V4_CNT_TYPE_DBE 0x00000001
+/* FB addresses */
+#define NV_MSGBOX_CMD_ARG1_ECC_V4_FBA_SC 13:13 /* scope */
+#define NV_MSGBOX_CMD_ARG1_ECC_V4_FBA_SC_IND 0x00000000 /* individual addresses */
+// These are not present in V4
+//#define NV_MSGBOX_CMD_ARG1_ECC_V4_FBA_SC_CUMUL 0x00000001 /* cumulative counters */
+#define NV_MSGBOX_CMD_ARG1_ECC_V4_FBA_IND_FLD 12:12 /* field */
+#define NV_MSGBOX_CMD_ARG1_ECC_V4_FBA_IND_FLD_CTRS 0x00000000 /* counters: sbe, dbe */
+#define NV_MSGBOX_CMD_ARG1_ECC_V4_FBA_IND_FLD_ADDR 0x00000001 /* address value */
+#define NV_MSGBOX_CMD_ARG1_ECC_V4_FBA_IND_INDEX 11:8 /* address array index: 0-13 */
+
+#define NV_MSGBOX_CMD_ARG1_ECC_V5_SEL 15:15
+#define NV_MSGBOX_CMD_ARG1_ECC_V5_SEL_COUNTS 0x00000000 /* address/region counts */
+#define NV_MSGBOX_CMD_ARG1_ECC_V5_SEL_ERR_BUFFER 0x00000001 /* SRAM error buffer */
+
+#define NV_MSGBOX_CMD_ARG1_ECC_V5_COUNTS_INDEX_LO 14:8 /* 7 least significant index bits */
+
+#define NV_MSGBOX_CMD_ARG1_ECC_V5_ERR_BUF_INDEX 11:8 /* buffer entry index */
+
+#define NV_MSGBOX_CMD_ARG1_ACCESS_WP_MODE_ACTION 8:8
+#define NV_MSGBOX_CMD_ARG1_ACCESS_WP_MODE_ACTION_GET 0x00000000
+#define NV_MSGBOX_CMD_ARG1_ACCESS_WP_MODE_ACTION_SET 0x00000001
+
+#define NV_MSGBOX_CMD_ARG1_BUNDLE_REQUEST_COUNT 11:8
+#define NV_MSGBOX_CMD_ARG1_BUNDLE_DISP_RULE_COUNT 15:12
+
+#define NV_MSGBOX_CMD_ARG1_GET_DEM_OLDEST 0x00000000
+#define NV_MSGBOX_CMD_ARG1_GET_DEM_BY_SEQ_NUMBER 0x00000001
+#define NV_MSGBOX_CMD_ARG1_GET_DEM_BY_TIMESTAMP 0x00000002
+
+#define NV_MSGBOX_CMD_ARG1_ECC_V6_ERROR_TYPE 15:8
+#define NV_MSGBOX_CMD_ARG1_ECC_V6_ERROR_TYPE_CORRECTABLE_ERROR 0
+#define NV_MSGBOX_CMD_ARG1_ECC_V6_ERROR_TYPE_UNCORRECTABLE_ERROR 1
+#define NV_MSGBOX_CMD_ARG1_ECC_V6_ERROR_TYPE_ECC_STATE_FLAGS 2
+
+#define NV_MSGBOX_CMD_ARG1_ENERGY_COUNTER_GPU 0x00000000
+#define NV_MSGBOX_CMD_ARG1_ENERGY_COUNTER_MODULE 0x00000003
+
+// Query type of _GET_POWER_HINT_INFO
+#define NV_MSGBOX_CMD_ARG1_GET_POWER_HINT_INFO_CLK 0x00000000
+#define NV_MSGBOX_CMD_ARG1_GET_POWER_HINT_INFO_TEMP 0x00000001
+#define NV_MSGBOX_CMD_ARG1_GET_POWER_HINT_INFO_PROFILES 0x00000002
+#define NV_MSGBOX_CMD_ARG1_GET_POWER_HINT_INFO_NUM \
+ (NV_MSGBOX_CMD_ARG1_GET_POWER_HINT_INFO_PROFILES + 1)
+
+// Arg1 for _GPU_PERFORMANCE_MONITORING
+#define NV_MSGBOX_CMD_ARG1_GPM_ACTION 15:14
+#define NV_MSGBOX_CMD_ARG1_GPM_ACTION_GET_INSTANTANEOUS_METRIC 0x00000000
+#define NV_MSGBOX_CMD_ARG1_GPM_ACTION_GET_SNAPSHOT_METRIC 0x00000001
+#define NV_MSGBOX_CMD_ARG1_GPM_ACTION_CAPTURE_SNAPSHOT 0x00000002
+#define NV_MSGBOX_CMD_ARG1_GPM_ACTION_SET_MULTIPLIER 0x00000003
+
+#define NV_MSGBOX_CMD_ARG1_GPM_METRIC 13:8
+#define NV_MSGBOX_CMD_ARG1_GPM_METRIC_GRAPHICS_ENGINE 0x00000000
+#define NV_MSGBOX_CMD_ARG1_GPM_METRIC_SM_ACTIVITY 0x00000001
+#define NV_MSGBOX_CMD_ARG1_GPM_METRIC_SM_OCCUPANCY 0x00000002
+#define NV_MSGBOX_CMD_ARG1_GPM_METRIC_TENSOR_CORE_ACTIVITY 0x00000003
+#define NV_MSGBOX_CMD_ARG1_GPM_METRIC_DRAM_USAGE 0x00000004
+#define NV_MSGBOX_CMD_ARG1_GPM_METRIC_FP64_ACTIVITY 0x00000005
+#define NV_MSGBOX_CMD_ARG1_GPM_METRIC_FP32_ACTIVITY 0x00000006
+#define NV_MSGBOX_CMD_ARG1_GPM_METRIC_FP16_ACTIVITY 0x00000007
+#define NV_MSGBOX_CMD_ARG1_GPM_METRIC_PCIE_TX_BANDWIDTH 0x00000008
+#define NV_MSGBOX_CMD_ARG1_GPM_METRIC_PCIE_RX_BANDWIDTH 0x00000009
+#define NV_MSGBOX_CMD_ARG1_GPM_METRIC_NVLINK_RAW_TX_BANDWIDTH 0x0000000A
+#define NV_MSGBOX_CMD_ARG1_GPM_METRIC_NVLINK_DATA_TX_BANDWIDTH 0x0000000B
+#define NV_MSGBOX_CMD_ARG1_GPM_METRIC_NVLINK_RAW_RX_BANDWIDTH 0x0000000C
+#define NV_MSGBOX_CMD_ARG1_GPM_METRIC_NVLINK_DATA_RX_BANDWIDTH 0x0000000D
+#define NV_MSGBOX_CMD_ARG1_GPM_METRIC_NVDEC_UTILIZATION 0x0000000E
+#define NV_MSGBOX_CMD_ARG1_GPM_METRIC_NVJPG_UTILIZATION 0x0000000F
+#define NV_MSGBOX_CMD_ARG1_GPM_METRIC_NVOFA_UTILIZATION 0x00000010
+#define NV_MSGBOX_CMD_ARG1_GPM_METRIC_NVLINK_RAW_TX_BW_PER_LINK 0x00000011
+#define NV_MSGBOX_CMD_ARG1_GPM_METRIC_NVLINK_DATA_TX_BW_PER_LINK 0x00000012
+#define NV_MSGBOX_CMD_ARG1_GPM_METRIC_NVLINK_RAW_RX_BW_PER_LINK 0x00000013
+#define NV_MSGBOX_CMD_ARG1_GPM_METRIC_NVLINK_DATA_RX_BW_PER_LINK 0x00000014
+#define NV_MSGBOX_CMD_ARG1_GPM_METRIC_NVDEC_UTIL_PER_INSTANCE 0x00000015
+#define NV_MSGBOX_CMD_ARG1_GPM_METRIC_NVJPG_UTIL_PER_INSTANCE 0x00000016
+#define NV_MSGBOX_CMD_ARG1_GPM_METRIC_INTEGER_UTILIZATION 0x00000017
+#define NV_MSGBOX_CMD_ARG1_GPM_METRIC_DMMA_UTILIZATION 0x00000018
+#define NV_MSGBOX_CMD_ARG1_GPM_METRIC_HMMA_UTILIZATION 0x00000019
+#define NV_MSGBOX_CMD_ARG1_GPM_METRIC_IMMA_UTILIZATION 0x0000001A
+
+#define NV_MSGBOX_CMD_ARG1_DYN_SYS_INFO_DRIVER_VERSION_V1 0x00000000
+
+#define NV_MSGBOX_CMD_ARG2 23:16
+#define NV_MSGBOX_CMD_ARG2_NULL 0x00000000
+
+#define NV_MSGBOX_CMD_ARG2_ECC_V2_FB_PARTITION 23:20
+#define NV_MSGBOX_CMD_ARG2_ECC_V2_FB_SLICE 19:16
+#define NV_MSGBOX_CMD_ARG2_ECC_V2_GR_GPC 23:20
+#define NV_MSGBOX_CMD_ARG2_ECC_V2_GR_TPC 19:16
+
+#define NV_MSGBOX_CMD_ARG2_ECC_V3_FB_PARTITION 23:20
+#define NV_MSGBOX_CMD_ARG2_ECC_V3_FB_SLICE 19:16
+#define NV_MSGBOX_CMD_ARG2_ECC_V3_FB_SUBPARTITION 19:16
+#define NV_MSGBOX_CMD_ARG2_ECC_V3_GR_TEX 23:22
+#define NV_MSGBOX_CMD_ARG2_ECC_V3_GR_GPC 21:19
+#define NV_MSGBOX_CMD_ARG2_ECC_V3_GR_TPC 18:16
+
+#define NV_MSGBOX_CMD_ARG2_ECC_V4_FB_PARTITION 23:20
+#define NV_MSGBOX_CMD_ARG2_ECC_V4_FB_SLICE 19:16
+#define NV_MSGBOX_CMD_ARG2_ECC_V4_FB_SUBPARTITION 19:16
+#define NV_MSGBOX_CMD_ARG2_ECC_V4_GR_TEX 23:22
+#define NV_MSGBOX_CMD_ARG2_ECC_V4_GR_GPC 21:19
+#define NV_MSGBOX_CMD_ARG2_ECC_V4_GR_TPC 18:16
+
+#define NV_MSGBOX_CMD_ARG2_ECC_V5_COUNTS_INDEX_HI 23:21
+#define NV_MSGBOX_CMD_ARG2_ECC_V5_COUNTS_TYPE 18:16
+#define NV_MSGBOX_CMD_ARG2_ECC_V5_COUNTS_TYPE_HDR_META 0x0 /* header and metadata */
+
+#define NV_MSGBOX_CMD_ARG2_ECC_V5_COUNTS_TYPE_ADDR_ADDR 0x1 /* addr: address */
+#define NV_MSGBOX_CMD_ARG2_ECC_V5_COUNTS_TYPE_ADDR_UNCORRECTED_COUNTS 0x2 /* addr: uncorrectedCounts */
+#define NV_MSGBOX_CMD_ARG2_ECC_V5_COUNTS_TYPE_ADDR_CORRECTED_TOTAL 0x3 /* addr: correctedTotal */
+#define NV_MSGBOX_CMD_ARG2_ECC_V5_COUNTS_TYPE_ADDR_CORRECTED_UNIQUE 0x4 /* addr: correctedUnique */
+
+#define NV_MSGBOX_CMD_ARG2_ECC_V5_COUNTS_TYPE_REGN_CORRECTED_TOTAL 0x1 /* region: correctedTotal */
+#define NV_MSGBOX_CMD_ARG2_ECC_V5_COUNTS_TYPE_REGN_CORRECTED_UNIQUE 0x2 /* region: correctedUnique */
+#define NV_MSGBOX_CMD_ARG2_ECC_V5_COUNTS_TYPE_REGN_UNCORRECTED_TOTAL 0x3 /* region: uncorrectedTotal */
+#define NV_MSGBOX_CMD_ARG2_ECC_V5_COUNTS_TYPE_REGN_UNCORRECTED_UNIQUE 0x4 /* region: uncorrectedUnique */
+
+#define NV_MSGBOX_CMD_ARG2_ECC_V5_COUNTS_TYPE_MAX 0x4
+
+#define NV_MSGBOX_CMD_ARG2_ECC_V5_ERR_BUF_TYPE 17:16 /* entry element type */
+#define NV_MSGBOX_CMD_ARG2_ECC_V5_ERR_BUF_TYPE_ERR_TYPE_META 0x0 /* errorType and metadata */
+#define NV_MSGBOX_CMD_ARG2_ECC_V5_ERR_BUF_TYPE_TIME_STAMP 0x1 /* time stamp */
+#define NV_MSGBOX_CMD_ARG2_ECC_V5_ERR_BUF_TYPE_ADDR 0x2 /* address */
+
+#define NV_MSGBOX_CMD_ARG2_ECC_V5_ERR_BUF_TYPE_MAX 0x2
+
+#define NV_MSGBOX_CMD_ARG2_REG_INDEX_SCRATCH_PAGE 0x00000000
+#define NV_MSGBOX_CMD_ARG2_REG_INDEX_EVENTS_PENDING 0x00000001
+#define NV_MSGBOX_CMD_ARG2_REG_INDEX_EVENT_MASK 0x00000002
+#define NV_MSGBOX_CMD_ARG2_REG_INDEX_MAX 0x00000002 /* increase when adding
+ new registers */
+
+#define NV_MSGBOX_CMD_ARG2_NVLINK_INFO_AGGREGATE 0x000000FF
+
+#define NV_MSGBOX_CMD_ARG2_ACCESS_WP_MODE_SET_STATE 23:16
+#define NV_MSGBOX_CMD_ARG2_ACCESS_WP_MODE_SET_STATE_DISABLED 0x0000005A
+#define NV_MSGBOX_CMD_ARG2_ACCESS_WP_MODE_SET_STATE_ENABLED 0x000000A5
+
+#define NV_MSGBOX_CMD_ARG2_GET_CLOCK_FREQ_INFO_GPCCLK 0x00000000
+#define NV_MSGBOX_CMD_ARG2_GET_CLOCK_FREQ_INFO_MEMCLK 0x00000001
+
+#define NV_MSGBOX_CMD_ARG2_ECC_V6_COUNTER_TYPE 23:16
+#define NV_MSGBOX_CMD_ARG2_ECC_V6_COUNTER_TYPE_SRAM 0
+#define NV_MSGBOX_CMD_ARG2_ECC_V6_COUNTER_TYPE_DRAM 1
+
+#define NV_MSGBOX_CMD_ARG2_REMAP_ROW_RAW_CNT_COMBINED 0x00000000
+#define NV_MSGBOX_CMD_ARG2_REMAP_ROW_RAW_CNT_UNCORR 0x00000001
+#define NV_MSGBOX_CMD_ARG2_REMAP_ROW_RAW_CNT_CORR 0x00000002
+
+#define NV_MSGBOX_CMD_ARG2_REMAP_ROWS_STATE_FLAGS_PAGE0 0x00000000
+
+/*!
+ * Arg2 for _GET_PCIE_LINK_INFO
+ * Arg1 == _GET_PCIE_LINK_INFO_PAGE_8
+ * Return TX EQ parameters
+ */
+#define NV_MSGBOX_CMD_ARG2_GET_PCIE_LINK_INFO_PAGE_8_LANE_IDX 3:0
+#define NV_MSGBOX_CMD_ARG2_GET_PCIE_LINK_INFO_PAGE_8_SPEED_SELECT 5:4
+#define NV_MSGBOX_CMD_ARG2_GET_PCIE_LINK_INFO_PAGE_8_SPEED_SELECT_GEN_3 \
+ 0x00000000
+#define NV_MSGBOX_CMD_ARG2_GET_PCIE_LINK_INFO_PAGE_8_SPEED_SELECT_GEN_4 \
+ 0x00000001
+#define NV_MSGBOX_CMD_ARG2_GET_PCIE_LINK_INFO_PAGE_8_SPEED_SELECT_GEN_5 \
+ 0x00000002
+
+/*!
+ * Arg2 for _GET_PCIE_LINK_INFO
+ * Arg1 == _GET_PCIE_LINK_INFO_PAGE_9
+ * Return RX EQ parameters
+ */
+#define NV_MSGBOX_CMD_ARG2_GET_PCIE_LINK_INFO_PAGE_9_LANE_IDX 3:0
+#define NV_MSGBOX_CMD_ARG2_GET_PCIE_LINK_INFO_PAGE_9_SPEED_SELECT 5:4
+#define NV_MSGBOX_CMD_ARG2_GET_PCIE_LINK_INFO_PAGE_9_SPEED_SELECT_GEN_3 \
+ 0x00000000
+#define NV_MSGBOX_CMD_ARG2_GET_PCIE_LINK_INFO_PAGE_9_SPEED_SELECT_GEN_4 \
+ 0x00000001
+#define NV_MSGBOX_CMD_ARG2_GET_PCIE_LINK_INFO_PAGE_9_SPEED_SELECT_GEN_5 \
+ 0x00000002
+
+/*!
+ * Arg2 for _GET_POWER_HINT_INFO
+ * ARG1 == _GET_POWER_HINT_INFO_CLK
+ * Return Min/Max frequency in MHz
+ */
+#define NV_MSGBOX_CMD_ARG2_GET_POWER_HINT_INFO_CLK_GR 0x00000000
+#define NV_MSGBOX_CMD_ARG2_GET_POWER_HINT_INFO_CLK_MEM 0x00000001
+
+/*!
+ * Arg2 for _GET_POWER_HINT_INFO
+ * ARG1 == _GET_POWER_HINT_INFO_PROFILES
+ * Return bits represents which profiles are available
+ */
+#define NV_MSGBOX_CMD_ARG2_GET_POWER_HINT_INFO_PROFILES_PAGE_0 0x00000000
+#define NV_MSGBOX_CMD_ARG2_GET_POWER_HINT_INFO_PROFILES_PAGE_1 0x00000001
+#define NV_MSGBOX_CMD_ARG2_GET_POWER_HINT_INFO_PROFILES_PAGE_2 0x00000002
+#define NV_MSGBOX_CMD_ARG2_GET_POWER_HINT_INFO_PROFILES_PAGE_3 0x00000003
+#define NV_MSGBOX_CMD_ARG2_GET_POWER_HINT_INFO_PROFILES_TOTAL_PAGES \
+ (NV_MSGBOX_CMD_ARG2_GET_POWER_HINT_INFO_PROFILES_PAGE_3 + 1)
+
+// Arg2 for _GPU_PERFORMANCE_MONITORING
+#define NV_MSGBOX_CMD_ARG2_GPM_PARTITION_AGGREGATE 0x000000FF
+#define NV_MSGBOX_CMD_ARG2_GPM_PARTITION_INDEX 21:16
+#define NV_MSGBOX_CMD_ARG2_GPM_CI_METRICS_REQUESTED 23:23
+#define NV_MSGBOX_CMD_ARG2_GPM_CI_METRICS_REQUESTED_YES 0x00000001
+#define NV_MSGBOX_CMD_ARG2_GPM_CI_METRICS_REQUESTED_NO 0x00000000
+
+#define NV_MSGBOX_CMD_ARG2_GPM_MULTIPLIER 23:16
+#define NV_MSGBOX_CMD_ARG2_GPM_MULTIPLIER_1X 0x00000001
+#define NV_MSGBOX_CMD_ARG2_GPM_MULTIPLIER_2X 0x00000002
+#define NV_MSGBOX_CMD_ARG2_GPM_MULTIPLIER_5X 0x00000005
+#define NV_MSGBOX_CMD_ARG2_GPM_MULTIPLIER_10X 0x0000000A
+#define NV_MSGBOX_CMD_ARG2_GPM_MULTIPLIER_100X 0x00000064
+
+
+#define NV_MSGBOX_CMD_STATUS 28:24
+#define NV_MSGBOX_CMD_STATUS_NULL 0x00000000
+#define NV_MSGBOX_CMD_STATUS_ERR_REQUEST 0x00000001
+#define NV_MSGBOX_CMD_STATUS_ERR_OPCODE 0x00000002
+#define NV_MSGBOX_CMD_STATUS_ERR_ARG1 0x00000003
+#define NV_MSGBOX_CMD_STATUS_ERR_ARG2 0x00000004
+#define NV_MSGBOX_CMD_STATUS_ERR_DATA 0x00000005
+#define NV_MSGBOX_CMD_STATUS_ERR_MISC 0x00000006
+#define NV_MSGBOX_CMD_STATUS_ERR_I2C_ACCESS 0x00000007
+#define NV_MSGBOX_CMD_STATUS_ERR_NOT_SUPPORTED 0x00000008
+#define NV_MSGBOX_CMD_STATUS_ERR_NOT_AVAILABLE 0x00000009
+#define NV_MSGBOX_CMD_STATUS_ERR_BUSY 0x0000000a
+#define NV_MSGBOX_CMD_STATUS_ERR_AGAIN 0x0000000b
+#define NV_MSGBOX_CMD_STATUS_ERR_SENSOR_DATA 0x0000000c
+#define NV_MSGBOX_CMD_STATUS_ERR_DISPOSITION 0x0000000d
+#define NV_MSGBOX_CMD_STATUS_PARTIAL_FAILURE 0x0000001b
+#define NV_MSGBOX_CMD_STATUS_ACCEPTED 0x0000001c
+#define NV_MSGBOX_CMD_STATUS_INACTIVE 0x0000001d
+#define NV_MSGBOX_CMD_STATUS_READY 0x0000001e
+#define NV_MSGBOX_CMD_STATUS_SUCCESS 0x0000001f
+
+#define NV_MSGBOX_CMD_RSVD 29:29
+#define NV_MSGBOX_CMD_RSVD_INIT 0x00000000
+
+#define NV_MSGBOX_CMD_COPY_DATA 30:30
+#define NV_MSGBOX_CMD_COPY_DATA_OFF 0x00000000
+#define NV_MSGBOX_CMD_COPY_DATA_ON 0x00000001
+
+#define NV_MSGBOX_CMD_EVENT_PENDING 30:30
+#define NV_MSGBOX_CMD_EVENT_PENDING_OFF 0x00000000
+#define NV_MSGBOX_CMD_EVENT_PENDING_ON 0x00000001
+
+#define NV_MSGBOX_CMD_INTR 31:31
+#define NV_MSGBOX_CMD_INTR_NOT_PENDING 0x00000000
+#define NV_MSGBOX_CMD_INTR_PENDING 0x00000001
+#define NV_MSGBOX_CMD_INTR_CLEAR 0x00000000
+
+/* For individual requests in a bundle */
+
+#define NV_MSGBOX_CMD_ON_BUNDLE_FAILURE 31:31
+#define NV_MSGBOX_CMD_ON_BUNDLE_FAILURE_CONTINUE 0x00000000
+#define NV_MSGBOX_CMD_ON_BUNDLE_FAILURE_STOP 0x00000001
+
+#define NV_MSGBOX_CMD_DATA_COPY 23:0
+#define NV_MSGBOX_CMD_DATA_COPY_INIT 0x00000000
+#define NV_MSGBOX_CMD_EXT_STATUS 23:0
+
+// NV_MSGBOX_CMD_COPY_SIZE_ENCODING used for certain commands to embed size
+// indicators in the output when copy-bit is set in request
+
+#define NV_MSGBOX_CMD_COPY_SIZE_ENCODING_READ_DATA_OUT 0:0
+#define NV_MSGBOX_CMD_COPY_SIZE_ENCODING_READ_DATA_OUT_SET 1
+#define NV_MSGBOX_CMD_COPY_SIZE_ENCODING_READ_DATA_OUT_NOT_SET 0
+
+#define NV_MSGBOX_CMD_COPY_SIZE_ENCODING_READ_EXT_DATA_OUT 1:1
+#define NV_MSGBOX_CMD_COPY_SIZE_ENCODING_READ_EXT_DATA_OUT_SET 1
+#define NV_MSGBOX_CMD_COPY_SIZE_ENCODING_READ_EXT_DATA_OUT_NOT_SET 0
+
+#define NV_MSGBOX_CMD_COPY_SIZE_ENCODING_DATA 23:2
+#define NV_MSGBOX_CMD_COPY_SIZE_ENCODING_DATA_INIT 0x00000000
+
+/* Response to NV_MSGBOX_CMD_ARG1_REMAP_ROWS_HISTOGRAM */
+#define NV_MSGBOX_CMD_REMAP_ROW_HISTOGRAM_NONE_AVAILABILITY 15:0
+
+/* Response to NV_MSGBOX_CMD_ARG1_GET_NVLINK_INFO_THROUGHPUT_* */
+#define NV_MSGBOX_CMD_NVLINK_INFO_THROUGHPUT_GRANULARITY 1:0
+#define NV_MSGBOX_CMD_NVLINK_INFO_THROUGHPUT_GRANULARITY_KIB 0x00000000
+#define NV_MSGBOX_CMD_NVLINK_INFO_THROUGHPUT_GRANULARITY_MIB 0x00000001
+#define NV_MSGBOX_CMD_NVLINK_INFO_THROUGHPUT_GRANULARITY_GIB 0x00000002
+#define NV_MSGBOX_CMD_NVLINK_INFO_THROUGHPUT_GRANULARITY_TIB 0x00000003
+#define NV_MSGBOX_CMD_NVLINK_INFO_THROUGHPUT_NEW_SAMPLE 2:2
+#define NV_MSGBOX_CMD_NVLINK_INFO_THROUGHPUT_NEW_SAMPLE_FALSE 0x00000000
+#define NV_MSGBOX_CMD_NVLINK_INFO_THROUGHPUT_NEW_SAMPLE_TRUE 0x00000001
+#define NV_MSGBOX_CMD_NVLINK_INFO_THROUGHPUT_INVALID_DELTA 3:3
+#define NV_MSGBOX_CMD_NVLINK_INFO_THROUGHPUT_INVALID_DELTA_FALSE 0x00000000
+#define NV_MSGBOX_CMD_NVLINK_INFO_THROUGHPUT_INVALID_DELTA_TRUE 0x00000001
+#define NV_MSGBOX_CMD_NVLINK_INFO_THROUGHPUT_DELTA 23:4
+
+/*
+ * Response to NV_MSGBOX_CMD_ARG1_GET_NVLINK_INFO_TRAINING_ERR_STATE
+ * NV_MSGBOX_CMD_ARG1_GET_NVLINK_INFO_RUNTIME_ERR_STATE
+ */
+#define NV_MSGBOX_CMD_NVLINK_INFO_TRAINING_ERROR_COUNT 11:0
+#define NV_MSGBOX_CMD_NVLINK_INFO_RUNTIME_ERROR_COUNT 23:12
+#define NV_MSGBOX_CMD_NVLINK_INFO_ERROR_COUNT_MAX \
+ DRF_MASK(NV_MSGBOX_CMD_NVLINK_INFO_TRAINING_ERROR_COUNT)
+
+/**
+ * Response to NV_MSGBOX_CMD_ARG1_GET_NVLINK_INFO_AVAILABILITY
+ */
+#define NV_MSGBOX_CMD_NVLINK_INFO_GET_NVLINK_INFO_AVAILABILTY_PAGE_0 0x00000000
+
+/**
+ * This field is populated as response to the following metrics:
+ * - NV_MSGBOX_CMD_ARG1_GPM_METRIC_DRAM_USAGE
+ * - NV_MSGBOX_CMD_ARG1_GPM_METRIC_PCIE_TX_BANDWIDTH
+ * - NV_MSGBOX_CMD_ARG1_GPM_METRIC_PCIE_RX_BANDWIDTH
+ * - NV_MSGBOX_CMD_ARG1_GPM_METRIC_NVLINK_RAW_TX_BANDWIDTH
+ * - NV_MSGBOX_CMD_ARG1_GPM_METRIC_NVLINK_DATA_TX_BANDWIDTH
+ * - NV_MSGBOX_CMD_ARG1_GPM_METRIC_NVLINK_RAW_RX_BANDWIDTH
+ * - NV_MSGBOX_CMD_ARG1_GPM_METRIC_NVLINK_DATA_RX_BANDWIDTH
+ */
+#define NV_MSGBOX_CMD_GPM_DATA_GRANULARITY 2:0
+#define NV_MSGBOX_CMD_GPM_DATA_GRANULARITY_B 0x00000000
+#define NV_MSGBOX_CMD_GPM_DATA_GRANULARITY_KIB 0x00000001
+#define NV_MSGBOX_CMD_GPM_DATA_GRANULARITY_MIB 0x00000002
+#define NV_MSGBOX_CMD_GPM_DATA_GRANULARITY_GIB 0x00000003
+
+/* MSGBOX data, capability dword structure */
+
+#define NV_MSGBOX_DATA_REG 31:0
+#define NV_MSGBOX_DATA_CAP_COUNT 6
+
+#define NV_MSGBOX_DATA_CAP_0 0
+#define NV_MSGBOX_DATA_CAP_0_TEMP_GPU_0 0:0
+#define NV_MSGBOX_DATA_CAP_0_TEMP_GPU_0_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_0_TEMP_GPU_0_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_0_TEMP_NVSWITCH_0 0:0
+#define NV_MSGBOX_DATA_CAP_0_TEMP_NVSWITCH_0_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_0_TEMP_NVSWITCH_0_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_0_TEMP_GPU_1 1:1
+#define NV_MSGBOX_DATA_CAP_0_TEMP_GPU_1_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_0_TEMP_GPU_1_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_0_TEMP_BOARD 4:4
+#define NV_MSGBOX_DATA_CAP_0_TEMP_BOARD_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_0_TEMP_BOARD_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_0_TEMP_MEMORY 5:5
+#define NV_MSGBOX_DATA_CAP_0_TEMP_MEMORY_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_0_TEMP_MEMORY_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_0_TEMP_PWR_SUPPLY 6:6
+#define NV_MSGBOX_DATA_CAP_0_TEMP_PWR_SUPPLY_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_0_TEMP_PWR_SUPPLY_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_0_TEMP_T_LIMIT 7:7
+#define NV_MSGBOX_DATA_CAP_0_TEMP_T_LIMIT_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_0_TEMP_T_LIMIT_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_0_EXT_TEMP_BITS 11:8
+#define NV_MSGBOX_DATA_CAP_0_EXT_TEMP_BITS_ZERO 0x00000000
+#define NV_MSGBOX_DATA_CAP_0_EXT_TEMP_BITS_ADT7473 0x00000002
+#define NV_MSGBOX_DATA_CAP_0_EXT_TEMP_BITS_SFXP11_5 0x00000005
+#define NV_MSGBOX_DATA_CAP_0_EXT_TEMP_BITS_SFXP24_8 0x00000008
+#define NV_MSGBOX_DATA_CAP_0_GET_ENERGY_COUNTER_MODULE 12:12
+#define NV_MSGBOX_DATA_CAP_0_GET_ENERGY_COUNTER_MODULE_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_0_GET_ENERGY_COUNTER_MODULE_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_0_MODULE_LIMIT_CONTROL_GET 13:13
+#define NV_MSGBOX_DATA_CAP_0_MODULE_LIMIT_CONTROL_GET_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_0_MODULE_LIMIT_CONTROL_GET_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_0_MODULE_LIMIT_CONTROL_SET 14:14
+#define NV_MSGBOX_DATA_CAP_0_MODULE_LIMIT_CONTROL_SET_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_0_MODULE_LIMIT_CONTROL_SET_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_0_MODULE_LIMIT_INFO_GET 15:15
+#define NV_MSGBOX_DATA_CAP_0_MODULE_LIMIT_INFO_GET_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_0_MODULE_LIMIT_INFO_GET_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_0_POWER_TOTAL 16:16
+#define NV_MSGBOX_DATA_CAP_0_POWER_TOTAL_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_0_POWER_TOTAL_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_0_GPU_PCONTROL 17:17
+#define NV_MSGBOX_DATA_CAP_0_GPU_PCONTROL_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_0_GPU_PCONTROL_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_0_GPU_SYSCONTROL 18:18
+#define NV_MSGBOX_DATA_CAP_0_GPU_SYSCONTROL_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_0_GPU_SYSCONTROL_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_0_THERMP_BITS 28:19 // Adjust when adding new bits
+#define NV_MSGBOX_DATA_CAP_0_THERMP_TEMP_TLIMIT_BITS 23:19 // Adjust when adding new bits
+#define NV_MSGBOX_DATA_CAP_0_THERMP_TEMP_BITS 28:24 // Adjust when adding new bits
+#define NV_MSGBOX_DATA_CAP_0_THERMP_TEMP_ACOUSTIC_TLIMIT 19:19
+#define NV_MSGBOX_DATA_CAP_0_THERMP_TEMP_ACOUSTIC_TLIMIT_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_0_THERMP_TEMP_ACOUSTIC_TLIMIT_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_0_THERMP_TEMP_SLOWDN_TLIMIT 20:20
+#define NV_MSGBOX_DATA_CAP_0_THERMP_TEMP_SLOWDN_TLIMIT_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_0_THERMP_TEMP_SLOWDN_TLIMIT_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_0_THERMP_TEMP_SHUTDN_TLIMIT 21:21
+#define NV_MSGBOX_DATA_CAP_0_THERMP_TEMP_SHUTDN_TLIMIT_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_0_THERMP_TEMP_SHUTDN_TLIMIT_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_0_THERMP_TEMP_MEMORY_TLIMIT 22:22
+#define NV_MSGBOX_DATA_CAP_0_THERMP_TEMP_MEMORY_TLIMIT_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_0_THERMP_TEMP_MEMORY_TLIMIT_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_0_THERMP_TEMP_GPU_SW_SLOWDOWN_TLIMIT 23:23
+#define NV_MSGBOX_DATA_CAP_0_THERMP_TEMP_GPU_SW_SLOWDOWN_TLIMIT_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_0_THERMP_TEMP_GPU_SW_SLOWDOWN_TLIMIT_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_0_THERMP_TEMP_ACOUSTIC 24:24
+#define NV_MSGBOX_DATA_CAP_0_THERMP_TEMP_ACOUSTIC_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_0_THERMP_TEMP_ACOUSTIC_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_0_THERMP_TEMP_SLOWDN 25:25
+#define NV_MSGBOX_DATA_CAP_0_THERMP_TEMP_SLOWDN_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_0_THERMP_TEMP_SLOWDN_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_0_THERMP_TEMP_SHUTDN 26:26
+#define NV_MSGBOX_DATA_CAP_0_THERMP_TEMP_SHUTDN_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_0_THERMP_TEMP_SHUTDN_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_0_THERMP_TEMP_MEMORY 27:27
+#define NV_MSGBOX_DATA_CAP_0_THERMP_TEMP_MEMORY_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_0_THERMP_TEMP_MEMORY_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_0_THERMP_TEMP_GPU_SW_SLOWDOWN 28:28
+#define NV_MSGBOX_DATA_CAP_0_THERMP_TEMP_GPU_SW_SLOWDOWN_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_0_THERMP_TEMP_GPU_SW_SLOWDOWN_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_0_GET_FABRIC_STATE_FLAGS 29:29
+#define NV_MSGBOX_DATA_CAP_0_GET_FABRIC_STATE_FLAGS_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_0_GET_FABRIC_STATE_FLAGS_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_0_POWER_FB 30:30
+#define NV_MSGBOX_DATA_CAP_0_POWER_FB_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_0_POWER_FB_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_0_POWER_MODULE 31:31
+#define NV_MSGBOX_DATA_CAP_0_POWER_MODULE_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_0_POWER_MODULE_AVAILABLE 0x00000001
+
+#define NV_MSGBOX_DATA_CAP_1 1
+#define NV_MSGBOX_DATA_CAP_1_BOARD_PART_NUM_V1 0:0
+#define NV_MSGBOX_DATA_CAP_1_BOARD_PART_NUM_V1_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_1_BOARD_PART_NUM_V1_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_1_OEM_INFO_V1 1:1
+#define NV_MSGBOX_DATA_CAP_1_OEM_INFO_V1_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_1_OEM_INFO_V1_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_1_SERIAL_NUM_V1 2:2
+#define NV_MSGBOX_DATA_CAP_1_SERIAL_NUM_V1_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_1_SERIAL_NUM_V1_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_1_MARKETING_NAME_V1 3:3
+#define NV_MSGBOX_DATA_CAP_1_MARKETING_NAME_V1_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_1_MARKETING_NAME_V1_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_1_GPU_PART_NUM_V1 4:4
+#define NV_MSGBOX_DATA_CAP_1_GPU_PART_NUM_V1_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_1_GPU_PART_NUM_V1_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_1_MEMORY_VENDOR_V1 5:5
+#define NV_MSGBOX_DATA_CAP_1_MEMORY_VENDOR_V1_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_1_MEMORY_VENDOR_V1_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_1_MEMORY_PART_NUM_V1 6:6
+#define NV_MSGBOX_DATA_CAP_1_MEMORY_PART_NUM_V1_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_1_MEMORY_PART_NUM_V1_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_1_BUILD_DATE_V1 7:7
+#define NV_MSGBOX_DATA_CAP_1_BUILD_DATE_V1_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_1_BUILD_DATE_V1_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_1_FIRMWARE_VER_V1 8:8
+#define NV_MSGBOX_DATA_CAP_1_FIRMWARE_VER_V1_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_1_FIRMWARE_VER_V1_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_1_VENDOR_ID_V1 9:9
+#define NV_MSGBOX_DATA_CAP_1_VENDOR_ID_V1_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_1_VENDOR_ID_V1_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_1_DEV_ID_V1 10:10
+#define NV_MSGBOX_DATA_CAP_1_DEV_ID_V1_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_1_DEV_ID_V1_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_1_SUB_VENDOR_ID_V1 11:11
+#define NV_MSGBOX_DATA_CAP_1_SUB_VENDOR_ID_V1_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_1_SUB_VENDOR_ID_V1_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_1_SUB_ID_V1 12:12
+#define NV_MSGBOX_DATA_CAP_1_SUB_ID_V1_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_1_SUB_ID_V1_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_1_GPU_GUID_V1 13:13
+#define NV_MSGBOX_DATA_CAP_1_GPU_GUID_V1_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_1_GPU_GUID_V1_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_1_INFOROM_VER_V1 14:14
+#define NV_MSGBOX_DATA_CAP_1_INFOROM_VER_V1_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_1_INFOROM_VER_V1_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_1_MODULE_POWER_LIMIT_V1 15:15
+#define NV_MSGBOX_DATA_CAP_1_MODULE_POWER_LIMIT_V1_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_1_MODULE_POWER_LIMIT_V1_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_1_ECC_V1 16:16
+#define NV_MSGBOX_DATA_CAP_1_ECC_V1_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_1_ECC_V1_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_1_ECC_V2 17:17
+#define NV_MSGBOX_DATA_CAP_1_ECC_V2_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_1_ECC_V2_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_1_ECC_V3 18:18
+#define NV_MSGBOX_DATA_CAP_1_ECC_V3_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_1_ECC_V3_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_1_RET_PG_CNT 19:19
+#define NV_MSGBOX_DATA_CAP_1_RET_PG_CNT_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_1_RET_PG_CNT_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_1_ECC_V4 20:20
+#define NV_MSGBOX_DATA_CAP_1_ECC_V4_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_1_ECC_V4_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_1_ECC_V5 21:21
+#define NV_MSGBOX_DATA_CAP_1_ECC_V5_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_1_ECC_V5_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_1_ACCESS_WP_MODE 22:22
+#define NV_MSGBOX_DATA_CAP_1_ACCESS_WP_MODE_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_1_ACCESS_WP_MODE_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_1_GET_ECC_ENABLED_STATE 23:23
+#define NV_MSGBOX_DATA_CAP_1_GET_ECC_ENABLED_STATE_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_1_GET_ECC_ENABLED_STATE_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_1_GET_GPU_RESET_REQUIRED 24:24
+#define NV_MSGBOX_DATA_CAP_1_GET_GPU_RESET_REQUIRED_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_1_GET_GPU_RESET_REQUIRED_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_1_GPU_UTIL_COUNTERS 25:25
+#define NV_MSGBOX_DATA_CAP_1_GPU_UTIL_COUNTERS_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_1_GPU_UTIL_COUNTERS_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_1_NVLINK_INFO_STATE_V1 26:26
+#define NV_MSGBOX_DATA_CAP_1_NVLINK_INFO_STATE_V1_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_1_NVLINK_INFO_STATE_V1_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_1_NVLINK_ERROR_COUNTERS 27:27
+#define NV_MSGBOX_DATA_CAP_1_NVLINK_ERROR_COUNTERS_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_1_NVLINK_ERROR_COUNTERS_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_1_CLOCK_FREQ_INFO 28:28
+#define NV_MSGBOX_DATA_CAP_1_CLOCK_FREQ_INFO_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_1_CLOCK_FREQ_INFO_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_1_GET_MIG_ENABLED_STATE 29:29
+#define NV_MSGBOX_DATA_CAP_1_GET_MIG_ENABLED_STATE_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_1_GET_MIG_ENABLED_STATE_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_1_ECC_V6 30:30
+#define NV_MSGBOX_DATA_CAP_1_ECC_V6_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_1_ECC_V6_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_1_CLOCK_THROTTLE_REASON 31:31
+#define NV_MSGBOX_DATA_CAP_1_CLOCK_THROTTLE_REASON_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_1_CLOCK_THROTTLE_REASON_AVAILABLE 0x00000001
+
+#define NV_MSGBOX_DATA_CAP_2 2
+#define NV_MSGBOX_DATA_CAP_2_GPU_DRIVER 0:0
+#define NV_MSGBOX_DATA_CAP_2_GPU_DRIVER_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_2_GPU_DRIVER_NOT_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_2_NVSWITCH_DRIVER 0:0
+#define NV_MSGBOX_DATA_CAP_2_NVSWITCH_DRIVER_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_2_NVSWITCH_DRIVER_NOT_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_2_GPU_REQUEST 1:1
+#define NV_MSGBOX_DATA_CAP_2_GPU_REQUEST_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_2_GPU_REQUEST_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_2_NUM_SCRATCH_BANKS 4:2
+#define NV_MSGBOX_DATA_CAP_2_NUM_SCRATCH_BANKS_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_2_FAN_V1_CONTROL 5:5
+#define NV_MSGBOX_DATA_CAP_2_FAN_V1_CONTROL_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_2_FAN_V1_CONTROL_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_2_PRODUCT_LENGTH_V1 6:6
+#define NV_MSGBOX_DATA_CAP_2_PRODUCT_LENGTH_V1_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_2_PRODUCT_LENGTH_V1_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_2_PRODUCT_WIDTH_V1 7:7
+#define NV_MSGBOX_DATA_CAP_2_PRODUCT_WIDTH_V1_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_2_PRODUCT_WIDTH_V1_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_2_PRODUCT_HEIGHT_V1 8:8
+#define NV_MSGBOX_DATA_CAP_2_PRODUCT_HEIGHT_V1_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_2_PRODUCT_HEIGHT_V1_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_2_PCIE_SPEED_V1 9:9
+#define NV_MSGBOX_DATA_CAP_2_PCIE_SPEED_V1_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_2_PCIE_SPEED_V1_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_2_PCIE_WIDTH_V1 10:10
+#define NV_MSGBOX_DATA_CAP_2_PCIE_WIDTH_V1_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_2_PCIE_WIDTH_V1_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_2_TGP_LIMIT_V1 11:11
+#define NV_MSGBOX_DATA_CAP_2_TGP_LIMIT_V1_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_2_TGP_LIMIT_V1_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_2_SCRATCH_PAGE_SIZE 12:12
+#define NV_MSGBOX_DATA_CAP_2_SCRATCH_PAGE_SIZE_1024B 0x00000000
+#define NV_MSGBOX_DATA_CAP_2_SCRATCH_PAGE_SIZE_256B 0x00000001
+#define NV_MSGBOX_DATA_CAP_2_REMAP_ROW_STATS 13:13
+#define NV_MSGBOX_DATA_CAP_2_REMAP_ROW_STATS_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_2_REMAP_ROW_STATS_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_2_GET_PCIE_LINK_INFO 14:14
+#define NV_MSGBOX_DATA_CAP_2_GET_PCIE_LINK_INFO_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_2_GET_PCIE_LINK_INFO_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_2_GET_GPU_DRAIN_AND_RESET_RECOMMENDED 15:15
+#define NV_MSGBOX_DATA_CAP_2_GET_GPU_DRAIN_AND_RESET_RECOMMENDED_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_2_GET_GPU_DRAIN_AND_RESET_RECOMMENDED_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_2_NVLINK_INFO_THROUGHPUT 16:16
+#define NV_MSGBOX_DATA_CAP_2_NVLINK_INFO_THROUGHPUT_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_2_NVLINK_INFO_THROUGHPUT_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_2_NVLINK_INFO_LINK_STATE_V2 17:17
+#define NV_MSGBOX_DATA_CAP_2_NVLINK_INFO_LINK_STATE_V2_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_2_NVLINK_INFO_LINK_STATE_V2_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_2_NVLINK_INFO_SUBLINK_WIDTH 18:18
+#define NV_MSGBOX_DATA_CAP_2_NVLINK_INFO_SUBLINK_WIDTH_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_2_NVLINK_INFO_SUBLINK_WIDTH_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_2_GET_ENERGY_COUNTER 19:19
+#define NV_MSGBOX_DATA_CAP_2_GET_ENERGY_COUNTER_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_2_GET_ENERGY_COUNTER_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_2_REMAP_ROW_PENDING 20:20
+#define NV_MSGBOX_DATA_CAP_2_REMAP_ROW_PENDING_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_2_REMAP_ROW_PENDING_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_2_REMAP_ROW_HISTOGRAM 21:21
+#define NV_MSGBOX_DATA_CAP_2_REMAP_ROW_HISTOGRAM_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_2_REMAP_ROW_HISTOGRAM_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_2_NVLINK_INFO_TRAINING_ERROR_STATE 22:22
+#define NV_MSGBOX_DATA_CAP_2_NVLINK_INFO_TRAINING_ERROR_STATE_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_2_NVLINK_INFO_TRAINING_ERROR_STATE_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_2_NVLINK_INFO_RUNTIME_ERROR_STATE 23:23
+#define NV_MSGBOX_DATA_CAP_2_NVLINK_INFO_RUNTIME_ERROR_STATE_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_2_NVLINK_INFO_RUNTIME_ERROR_STATE_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_2_GET_PCIE_LINK_TARGET_SPEED 25:25
+#define NV_MSGBOX_DATA_CAP_2_GET_PCIE_LINK_TARGET_SPEED_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_2_GET_PCIE_LINK_TARGET_SPEED_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_2_CURRENT_PSTATE 26:26
+#define NV_MSGBOX_DATA_CAP_2_CURRENT_PSTATE_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_2_CURRENT_PSTATE_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_2_NVLINK_INFO_AVAILABILITY 27:27
+#define NV_MSGBOX_DATA_CAP_2_NVLINK_INFO_AVAILABILITY_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_2_NVLINK_INFO_AVAILABILITY_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_2_FRU_PART_NUMBER_V1 31:31
+#define NV_MSGBOX_DATA_CAP_2_FRU_PART_NUMBER_V1_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_2_FRU_PART_NUMBER_V1_AVAILABLE 0x00000001
+
+#define NV_MSGBOX_DATA_CAP_4 4
+#define NV_MSGBOX_DATA_CAP_4_HW_VIOLATION_TIME 0:0
+#define NV_MSGBOX_DATA_CAP_4_HW_VIOLATION_TIME_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_4_HW_VIOLATION_TIME_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_4_SW_VIOLATION_TIME 1:1
+#define NV_MSGBOX_DATA_CAP_4_SW_VIOLATION_TIME_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_4_SW_VIOLATION_TIME_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_4_SW_POWER_VIOLATION_TIME 2:2
+#define NV_MSGBOX_DATA_CAP_4_SW_POWER_VIOLATION_TIME_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_4_SW_POWER_VIOLATION_TIME_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_4_SW_THERMAL_VIOLATION_TIME 3:3
+#define NV_MSGBOX_DATA_CAP_4_SW_THERMAL_VIOLATION_TIME_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_4_SW_THERMAL_VIOLATION_TIME_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_4_UTILIZATION_RATE 4:4
+#define NV_MSGBOX_DATA_CAP_4_UTILIZATION_RATE_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_4_UTILIZATION_RATE_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_4_GET_DRIVER_EVENT_MSG 5:5
+#define NV_MSGBOX_DATA_CAP_4_GET_DRIVER_EVENT_MSG_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_4_GET_DRIVER_EVENT_MSG_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_4_REQUEST_BUNDLING 6:6
+#define NV_MSGBOX_DATA_CAP_4_REQUEST_BUNDLING_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_4_REQUEST_BUNDLING_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_4_SET_DEVICE_DISABLE 7:7
+#define NV_MSGBOX_DATA_CAP_4_SET_DEVICE_DISABLE_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_4_SET_DEVICE_DISABLE_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_4_SET_ECC_MODE 8:8
+#define NV_MSGBOX_DATA_CAP_4_SET_ECC_MODE_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_4_SET_ECC_MODE_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_4_SET_MIG_MODE 10:10
+#define NV_MSGBOX_DATA_CAP_4_SET_MIG_MODE_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_4_SET_MIG_MODE_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_4_FAN_CURVE_POINTS_GET_SET 11:11
+#define NV_MSGBOX_DATA_CAP_4_FAN_CURVE_POINTS_GET_SET_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_4_FAN_CURVE_POINTS_GET_SET_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_4_POWER_HINT 22:22
+#define NV_MSGBOX_DATA_CAP_4_POWER_HINT_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_4_POWER_HINT_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_4_DRIVER_VERSION_V1 23:23
+#define NV_MSGBOX_DATA_CAP_4_DRIVER_VERSION_V1_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_4_DRIVER_VERSION_V1_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_4_GPU_PERFORMANCE_MONITORING 24:24
+#define NV_MSGBOX_DATA_CAP_4_GPU_PERFORMANCE_MONITORING_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_4_GPU_PERFORMANCE_MONITORING_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_4_DEM_BY_SEQNUM_TIMESTAMP 26:26
+#define NV_MSGBOX_DATA_CAP_4_DEM_BY_SEQNUM_TIMESTAMP_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_4_DEM_BY_SEQNUM_TIMESTAMP_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_4_CONFIGURE_PROGRAMMABLE_EDPP 30:30
+#define NV_MSGBOX_DATA_CAP_4_CONFIGURE_PROGRAMMABLE_EDPP_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_4_CONFIGURE_PROGRAMMABLE_EDPP_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_CAP_4_MAX_DRAM_CAPACITY_V1 31:31
+#define NV_MSGBOX_DATA_CAP_4_MAX_DRAM_CAPACITY_V1_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_4_MAX_DRAM_CAPACITY_V1_AVAILABLE 0x00000001
+
+#define NV_MSGBOX_DATA_CAP_5 5
+#define NV_MSGBOX_DATA_CAP_5_MEMORY_CAPACITY_UTILIZATION 6:6
+#define NV_MSGBOX_DATA_CAP_5_MEMORY_CAPACITY_UTILIZATION_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_5_MEMORY_CAPACITY_UTILIZATION_AVAILABLE 0x00000001
+
+#define NV_MSGBOX_DATA_CAP_5_SRAM_ERROR_THRESHOLD_EXCEEDED 9:9
+#define NV_MSGBOX_DATA_CAP_5_SRAM_ERROR_THRESHOLD_EXCEEDED_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_CAP_5_SRAM_ERROR_THRESHOLD_EXCEEDED_AVAILABLE 0x00000001
+
+/* ECC counters */
+#define NV_MSGBOX_DATA_ECC_CNT_16BIT_DBE 31:16
+#define NV_MSGBOX_DATA_ECC_CNT_16BIT_SBE 16:0
+#define NV_MSGBOX_DATA_ECC_CNT_8BIT_DBE 23:16
+#define NV_MSGBOX_DATA_ECC_CNT_8BIT_SBE 7:0
+
+#define NV_MSGBOX_DATA_ECC_V5_COUNT_HEADER 7:0
+
+#define NV_MSGBOX_DATA_ECC_V5_COUNT_HDR_ID 1:0
+#define NV_MSGBOX_DATA_ECC_V5_COUNT_HDR_ID_INVAL 0
+#define NV_MSGBOX_DATA_ECC_V5_COUNT_HDR_ID_ADDR 1
+#define NV_MSGBOX_DATA_ECC_V5_COUNT_HDR_ID_REGN 2
+
+#define NV_MSGBOX_DATA_ECC_V5_COUNT_METADATA 31:16
+
+#define NV_MSGBOX_DATA_ECC_V5_ERR_BUF_ERR_TYPE 7:0
+
+#define NV_MSGBOX_DATA_ECC_V5_ERR_BUF_ERR_TYPE_ID 0:0
+#define NV_MSGBOX_DATA_ECC_V5_ERR_BUF_ERR_TYPE_ID_UNCORR 0
+#define NV_MSGBOX_DATA_ECC_V5_ERR_BUF_ERR_TYPE_ID_CORR 1
+
+#define NV_MSGBOX_DATA_ECC_V5_ERR_BUF_METADATA 31:16
+
+#define NV_MSGBOX_DATA_ECC_V5_METADATA_STRUCT_ID 21:16
+#define NV_MSGBOX_DATA_ECC_V5_METADATA_STRUCT_ID_LRF 0
+#define NV_MSGBOX_DATA_ECC_V5_METADATA_STRUCT_ID_L1DATA 1
+#define NV_MSGBOX_DATA_ECC_V5_METADATA_STRUCT_ID_L1TAG 2
+#define NV_MSGBOX_DATA_ECC_V5_METADATA_STRUCT_ID_CBU 3
+#define NV_MSGBOX_DATA_ECC_V5_METADATA_STRUCT_ID_LTC 4
+#define NV_MSGBOX_DATA_ECC_V5_METADATA_STRUCT_ID_DRAM 5
+
+#define NV_MSGBOX_DATA_ECC_V5_METADATA_LOCATION_ID 26:22
+#define NV_MSGBOX_DATA_ECC_V5_METADATA_SUBLOCATION_ID 31:27
+
+/* ECC state flags */
+#define NV_MSGBOX_DATA_ECC_V6_STATE_FLAGS 31:0
+
+#define NV_MSGBOX_DATA_ECC_V6_STATE_FLAGS_SRAM_ERROR_THRESHOLD_EXCEEDED 0:0
+#define NV_MSGBOX_DATA_ECC_V6_STATE_FLAGS_SRAM_ERROR_THRESHOLD_EXCEEDED_FALSE 0
+#define NV_MSGBOX_DATA_ECC_V6_STATE_FLAGS_SRAM_ERROR_THRESHOLD_EXCEEDED_TRUE 1
+
+/* NV_MSGBOX_CMD_OPCODE_SCRATCH_COPY src offset argument */
+#define NV_MSGBOX_DATA_COPY_SRC_OFFSET 7:0
+
+/* NV_MSGBOX_CMD_ARG2_REG_INDEX_SCRATCH_PAGE register layout */
+#define NV_MSGBOX_DATA_SCRATCH_PAGE_DST 7:0
+#define NV_MSGBOX_DATA_SCRATCH_PAGE_SRC 15:8
+
+/* Async request status codes returned in the data register */
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS 7:0
+
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_SUCCESS 0x00000000
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_CARD_NOT_PRESENT 0x00000001
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_DUAL_LINK_INUSE 0x00000002
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_GENERIC 0x00000003
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_GPU_NOT_FULL_POWER 0x00000004
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_IN_USE 0x00000005
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_INSUFFICIENT_RESOURCES 0x00000006
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_INVALID_ACCESS_TYPE 0x00000007
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_INVALID_ARGUMENT 0x00000008
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_INVALID_BASE 0x00000009
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_INVALID_CHANNEL 0x0000000A
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_INVALID_CLASS 0x0000000B
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_INVALID_CLIENT 0x0000000C
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_INVALID_COMMAND 0x0000000D
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_INVALID_DATA 0x0000000E
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_INVALID_DEVICE 0x0000000F
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_INVALID_DMA_SPECIFIER 0x00000010
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_INVALID_EVENT 0x00000011
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_INVALID_FLAGS 0x00000012
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_INVALID_FUNCTION 0x00000013
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_INVALID_HEAP 0x00000014
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_INVALID_INDEX 0x00000015
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_INVALID_LIMIT 0x00000016
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_INVALID_METHOD 0x00000017
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_INVALID_OBJECT_BUFFER 0x00000018
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_INVALID_OBJECT_ERROR 0x00000019
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_INVALID_OBJECT_HANDLE 0x0000001A
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_INVALID_OBJECT_NEW 0x0000001B
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_INVALID_OBJECT_OLD 0x0000001C
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_INVALID_OBJECT_PARENT 0x0000001D
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_INVALID_OFFSET 0x0000001E
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_INVALID_OWNER 0x0000001F
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_INVALID_PARAM_STRUCT 0x00000020
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_INVALID_PARAMETER 0x00000021
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_INVALID_POINTER 0x00000022
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_INVALID_REGISTRY_KEY 0x00000023
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_INVALID_STATE 0x00000024
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_INVALID_STRING_LENGTH 0x00000025
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_INVALID_XLATE 0x00000026
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_IRQ_NOT_FIRING 0x00000027
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_MULTIPLE_MEMORY_TYPES 0x00000028
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_NOT_SUPPORTED 0x00000029
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_OPERATING_SYSTEM 0x0000002A
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_PROTECTION_FAULT 0x0000002B
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_TIMEOUT 0x0000002C
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_TOO_MANY_PRIMARIES 0x0000002D
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_IRQ_EDGE_TRIGGERED 0x0000002E
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_INVALID_OPERATION 0x0000002F
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_NOT_COMPATIBLE 0x00000030
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_MORE_PROCESSING_REQUIRED 0x00000031
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_INSUFFICIENT_PERMISSIONS 0x00000032
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_TIMEOUT_RETRY 0x00000033
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_NOT_READY 0x00000034
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_GPU_IS_LOST 0x00000035
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_IN_FULLCHIP_RESET 0x00000036
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_INVALID_LOCK_STATE 0x00000037
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_INVALID_ADDRESS 0x00000038
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_INVALID_IRQ_LEVEL 0x00000039
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_MEMORY_TRAINING_FAILED 0x00000040
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_BUSY_RETRY 0x00000041
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_INSUFFICIENT_POWER 0x00000042
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_OBJECT_NOT_FOUND 0x00000043
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_BUFFER_TOO_SMALL 0x00000044
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_RESET_REQUIRED 0x00000045
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_PRIV_SEC_VIOLATION 0x00000046
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_DEFERRED 0x00000047
+#define NV_MSGBOX_DATA_ASYNC_REQ_STATUS_ERROR_FREQ_NOT_SUPPORTED 0x00000048
+
+/* Response to NV_MSGBOX_CMD_OPCODE_GET_POWER_CONNECTOR_STATE */
+#define NV_MSGBOX_DATA_POWER_CONNECTED 0:0
+#define NV_MSGBOX_DATA_POWER_CONNECTED_SUFFICIENT 0x00000000
+#define NV_MSGBOX_DATA_POWER_CONNECTED_INSUFFICIENT 0x00000001
+
+/* Response to NV_MSGBOX_CMD_OPCODE_GET_PAGE_RETIREMENT_STATS */
+#define NV_MSGBOX_DATA_RETIRED_PAGES_CNT_SBE 7:0
+#define NV_MSGBOX_DATA_RETIRED_PAGES_CNT_DBE 15:8
+
+/*
+ * Response to
+ * NV_MSGBOX_CMD_ARG1_GET_MISC_ECC_ENABLED_STATE
+ * NV_MSGBOX_CMD_ARG1_GET_MISC_GPU_FLAGS_PAGE_0
+ */
+#define NV_MSGBOX_DATA_ECC_ENABLED_STATE_SUPPORTED 0:0
+#define NV_MSGBOX_DATA_ECC_ENABLED_STATE_SUPPORTED_OFF 0x00000000
+#define NV_MSGBOX_DATA_ECC_ENABLED_STATE_SUPPORTED_ON 0x00000001
+#define NV_MSGBOX_DATA_ECC_ENABLED_STATE_CURRENT 1:1
+#define NV_MSGBOX_DATA_ECC_ENABLED_STATE_CURRENT_OFF 0x00000000
+#define NV_MSGBOX_DATA_ECC_ENABLED_STATE_CURRENT_ON 0x00000001
+#define NV_MSGBOX_DATA_ECC_ENABLED_STATE_PENDING 2:2
+#define NV_MSGBOX_DATA_ECC_ENABLED_STATE_PENDING_OFF 0x00000000
+#define NV_MSGBOX_DATA_ECC_ENABLED_STATE_PENDING_ON 0x00000001
+
+/* Response to NV_MSGBOX_CMD_ARG1_GET_MISC_GPU_FLAGS_PAGE_0 */
+#define NV_MSGBOX_DATA_MIG_ENABLED_STATE_SUPPORTED 3:3
+#define NV_MSGBOX_DATA_MIG_ENABLED_STATE_SUPPORTED_OFF 0x00000000
+#define NV_MSGBOX_DATA_MIG_ENABLED_STATE_SUPPORTED_ON 0x00000001
+#define NV_MSGBOX_DATA_MIG_ENABLED_STATE_CURRENT 4:4
+#define NV_MSGBOX_DATA_MIG_ENABLED_STATE_CURRENT_OFF 0x00000000
+#define NV_MSGBOX_DATA_MIG_ENABLED_STATE_CURRENT_ON 0x00000001
+#define NV_MSGBOX_DATA_MIG_ENABLED_STATE_PENDING 5:5
+#define NV_MSGBOX_DATA_MIG_ENABLED_STATE_PENDING_OFF 0x00000000
+#define NV_MSGBOX_DATA_MIG_ENABLED_STATE_PENDING_ON 0x00000001
+
+/* Response to NV_MSGBOX_CMD_ARG1_GET_MISC_DEVICE_FLAGS_PAGE_0 */
+#define NV_MSGBOX_DATA_DEVICE_DISABLE_STATE_DRIVER_STATUS 6:6
+#define NV_MSGBOX_DATA_DEVICE_DISABLE_STATE_DRIVER_STATUS_NOT_RUNNING 0x00000000
+#define NV_MSGBOX_DATA_DEVICE_DISABLE_STATE_DRIVER_STATUS_RUNNING 0x00000001
+#define NV_MSGBOX_DATA_DEVICE_DISABLE_STATE_DEVICE_STATUS 7:7
+#define NV_MSGBOX_DATA_DEVICE_DISABLE_STATE_DEVICE_STATUS_ENABLED 0x00000000
+#define NV_MSGBOX_DATA_DEVICE_DISABLE_STATE_DEVICE_STATUS_DISABLED 0x00000001
+#define NV_MSGBOX_DATA_DEVICE_DISABLE_STATE_FABRIC_MANAGER_STATUS 10:8
+#define NV_MSGBOX_DATA_DEVICE_DISABLE_STATE_FABRIC_MANAGER_STATUS_NOT_RUNNING 0x00000000
+#define NV_MSGBOX_DATA_DEVICE_DISABLE_STATE_FABRIC_MANAGER_STATUS_RUNNING 0x00000001
+#define NV_MSGBOX_DATA_DEVICE_DISABLE_STATE_FABRIC_MANAGER_STATUS_TIMEOUT 0x00000002
+#define NV_MSGBOX_DATA_DEVICE_DISABLE_STATE_FABRIC_MANAGER_STATUS_ERROR 0x00000003
+#define NV_MSGBOX_DATA_DEVICE_DISABLE_STATE_DISABLE_SOURCE 13:11
+#define NV_MSGBOX_DATA_DEVICE_DISABLE_STATE_DISABLE_SOURCE_NONE 0x00000000
+#define NV_MSGBOX_DATA_DEVICE_DISABLE_STATE_DISABLE_SOURCE_LOCAL_DEVICE 0x00000001
+#define NV_MSGBOX_DATA_DEVICE_DISABLE_STATE_DISABLE_SOURCE_PEER_DEVICE 0x00000002
+#define NV_MSGBOX_DATA_DEVICE_DISABLE_STATE_DISABLE_SOURCE_IN_BAND 0x00000003
+#define NV_MSGBOX_DATA_DEVICE_DISABLE_STATE_DISABLE_SOURCE_OUT_OF_BAND 0x00000004
+#define NV_MSGBOX_DATA_DEVICE_DISABLE_STATE_DISABLE_REASON 16:14
+#define NV_MSGBOX_DATA_DEVICE_DISABLE_STATE_DISABLE_REASON_NONE 0x00000000
+#define NV_MSGBOX_DATA_DEVICE_DISABLE_STATE_DISABLE_REASON_CLIENT_OVERRIDE 0x00000001
+#define NV_MSGBOX_DATA_DEVICE_DISABLE_STATE_DISABLE_REASON_TRUNK_LINK_FAILED 0x00000002
+#define NV_MSGBOX_DATA_DEVICE_DISABLE_STATE_DISABLE_REASON_ACCESS_LINK_FAILED 0x00000003
+#define NV_MSGBOX_DATA_DEVICE_DISABLE_STATE_DISABLE_REASON_UNSPECIFIED_FAILURE 0x00000004
+#define NV_MSGBOX_DATA_DEVICE_DISABLE_STATE_DRIVER_RELOAD 17:17
+#define NV_MSGBOX_DATA_DEVICE_DISABLE_STATE_DRIVER_RELOAD_NOT_PENDING 0x00000000
+#define NV_MSGBOX_DATA_DEVICE_DISABLE_STATE_DRIVER_RELOAD_PENDING 0x00000001
+
+/* Response to NV_MSGBOX_CMD_ARG1_ACCESS_WP_MODE_ACTION_GET */
+#define NV_MSGBOX_DATA_ACCESS_WP_MODE_GET_STATE 7:0
+#define NV_MSGBOX_DATA_ACCESS_WP_MODE_GET_STATE_DISABLED 0x0000005A
+#define NV_MSGBOX_DATA_ACCESS_WP_MODE_GET_STATE_ENABLED 0x000000A5
+
+/*
+ * Response to
+ * NV_MSGBOX_CMD_ARG1_GET_MISC_GPU_RESET_REQUIRED
+ * NV_MSGBOX_CMD_ARG1_GET_MISC_GPU_FLAGS_PAGE_1
+ */
+#define NV_MSGBOX_DATA_GPU_RESET_REQUIRED 0:0
+#define NV_MSGBOX_DATA_GPU_RESET_REQUIRED_OFF 0x00000000
+#define NV_MSGBOX_DATA_GPU_RESET_REQUIRED_ON 0x00000001
+#define NV_MSGBOX_DATA_GPU_DRAIN_AND_RESET_RECOMMENDED 1:1
+#define NV_MSGBOX_DATA_GPU_DRAIN_AND_RESET_RECOMMENDED_NO 0x00000000
+#define NV_MSGBOX_DATA_GPU_DRAIN_AND_RESET_RECOMMENDED_YES 0x00000001
+
+/**
+ * Response to
+ * NV_MSGBOX_CMD_ARG1_GET_CLOCK_FREQ_INFO_PAGE_3
+ */
+#define NV_MSGBOX_DATA_GET_CLOCK_FREQ_INFO_PAGE_3_CURRENT_PSTATE 3:0
+#define NV_MSGBOX_DATA_GET_CLOCK_FREQ_INFO_PAGE_3_CURRENT_PSTATE_INVALID 0x0000000F
+
+/**
+ * Response to
+ * NV_MSGBOX_CMD_ARG1_GET_CLOCK_THROTTLE_REASON
+ */
+#define NV_MSGBOX_DATA_CLOCK_THROTTLE_REASON 31:0
+#define NV_MSGBOX_DATA_CLOCK_THROTTLE_REASON_NONE 0x00000000
+#define NV_MSGBOX_DATA_CLOCK_THROTTLE_REASON_SW_POWER_CAP 0x00000001
+#define NV_MSGBOX_DATA_CLOCK_THROTTLE_REASON_HW_SLOWDOWN 0x00000002
+#define NV_MSGBOX_DATA_CLOCK_THROTTLE_REASON_HW_THERMAL_SLOWDOWN 0x00000004
+#define NV_MSGBOX_DATA_CLOCK_THROTTLE_REASON_HW_POWER_BREAK_SLOWDOWN 0x00000008
+#define NV_MSGBOX_DATA_CLOCK_THROTTLE_REASON_SYNC_BOOST 0x00000010
+#define NV_MSGBOX_DATA_CLOCK_THROTTLE_REASON_SW_THERMAL_SLOWDOWN 0x00000020
+
+/*
+ * Number of Nvlink data outputs (dataOut, extData) for
+ * NV_MSGBOX_CMD_ARG1_GET_NVLINK_INFO_LINK queries
+ */
+#define NV_MSGBOX_DATA_NVLINK_INFO_DATA_WIDTH 2
+
+/*
+ * Encoding for Invalid data
+ */
+#define NV_MSGBOX_DATA_NVLINK_INFO_DATA_INVALID 0xFFFFFFFF
+
+/* Response to NV_MSGBOX_CMD_ARG1_GET_NVLINK_INFO_LINK_STATE_V1 */
+#define NV_MSGBOX_DATA_NVLINK_INFO_LINK_STATE_V1__SIZE 32
+#define NV_MSGBOX_DATA_NVLINK_INFO_LINK_STATE_V1_DOWN 0x00000000
+#define NV_MSGBOX_DATA_NVLINK_INFO_LINK_STATE_V1_UP 0x00000001
+#define NV_MSGBOX_DATA_NVLINK_INFO_LINK_STATE_V1_INVALID 0x000000ff
+
+/* Response to NV_MSGBOX_CMD_ARG1_GET_NVLINK_INFO_LINK_STATE_V2 */
+#define NV_MSGBOX_DATA_NVLINK_INFO_LINK_STATE_V2(i) (3+(i)*4):(0+(i)*4)
+#define NV_MSGBOX_DATA_NVLINK_INFO_LINK_STATE_V2__SIZE 8
+#define NV_MSGBOX_DATA_NVLINK_INFO_LINK_STATE_V2_OFF 0x00000000
+#define NV_MSGBOX_DATA_NVLINK_INFO_LINK_STATE_V2_SAFE 0x00000001
+#define NV_MSGBOX_DATA_NVLINK_INFO_LINK_STATE_V2_ACTIVE 0x00000002
+#define NV_MSGBOX_DATA_NVLINK_INFO_LINK_STATE_V2_ERROR 0x00000003
+#define NV_MSGBOX_DATA_NVLINK_INFO_LINK_STATE_V2_L1_LOW_POWER 0x00000004
+#define NV_MSGBOX_DATA_NVLINK_INFO_LINK_STATE_V2_NVLINK_DISABLED 0x00000005
+#define NV_MSGBOX_DATA_NVLINK_INFO_LINK_STATE_V2_INVALID 0x000000ff
+
+/* Response to NV_MSGBOX_CMD_ARG1_GET_NVLINK_INFO_LINK_BANDWIDTH (in Mps) */
+#define NV_MSGBOX_DATA_NVLINK_INFO_LINK_BANDWIDTH__SIZE 1
+#define NV_MSGBOX_DATA_NVLINK_LINE_RATE_INVALID 0xFFFFFFFF
+#define NV_MSGBOX_DATA_NVLINK_LINE_RATE_00000_MBPS 0
+#define NV_MSGBOX_DATA_NVLINK_LINE_RATE_16000_MBPS 16000
+#define NV_MSGBOX_DATA_NVLINK_LINE_RATE_19200_MBPS 19200
+#define NV_MSGBOX_DATA_NVLINK_LINE_RATE_20000_MBPS 20000
+#define NV_MSGBOX_DATA_NVLINK_LINE_RATE_25000_MBPS 25000
+#define NV_MSGBOX_DATA_NVLINK_LINE_RATE_25781_MBPS 25781
+#define NV_MSGBOX_DATA_NVLINK_LINE_RATE_32000_MBPS 32000
+#define NV_MSGBOX_DATA_NVLINK_LINE_RATE_40000_MBPS 40000
+#define NV_MSGBOX_DATA_NVLINK_LINE_RATE_50000_MBPS 50000
+#define NV_MSGBOX_DATA_NVLINK_LINE_RATE_53125_MBPS 53125
+
+/* Response to NV_MSGBOX_CMD_ARG1_GET_NVLINK_INFO_SUBLINK_WIDTH */
+#define NV_MSGBOX_DATA_NVLINK_INFO_SUBLINK_WIDTH(i) (5+(i)*6):(0+(i)*6)
+#define NV_MSGBOX_DATA_NVLINK_INFO_SUBLINK_WIDTH__SIZE 5
+#define NV_MSGBOX_DATA_NVLINK_INFO_SUBLINK_WIDTH_INVALID 0x000000ff
+#define NV_MSGBOX_DATA_NVLINK_INFO_SUBLINK_TX_WIDTH 2:0
+#define NV_MSGBOX_DATA_NVLINK_INFO_SUBLINK_TX_WIDTH_0 0x00000000
+#define NV_MSGBOX_DATA_NVLINK_INFO_SUBLINK_TX_WIDTH_1 0x00000001
+#define NV_MSGBOX_DATA_NVLINK_INFO_SUBLINK_TX_WIDTH_2 0x00000002
+#define NV_MSGBOX_DATA_NVLINK_INFO_SUBLINK_TX_WIDTH_4 0x00000003
+#define NV_MSGBOX_DATA_NVLINK_INFO_SUBLINK_TX_WIDTH_8 0x00000004
+#define NV_MSGBOX_DATA_NVLINK_INFO_SUBLINK_TX_WIDTH_INVALID 0x00000007
+#define NV_MSGBOX_DATA_NVLINK_INFO_SUBLINK_RX_WIDTH 5:3
+#define NV_MSGBOX_DATA_NVLINK_INFO_SUBLINK_RX_WIDTH_0 0x00000000
+#define NV_MSGBOX_DATA_NVLINK_INFO_SUBLINK_RX_WIDTH_1 0x00000001
+#define NV_MSGBOX_DATA_NVLINK_INFO_SUBLINK_RX_WIDTH_2 0x00000002
+#define NV_MSGBOX_DATA_NVLINK_INFO_SUBLINK_RX_WIDTH_4 0x00000003
+#define NV_MSGBOX_DATA_NVLINK_INFO_SUBLINK_RX_WIDTH_8 0x00000004
+#define NV_MSGBOX_DATA_NVLINK_INFO_SUBLINK_RX_WIDTH_INVALID 0x00000007
+
+/*
+ * Response to NV_MSGBOX_CMD_ARG1_GET_NVLINK_INFO_TRAINING_ERR_STATE
+ * NV_MSGBOX_CMD_ARG1_GET_NVLINK_INFO_RUNTIME_ERR_STATE
+ */
+#define NV_MSGBOX_DATA_NVLINK_INFO_ERROR_STATE__SIZE 32
+#define NV_MSGBOX_DATA_NVLINK_INFO_ERROR_STATE_INVALID 0x000000ff
+#define NV_MSGBOX_DATA_NVLINK_INFO_ERROR_STATE_NO_ERROR 0x00000000
+#define NV_MSGBOX_DATA_NVLINK_INFO_ERROR_STATE_ERROR 0x00000001
+
+/* Respones to NV_MSGBOX_CMD_ARG2_REMAP_ROW_RAW_CNT_COMBINED */
+#define NV_MSGBOX_DATA_REMAP_ROW_UNCORR_CNT 10:0
+#define NV_MSGBOX_DATA_REMAP_ROW_UNCORR_CNT_EXCESS 11:11
+#define NV_MSGBOX_DATA_REMAP_ROW_UNCORR_CNT_EXCESS_FALSE 0
+#define NV_MSGBOX_DATA_REMAP_ROW_UNCORR_CNT_EXCESS_TRUE 1
+#define NV_MSGBOX_DATA_REMAP_ROW_CORR_CNT 22:12
+#define NV_MSGBOX_DATA_REMAP_ROW_CORR_CNT_EXCESS 23:23
+#define NV_MSGBOX_DATA_REMAP_ROW_CORR_CNT_EXCESS_FALSE 0
+#define NV_MSGBOX_DATA_REMAP_ROW_CORR_CNT_EXCESS_TRUE 1
+
+/* Response to NV_MSGBOX_CMD_ARG1_REMAP_ROWS_STATE_FLAGS */
+#define NV_MSGBOX_DATA_REMAP_ROW_STATE_FLAGS_PAGE0_FAILED_REMAPPING 0:0
+#define NV_MSGBOX_DATA_REMAP_ROW_STATE_FLAGS_PAGE0_FAILED_REMAPPING_FALSE 0
+#define NV_MSGBOX_DATA_REMAP_ROW_STATE_FLAGS_PAGE0_FAILED_REMAPPING_TRUE 1
+#define NV_MSGBOX_DATA_REMAP_ROW_STATE_FLAGS_PAGE0_PENDING_REMAPPING 1:1
+#define NV_MSGBOX_DATA_REMAP_ROW_STATE_FLAGS_PAGE0_PENDING_REMAPPING_FALSE 0
+#define NV_MSGBOX_DATA_REMAP_ROW_STATE_FLAGS_PAGE0_PENDING_REMAPPING_TRUE 1
+
+/* Response to NV_MSGBOX_CMD_ARG1_REMAP_ROWS_HISTOGRAM */
+#define NV_MSGBOX_DATA_REMAP_ROW_HISTOGRAM_LOW_AVAILABILITY 15:0
+#define NV_MSGBOX_DATA_REMAP_ROW_HISTOGRAM_PARTIAL_AVAILABILITY 31:16
+
+/* Response to NV_MSGBOX_CMD_ARG1_GET_PCIE_LINK_INFO_PAGE_0 */
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_0_LINK_SPEED 2:0
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_0_LINK_SPEED_UNKNOWN 0x00000000
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_0_LINK_SPEED_2500_MTPS 0x00000001
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_0_LINK_SPEED_5000_MTPS 0x00000002
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_0_LINK_SPEED_8000_MTPS 0x00000003
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_0_LINK_SPEED_16000_MTPS 0x00000004
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_0_LINK_SPEED_32000_MTPS 0x00000005
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_0_LINK_WIDTH 6:4
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_0_LINK_WIDTH_UNKNOWN 0x00000000
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_0_LINK_WIDTH_X1 0x00000001
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_0_LINK_WIDTH_X2 0x00000002
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_0_LINK_WIDTH_X4 0x00000003
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_0_LINK_WIDTH_X8 0x00000004
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_0_LINK_WIDTH_X16 0x00000005
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_0_LINK_WIDTH_X32 0x00000006
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_0_NONFATAL_ERROR_COUNT 15:8
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_0_FATAL_ERROR_COUNT 23:16
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_0_UNSUPP_REQ_COUNT 31:24
+
+/* Response to NV_MSGBOX_CMD_ARG1_GET_PCIE_LINK_INFO_PAGE_1 */
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_1_L0_TO_RECOVERY_COUNT 31:0
+
+/* Response to NV_MSGBOX_CMD_ARG1_GET_PCIE_LINK_INFO_PAGE_2 */
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_2_REPLAY_ROLLOVER_COUNT 15:0
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_2_NAKS_RCVD_COUNT 31:16
+
+/* Response to NV_MSGBOX_CMD_ARG1_GET_PCIE_LINK_INFO_PAGE_3 */
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_3_TARGET_LINK_SPEED 2:0
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_3_TARGET_LINK_SPEED_UNKNOWN 0x00000000
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_3_TARGET_LINK_SPEED_2500_MTPS 0x00000001
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_3_TARGET_LINK_SPEED_5000_MTPS 0x00000002
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_3_TARGET_LINK_SPEED_8000_MTPS 0x00000003
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_3_TARGET_LINK_SPEED_16000_MTPS 0x00000004
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_3_TARGET_LINK_SPEED_32000_MTPS 0x00000005
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_3_TARGET_LINK_SPEED_RESERVED 2:0
+
+/* Response to NV_MSGBOX_CMD_ARG1_GET_PCIE_LINK_INFO_PAGE_4 */
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_4_TX_COUNT 31:0
+
+/* Response to NV_MSGBOX_CMD_ARG1_GET_PCIE_LINK_INFO_PAGE_6 */
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_6_LTSSM_STATE 4:0
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_6_LTSSM_STATE_DETECT 0x00000000
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_6_LTSSM_STATE_POLLING 0x00000001
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_6_LTSSM_STATE_CONFIGURATION 0x00000002
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_6_LTSSM_STATE_RECOVERY 0x00000003
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_6_LTSSM_STATE_RECOVERY_EQZN 0x00000004
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_6_LTSSM_STATE_L0 0x00000005
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_6_LTSSM_STATE_L0S 0x00000006
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_6_LTSSM_STATE_L1 0x00000007
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_6_LTSSM_STATE_L1_PLL_PD 0x00000008
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_6_LTSSM_STATE_L2 0x00000009
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_6_LTSSM_STATE_L1_CPM 0x0000000a
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_6_LTSSM_STATE_L1_1 0x0000000b
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_6_LTSSM_STATE_L1_2 0x0000000c
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_6_LTSSM_STATE_HOT_RESET 0x0000000d
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_6_LTSSM_STATE_LOOPBACK 0x0000000e
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_6_LTSSM_STATE_DISABLED 0x0000000f
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_6_LTSSM_STATE_LINK_DOWN 0x00000010
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_6_LTSSM_STATE_LINK_READY 0x00000011
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_6_LTSSM_STATE_LANES_IN_SLEEP 0x00000012
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_6_LTSSM_STATE_ILLEGAL 0x0000001f
+
+/* Response to NV_MSGBOX_CMD_ARG1_GET_PCIE_LINK_INFO_PAGE_8 */
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_8_EQ_TX_LOCAL_PRESET 3:0
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_8_EQ_TX_LOCAL_USE_PRESET 4:4
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_8_EQ_TX_LOCAL_FS 10:5
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_8_EQ_TX_LOCAL_LF 16:11
+
+/* Response to NV_MSGBOX_CMD_ARG1_GET_PCIE_LINK_INFO_PAGE_9 */
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_9_EQ_RX_REMOTE_PRESET 3:0
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_9_EQ_RX_REMOTE_USE_PRESET 4:4
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_9_EQ_RX_REMOTE_FS 10:5
+#define NV_MSGBOX_DATA_PCIE_LINK_INFO_PAGE_9_EQ_RX_REMOTE_LF 16:11
+
+/*
+ * Input for NV_MSGBOX_CMD_OPCODE_GPU_PERFORMANCE_MONITORING. Value is valid
+ * only if Arg2 != GPM_PARTITION_AGGREGATE and Arg2.Bit7 == 1
+ */
+#define NV_MSGBOX_DATA_GPM_COMPUTE_INSTANCE_INDEX 15:8
+
+/*
+ * The following three fields correspond to the data which is interpreted
+ * differently depending on GPM Metric specified in Arg1.
+ */
+#define NV_MSGBOX_DATA_GPM_NVLINK_INDEX 7:0
+#define NV_MSGBOX_DATA_GPM_NVDEC_INSTANCE 7:0
+#define NV_MSGBOX_DATA_GPM_NVJPG_INSTANCE 7:0
+
+/* MSGBOX Extended Data Register */
+#define NV_MSGBOX_EXT_DATA_REG 31:0
+
+/* Respones to NV_MSGBOX_CMD_ARG1_GET_PCIE_LINK_INFO_PAGE_0 */
+#define NV_MSGBOX_EXT_DATA_PCIE_LINK_INFO_PAGE_0_CORRECTABLE_ERROR_COUNT 15:0
+
+/* Respones to NV_MSGBOX_CMD_ARG1_GET_PCIE_LINK_INFO_PAGE_1 */
+#define NV_MSGBOX_EXT_DATA_PCIE_LINK_INFO_PAGE_1_REPLAY_COUNT 31:0
+
+/* Respones to NV_MSGBOX_CMD_ARG1_GET_PCIE_LINK_INFO_PAGE_2 */
+#define NV_MSGBOX_EXT_DATA_PCIE_LINK_INFO_PAGE_2_NAKS_SENT_COUNT 15:0
+
+/* Response to NV_MSGBOX_CMD_ARG1_GET_PCIE_LINK_INFO_PAGE_4 */
+#define NV_MSGBOX_EXT_DATA_PCIE_LINK_INFO_PAGE_4_RX_COUNT 31:0
+
+/* Response to NV_MSGBOX_CMD_ARG1_GET_PCIE_LINK_INFO_PAGE_8 */
+#define NV_MSGBOX_EXT_DATA_PCIE_LINK_INFO_PAGE_8_EQ_TX_LOCAL_PRECUR 5:0
+#define NV_MSGBOX_EXT_DATA_PCIE_LINK_INFO_PAGE_8_EQ_TX_LOCAL_MAINCUR 11:6
+#define NV_MSGBOX_EXT_DATA_PCIE_LINK_INFO_PAGE_8_EQ_TX_LOCAL_POSTCUR 17:12
+
+/* Response to NV_MSGBOX_CMD_ARG1_GET_PCIE_LINK_INFO_PAGE_9 */
+#define NV_MSGBOX_EXT_DATA_PCIE_LINK_INFO_PAGE_9_EQ_RX_REMOTE_PRECUR 5:0
+#define NV_MSGBOX_EXT_DATA_PCIE_LINK_INFO_PAGE_9_EQ_RX_REMOTE_MAINCUR 11:6
+#define NV_MSGBOX_EXT_DATA_PCIE_LINK_INFO_PAGE_9_EQ_RX_REMOTE_POSTCUR 17:12
+
+/* Response to NV_MSGBOX_CMD_ARG1_REMAP_ROWS_HISTOGRAM */
+#define NV_MSGBOX_EXT_DATA_REMAP_ROW_HISTOGRAM_MAX_AVAILABILITY 31:16
+#define NV_MSGBOX_EXT_DATA_REMAP_ROW_HISTOGRAM_HIGH_AVAILABILITY 15:0
+
+/* SysId info per type sizes */
+#define NV_MSGBOX_SYSID_DATA_SIZE_BOARD_PART_NUM_V1 24
+#define NV_MSGBOX_SYSID_DATA_SIZE_OEM_INFO_V1 24
+#define NV_MSGBOX_SYSID_DATA_SIZE_SERIAL_NUM_V1 16
+#define NV_MSGBOX_SYSID_DATA_SIZE_MARKETING_NAME_V1 24
+#define NV_MSGBOX_SYSID_DATA_SIZE_GPU_PART_NUM_V1 16
+#define NV_MSGBOX_SYSID_DATA_SIZE_MEMORY_VENDOR_V1 1
+#define NV_MSGBOX_SYSID_DATA_SIZE_MEMORY_PART_NUM_V1 20
+#define NV_MSGBOX_SYSID_DATA_SIZE_BUILD_DATE_V1 4
+#define NV_MSGBOX_SYSID_DATA_SIZE_FIRMWARE_VER_V1 14
+#define NV_MSGBOX_SYSID_DATA_SIZE_VENDOR_ID_V1 2
+#define NV_MSGBOX_SYSID_DATA_SIZE_DEV_ID_V1 2
+#define NV_MSGBOX_SYSID_DATA_SIZE_SUB_VENDOR_ID_V1 2
+#define NV_MSGBOX_SYSID_DATA_SIZE_SUB_ID_V1 2
+#define NV_MSGBOX_SYSID_DATA_SIZE_GPU_GUID_V1 16
+#define NV_MSGBOX_SYSID_DATA_SIZE_INFOROM_VER_V1 16
+#define NV_MSGBOX_SYSID_DATA_SIZE_PRODUCT_LENGTH_V1 4
+#define NV_MSGBOX_SYSID_DATA_SIZE_PRODUCT_WIDTH_V1 4
+#define NV_MSGBOX_SYSID_DATA_SIZE_PRODUCT_HEIGHT_V1 4
+#define NV_MSGBOX_SYSID_DATA_SIZE_PCIE_SPEED_V1 1
+#define NV_MSGBOX_SYSID_DATA_SIZE_PCIE_WIDTH_V1 1
+#define NV_MSGBOX_SYSID_DATA_SIZE_TGP_LIMIT_V1 4
+#define NV_MSGBOX_SYSID_DATA_SIZE_FRU_PART_NUMBER_V1 20
+#define NV_MSGBOX_SYSID_DATA_SIZE_MODULE_POWER_LIMIT_V1 4
+#define NV_MSGBOX_SYSID_DATA_SIZE_MAX_DRAM_CAPACITY_V1 4
+
+/*!
+ * Response to NV_MSGBOX_CMD_ARG1_GET_POWER_HINT_INFO_CLK
+ * 16-bit frequency in MHz
+ */
+#define NV_MSGBOX_DATA_POWER_HINT_INFO_CLK_GR_MIN 15:0
+#define NV_MSGBOX_DATA_POWER_HINT_INFO_CLK_GR_MAX 31:16
+#define NV_MSGBOX_DATA_POWER_HINT_INFO_CLK_MEM_MIN 15:0
+#define NV_MSGBOX_DATA_POWER_HINT_INFO_CLK_MEM_MAX 31:16
+
+/*!
+ * Response to NV_MSGBOX_CMD_ARG1_GET_POWER_HINT_INFO_TEMP
+ * 16-bit frequency in MHz
+ */
+#define NV_MSGBOX_DATA_POWER_HINT_INFO_TEMP_MIN 15:0
+#define NV_MSGBOX_DATA_POWER_HINT_INFO_TEMP_MAX 31:16
+
+/*!
+ * Response to _ARG1_GET_POWER_HINT_INFO_PROFILES, 1 page consists of data and
+ * ext data, then we can support up to 256 profiles
+ * Bit index represents profile ID
+ */
+#define NV_MSGBOX_DATA_POWER_HINT_INFO_PROFILES_PAGE_0_DMMA_PERF 0:0
+#define NV_MSGBOX_DATA_POWER_HINT_INFO_PROFILES_PAGE_0_DMMA_PERF_NOT_AVAILABLE 0
+#define NV_MSGBOX_DATA_POWER_HINT_INFO_PROFILES_PAGE_0_DMMA_PERF_AVAILABLE 1
+#define NV_MSGBOX_DATA_POWER_HINT_INFO_PROFILES_PAGE_0_DMMA_HIGH_K 1:1
+#define NV_MSGBOX_DATA_POWER_HINT_INFO_PROFILES_PAGE_0_DMMA_HIGH_K_NOT_AVAILABLE 0
+#define NV_MSGBOX_DATA_POWER_HINT_INFO_PROFILES_PAGE_0_DMMA_HIGH_K_AVAILABLE 1
+#define NV_MSGBOX_DATA_POWER_HINT_INFO_PROFILES_PAGE_0_DMMA_LOW_K 2:2
+#define NV_MSGBOX_DATA_POWER_HINT_INFO_PROFILES_PAGE_0_DMMA_LOW_K_NOT_AVAILABLE 0
+#define NV_MSGBOX_DATA_POWER_HINT_INFO_PROFILES_PAGE_0_DMMA_LOW_K_AVAILABLE 1
+#define NV_MSGBOX_DATA_POWER_HINT_INFO_PROFILES_PAGE_0_HMMA 3:3
+#define NV_MSGBOX_DATA_POWER_HINT_INFO_PROFILES_PAGE_0_HMMA_NOT_AVAILABLE 0
+#define NV_MSGBOX_DATA_POWER_HINT_INFO_PROFILES_PAGE_0_HMMA_AVAILABLE 1
+#define NV_MSGBOX_DATA_POWER_HINT_INFO_PROFILES_PAGE_0_IMMA 4:4
+#define NV_MSGBOX_DATA_POWER_HINT_INFO_PROFILES_PAGE_0_IMMA_NOT_AVAILABLE 0
+#define NV_MSGBOX_DATA_POWER_HINT_INFO_PROFILES_PAGE_0_IMMA_AVAILABLE 1
+#define NV_MSGBOX_DATA_POWER_HINT_INFO_PROFILES_PAGE_0_SGEMM 5:5
+#define NV_MSGBOX_DATA_POWER_HINT_INFO_PROFILES_PAGE_0_SGEMM_NOT_AVAILABLE 0
+#define NV_MSGBOX_DATA_POWER_HINT_INFO_PROFILES_PAGE_0_SGEMM_AVAILABLE 1
+#define NV_MSGBOX_DATA_POWER_HINT_INFO_PROFILES_PAGE_0_TRANSFORMER 6:6
+#define NV_MSGBOX_DATA_POWER_HINT_INFO_PROFILES_PAGE_0_TRANSFORMER_NOT_AVAILABLE 0
+#define NV_MSGBOX_DATA_POWER_HINT_INFO_PROFILES_PAGE_0_TRANSFORMER_AVAILABLE 1
+#define NV_MSGBOX_DATA_POWER_HINT_INFO_PROFILES_PAGE_0_CUSTOMER_CUSTOM_0 7:7
+#define NV_MSGBOX_DATA_POWER_HINT_INFO_PROFILES_PAGE_0_CUSTOMER_CUSTOM_0_NOT_AVAILABLE 0
+#define NV_MSGBOX_DATA_POWER_HINT_INFO_PROFILES_PAGE_0_CUSTOMER_CUSTOM_0_AVAILABLE 1
+#define NV_MSGBOX_DATA_POWER_HINT_INFO_PROFILES_PAGE_0_CUSTOMER_CUSTOM_1 8:8
+#define NV_MSGBOX_DATA_POWER_HINT_INFO_PROFILES_PAGE_0_CUSTOMER_CUSTOM_1_NOT_AVAILABLE 0
+#define NV_MSGBOX_DATA_POWER_HINT_INFO_PROFILES_PAGE_0_CUSTOMER_CUSTOM_1_AVAILABLE 1
+#define NV_MSGBOX_DATA_POWER_HINT_INFO_PROFILES_PAGE_0_CUSTOMER_CUSTOM_2 9:9
+#define NV_MSGBOX_DATA_POWER_HINT_INFO_PROFILES_PAGE_0_CUSTOMER_CUSTOM_2_NOT_AVAILABLE 0
+#define NV_MSGBOX_DATA_POWER_HINT_INFO_PROFILES_PAGE_0_CUSTOMER_CUSTOM_2_AVAILABLE 1
+#define NV_MSGBOX_DATA_POWER_HINT_INFO_PROFILES_PAGE_0_CUSTOMER_CUSTOM_3 10:10
+#define NV_MSGBOX_DATA_POWER_HINT_INFO_PROFILES_PAGE_0_CUSTOMER_CUSTOM_3_NOT_AVAILABLE 0
+#define NV_MSGBOX_DATA_POWER_HINT_INFO_PROFILES_PAGE_0_CUSTOMER_CUSTOM_3_AVAILABLE 1
+#define NV_MSGBOX_DATA_POWER_HINT_INFO_PROFILES_PAGE_0_CUSTOMER_CUSTOM_4 11:11
+#define NV_MSGBOX_DATA_POWER_HINT_INFO_PROFILES_PAGE_0_CUSTOMER_CUSTOM_4_NOT_AVAILABLE 0
+#define NV_MSGBOX_DATA_POWER_HINT_INFO_PROFILES_PAGE_0_CUSTOMER_CUSTOM_4_AVAILABLE 1
+#define NV_MSGBOX_DATA_POWER_HINT_INFO_PROFILES_PAGE_0_CUSTOMER_CUSTOM_5 12:12
+#define NV_MSGBOX_DATA_POWER_HINT_INFO_PROFILES_PAGE_0_CUSTOMER_CUSTOM_5_NOT_AVAILABLE 0
+#define NV_MSGBOX_DATA_POWER_HINT_INFO_PROFILES_PAGE_0_CUSTOMER_CUSTOM_5_AVAILABLE 1
+#define NV_MSGBOX_DATA_POWER_HINT_INFO_PROFILES_PAGE_0_CUSTOMER_CUSTOM_6 13:13
+#define NV_MSGBOX_DATA_POWER_HINT_INFO_PROFILES_PAGE_0_CUSTOMER_CUSTOM_6_NOT_AVAILABLE 0
+#define NV_MSGBOX_DATA_POWER_HINT_INFO_PROFILES_PAGE_0_CUSTOMER_CUSTOM_6_AVAILABLE 1
+#define NV_MSGBOX_DATA_POWER_HINT_INFO_PROFILES_PAGE_0_CUSTOMER_CUSTOM_7 14:14
+#define NV_MSGBOX_DATA_POWER_HINT_INFO_PROFILES_PAGE_0_CUSTOMER_CUSTOM_7_NOT_AVAILABLE 0
+#define NV_MSGBOX_DATA_POWER_HINT_INFO_PROFILES_PAGE_0_CUSTOMER_CUSTOM_7_AVAILABLE 1
+
+#define NV_MSGBOX_DATA_DYN_SYS_INFO_SIZE_DRIVER_VERSION 64
+
+/* Event types */
+typedef enum
+{
+ NV_MSGBOX_EVENT_TYPE_SERVER_RESTART_COLD = 0,
+ NV_MSGBOX_EVENT_TYPE_GPU_RESET_REQUIRED,
+ NV_MSGBOX_EVENT_TYPE_DRIVER_ERROR_MESSAGE_OLDEST,
+ NV_MSGBOX_EVENT_TYPE_TGP_LIMIT_SET_SUCCESS,
+ NV_MSGBOX_EVENT_TYPE_CLOCK_LIMIT_SET_SUCCESS,
+ NV_MSGBOX_EVENT_TYPE_ECC_TOGGLE_SUCCESS,
+ NV_MSGBOX_EVENT_TYPE_MIG_TOGGLE_SUCCESS,
+ NV_MSGBOX_EVENT_TYPE_SERVER_RESTART_WARM,
+ NV_MSGBOX_EVENT_TYPE_DRIVER_ERROR_MESSAGE_NEW,
+ NV_MSGBOX_EVENT_TYPE_MODULE_LIMIT_SET_SUCCESS,
+ NV_MSGBOX_NUM_EVENTS, /* insert new event types before this line */
+} NvMsgboxEventType;
+
+/* Legacy event names for compatipility */
+#define NV_MSGBOX_EVENT_TYPE_SERVER_RESTART NV_MSGBOX_EVENT_TYPE_SERVER_RESTART_COLD
+#define NV_MSGBOX_EVENT_TYPE_DRIVER_ERROR_MESSAGE NV_MSGBOX_EVENT_TYPE_DRIVER_ERROR_MESSAGE_OLDEST
+
+/* Bit mask of all defined events */
+#define NV_MSGBOX_EVENT_TYPE__ALL (NVBIT(NV_MSGBOX_NUM_EVENTS) - 1)
+
+/* ----------------------- Set Master Capabilities ---------------------------- */
+
+//
+// SET_MASTER_CAPS
+//
+// Descripiton:
+// Set/declare SMBPBI Master capabilities.
+//
+// Common Encoding:
+// 7 0 7 0
+// .-+-+-+-+-+-+-+-. .-+-+-+-+-+-+-+-.
+// | CLASS | ARG1 | CAP_INDEX | ARG2
+// `-+-+-+-+-+-+-+-' `-+-+-+-+-+-+-+-'
+//
+// The SMBPBI Master capabilities are logically grouped into classes (specified
+// in arg1). Capabilities are sent 32 at a time (dword index stored in arg2)
+// per-class (typically once during system-initialization).
+//
+// Classes:
+// _GPU_REQ - Class of capability bits corresponding 1:1 with the GPU-
+// Request opcodes the master supports.
+//
+#define NV_MSGBOX_CMD_SET_MASTER_CAPS_ARG1_CLASS 7:0
+#define NV_MSGBOX_CMD_SET_MASTER_CAPS_ARG1_CLASS_GPU_REQ 0x00000000
+
+#define NV_MSGBOX_DATA_MASTER_CAPS_GPU_REQ_COUNT 1
+
+#define NV_MSGBOX_DATA_MASTER_CAPS_GPU_REQ_0 31:0
+#define NV_MSGBOX_DATA_MASTER_CAPS_GPU_REQ_0_CPU_PCONTROL 0:0
+#define NV_MSGBOX_DATA_MASTER_CAPS_GPU_REQ_0_CPU_PCONTROL_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_MASTER_CAPS_GPU_REQ_0_CPU_PCONTROL_AVAILABLE 0x00000001
+#define NV_MSGBOX_DATA_MASTER_CAPS_GPU_REQ_0_SYS_PCONTROL 1:1
+#define NV_MSGBOX_DATA_MASTER_CAPS_GPU_REQ_0_SYS_PCONTROL_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_DATA_MASTER_CAPS_GPU_REQ_0_SYS_PCONTROL_AVAILABLE 0x00000001
+
+/* ------------------ GPU Performance Control (PCONTROL) ---------------------- */
+
+//
+// GPU_PCONTROL arg1, arg2, and data encoding (fields are relative to zero, not
+// relative to their position in the COMMAND/DATA registers).
+//
+
+//
+// ARG1/ARG2 Encoding
+//
+// 7 3 2 0 7 0
+// .-+-+-+-+-+-+-+-. .-+-+-+-+-+-+-+-.
+// | TARGET | ACT | ARG1 |0 0 0 0 0 0 0 0| ARG2 (reserved)
+// `-+-+-+-+-+-+-+-' `-+-+-+-+-+-+-+-'
+//
+#define NV_MSGBOX_CMD_GPU_PCONTROL_ARG1_ACTION 2:0
+#define NV_MSGBOX_CMD_GPU_PCONTROL_ARG1_ACTION_GET_INFO 0x00000000
+#define NV_MSGBOX_CMD_GPU_PCONTROL_ARG1_ACTION_GET_LIMIT 0x00000001
+#define NV_MSGBOX_CMD_GPU_PCONTROL_ARG1_ACTION_SET_LIMIT 0x00000002
+#define NV_MSGBOX_CMD_GPU_PCONTROL_ARG1_ACTION_GET_STATUS 0x00000003
+#define NV_MSGBOX_CMD_GPU_PCONTROL_ARG1_TARGET 7:3
+#define NV_MSGBOX_CMD_GPU_PCONTROL_ARG1_TARGET_VPSTATE 0x00000000
+#define NV_MSGBOX_CMD_GPU_PCONTROL_ARG1_TARGET_POWER_SMBIDX 0x00000001
+#define NV_MSGBOX_CMD_GPU_PCONTROL_ARG2_RSVD 7:0
+
+#define NV_MSGBOX_CMD_GPU_PCONTROL_ARG1_SET_ACTION(arg1, action) \
+ (arg1) = FLD_SET_DRF(_MSGBOX_CMD, _GPU_PCONTROL_ARG1, _ACTION, \
+ action, (arg1))
+
+#define NV_MSGBOX_CMD_GPU_PCONTROL_ARG1_GET_ACTION(arg1) \
+ DRF_VAL(_MSGBOX_CMD, _GPU_PCONTROL_ARG1, _ACTION, (arg1))
+
+#define NV_MSGBOX_CMD_GPU_PCONTROL_ARG1_SET_TARGET(arg1, target) \
+ (arg1) = FLD_SET_DRF(_MSGBOX_CMD, _GPU_PCONTROL_ARG1, _TARGET, \
+ target, (arg1))
+
+#define NV_MSGBOX_CMD_GPU_PCONTROL_ARG1_GET_TARGET(arg1) \
+ DRF_VAL(_MSGBOX_CMD, _GPU_PCONTROL_ARG1, _TARGET, (arg1))
+
+//
+// Getting GPU vPstate Information
+//
+// Inputs:
+// ARG1 - {TARGET=VPSTATE, ACTION=GET_INFO}
+// ARG2 - Unused/reserved (must be zero)
+//
+// Outputs:
+// DATA - Current min/max range of externally available vpstates
+// (vPmin=fastest, vPmax=slowest)
+//
+// Encoding:
+// 31 16 15 8 7 0
+// .-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-.
+// |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0| MIN | MAX | DATA
+// `-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-'
+//
+#define NV_MSGBOX_CMD_GPU_PCONTROL_DATA_VPSTATE_GET_INFO_MAX 7:0
+#define NV_MSGBOX_CMD_GPU_PCONTROL_DATA_VPSTATE_GET_INFO_MIN 15:8
+#define NV_MSGBOX_CMD_GPU_PCONTROL_DATA_VPSTATE_GET_INFO_RSVD 31:16
+
+#define NV_MSGBOX_CMD_GPU_PCONTROL_DATA_VPSTATE_GET_INFO_SET_MAX(data, max) \
+ (data) = FLD_SET_DRF_NUM(_MSGBOX_CMD, _GPU_PCONTROL_DATA, \
+ _VPSTATE_GET_INFO_MAX, (max), (data))
+
+#define NV_MSGBOX_CMD_GPU_PCONTROL_DATA_VPSTATE_GET_INFO_GET_MAX(data) \
+ DRF_VAL(_MSGBOX_CMD, _GPU_PCONTROL_DATA, _VPSTATE_GET_INFO_MAX, (data))
+
+#define NV_MSGBOX_CMD_GPU_PCONTROL_DATA_VPSTATE_GET_INFO_SET_MIN(data, min) \
+ (data) = FLD_SET_DRF_NUM(_MSGBOX_CMD, _GPU_PCONTROL_DATA, \
+ _VPSTATE_GET_INFO_MIN, (min), (data))
+
+#define NV_MSGBOX_CMD_GPU_PCONTROL_DATA_VPSTATE_GET_INFO_GET_MIN(data) \
+ DRF_VAL(_MSGBOX_CMD, _GPU_PCONTROL_DATA, _VPSTATE_GET_INFO_MIN, (data))
+
+//
+// Getting GPU vPstate Limits
+//
+// Inputs:
+// ARG1 - {TARGET=VPSTATE, ACTION=GET_LIMIT}
+// ARG2 - Unused/reserved (must be zero)
+//
+// Outputs:
+// DATA - Last requested vpstate limit/value, zero when no limit has been set.
+//
+// Encoding:
+// 31 8 7 0
+// .-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-.
+// |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0| VALUE | DATA
+// `-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-'
+//
+#define NV_MSGBOX_CMD_GPU_PCONTROL_DATA_VPSTATE_GET_LIMIT_VALUE 7:0
+#define NV_MSGBOX_CMD_GPU_PCONTROL_DATA_VPSTATE_GET_LIMIT_RSVD 31:8
+
+#define NV_MSGBOX_CMD_GPU_PCONTROL_DATA_VPSTATE_GET_LIMIT_SET_VALUE(data, value) \
+ (data) = FLD_SET_DRF_NUM(_MSGBOX_CMD, _GPU_PCONTROL_DATA, \
+ _VPSTATE_GET_LIMIT_VALUE, (value), (data))
+
+#define NV_MSGBOX_CMD_GPU_PCONTROL_DATA_VPSTATE_GET_LIMIT_GET_VALUE(data) \
+ DRF_VAL(_MSGBOX_CMD, _GPU_PCONTROL_DATA, _VPSTATE_GET_LIMIT_VALUE, (data))
+
+//
+// Setting GPU vPstate Limits:
+//
+// Inputs:
+// ARG1 - {TARGET=VPSTATE, ACTION=SET_LIMIT}
+// ARG2 - Unused/reserved (must be zero)
+// DATA - Desired vpstate limit/value between vPmin and vPmax (inclusive),
+// zero to clear active limits.
+// Outputs:
+// none
+//
+// Encoding:
+// 31 8 7 0
+// .-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-.
+// |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0| VALUE | DATA
+// `-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-'
+//
+#define NV_MSGBOX_CMD_GPU_PCONTROL_DATA_VPSTATE_SET_LIMIT_VALUE 7:0
+#define NV_MSGBOX_CMD_GPU_PCONTROL_DATA_VPSTATE_SET_LIMIT_VALUE_CLEAR 0x00000000
+#define NV_MSGBOX_CMD_GPU_PCONTROL_DATA_VPSTATE_SET_LIMIT_VALUE_INIT 0x00000000
+#define NV_MSGBOX_CMD_GPU_PCONTROL_DATA_VPSTATE_SET_LIMIT_RSVD 31:8
+
+#define NV_MSGBOX_CMD_GPU_PCONTROL_DATA_VPSTATE_SET_LIMIT_SET_VALUE(data, limit) \
+ (data) = FLD_SET_DRF_NUM(_MSGBOX_CMD, _GPU_PCONTROL_DATA, \
+ _VPSTATE_SET_LIMIT_VALUE, (limit), (data))
+
+#define NV_MSGBOX_CMD_GPU_PCONTROL_DATA_VPSTATE_SET_LIMIT_GET_VALUE(data) \
+ DRF_VAL(_MSGBOX_CMD, _GPU_PCONTROL_DATA, _VPSTATE_SET_LIMIT_VALUE, (data))
+
+//
+// Getting GPU vPstate Status
+//
+// Inputs:
+// ARG1 - {TARGET=VPSTATE, ACTION=GET_STATUS}
+// ARG2 - Unused/reserved (must be zero)
+//
+// Outputs:
+// DATA - Current vPstate
+//
+// Encoding:
+// 31 8 7 0
+// .-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-.
+// |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0| CURRENT | DATA
+// `-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-'
+//
+#define NV_MSGBOX_CMD_GPU_PCONTROL_DATA_VPSTATE_GET_STATUS_CURRENT 7:0
+#define NV_MSGBOX_CMD_GPU_PCONTROL_DATA_VPSTATE_GET_STATUS_RSVD 31:8
+
+#define NV_MSGBOX_CMD_GPU_PCONTROL_DATA_VPSTATE_GET_STATUS_SET_CURRENT(data, curr) \
+ (data) = FLD_SET_DRF_NUM(_MSGBOX_CMD, _GPU_PCONTROL_DATA, \
+ _VPSTATE_GET_STATUS_CURRENT, (curr), (data))
+
+#define NV_MSGBOX_CMD_GPU_PCONTROL_DATA_VPSTATE_GET_STATUS_GET_CURRENT(data) \
+ DRF_VAL(_MSGBOX_CMD, _GPU_PCONTROL_DATA, _VPSTATE_GET_STATUS_CURRENT, (data))
+
+
+/* ------------------------- GPU System Control ------------------------------- */
+
+//
+// GPU_SYSCONTROL
+//
+// Description:
+// Command sent to the GPU to set/remove a system-imposed operating limit
+// on a specific system-parameter.
+//
+// Common Encoding:
+// 7 2 1 0 7 0
+// .-+-+-+-+-+-+-+-. .-+-+-+-+-+-+-+-.
+// | TARGET |ACT| ARG1 |0 0 0 0 0 0 0 0| ARG2 (reserved)
+// `-+-+-+-+-+-+-+-' `-+-+-+-+-+-+-+-'
+//
+// Notes:
+// - TARGET accepts NV0000_CTRL_SYSTEM_PARAM_* definitions
+// - arg1, arg2, and data encoding (fields are relative to zero, not relative
+// to their position in the DATA_OUT register).
+//
+#define NV_MSGBOX_CMD_GPU_SYSCONTROL_ARG1_ACTION 1:0
+#define NV_MSGBOX_CMD_GPU_SYSCONTROL_ARG1_ACTION_CLEAR_LIMIT 0x00000000
+#define NV_MSGBOX_CMD_GPU_SYSCONTROL_ARG1_ACTION_SET_LIMIT 0x00000001
+#define NV_MSGBOX_CMD_GPU_SYSCONTROL_ARG1_TARGET 7:2
+#define NV_MSGBOX_CMD_GPU_SYSCONTROL_ARG2_RSVD 7:0
+
+#define NV_MSGBOX_CMD_GPU_SYSCONTROL_ARG1_SET_ACTION(arg1, action) \
+ (arg1) = FLD_SET_DRF(_MSGBOX_CMD, _GPU_SYSCONTROL_ARG1, _ACTION, \
+ action, (arg1))
+
+#define NV_MSGBOX_CMD_GPU_SYSCONTROL_ARG1_GET_ACTION(arg1) \
+ DRF_VAL(_MSGBOX_CMD, _GPU_SYSCONTROL_ARG1, _ACTION, (arg1))
+
+#define NV_MSGBOX_CMD_GPU_SYSCONTROL_ARG1_SET_TARGET(arg1, target) \
+ (arg1) = FLD_SET_DRF_NUM(_MSGBOX_CMD, _GPU_SYSCONTROL_ARG1, _TARGET, \
+ target, (arg1))
+
+#define NV_MSGBOX_CMD_GPU_SYSCONTROL_ARG1_GET_TARGET(arg1) \
+ DRF_VAL(_MSGBOX_CMD, _GPU_SYSCONTROL_ARG1, _TARGET, (arg1))
+
+//
+// Setting a System-Parameter Operating-Limit:
+//
+// Inputs:
+// ARG1 - {TARGET=NV_MSGBOX_SYS_PARAM_*, ACTION=SET_LIMIT}
+// ARG2 - Unused/reserved (must be zero)
+// DATA - Desired limit/value.
+//
+// Outputs:
+// none
+//
+// Encoding:
+// 31 0
+// .-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-.
+// | VALUE | DATA
+// `-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-'
+//
+#define NV_MSGBOX_CMD_GPU_SYSCONTROL_DATA_SET_LIMIT_VALUE 31:0
+
+#define NV_MSGBOX_CMD_GPU_SYSCONTROL_DATA_SET_LIMIT_SET_VALUE(data, limit) \
+ (data) = FLD_SET_DRF_NUM(_MSGBOX_CMD, _GPU_SYSCONTROL_DATA, \
+ _SET_LIMIT_VALUE, (limit), (data))
+
+#define NV_MSGBOX_CMD_GPU_SYSCONTROL_DATA_PARAM_SET_LIMIT_GET_VALUE(data) \
+ DRF_VAL(_MSGBOX_CMD, _GPU_SYSCONTROL_DATA, _SET_LIMIT_VALUE, (data))
+
+//
+// Host side scratch memory buffer
+// This memory buffer is allocated by the host CPU in its system memory
+// and is used for passing additional arguments and results, that don't
+// fit in the command/status and data registers due to their size.
+// This memory can be accessed by the BMC SMBus master through
+// dedicated requests.
+//
+// Page size is various on different SMBPBI servers.
+// Capability dword[2] bit 12 shows size in bytes
+//
+// _1024 --> 0xFF dwords
+// _256 --> 0x40 dowrds
+//
+#define NV_MSGBOX_SCRATCH_PAGE_SIZE_1024_D 0xFF
+#define NV_MSGBOX_SCRATCH_PAGE_SIZE_256_D 0x40
+
+//
+// TODO Once switch soc/pmu/oobtest remove the reference to this, this will be
+// removed.
+//
+#define NV_MSGBOX_SCRATCH_PAGE_SIZE 1024
+#define NV_MSGBOX_SCRATCH_NUM_PAGES_P 2 // expressed as a power of 2
+ // must be >= 2
+
+// This cap code plugs into NV_MSGBOX_DATA_CAP_2_NUM_SCRATCH_BANKS
+#define NV_MSGBOX_SCRATCH_NUM_PAGES_CAP_CODE \
+ (NV_MSGBOX_SCRATCH_NUM_PAGES_P > 0 ? \
+ NV_MSGBOX_SCRATCH_NUM_PAGES_P - 1 : 0)
+
+#define NV_MSGBOX_SCRATCH_NUM_PAGES (1 << NV_MSGBOX_SCRATCH_NUM_PAGES_P)
+#define NV_MSGBOX_SCRATCH_BUFFER_SIZE (NV_MSGBOX_SCRATCH_NUM_PAGES \
+ * NV_MSGBOX_SCRATCH_PAGE_SIZE)
+
+// Auxiliary definitions related to NV_MSGBOX_CMD_ARG1_GET_NVLINK_INFO_STATE_SPEED
+#define NV_MSGBOX_NVLINK_STATE_BITS_PER_NVLINK 4
+#define NV_MSGBOX_NVLINK_STATE_NVLINKS_PER_REGISTER (32 / NV_MSGBOX_NVLINK_STATE_BITS_PER_NVLINK)
+#define NV_MSGBOX_NVLINK_STATE_NUM_NVLINKS_VOLTA 6
+#define NV_MSGBOX_NVLINK_STATE_NUM_NVLINKS_TURING 2
+#define NV_MSGBOX_NVLINK_STATE_NUM_NVLIPT_GA100 3
+#define NV_MSGBOX_NVLINK_STATE_NUM_LINKS_PER_NVLIPT_NVL30 4
+#define NV_MSGBOX_NVLINK_SUBLINK_WIDTH_MAX_NVL30 4
+#define NV_MSGBOX_NVLINK_STATE_NUM_NVLINKS_GA100 \
+ (NV_MSGBOX_NVLINK_STATE_NUM_NVLIPT_GA100 * \
+ NV_MSGBOX_NVLINK_STATE_NUM_LINKS_PER_NVLIPT_NVL30)
+#define NV_MSGBOX_NVLINK_STATE_NUM_NVLIPT_GA10X 1
+#define NV_MSGBOX_NVLINK_STATE_NUM_NVLINKS_GA10X \
+ (NV_MSGBOX_NVLINK_STATE_NUM_NVLIPT_GA10X * \
+ NV_MSGBOX_NVLINK_STATE_NUM_LINKS_PER_NVLIPT_NVL30)
+#define NV_MSGBOX_NVLINK_STATE_NUM_NVLIPT_LR10 9
+#define NV_MSGBOX_NVLINK_STATE_NUM_NVLINKS_LR10 \
+ (NV_MSGBOX_NVLINK_STATE_NUM_NVLIPT_LR10 * \
+ NV_MSGBOX_NVLINK_STATE_NUM_LINKS_PER_NVLIPT_NVL30)
+#define NV_MSGBOX_NVLINK_STATE_NUM_REGISTERS(arch) \
+ ((NV_MSGBOX_NVLINK_STATE_NUM_NVLINKS##arch + NV_MSGBOX_NVLINK_STATE_NVLINKS_PER_REGISTER - 1) \
+ / NV_MSGBOX_NVLINK_STATE_NVLINKS_PER_REGISTER)
+
+// Auxiliary definitions related to NV_MSGBOX_CMD_ARG1_GET_NVLINK_INFO_THROUGHPUT_*
+#define NV_MSGBOX_NVLINK_THROUGHPUT_COUNTER_INDEX_DATA_TX 0x00000000
+#define NV_MSGBOX_NVLINK_THROUGHPUT_COUNTER_INDEX_DATA_RX 0x00000001
+#define NV_MSGBOX_NVLINK_THROUGHPUT_COUNTER_INDEX_RAW_TX 0x00000002
+#define NV_MSGBOX_NVLINK_THROUGHPUT_COUNTER_INDEX_RAW_RX 0x00000003
+#define NV_MSGBOX_NVLINK_THROUGHPUT_COUNTER_INDEX_MAX 0x00000004
+
+#if !defined(NV_MSGBOX_NO_PARAM_STRUCTS)
+//
+// Parameter structures for asynchronous requests
+// passed in scratch space
+//
+
+/*!
+ * This structure is used to hold parameters for
+ * NV_MSGBOX_CMD_ARG1_ASYNC_REQUEST_PMGR_PWR_TGP_LIMIT_CONTROL_GET,
+ * NV_MSGBOX_CMD_ARG1_ASYNC_REQUEST_PMGR_PWR_TGP_LIMIT_CONTROL_SET,
+ * NV_MSGBOX_CMD_ARG1_ASYNC_REQUEST_PMGR_PWR_MODULE_LIMIT_CONTROL_GET and
+ * NV_MSGBOX_CMD_ARG1_ASYNC_REQUEST_PMGR_PWR_MODULE_LIMIT_CONTROL_SET
+ */
+typedef struct
+{
+ NvU32 flags;
+ /*!
+ * If flags:_PERSIST is _ON, make limitCurrInput persistent,
+ * surviving the driver reload and the system reboot.
+ *
+ * If flags:_CLEAR is _ON, it will clear the TGP limit. The
+ * persistence still depends on persist flag.
+ */
+#define NV_MSGBOX_PMGR_PWR_POWER_LIMIT_CONTROL_PARAMS_FLAGS_PERSIST 0:0
+#define NV_MSGBOX_PMGR_PWR_POWER_LIMIT_CONTROL_PARAMS_FLAGS_PERSIST_OFF 0x00000000
+#define NV_MSGBOX_PMGR_PWR_POWER_LIMIT_CONTROL_PARAMS_FLAGS_PERSIST_ON 0x00000001
+#define NV_MSGBOX_PMGR_PWR_POWER_LIMIT_CONTROL_PARAMS_FLAGS_CLEAR 1:1
+#define NV_MSGBOX_PMGR_PWR_POWER_LIMIT_CONTROL_PARAMS_FLAGS_CLEAR_OFF 0x00000000
+#define NV_MSGBOX_PMGR_PWR_POWER_LIMIT_CONTROL_PARAMS_FLAGS_CLEAR_ON 0x00000001
+
+ /*!
+ * Current total GPU power limit value to enforce, requested by the
+ * SMBPBI client, expressed in milliwatts.
+ * Must always be within range imposed by the current policy.
+ * 0xffffffff is returned, if the limit has not been set by the SMBPBI client.
+ */
+ NvU32 limitCurrInput;
+
+ /*!
+ * Currently arbitrated total GPU power limit value after taking
+ * into account limits, requested by all clients, expressed
+ * in milliwatts.
+ */
+ NvU32 limitCurrOutput;
+} NV_MSGBOX_PMGR_PWR_POWER_LIMIT_CONTROL_PARAMS;
+
+/*!
+ * This structure is used to hold parameters for
+ * NV_MSGBOX_CMD_ARG1_ASYNC_REQUEST_PMGR_PWR_TGP_LIMIT_INFO_GET and
+ * NV_MSGBOX_CMD_ARG1_ASYNC_REQUEST_PMGR_PWR_MODULE_LIMIT_INFO_GET
+ */
+typedef struct
+{
+ /*!
+ * Current total GPU power limit lower and upper bounds and the
+ * default setting, expressed in milliwatts.
+ * These constraints must be observed, when the limit
+ * is being set with either
+ * NV_MSGBOX_CMD_ARG1_ASYNC_REQUEST_PMGR_PWR_TGP_LIMIT_CONTROL_SET or
+ * NV_MSGBOX_CMD_ARG1_ASYNC_REQUEST_PMGR_PWR_MODULE_LIMIT_CONTROL_SET.
+ */
+ NvU32 limitMin;
+ NvU32 limitMax;
+ NvU32 limitDefault;
+} NV_MSGBOX_PMGR_PWR_POWER_LIMIT_INFO_PARAMS;
+
+/*!
+ * This structure is used to hold parameters for
+ * NV_MSGBOX_CMD_ARG1_ASYNC_REQUEST_THERMAL_FAN_V1_COUNT_GET
+ */
+typedef struct
+{
+ NvU32 fanCount; //<! number of fans on the board
+} NV_MSGBOX_THERMAL_FAN_V1_COUNT_PARAMS;
+
+/*!
+ * This structure is used to hold parameters for
+ * NV_MSGBOX_CMD_ARG1_ASYNC_REQUEST_THERMAL_FAN_V1_INFO_GET
+ */
+typedef struct
+{
+ NvU32 fanIndex; //<! fan ID to be filled by the caller
+ NvU32 fanProperties; //<! fan properties, detailed below
+
+//! Fan level metric
+#define NV_MSGBOX_FAN_V1_PROP_LEVEL_METRIC 0:0
+#define NV_MSGBOX_FAN_V1_PROP_LEVEL_METRIC_PWM 0x00000000
+#define NV_MSGBOX_FAN_V1_PROP_LEVEL_METRIC_RPM 0x00000001
+
+//! Fan tachometer availability
+#define NV_MSGBOX_FAN_V1_PROP_TACH 1:1
+#define NV_MSGBOX_FAN_V1_PROP_TACH_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_FAN_V1_PROP_TACH_AVAILABLE 0x00000001
+
+//! Fan tachometer bounds (min/max) availability
+#define NV_MSGBOX_FAN_V1_PROP_TACH_BOUNDS 2:2
+#define NV_MSGBOX_FAN_V1_PROP_TACH_BOUNDS_NOT_AVAILABLE 0x00000000
+#define NV_MSGBOX_FAN_V1_PROP_TACH_BOUNDS_AVAILABLE 0x00000001
+
+ NvU16 fanLevelMin; //<! minimum fan level
+ NvU16 fanLevelMax; //<! maximum fan level
+ NvU16 fanTachMin; //<! tachometer minimum
+ NvU16 fanTachMax; //<! tachometer maximum
+} NV_MSGBOX_THERMAL_FAN_V1_INFO_PARAMS;
+
+/*!
+ * This structure is used to hold parameters for
+ * NV_MSGBOX_CMD_ARG1_ASYNC_REQUEST_THERMAL_FAN_V1_STATUS_GET
+ */
+typedef struct
+{
+ NvU32 fanIndex; //<! fan ID to be filled by the caller
+ /*!
+ * Current fan level and speed
+ */
+ NvU8 levelCurr; //<! current fan level, 0 if n/a
+ NvU16 speedCurr; //<! current fan speed (RPM), 0 if no tach
+
+} NV_MSGBOX_THERMAL_FAN_V1_STATUS_PARAMS;
+
+/*!
+ * This structure is used to hold parameters for
+ * NV_MSGBOX_CMD_ARG1_ASYNC_REQUEST_OVERCLOCKING_LIMIT_CONTROL
+ */
+typedef struct
+{
+ NvU32 limitType; //<! Argument representing VPSTATE/CLOCK
+
+//! CLOCK/VPSTATE types - add types below
+#define NV_MSGBOX_OVERCLOCKING_LIMIT_TYPE_MAX_CUSTOMER_BOOST_VPSTATE 0x00000001
+
+ NvU32 maxClkLimitMHz; //<! Clock limit
+
+} NV_MSGBOX_OVERCLOCKING_LIMIT_CONTROL_PARAMS;
+
+/*!
+ * This structure is used to hold parameters for
+ * NV_MSGBOX_CMD_ARG1_ASYNC_REQUEST_ENERGY_COUNTER_STATUS_GET
+ */
+typedef struct
+{
+ NV_DECLARE_ALIGNED(NvU64 energyCountermJ, 8); //<! Energy counter value
+
+} NV_MSGBOX_ENERGY_COUNTER_STATUS_PARAMS;
+
+/*!
+ * This structure is used to hold parameters for
+ * NV_MSGBOX_CMD_ARG1_ASYNC_REQUEST_VIOLATION_COUNTERS_STATUS_GET
+ */
+typedef struct
+{
+ NvU32 policyMask;
+ /*!
+ * Argument representing policies whose violation times
+ * are being requested/provided
+ */
+
+//! NVBIT OFFSET <> POLICY - add types below
+#define NV_MSGBOX_VIOLATION_COUNTERS_TYPE_ALL_SUPPORTED_POLICIES 0xFFFFFFFF //-1 represents All Supported policies
+#define NV_MSGBOX_VIOLATION_COUNTERS_TYPE_HW_VIOLATION 0
+#define NV_MSGBOX_VIOLATION_COUNTERS_TYPE_SW_GLOBAL_VIOLATION 1
+#define NV_MSGBOX_VIOLATION_COUNTERS_TYPE_SW_POWER_VIOLATION 2
+#define NV_MSGBOX_VIOLATION_COUNTERS_TYPE_SW_THERMAL_VIOLATION 3
+
+ NV_DECLARE_ALIGNED(NvU64 violationTime[32], 8); //<! Violation counter value
+
+} NV_MSGBOX_VIOLATION_COUNTERS_STATUS_PARAMS;
+
+//! Number of clock domains to track for gathering utilization data.
+#define NV_MSGBOX_UTILIZATION_RATE_CLOCK_DOMAIN_COUNT 2
+
+/*!
+ * This structure is used to hold parameters for
+ * NV_MSGBOX_CMD_ARG1_ASYNC_REQUEST_UTILIZATION_RATE_GET
+ */
+typedef struct
+{
+ NvU32 gpuUtil; //<! Percent of sample that the Graphics/SM unit remains busy.
+ NvU32 memUtil; //<! Percent of sample that the memory unit remains busy.
+
+} NV_MSGBOX_UTILIZATION_RATE_PARAMS;
+
+/*!
+ * This structure is used to hold parameters for
+ * NV_MSGBOX_CMD_ARG1_ASYNC_REQUEST_OOB_CLOCK_LIMIT_SET
+ *
+ * Masks of NV_MSGBOX_OOB_CLOCK_LIMIT_CTRL_PARAMS_FLAGS_<XYZ>.
+ */
+typedef struct
+{
+ NvU32 flags;
+ /*!
+ * If flags: _CLEAR is _ON, it will clear the limits. Otherwise,
+ * set the clock limits.
+ *
+ * If flags: _PERSIST is _ON, set/clear limits persistently,
+ * surviving the driver reload and the system reboot.
+ *
+ */
+#define NV_MSGBOX_OOB_CLOCK_LIMIT_CTRL_PARAMS_FLAGS_PERSIST 0:0
+#define NV_MSGBOX_OOB_CLOCK_LIMIT_CTRL_PARAMS_FLAGS_PERSIST_OFF 0x00000000
+#define NV_MSGBOX_OOB_CLOCK_LIMIT_CTRL_PARAMS_FLAGS_PERSIST_ON 0x00000001
+#define NV_MSGBOX_OOB_CLOCK_LIMIT_CTRL_PARAMS_FLAGS_CLEAR 1:1
+#define NV_MSGBOX_OOB_CLOCK_LIMIT_CTRL_PARAMS_FLAGS_CLEAR_OFF 0x00000000
+#define NV_MSGBOX_OOB_CLOCK_LIMIT_CTRL_PARAMS_FLAGS_CLEAR_ON 0x00000001
+
+ /*!
+ * Graphics clock limit in MHz
+ */
+ NvU32 clkMinFreqMHz;
+ NvU32 clkMaxFreqMHz;
+} NV_MSGBOX_OOB_CLOCK_LIMIT_CTRL_PARAMS;
+
+/*!
+ * This structure is used to hold parameters for
+ * NV_MSGBOX_CMD_ARG1_ASYNC_REQUEST_MEMORY_CAPACITY_UTILIZATION_GET
+ */
+typedef struct
+{
+ NvU32 capacityReservedMiB; //<! Device memory (in MiB) reserved for system use.
+ NvU32 capacityUsedMiB; //<! Allocated device memory (in MiB).
+} NV_MSGBOX_MEMORY_CAPACITY_UTILIZATION_PARAMS;
+
+/*
+ * Parameters for NV_MSGBOX_CMD_ARG1_ASYNC_REQUEST_TEST_MESSAGE_SEND
+ */
+#define NV_MSGBOX_TEST_MESSAGE_SEND_STRING_SIZE_MAX 32
+/*
+ * If the message starts with this character, the message
+ * will not be sent to the kernel.
+ */
+#define NV_MSGBOX_TEST_MESSAGE_SEND_SILENT_CHAR '@'
+typedef struct
+{
+ NvU8 string[NV_MSGBOX_TEST_MESSAGE_SEND_STRING_SIZE_MAX];
+} NV_MSGBOX_TEST_MESSAGE_SEND_PARAMS;
+
+/*
+ * Individual request structure definition for bundled requests
+ */
+typedef struct
+{
+ NvU32 cmdStatus; //<! Command/Status
+ NvU32 dataIn; //<! Data In
+ NvU32 dataOut; //<! Data Out
+ NvU32 extData; //<! Extended Data
+} NV_MSGBOX_IND_REQUEST;
+
+/*!
+ * Driver Event Message record
+ */
+typedef struct
+{
+ NvU8 recordSize; //<! in 32-bit words
+ NvU8 xidId; //<! event type Id (Xid)
+ NvU8 flags; //<! bit 0: some DEMs after this one
+ //<! have been lost
+ //<! bit 1: the text message has been
+ //<! truncated
+ NvU8 xidIdExt; //<! event type Id (Xid) extension
+ NvU32 seqNumber; //<! record sequential number
+ NvU32 timeStamp; //<! seconds since the epoch UTC
+
+ /*
+ * Some Windows builds include this file, and older Microsoft
+ * compilers won't accept a zero size array in this context:
+ * "C4200 nonstandard extension used: zero-sized array in struct/union",
+ * despite this being a legitimate C99.
+ * We need to find a way to fix this, if we ever decide to
+ * implement DEM/Xid logging for Windows.
+ */
+ NvU8 textMessage[]; //<! NUL terminated
+
+} NV_MSGBOX_DEM_RECORD;
+#define NV_MSGBOX_DEM_RECORD_FLAGS_OVFL 0:0
+#define NV_MSGBOX_DEM_RECORD_FLAGS_OVFL_NOT_SET 0x00000000
+#define NV_MSGBOX_DEM_RECORD_FLAGS_OVFL_SET 0x00000001
+#define NV_MSGBOX_DEM_RECORD_FLAGS_TRUNC 1:1
+#define NV_MSGBOX_DEM_RECORD_FLAGS_TRUNC_NOT_SET 0x00000000
+#define NV_MSGBOX_DEM_RECORD_FLAGS_TRUNC_SET 0x00000001
+
+/*!
+ * Result Disposition Rule word layout
+ */
+#define NV_MSGBOX_DISP_RULE_REQ_IDX 2:0
+#define NV_MSGBOX_DISP_RULE_SRC_REG 4:3
+#define NV_MSGBOX_DISP_RULE_SRC_REG_STATUS 0x00000000
+#define NV_MSGBOX_DISP_RULE_SRC_REG_DATA 0x00000001
+#define NV_MSGBOX_DISP_RULE_SRC_REG_EXT_DATA 0x00000002
+#define NV_MSGBOX_DISP_RULE_SRC_REG_MAX 0x00000002
+#define NV_MSGBOX_DISP_RULE_SRC_RIGHT_BIT 9:5
+#define NV_MSGBOX_DISP_RULE_SRC_WIDTH 14:10
+#define NV_MSGBOX_DISP_RULE_DST_REG 16:15
+#define NV_MSGBOX_DISP_RULE_DST_REG_STATUS 0x00000000
+#define NV_MSGBOX_DISP_RULE_DST_REG_DATA 0x00000001
+#define NV_MSGBOX_DISP_RULE_DST_REG_EXT_DATA 0x00000002
+#define NV_MSGBOX_DISP_RULE_DST_REG_MAX 0x00000002
+#define NV_MSGBOX_DISP_RULE_DST_RIGHT_BIT 21:17
+
+/*!
+ * This structure is used to hold parameters for
+ * NV_MSGBOX_CMD_ARG1_ASYNC_REQUEST_CLOCK_LIMIT_GET
+ * Masks of NV_MSGBOX_OOB_CLOCK_LIMIT_CTRL_PARAMS_FLAGS_<XYZ>.
+ */
+typedef struct {
+ /*!
+ * Graphics clock limit in MHz
+ * if there is no cap, return
+ * NV_MSGBOX_CLOCK_LIMIT_GET_PARAMS_CLOCK_LIMIT_NOT_SET
+ */
+ NvU16 oobClientMin;
+ NvU16 oobClientMax;
+ NvU16 enforcedMin;
+ NvU16 enforcedMax;
+#define NV_MSGBOX_CLOCK_LIMIT_GET_PARAMS_CLOCK_LIMIT_NOT_SET 0xffff
+} NV_MSGBOX_CLOCK_LIMIT_GET_PARAMS;
+
+/*!
+ * This structure is used to hold parameters for
+ * NV_MSGBOX_CMD_ARG1_ASYNC_REQUEST_DEVICE_MODE_CONTROL
+ */
+typedef struct
+{
+ NvU16 modeType; //<! Mode type
+#define NV_MSGBOX_DEVICE_MODE_CONTROL_PARAMS_MODE_TYPE_ECC 0x00000000
+#define NV_MSGBOX_DEVICE_MODE_CONTROL_PARAMS_MODE_TYPE_MIG 0x00000001
+#define NV_MSGBOX_DEVICE_MODE_CONTROL_PARAMS_MODE_TYPE_DISABLE 0x00000002
+
+ NvU16 flags; //<! flags
+#define NV_MSGBOX_DEVICE_MODE_CONTROL_PARAMS_FLAGS_CONTROL 0:0
+#define NV_MSGBOX_DEVICE_MODE_CONTROL_PARAMS_FLAGS_CONTROL_CLEAR 0x00000000
+#define NV_MSGBOX_DEVICE_MODE_CONTROL_PARAMS_FLAGS_CONTROL_SET 0x00000001
+
+} NV_MSGBOX_DEVICE_MODE_CONTROL_PARAMS;
+
+//
+// This is the maximum number of curve points this API will be able to carry.
+// With the understanding that the maximum number of points currently
+// implemented in the RM is 3, we are leaving 2 additional slots as a room
+// for possible future growth, so that we don't have to spin the API definition
+// in case we ever want to implement more than 3 points.
+//
+#define NV_MSGBOX_THERMAL_FAN_V3_FAN_CURVE_POINTS_MAX_POINTS 5
+
+typedef struct
+{
+ NvS16 temperature; //<! degrees C, signed 16 bit value
+
+ union {
+ NvU16 level; //<! Fan PWM setting in the range 0..100
+ //<! 0: no rotation
+ //<! 100: full speed
+ NvU16 rpmValue; //<! tach speed in RPM
+ } fanSetting;
+} NV_MSGBOX_THERMAL_FAN_V3_FAN_CURVE_POINT;
+
+#define NV_MSGBOX_THERMAL_FAN_V3_FAN_CURVE_POINTS_ACTION_GET 0
+#define NV_MSGBOX_THERMAL_FAN_V3_FAN_CURVE_POINTS_ACTION_GET_DEFAULT 1
+#define NV_MSGBOX_THERMAL_FAN_V3_FAN_CURVE_POINTS_ACTION_SET 2
+typedef struct
+{
+ NvU8 action; //<! [in]
+ //<! NV_MSGBOX_THERMAL_FAN_V3_FAN_CURVE_POINTS_ACTION_GET:
+ //<! get currently active point values
+ //<! NV_MSGBOX_THERMAL_FAN_V3_FAN_CURVE_POINTS_ACTION_GET_DEFAULT:
+ //<! get VBIOS default point values
+ //<! NV_MSGBOX_THERMAL_FAN_V3_FAN_CURVE_POINTS_ACTION_SET:
+ //<! set new active point values
+
+ NvU8 fanIndex; //<! [in]
+
+ NvU8 numEffectivePoints; //<! [out] for fanGetCurvePoints. This is the
+ //<! number of points actually implemented
+ //<! and filled in the array below
+ //<! [in] for fanSetCurvePoints. This is how
+ //<! many points the caller is sending to
+ //<! the API. Must not exceed what was
+ //<! returned by fanGetCurvePoints.
+
+ NV_MSGBOX_THERMAL_FAN_V3_FAN_CURVE_POINT
+ curvePoints[NV_MSGBOX_THERMAL_FAN_V3_FAN_CURVE_POINTS_MAX_POINTS];
+ //<! [out] for fanGetCurvePoints.
+ //<! [in] for fanSetCurvePoints.
+} NV_MSGBOX_THERMAL_FAN_V3_FAN_CURVE_POINTS_PARAMS;
+
+#define NV_MSGBOX_POWER_HINT_PROFILES_ID_DMMA_PERF 0
+#define NV_MSGBOX_POWER_HINT_PROFILES_ID_DMMA_HIGH_K 1
+#define NV_MSGBOX_POWER_HINT_PROFILES_ID_DMMA_LOW_K 2
+#define NV_MSGBOX_POWER_HINT_PROFILES_ID_HMMA 3
+#define NV_MSGBOX_POWER_HINT_PROFILES_ID_IMMA 4
+#define NV_MSGBOX_POWER_HINT_PROFILES_ID_SGEMM 5
+#define NV_MSGBOX_POWER_HINT_PROFILES_ID_TRANSFORMER 6
+#define NV_MSGBOX_POWER_HINT_PROFILES_ID_CUSTOMER_CUSTOM_0 7
+#define NV_MSGBOX_POWER_HINT_PROFILES_ID_CUSTOMER_CUSTOM_1 8
+#define NV_MSGBOX_POWER_HINT_PROFILES_ID_CUSTOMER_CUSTOM_2 9
+#define NV_MSGBOX_POWER_HINT_PROFILES_ID_CUSTOMER_CUSTOM_3 10
+#define NV_MSGBOX_POWER_HINT_PROFILES_ID_CUSTOMER_CUSTOM_4 11
+#define NV_MSGBOX_POWER_HINT_PROFILES_ID_CUSTOMER_CUSTOM_5 12
+#define NV_MSGBOX_POWER_HINT_PROFILES_ID_CUSTOMER_CUSTOM_6 13
+#define NV_MSGBOX_POWER_HINT_PROFILES_ID_CUSTOMER_CUSTOM_7 14
+/*!
+ * This param is used for NV_MSGBOX_CMD_ARG1_ASYNC_REQUEST_POWER_HINT_GET
+ */
+typedef struct
+{
+ /*!
+ * [out] Power Hint in mW
+ */
+ NvU32 powermW;
+ /*!
+ * [in] Graphics Clock in MHz
+ */
+ NvU16 grClkMHz;
+ /*!
+ * [in] Memory Clock
+ */
+ NvU16 memClkMHz;
+ /*!
+ * [in] GPU Temperature
+ */
+ NvS16 temperature;
+ /*!
+ * [in] Profile ID
+ */
+ NvU8 profile;
+ // new param starting from here.
+} NV_MSGBOX_POWER_HINT_PARAMS;
+
+/*!
+ * This param is used for NV_MSGBOX_CMD_ARG1_ASYNC_REQUEST_CONFIGURE_PROGRAMMABLE_EDPP
+ */
+typedef struct
+{
+ /*!
+ * [out] Power Hint in mW
+ */
+ NvU32 data;
+} NV_MSGBOX_PROGRAMMABLE_EDPP_PARAMS;
+
+#define NV_MSGBOX_PROGRAMMABLE_EDPP_PARAMS_DATA 31:0
+#define NV_MSGBOX_PROGRAMMABLE_EDPP_PARAMS_DATA_OPERATION 1:0
+#define NV_MSGBOX_PROGRAMMABLE_EDPP_PARAMS_DATA_OPERATION_GET 0x0
+#define NV_MSGBOX_PROGRAMMABLE_EDPP_PARAMS_DATA_OPERATION_SET 0x1
+#define NV_MSGBOX_PROGRAMMABLE_EDPP_PARAMS_DATA_OPERATION_CLEAR 0x2
+
+#define NV_MSGBOX_PROGRAMMABLE_EDPP_PARAMS_DATA_MODE 3:2
+#define NV_MSGBOX_PROGRAMMABLE_EDPP_PARAMS_DATA_MODE_PERSISTENT 0x0
+#define NV_MSGBOX_PROGRAMMABLE_EDPP_PARAMS_DATA_MODE_ONESHOT 0x1
+
+#define NV_MSGBOX_PROGRAMMABLE_EDPP_PARAMS_DATA_LIMIT_CURRENT 10:4
+#define NV_MSGBOX_PROGRAMMABLE_EDPP_PARAMS_DATA_LIMIT_RATED 17:11
+#define NV_MSGBOX_PROGRAMMABLE_EDPP_PARAMS_DATA_LIMIT_MAXIMUM 24:18
+#define NV_MSGBOX_PROGRAMMABLE_EDPP_PARAMS_DATA_LIMIT_MINIMUM 31:25
+
+#define NV_MSGBOX_PROGRAMMABLE_EDPP_PARAMS_LIMIT_NOT_SET 0x7F
+
+/*!
+ * @brief Union of all possible parameter struct. Used to determine the maximum
+ * amount of space parameter blocks can take.
+ */
+typedef union {
+ NV_MSGBOX_PMGR_PWR_POWER_LIMIT_CONTROL_PARAMS tgpLimitControl;
+ NV_MSGBOX_THERMAL_FAN_V1_COUNT_PARAMS fanCountV1Get;
+ NV_MSGBOX_THERMAL_FAN_V1_INFO_PARAMS fanCountV1Info;
+ NV_MSGBOX_THERMAL_FAN_V1_STATUS_PARAMS fanCountV1Status;
+ NV_MSGBOX_OVERCLOCKING_LIMIT_CONTROL_PARAMS overclockingLimitControl;
+ NV_MSGBOX_ENERGY_COUNTER_STATUS_PARAMS energyCounterStatus;
+ NV_MSGBOX_VIOLATION_COUNTERS_STATUS_PARAMS violationCountersStatus;
+ NV_MSGBOX_UTILIZATION_RATE_PARAMS utilizationRate;
+ NV_MSGBOX_OOB_CLOCK_LIMIT_CTRL_PARAMS oobClockLimitCtrlParams;
+ NV_MSGBOX_DEVICE_MODE_CONTROL_PARAMS deviceModeControlParams;
+ NV_MSGBOX_TEST_MESSAGE_SEND_PARAMS testMessageSend;
+ NV_MSGBOX_CLOCK_LIMIT_GET_PARAMS clockLimitGet;
+ NV_MSGBOX_THERMAL_FAN_V3_FAN_CURVE_POINTS_PARAMS fanCurvePointsV3;
+ NV_MSGBOX_POWER_HINT_PARAMS powerHintParams;
+ NV_MSGBOX_PROGRAMMABLE_EDPP_PARAMS programmableEdppParams;
+} NV_MSGBOX_ASYNC_REQ_PARAMS_UNION;
+
+#endif // !NV_MSGBOX_NO_PARAM_STRUCTS
+
+/* Utility command constructor macros */
+
+#define NV_MSGBOX_CMD(opcode, arg1, arg2) \
+ ( \
+ DRF_DEF(_MSGBOX, _CMD, _OPCODE, opcode) | \
+ DRF_NUM(_MSGBOX, _CMD, _ARG1, (arg1)) | \
+ DRF_NUM(_MSGBOX, _CMD, _ARG2, (arg2)) | \
+ DRF_DEF(_MSGBOX, _CMD, _STATUS, _NULL) | \
+ DRF_DEF(_MSGBOX, _CMD, _RSVD, _INIT) | \
+ DRF_DEF(_MSGBOX, _CMD, _INTR, _PENDING) \
+ )
+#define NV_MSGBOX_CMD_NULL_CMD() NV_MSGBOX_CMD(_NULL_CMD, 0, 0)
+#define NV_MSGBOX_CMD_GET_CAP_DWORD(index) NV_MSGBOX_CMD(_GET_CAP_DWORD, (index), 0)
+#define NV_MSGBOX_CMD_GET_TEMP(source) NV_MSGBOX_CMD(_GET_TEMP, (source), 0)
+#define NV_MSGBOX_CMD_GET_EXT_TEMP(source) NV_MSGBOX_CMD(_GET_EXT_TEMP, (source), 0)
+#define NV_MSGBOX_CMD_GET_POWER(source) NV_MSGBOX_CMD(_GET_POWER, (source), 0)
+#define NV_MSGBOX_CMD_GET_SYS_ID_DATA(type, offset) \
+ NV_MSGBOX_CMD(_GET_SYS_ID_DATA, (type), (offset) / 4)
+#define NV_MSGBOX_CMD_SCRATCH_READ(off) NV_MSGBOX_CMD(_SCRATCH_READ, (off), 0)
+#define NV_MSGBOX_CMD_SCRATCH_WRITE(off, cnt) NV_MSGBOX_CMD(_SCRATCH_WRITE, (off), (cnt) - 1)
+#define NV_MSGBOX_CMD_SCRATCH_COPY(off, cnt) NV_MSGBOX_CMD(_SCRATCH_COPY, (off), (cnt) - 1)
+#define NV_MSGBOX_CMD_ASYNC_REQUEST(req_type, scratch_offset) \
+ NV_MSGBOX_CMD(_ASYNC_REQUEST, (req_type), (scratch_offset) / 4)
+#define NV_MSGBOX_CMD_ASYNC_REQUEST_POLL(req_id) \
+ NV_MSGBOX_CMD(_ASYNC_REQUEST, \
+ NV_MSGBOX_CMD_ARG1_ASYNC_REQUEST_POLL, \
+ (req_id))
+#define NV_MSGBOX_CMD_REGISTER_READ(addr) NV_MSGBOX_CMD(_REGISTER_ACCESS, \
+ NV_MSGBOX_CMD_ARG1_REGISTER_ACCESS_READ, \
+ (addr))
+#define NV_MSGBOX_CMD_REGISTER_WRITE(addr) NV_MSGBOX_CMD(_REGISTER_ACCESS, \
+ NV_MSGBOX_CMD_ARG1_REGISTER_ACCESS_WRITE, \
+ (addr))
+#define NV_MSGBOX_CMD_GET_THERM_PARAM(param) NV_MSGBOX_CMD(_GET_THERM_PARAM, \
+ NV_MSGBOX_CMD_ARG1_THERM_PARAM##param, 0)
+
+#define NV_MSGBOX_CMD_ACCESS_WP_MODE(action, state) \
+ NV_MSGBOX_CMD(_ACCESS_WP_MODE, (action), (state))
+
+#define NV_MSGBOX_CMD_GET_WP_MODE() \
+ NV_MSGBOX_CMD_ACCESS_WP_MODE(NV_MSGBOX_CMD_ARG1_ACCESS_WP_MODE_ACTION_GET, 0)
+
+#define NV_MSGBOX_CMD_SET_WP_MODE(state) \
+ NV_MSGBOX_CMD_ACCESS_WP_MODE(NV_MSGBOX_CMD_ARG1_ACCESS_WP_MODE_ACTION_SET, (state))
+
+#define NV_MSGBOX_CMD_GET_MISC_GPU_FLAGS(subtype, arg2) \
+ NV_MSGBOX_CMD(_GET_MISC_GPU_FLAGS, (subtype), (arg2))
+
+#define NV_MSGBOX_CMD_GET_ECC_ENABLED_STATE() \
+ NV_MSGBOX_CMD_GET_MISC_GPU_FLAGS(NV_MSGBOX_CMD_ARG1_GET_MISC_ECC_ENABLED_STATE, 0)
+
+#define NV_MSGBOX_CMD_GET_GPU_RESET_REQUIRED() \
+ NV_MSGBOX_CMD_GET_MISC_GPU_FLAGS(NV_MSGBOX_CMD_ARG1_GET_MISC_GPU_RESET_REQUIRED, 0)
+
+#define NV_MSGBOX_CMD_GET_MISC_GPU_FLAGS_PAGE_0() \
+ NV_MSGBOX_CMD_GET_MISC_GPU_FLAGS(NV_MSGBOX_CMD_ARG1_GET_MISC_GPU_FLAGS_PAGE_0, 0)
+
+#define NV_MSGBOX_CMD_GET_MISC_GPU_FLAGS_PAGE_1() \
+ NV_MSGBOX_CMD_GET_MISC_GPU_FLAGS(NV_MSGBOX_CMD_ARG1_GET_MISC_GPU_FLAGS_PAGE_1, 0)
+
+#define NV_MSGBOX_CMD_GET_NVLINK_INFO(subtype, arg2) \
+ NV_MSGBOX_CMD(_GET_NVLINK_INFO, (subtype), (arg2))
+
+#define NV_MSGBOX_CMD_GET_NVLINK_INFO_ERR_CNT(errtype, link_index) \
+ NV_MSGBOX_CMD(_GET_NVLINK_INFO, \
+ NV_MSGBOX_CMD_ARG1_GET_NVLINK_INFO_ERR_COUNTER##errtype,\
+ (link_index))
+
+#define NV_MSGBOX_CMD_GET_NVLINK_INFO_ERR_STATE(errtype, link_page) \
+ NV_MSGBOX_CMD(_GET_NVLINK_INFO, \
+ NV_MSGBOX_CMD_ARG1_GET_NVLINK_INFO##errtype##_ERROR_STATE, \
+ (link_page))
+
+#define NV_MSGBOX_CMD_GET_GPU_UTIL_COUNTERS(subtype) \
+ NV_MSGBOX_CMD(_GPU_UTIL_COUNTERS, (subtype), 0)
+
+#define NV_MSGBOX_CMD_GET_GPU_UTIL_COUNTERS_CONTEXT_TIME() \
+ NV_MSGBOX_CMD_GET_GPU_UTIL_COUNTERS(NV_MSGBOX_CMD_ARG1_GPU_UTIL_COUNTERS_CONTEXT_TIME)
+
+#define NV_MSGBOX_CMD_GET_GPU_UTIL_COUNTERS_SM_TIME() \
+ NV_MSGBOX_CMD_GET_GPU_UTIL_COUNTERS(NV_MSGBOX_CMD_ARG1_GPU_UTIL_COUNTERS_SM_TIME)
+
+#define NV_MSGBOX_CMD_GET_GPU_UTIL_COUNTERS_RESET_COUNTERS() \
+ NV_MSGBOX_CMD_GET_GPU_UTIL_COUNTERS(NV_MSGBOX_CMD_ARG1_GPU_UTIL_COUNTERS_RESET_COUNTERS)
+
+#define NV_MSGBOX_CMD_GET_NVLINK_INFO_ERR_CNT_REPLAY(link_index) \
+ NV_MSGBOX_CMD_GET_NVLINK_INFO_ERR_CNT(_REPLAY, (link_index))
+
+#define NV_MSGBOX_CMD_GET_NVLINK_INFO_ERR_CNT_RECOVERY(link_index) \
+ NV_MSGBOX_CMD_GET_NVLINK_INFO_ERR_CNT(_RECOVERY, (link_index))
+
+#define NV_MSGBOX_CMD_GET_NVLINK_INFO_ERR_CNT_FLIT_CRC(link_index) \
+ NV_MSGBOX_CMD_GET_NVLINK_INFO_ERR_CNT(_FLIT_CRC, (link_index))
+
+#define NV_MSGBOX_CMD_GET_NVLINK_INFO_ERR_CNT_DATA_CRC(link_index) \
+ NV_MSGBOX_CMD_GET_NVLINK_INFO_ERR_CNT(_DATA_CRC, (link_index))
+
+#define NV_MSGBOX_CMD_GET_CLOCK_FREQ_INFO(subtype, clkdomain) \
+ NV_MSGBOX_CMD(_GET_CLOCK_FREQ_INFO, (subtype), (clkdomain))
+
+#define NV_MSGBOX_CMD_GET_CLOCK_FREQ_INFO_GPC_CURRENT() \
+ NV_MSGBOX_CMD_GET_CLOCK_FREQ_RANGE(NV_MSGBOX_CMD_ARG1_GET_CLOCK_FREQ_RANGE_GPC_CURRENT, \
+ NV_MSGBOX_CMD_ARG2_GET_CLOCK_FREQ_INFO_GPCCLK)
+
+#define NV_MSGBOX_CMD_GET_CLOCK_FREQ_INFO_GPC_MIN() \
+ NV_MSGBOX_CMD_GET_CLOCK_FREQ_RANGE(NV_MSGBOX_CMD_ARG1_GET_CLOCK_FREQ_INFO_GPC_MIN, \
+ NV_MSGBOX_CMD_ARG2_GET_CLOCK_FREQ_INFO_GPCCLK)
+
+#define NV_MSGBOX_CMD_GET_CLOCK_FREQ_INFO_GPC_MAX() \
+ NV_MSGBOX_CMD_GET_CLOCK_FREQ_RANGE(NV_MSGBOX_CMD_ARG1_GET_CLOCK_FREQ_INFO_GPC_MAX, \
+ NV_MSGBOX_CMD_ARG2_GET_CLOCK_FREQ_INFO_GPCCLK)
+
+#define NV_MSGBOX_CMD_GET_DRIVER_EVENT_MSG(ptr) NV_MSGBOX_CMD(_GET_DRIVER_EVENT_MSG, 0, (ptr))
+
+//
+// ECC V2
+//
+#define NV_MSGBOX_CMD_ECC_V2_CNT_FB(src, type, partition, slice) \
+ ( \
+ NV_MSGBOX_CMD(_GET_ECC_V2, 0, 0) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V2_SEL, _CNT) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V2_CNT_DEV, _FB) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V2_CNT_FB_SRC, src) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V2_CNT_TYPE, type) | \
+ DRF_NUM(_MSGBOX, _CMD, _ARG2_ECC_V2_FB_PARTITION, (partition)) | \
+ DRF_NUM(_MSGBOX, _CMD, _ARG2_ECC_V2_FB_SLICE, (slice)) \
+ )
+
+#define NV_MSGBOX_CMD_ECC_V2_CNT_GR(src, type, gpc, tpc) \
+ ( \
+ NV_MSGBOX_CMD(_GET_ECC_V2, 0, 0) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V2_SEL, _CNT) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V2_CNT_DEV, _GR) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V2_CNT_GR_SRC, src) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V2_CNT_TYPE, type) | \
+ DRF_NUM(_MSGBOX, _CMD, _ARG2_ECC_V2_GR_GPC, (gpc)) | \
+ DRF_NUM(_MSGBOX, _CMD, _ARG2_ECC_V2_GR_TPC, (tpc)) \
+ )
+
+#define NV_MSGBOX_CMD_ECC_V2_FBA_CUMUL(partition, slice) \
+ ( \
+ NV_MSGBOX_CMD(_GET_ECC_V2, 0, 0) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V2_SEL, _FBA) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V2_FBA_SC, _CUMUL) | \
+ DRF_NUM(_MSGBOX, _CMD, _ARG2_ECC_V2_FB_PARTITION, (partition)) | \
+ DRF_NUM(_MSGBOX, _CMD, _ARG2_ECC_V2_FB_SLICE, (slice)) \
+ )
+
+#define NV_MSGBOX_CMD_ECC_V2_FBA_IND_ADDR(partition, slice, index) \
+ ( \
+ NV_MSGBOX_CMD(_GET_ECC_V2, 0, 0) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V2_SEL, _FBA) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V2_FBA_SC, _IND) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V2_FBA_IND_FLD, _ADDR) | \
+ DRF_NUM(_MSGBOX, _CMD, _ARG1_ECC_V2_FBA_IND_INDEX, (index)) | \
+ DRF_NUM(_MSGBOX, _CMD, _ARG2_ECC_V2_FB_PARTITION, (partition)) | \
+ DRF_NUM(_MSGBOX, _CMD, _ARG2_ECC_V2_FB_SLICE, (slice)) \
+ )
+
+#define NV_MSGBOX_CMD_ECC_V2_FBA_IND_CTRS(partition, slice, index) \
+ ( \
+ NV_MSGBOX_CMD(_GET_ECC_V2, 0, 0) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V2_SEL, _FBA) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V2_FBA_SC, _IND) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V2_FBA_IND_FLD, _CTRS) | \
+ DRF_NUM(_MSGBOX, _CMD, _ARG1_ECC_V2_FBA_IND_INDEX, (index)) | \
+ DRF_NUM(_MSGBOX, _CMD, _ARG2_ECC_V2_FB_PARTITION, (partition)) | \
+ DRF_NUM(_MSGBOX, _CMD, _ARG2_ECC_V2_FB_SLICE, (slice)) \
+ )
+
+//
+// ECC V3
+//
+#define NV_MSGBOX_CMD_ECC_V3_CNT_FB_LTC(type, partition, slice) \
+ ( \
+ NV_MSGBOX_CMD(_GET_ECC_V3, 0, 0) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V3_SEL, _CNT) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V3_CNT_DEV, _FB) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V3_CNT_FB_SRC, _LTC) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V3_CNT_TYPE, type) | \
+ DRF_NUM(_MSGBOX, _CMD, _ARG2_ECC_V3_FB_PARTITION, (partition)) | \
+ DRF_NUM(_MSGBOX, _CMD, _ARG2_ECC_V3_FB_SLICE, (slice)) \
+ )
+
+#define NV_MSGBOX_CMD_ECC_V3_CNT_FB_FB(type, partition, subpart) \
+ ( \
+ NV_MSGBOX_CMD(_GET_ECC_V3, 0, 0) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V3_SEL, _CNT) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V3_CNT_DEV, _FB) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V3_CNT_FB_SRC, _FB) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V3_CNT_TYPE, type) | \
+ DRF_NUM(_MSGBOX, _CMD, _ARG2_ECC_V3_FB_PARTITION, (partition)) | \
+ DRF_NUM(_MSGBOX, _CMD, _ARG2_ECC_V3_FB_SUBPARTITION, (subpart)) \
+ )
+
+#define NV_MSGBOX_CMD_ECC_V3_CNT_GR(src, type, gpc, tpc) \
+ ( \
+ NV_MSGBOX_CMD(_GET_ECC_V3, 0, 0) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V3_SEL, _CNT) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V3_CNT_DEV, _GR) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V3_CNT_GR_SRC, src) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V3_CNT_TYPE, type) | \
+ DRF_NUM(_MSGBOX, _CMD, _ARG2_ECC_V3_GR_GPC, (gpc)) | \
+ DRF_NUM(_MSGBOX, _CMD, _ARG2_ECC_V3_GR_TPC, (tpc)) \
+ )
+
+#define NV_MSGBOX_CMD_ECC_V3_CNT_GR_TEX(type, gpc, tpc, tex) \
+ ( \
+ NV_MSGBOX_CMD(_GET_ECC_V3, 0, 0) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V3_SEL, _CNT) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V3_CNT_DEV, _GR) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V3_CNT_GR_SRC, _TEX) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V3_CNT_TYPE, type) | \
+ DRF_NUM(_MSGBOX, _CMD, _ARG2_ECC_V3_GR_GPC, (gpc)) | \
+ DRF_NUM(_MSGBOX, _CMD, _ARG2_ECC_V3_GR_TPC, (tpc)) | \
+ DRF_NUM(_MSGBOX, _CMD, _ARG2_ECC_V3_GR_TEX, (tex)) \
+ )
+
+#define NV_MSGBOX_CMD_ECC_V3_FBA_IND_ADDR(partition, subpart, index) \
+ ( \
+ NV_MSGBOX_CMD(_GET_ECC_V3, 0, 0) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V3_SEL, _FBA) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V3_FBA_SC, _IND) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V3_FBA_IND_FLD, _ADDR) | \
+ DRF_NUM(_MSGBOX, _CMD, _ARG1_ECC_V3_FBA_IND_INDEX, (index)) | \
+ DRF_NUM(_MSGBOX, _CMD, _ARG2_ECC_V3_FB_PARTITION, (partition)) | \
+ DRF_NUM(_MSGBOX, _CMD, _ARG2_ECC_V3_FB_SUBPARTITION, (subpart)) \
+ )
+
+#define NV_MSGBOX_CMD_ECC_V3_FBA_IND_CTRS(partition, subpart, index) \
+ ( \
+ NV_MSGBOX_CMD(_GET_ECC_V3, 0, 0) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V3_SEL, _FBA) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V3_FBA_SC, _IND) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V3_FBA_IND_FLD, _CTRS) | \
+ DRF_NUM(_MSGBOX, _CMD, _ARG1_ECC_V3_FBA_IND_INDEX, (index)) | \
+ DRF_NUM(_MSGBOX, _CMD, _ARG2_ECC_V3_FB_PARTITION, (partition)) | \
+ DRF_NUM(_MSGBOX, _CMD, _ARG2_ECC_V3_FB_SUBPARTITION, (subpart)) \
+ )
+
+//
+// ECC V4
+//
+#define NV_MSGBOX_CMD_ECC_V4_CNT_FB_LTC(type, partition, slice) \
+ ( \
+ NV_MSGBOX_CMD(_GET_ECC_V4, 0, 0) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V4_SEL, _CNT) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V4_CNT_DEV, _FB) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V4_CNT_FB_SRC, _LTC) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V4_CNT_TYPE, type) | \
+ DRF_NUM(_MSGBOX, _CMD, _ARG2_ECC_V4_FB_PARTITION, (partition)) | \
+ DRF_NUM(_MSGBOX, _CMD, _ARG2_ECC_V4_FB_SLICE, (slice)) \
+ )
+
+#define NV_MSGBOX_CMD_ECC_V4_CNT_FB_FB(type, partition, subpart) \
+ ( \
+ NV_MSGBOX_CMD(_GET_ECC_V4, 0, 0) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V4_SEL, _CNT) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V4_CNT_DEV, _FB) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V4_CNT_FB_SRC, _FB) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V4_CNT_TYPE, type) | \
+ DRF_NUM(_MSGBOX, _CMD, _ARG2_ECC_V4_FB_PARTITION, (partition)) | \
+ DRF_NUM(_MSGBOX, _CMD, _ARG2_ECC_V4_FB_SUBPARTITION, (subpart)) \
+ )
+
+#define NV_MSGBOX_CMD_ECC_V4_CNT_GR(src, type, gpc, tpc) \
+ ( \
+ NV_MSGBOX_CMD(_GET_ECC_V4, 0, 0) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V4_SEL, _CNT) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V4_CNT_DEV, _GR) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V4_CNT_GR_SRC, src) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V4_CNT_TYPE, type) | \
+ DRF_NUM(_MSGBOX, _CMD, _ARG2_ECC_V4_GR_GPC, (gpc)) | \
+ DRF_NUM(_MSGBOX, _CMD, _ARG2_ECC_V4_GR_TPC, (tpc)) \
+ )
+
+#define NV_MSGBOX_CMD_ECC_V4_CNT_GR_TEX(type, gpc, tpc, tex) \
+ ( \
+ NV_MSGBOX_CMD(_GET_ECC_V4, 0, 0) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V4_SEL, _CNT) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V4_CNT_DEV, _GR) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V4_CNT_GR_SRC, _TEX) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V4_CNT_TYPE, type) | \
+ DRF_NUM(_MSGBOX, _CMD, _ARG2_ECC_V4_GR_GPC, (gpc)) | \
+ DRF_NUM(_MSGBOX, _CMD, _ARG2_ECC_V4_GR_TPC, (tpc)) | \
+ DRF_NUM(_MSGBOX, _CMD, _ARG2_ECC_V4_GR_TEX, (tex)) \
+ )
+
+#define NV_MSGBOX_CMD_ECC_V4_FBA_IND_ADDR(partition, subpart, index) \
+ ( \
+ NV_MSGBOX_CMD(_GET_ECC_V4, 0, 0) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V4_SEL, _FBA) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V4_FBA_SC, _IND) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V4_FBA_IND_FLD, _ADDR) | \
+ DRF_NUM(_MSGBOX, _CMD, _ARG1_ECC_V4_FBA_IND_INDEX, (index)) | \
+ DRF_NUM(_MSGBOX, _CMD, _ARG2_ECC_V4_FB_PARTITION, (partition)) | \
+ DRF_NUM(_MSGBOX, _CMD, _ARG2_ECC_V4_FB_SUBPARTITION, (subpart)) \
+ )
+
+#define NV_MSGBOX_CMD_ECC_V4_FBA_IND_CTRS(partition, subpart, index) \
+ ( \
+ NV_MSGBOX_CMD(_GET_ECC_V4, 0, 0) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V4_SEL, _FBA) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V4_FBA_SC, _IND) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V4_FBA_IND_FLD, _CTRS) | \
+ DRF_NUM(_MSGBOX, _CMD, _ARG1_ECC_V4_FBA_IND_INDEX, (index)) | \
+ DRF_NUM(_MSGBOX, _CMD, _ARG2_ECC_V4_FB_PARTITION, (partition)) | \
+ DRF_NUM(_MSGBOX, _CMD, _ARG2_ECC_V4_FB_SUBPARTITION, (subpart)) \
+ )
+
+//
+// ECC V5
+//
+#define NV_MSGBOX_CMD_ECC_V5_CNT(index) \
+ ( \
+ NV_MSGBOX_CMD(_GET_ECC_V5, 0, 0) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V5_SEL, _COUNTS) | \
+ DRF_NUM(_MSGBOX, _CMD, _ARG1_ECC_V5_COUNTS_INDEX_LO, (index)) | \
+ DRF_NUM(_MSGBOX, _CMD, _ARG2_ECC_V5_COUNTS_INDEX_HI, (index) >> 7) \
+ )
+#define NV_MSGBOX_ECC_V5_COUNTS_NUM_ENTRIES 600
+
+#define NV_MSGBOX_CMD_ECC_V5_CNT_HDR_META(index) \
+ ( \
+ NV_MSGBOX_CMD_ECC_V5_CNT(index) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG2_ECC_V5_COUNTS_TYPE, _HDR_META) \
+ )
+
+#define NV_MSGBOX_CMD_ECC_V5_CNT_REGN_CORRECTED_TOTAL(index) \
+ ( \
+ NV_MSGBOX_CMD_ECC_V5_CNT(index) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG2_ECC_V5_COUNTS_TYPE, _REGN_CORRECTED_TOTAL) \
+ )
+
+#define NV_MSGBOX_CMD_ECC_V5_CNT_REGN_CORRECTED_UNIQUE(index) \
+ ( \
+ NV_MSGBOX_CMD_ECC_V5_CNT(index) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG2_ECC_V5_COUNTS_TYPE, _REGN_CORRECTED_UNIQUE) \
+ )
+
+#define NV_MSGBOX_CMD_ECC_V5_CNT_REGN_UNCORRECTED_TOTAL(index) \
+ ( \
+ NV_MSGBOX_CMD_ECC_V5_CNT(index) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG2_ECC_V5_COUNTS_TYPE, _REGN_UNCORRECTED_TOTAL) \
+ )
+
+#define NV_MSGBOX_CMD_ECC_V5_CNT_REGN_UNCORRECTED_UNIQUE(index) \
+ ( \
+ NV_MSGBOX_CMD_ECC_V5_CNT(index) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG2_ECC_V5_COUNTS_TYPE, _REGN_UNCORRECTED_UNIQUE) \
+ )
+
+#define NV_MSGBOX_CMD_ECC_V5_CNT_ADDR_ADDR(index) \
+ ( \
+ NV_MSGBOX_CMD_ECC_V5_CNT(index) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG2_ECC_V5_COUNTS_TYPE, _ADDR_ADDR) \
+ )
+
+#define NV_MSGBOX_CMD_ECC_V5_CNT_ADDR_UNCORRECTED_COUNTS(index) \
+ ( \
+ NV_MSGBOX_CMD_ECC_V5_CNT(index) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG2_ECC_V5_COUNTS_TYPE, _ADDR_UNCORRECTED_COUNTS) \
+ )
+
+#define NV_MSGBOX_CMD_ECC_V5_CNT_ADDR_CORRECTED_TOTAL(index) \
+ ( \
+ NV_MSGBOX_CMD_ECC_V5_CNT(index) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG2_ECC_V5_COUNTS_TYPE, _ADDR_CORRECTED_TOTAL) \
+ )
+
+#define NV_MSGBOX_CMD_ECC_V5_CNT_ADDR_CORRECTED_UNIQUE(index) \
+ ( \
+ NV_MSGBOX_CMD_ECC_V5_CNT(index) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG2_ECC_V5_COUNTS_TYPE, _ADDR_CORRECTED_UNIQUE) \
+ )
+
+#define NV_MSGBOX_CMD_ECC_V5_ERR_BUF(index) \
+ ( \
+ NV_MSGBOX_CMD(_GET_ECC_V5, 0, 0) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_ECC_V5_SEL, _ERR_BUFFER) | \
+ DRF_NUM(_MSGBOX, _CMD, _ARG1_ECC_V5_ERR_BUF_INDEX, (index)) \
+ )
+#define NV_MSGBOX_ECC_V5_ERR_BUF_NUM_ENTRIES 16
+
+#define NV_MSGBOX_CMD_ECC_V5_ERR_BUF_ERR_TYPE_META(index) \
+ ( \
+ NV_MSGBOX_CMD_ECC_V5_ERR_BUF(index) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG2_ECC_V5_ERR_BUF_TYPE, _ERR_TYPE_META) \
+ )
+
+#define NV_MSGBOX_CMD_ECC_V5_ERR_BUF_TIME_STAMP(index) \
+ ( \
+ NV_MSGBOX_CMD_ECC_V5_ERR_BUF(index) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG2_ECC_V5_ERR_BUF_TYPE, _TIME_STAMP) \
+ )
+
+#define NV_MSGBOX_CMD_ECC_V5_ERR_BUF_ADDR(index) \
+ ( \
+ NV_MSGBOX_CMD_ECC_V5_ERR_BUF(index) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG2_ECC_V5_ERR_BUF_TYPE, _ADDR) \
+ )
+
+#define NV_MSGBOX_CMD_SET_COPY_DATA(cmd) \
+ ( \
+ FLD_SET_DRF(_MSGBOX, _CMD, _COPY_DATA, _ON, (cmd)) \
+ )
+
+#define NV_MSGBOX_CMD_GET_PCIE_LINK_INFO_1(page) \
+ ( \
+ NV_MSGBOX_CMD(_GET_PCIE_LINK_INFO, \
+ (page), \
+ 0) \
+ )
+
+// We use the fact here that for pages ## 8 and 9 Arg2 definitions are similar
+#define NV_MSGBOX_CMD_GET_PCIE_LINK_INFO_2(page, lane, speed) \
+ ( \
+ NV_MSGBOX_CMD(_GET_PCIE_LINK_INFO, \
+ (page), \
+ DRF_NUM(_MSGBOX, _CMD_ARG2_GET_PCIE_LINK_INFO_PAGE_8, \
+ _LANE_IDX, (lane)) | \
+ DRF_NUM(_MSGBOX, _CMD_ARG2_GET_PCIE_LINK_INFO_PAGE_8, \
+ _SPEED_SELECT, (speed))) \
+ )
+
+#define NV_MSGBOX_CMD_GPM_GET_METRIC(type, metric, req_ci_metrics, partition) \
+ ( \
+ NV_MSGBOX_CMD(_GPU_PERFORMANCE_MONITORING, 0, 0) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_GPM_ACTION, type) | \
+ DRF_NUM(_MSGBOX, _CMD, _ARG1_GPM_METRIC, metric) | \
+ DRF_NUM(_MSGBOX, _CMD, _ARG2_GPM_CI_METRICS_REQUESTED, req_ci_metrics) | \
+ DRF_NUM(_MSGBOX, _CMD, _ARG2_GPM_PARTITION_INDEX, partition) \
+ )
+
+#define NV_MSGBOX_CMD_GPM_GET_METRIC_AGGREGATE(type, metric) \
+ ( \
+ NV_MSGBOX_CMD(_GPU_PERFORMANCE_MONITORING, 0, 0) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_GPM_ACTION, type) | \
+ DRF_NUM(_MSGBOX, _CMD, _ARG1_GPM_METRIC, metric) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG2, _GPM_PARTITION_AGGREGATE) \
+ )
+
+#define NV_MSGBOX_DATA_IN_GPM(instance_id, ci_index) \
+ ( \
+ DRF_NUM(_MSGBOX, _DATA, _GPM_NVDEC_INSTANCE, instance_id) | \
+ DRF_NUM(_MSGBOX, _DATA, _GPM_COMPUTE_INSTANCE_INDEX, ci_index) \
+ )
+
+#define NV_MSGBOX_CMD_GPM_SET_MULTIPLIER(multiplier) \
+ ( \
+ NV_MSGBOX_CMD(_GPU_PERFORMANCE_MONITORING, 0, 0) | \
+ DRF_DEF(_MSGBOX, _CMD, _ARG1_GPM_ACTION, _SET_MULTIPLIER) | \
+ DRF_NUM(_MSGBOX, _CMD, _ARG2_GPM_MULTIPLIER, (multiplier)) \
+ )
+
+#define NV_MSGBOX_GET_CMD_OPCODE(cmd) DRF_VAL(_MSGBOX, _CMD, _OPCODE, (cmd))
+#define NV_MSGBOX_GET_CMD_ARG1(cmd) DRF_VAL(_MSGBOX, _CMD, _ARG1 , (cmd))
+#define NV_MSGBOX_GET_CMD_ARG2(cmd) DRF_VAL(_MSGBOX, _CMD, _ARG2 , (cmd))
+#define NV_MSGBOX_GET_CMD_STATUS(cmd) DRF_VAL(_MSGBOX, _CMD, _STATUS, (cmd))
+#define NV_MSGBOX_CMD_IS_COPY_DATA_SET(cmd) \
+ FLD_TEST_DRF(_MSGBOX, _CMD, _COPY_DATA, _ON, (cmd))
+
+#define NV_MSGBOX_CAP_IS_AVAILABLE(caps, idx, name) \
+ !(FLD_TEST_DRF(_MSGBOX, _DATA_CAP_##idx, name, _NOT_AVAILABLE, (caps)[idx]))
+
+#define NV_MSGBOX_CAP_SET_AVAILABLE(caps, idx, name) \
+ (caps)[idx] = FLD_SET_DRF(_MSGBOX, _DATA_CAP_##idx, name, _AVAILABLE, \
+ (caps)[idx])
+
+/********************************************************************************
+ * *
+ * GPU REQUESTS *
+ * *
+ ********************************************************************************/
+
+//
+// Encoding:
+// 31 24 23 16 15 8 7 0
+// .-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-.
+// | REQUEST ID | ARG2 | ARG1 | OPCODE | DATA_OUT
+// `-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-'
+//
+#define NV_MSGBOX_REQ_OPCODE 7:0
+#define NV_MSGBOX_REQ_OPCODE_CPU_PCONTROL 0x00000000
+#define NV_MSGBOX_REQ_OPCODE_SYS_PCONTROL 0x00000001
+#define NV_MSGBOX_REQ_ARG1 15:8
+#define NV_MSGBOX_REQ_ARG2 23:16
+#define NV_MSGBOX_REQ_REQUEST_ID 31:24
+#define NV_MSGBOX_REQ(opcode, arg1, arg2, requestId) \
+ ( \
+ DRF_NUM(_MSGBOX, _REQ, _OPCODE , (opcode)) | \
+ DRF_NUM(_MSGBOX, _REQ, _ARG1 , (arg1)) | \
+ DRF_NUM(_MSGBOX, _REQ, _ARG2 , (arg2)) | \
+ DRF_NUM(_MSGBOX, _REQ, _REQUEST_ID, (requestId)) \
+ )
+
+/* ---------------- CPU Performance Control (PCONTROL) ------------------------ */
+
+//
+// CPU_PCONTROL
+//
+// Description:
+// GPU-Request used to retrieve information and control various aspects of
+// CPU performance.
+//
+// Common Encoding:
+// 7 3 2 0
+// .-+-+-+-+-+-+-+-.
+// | TARGET | ACT | ARG1
+// `-+-+-+-+-+-+-+-'
+//
+// Notes:
+// arg1, arg2, and data encoding (fields are relative to zero, not relative
+// to their position in the DATA_OUT register).
+//
+#define NV_MSGBOX_REQ_CPU_PCONTROL_ARG1_ACTION 2:0
+#define NV_MSGBOX_REQ_CPU_PCONTROL_ARG1_ACTION_RSVD1 0x00000000
+#define NV_MSGBOX_REQ_CPU_PCONTROL_ARG1_ACTION_RSVD2 0x00000001
+#define NV_MSGBOX_REQ_CPU_PCONTROL_ARG1_ACTION_SET_LIMIT 0x00000002
+#define NV_MSGBOX_REQ_CPU_PCONTROL_ARG1_TARGET 7:3
+#define NV_MSGBOX_REQ_CPU_PCONTROL_ARG1_TARGET_PSTATE 0x00000000
+
+#define NV_MSGBOX_REQ_CPU_PCONTROL_ARG1_SET_ACTION(arg1, action) \
+ (arg1) = FLD_SET_DRF(_MSGBOX_REQ, _CPU_PCONTROL_ARG1, _ACTION, \
+ action, (arg1))
+
+#define NV_MSGBOX_REQ_CPU_PCONTROL_ARG1_GET_ACTION(arg1) \
+ DRF_VAL(_MSGBOX_REQ, _CPU_PCONTROL_ARG1, _ACTION, (arg1))
+
+#define NV_MSGBOX_REQ_CPU_PCONTROL_ARG1_SET_TARGET(arg1, target) \
+ (arg1) = FLD_SET_DRF(_MSGBOX_REQ, _CPU_PCONTROL_ARG1, _TARGET, \
+ target, (arg1))
+
+#define NV_MSGBOX_REQ_CPU_PCONTROL_ARG1_GET_TARGET(arg1) \
+ DRF_VAL(_MSGBOX_REQ, _CPU_PCONTROL_ARG1, _TARGET, (arg1))
+
+//
+// Setting CPU Pstate Limits:
+//
+// Inputs:
+// ARG1 - {TARGET=PSTATE, ACTION=SET_LIMIT}
+// ARG2 - Stores desired CPU Pstate limit
+//
+// Outputs:
+// none
+//
+// Encoding:
+// 7 3 2 0 7 0
+// .-+-+-+-+-+-+-+-. .-+-+-+-+-+-+-+-.
+// | TARGET | ACT | ARG1 | VALUE | ARG2
+// `-+-+-+-+-+-+-+-' `-+-+-+-+-+-+-+-'
+//
+#define NV_MSGBOX_REQ_CPU_PCONTROL_ARG2_PSTATE_SET_LIMIT_VALUE 7:0
+
+#define NV_MSGBOX_REQ_CPU_PCONTROL_ARG2_PSTATE_SET_LIMIT_SET_VALUE(arg2, limit) \
+ (arg2) = FLD_SET_DRF_NUM(_MSGBOX_REQ, _CPU_PCONTROL_ARG2, \
+ _PSTATE_SET_LIMIT_VALUE, (limit), (arg2))
+
+#define NV_MSGBOX_REQ_CPU_PCONTROL_ARG2_PSTATE_SET_LIMIT_GET_VALUE(arg2) \
+ DRF_VAL(_MSGBOX_REQ, _CPU_PCONTROL_ARG2, _PSTATE_SET_LIMIT_VALUE, (arg2))
+
+/* ----------------------- System Performance Control ------------------------- */
+
+//
+// SYS_PCONTROL
+//
+// Description:
+// GPU-Request used to retrieve information and control various aspects of
+// system-performance.
+//
+// Common Encoding:
+// 7 3 2 0 7 0
+// .-+-+-+-+-+-+-+-. .-+-+-+-+-+-+-+-.
+// | TARGET | ACT | ARG1 |0 0 0 0 0 0 0 0| ARG2 (reserved)
+// `-+-+-+-+-+-+-+-' `-+-+-+-+-+-+-+-'
+//
+// Notes:
+// - TARGET accepts NV0000_CTRL_SYSTEM_PARAM_* definitions
+// - arg1, arg2, and data encoding (fields are relative to zero, not relative
+// to their position in the DATA_OUT register).
+//
+#define NV_MSGBOX_REQ_SYS_PCONTROL_ARG1_ACTION 2:0
+#define NV_MSGBOX_REQ_SYS_PCONTROL_ARG1_ACTION_GET_STATUS 0x00000000
+#define NV_MSGBOX_REQ_SYS_PCONTROL_ARG1_ACTION_GET_LIMIT 0x00000001
+#define NV_MSGBOX_REQ_SYS_PCONTROL_ARG1_TARGET 7:3
+#define NV_MSGBOX_REQ_SYS_PCONTROL_ARG2_RSVD 7:0
+
+#define NV_MSGBOX_REQ_SYS_PCONTROL_ARG1_SET_ACTION(arg1, action) \
+ (arg1) = FLD_SET_DRF(_MSGBOX_REQ, _SYS_PCONTROL_ARG1, _ACTION, \
+ action, (arg1))
+
+#define NV_MSGBOX_REQ_SYS_PCONTROL_ARG1_GET_ACTION(arg1) \
+ DRF_VAL(_MSGBOX_REQ, _SYS_PCONTROL_ARG1, _ACTION, (arg1))
+
+#define NV_MSGBOX_REQ_SYS_PCONTROL_ARG1_SET_TARGET(arg1, target) \
+ (arg1) = FLD_SET_DRF_NUM(_MSGBOX_REQ, _SYS_PCONTROL_ARG1, _TARGET, \
+ (target), (arg1))
+
+#define NV_MSGBOX_REQ_SYS_PCONTROL_ARG1_GET_TARGET(arg1) \
+ DRF_VAL(_MSGBOX_REQ, _SYS_PCONTROL_ARG1, _TARGET, (arg1))
+
+#endif /* _SMBPBI_H */
diff --git a/userspace/sdks/nv570/nvalloc/common/inc/oob/smbpbi_impl.h b/userspace/sdks/nv570/nvalloc/common/inc/oob/smbpbi_impl.h
new file mode 100644
index 0000000..e7052c8
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/common/inc/oob/smbpbi_impl.h
@@ -0,0 +1,45 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2019-2020 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+#ifndef _SMBPBI_IMPL_H
+#define _SMBPBI_IMPL_H
+/*!
+ * This header file stores implementation dependent parameters of the SMBPBI server.
+ */
+
+/*!
+ * Maximum number of individual requests in a bundle
+ */
+#define NV_MSGBOX_PARAM_MAX_BUNDLE_SIZE 4
+
+/*!
+ * Maximum number of Result Disposition Rules
+ */
+#define NV_MSGBOX_PARAM_MAX_DISP_RULES 10
+
+/*!
+ * Maximum length of the Driver Event Message text string is 80, including
+ * the terminating NUL character.
+ */
+#define NV_MSGBOX_MAX_DRIVER_EVENT_MSG_TXT_SIZE 80
+
+#endif // _SMBPBI_IMPL_H
diff --git a/userspace/sdks/nv570/nvalloc/common/inc/oob/smbpbi_priv.h b/userspace/sdks/nv570/nvalloc/common/inc/oob/smbpbi_priv.h
new file mode 100644
index 0000000..53b48da
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/common/inc/oob/smbpbi_priv.h
@@ -0,0 +1,59 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2010-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _SMBPBI_PRIV_H_
+#define _SMBPBI_PRIV_H_
+
+/*!
+ * This file contains NVIDIA private defines for the SMBPBI
+ * interface.
+ */
+
+#include "oob/smbpbi.h"
+
+// MSGBOX command word structure
+
+//
+// Reserving opcodes above 0xC0 for internal/private functionationality.
+//
+// These opcodes should not be included in any documentation we release outside
+// of NVIDIA!
+//
+
+//
+// Only for internal use (should not be written to the command register). Used
+// for internal tracking when commands are redirected to the RM from the PMU.
+//
+#define NV_MSGBOX_CMD_ERR_MORE_PROCESSING_REQUIRED 0x000000F0
+
+//
+// Alternative encodings of the command word.
+// These were distinguished by a non-zero value in the 29:29 bit.
+// Bit 29 is now reserved and must be 0 i.e. only standard requests will be processed
+// and debug requests would fail.
+//
+#define NV_MSGBOX_CMD_ENCODING 29:29
+#define NV_MSGBOX_CMD_ENCODING_STANDARD 0x00000000
+
+#endif // _SMBPBI_PRIV_H_
+
diff --git a/userspace/sdks/nv570/nvalloc/common/inc/rmRiscvUcode.h b/userspace/sdks/nv570/nvalloc/common/inc/rmRiscvUcode.h
new file mode 100644
index 0000000..d2e4259
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/common/inc/rmRiscvUcode.h
@@ -0,0 +1,95 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2018-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/*
+ * << DO NOT EDIT >>
+ *
+ * This file describes the format of generated ucode binary. Please do not change the
+ * content unless the same change is applied to the target ucode builds.
+ */
+
+#ifndef RM_RISCV_UCODE_H
+#define RM_RISCV_UCODE_H
+
+#include "nvtypes.h"
+
+typedef struct {
+ //
+ // Version 1
+ // Version 2
+ // Version 3 = for Partition boot
+ // Version 4 = for eb riscv boot
+ // Version 5 = Support signing entire RISC-V image as "code" in code section for hopper and later.
+ //
+ NvU32 version; // structure version
+ NvU32 bootloaderOffset;
+ NvU32 bootloaderSize;
+ NvU32 bootloaderParamOffset;
+ NvU32 bootloaderParamSize;
+ NvU32 riscvElfOffset;
+ NvU32 riscvElfSize;
+ NvU32 appVersion; // Changelist number associated with the image
+ //
+ // Manifest contains information about Monitor and it is
+ // input to BR
+ //
+ NvU32 manifestOffset;
+ NvU32 manifestSize;
+ //
+ // Monitor Data offset within RISCV image and size
+ //
+ NvU32 monitorDataOffset;
+ NvU32 monitorDataSize;
+ //
+ // Monitor Code offset withtin RISCV image and size
+ //
+ NvU32 monitorCodeOffset;
+ NvU32 monitorCodeSize;
+ NvU32 bIsMonitorEnabled;
+ //
+ // Swbrom Code offset within RISCV image and size
+ //
+ NvU32 swbromCodeOffset;
+ NvU32 swbromCodeSize;
+ //
+ // Swbrom Data offset within RISCV image and size
+ //
+ NvU32 swbromDataOffset;
+ NvU32 swbromDataSize;
+ //
+ // Total size of FB carveout (image and reserved space).
+ //
+ NvU32 fbReservedSize;
+ //
+ // Indicates whether the entire RISC-V image is signed as "code" in code section.
+ //
+ NvU32 bSignedAsCode;
+ //
+ // SMP (multihart) and PLIC (split interrupts)
+ // enablement options
+ //
+ NvU32 bIsSmp;
+ NvU32 bIsPlicEnabled;
+} RM_RISCV_UCODE_DESC;
+
+#endif // RM_RISCV_UCODE_H
diff --git a/userspace/sdks/nv570/nvalloc/common/inc/rm_state_monitor.h b/userspace/sdks/nv570/nvalloc/common/inc/rm_state_monitor.h
new file mode 100644
index 0000000..e89fd16
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/common/inc/rm_state_monitor.h
@@ -0,0 +1,72 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef RM_STATE_MONITOR_H
+#define RM_STATE_MONITOR_H
+
+// run every 100ms to prevent excessive CPU usage
+// as RM dump task runs as a higher priority task
+// than RM main task
+#define RM_STATE_MONITOR_WAIT_PERIOD (100000000) // 100ms
+
+typedef enum {
+ RM_STATE_MONITOR_HEADER_REQUEST_EXIT,
+ RM_STATE_MONITOR_HEADER_REQUEST_RM_STATE,
+ RM_STATE_MONITOR_HEADER_RESPONSE
+} RM_STATE_MONITOR_HEADER;
+
+typedef struct {
+ RM_STATE_MONITOR_HEADER header;
+} RM_STATE_MONITOR_REQUEST_MESSAGE;
+
+typedef struct {
+ NV_STATUS status;
+} RM_STATE_MONITOR_RESPONSE_MESSAGE;
+
+typedef union {
+ RM_STATE_MONITOR_REQUEST_MESSAGE request;
+ RM_STATE_MONITOR_RESPONSE_MESSAGE response;
+} RM_STATE_MONITOR_MESSAGE;
+
+#define RM_STATE_MONITOR_MAX_DPC_QUEUE_ITEMS 16
+#define RM_STATE_MONITOR_MAX_WORK_ITEMS 32
+#define RM_STATE_MONITOR_MAX_INTERRUPTS 32
+#define RM_STATE_MONITOR_MAX_ENINGE_BYTE_ARRAY (4)
+
+typedef struct {
+ NvU64 dpcQueue[RM_STATE_MONITOR_MAX_DPC_QUEUE_ITEMS][RM_STATE_MONITOR_MAX_ENINGE_BYTE_ARRAY];
+ NvU64 workItemsQueue[RM_STATE_MONITOR_MAX_WORK_ITEMS];
+ NvU64 lastDpcExecutionTime;
+ NvU64 totalDpcExecutionTime;
+ NvU64 lastWorkItemsExecutionTime;
+ NvU64 totalWorkItemsExecutionTime;
+ NvU64 interrupts[RM_STATE_MONITOR_MAX_INTERRUPTS]; //TODO: should this get set? will affect perf
+} RM_STATE_MONITOR_DATA;
+
+typedef struct {
+ NvU64 requestSequenceNumber;
+ NvU64 responseSequenceNumber;
+ RM_STATE_MONITOR_DATA data;
+} RM_STATE_MONITOR_BUFFER_LAYOUT;
+
+#endif
diff --git a/userspace/sdks/nv570/nvalloc/common/inc/rmflcnbl.h b/userspace/sdks/nv570/nvalloc/common/inc/rmflcnbl.h
new file mode 100644
index 0000000..7a49306
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/common/inc/rmflcnbl.h
@@ -0,0 +1,147 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2013-2019 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/*!
+ * Data structures and interfaces used for generic falcon boot-loader.
+ *
+ * This generic boot-loader is designed to load both non-secure and
+ * secure code taking care of signature as well. This bootloader
+ * should be loaded at the end of the IMEM so that it doesnt overwrite
+ * itself when it tries to load the code into IMEM starting at blk 0.
+ * The data will be loaded into DMEM offset 0.
+ */
+
+#ifndef RMFLCNBL_H
+#define RMFLCNBL_H
+
+#include "flcnifcmn.h"
+
+/*!
+ * @brief Structure used by the boot-loader to load the rest of the code.
+ *
+ * This has to be filled by the GPU driver and copied into DMEM at offset
+ * provided in the @ref _def_rm_flcn_bl_desc.blDmemDescLoadOff.
+ */
+typedef struct _def_rm_flcn_bl_dmem_desc
+{
+ /*!
+ * reserved should be always first element
+ */
+ NvU32 reserved[4];
+ /*!
+ * signature should follow reserved 16B signature for secure code.
+ * 0s if no secure code
+ */
+ NvU32 signature[4];
+ /*!
+ * ctxDma is used by the bootloader while loading code/data.
+ */
+ NvU32 ctxDma;
+ /*!
+ * 256B aligned physical FB address where code is located.
+ */
+ RM_FLCN_U64 codeDmaBase;
+ /*!
+ * Offset from codeDmaBase where the nonSecure code is located.
+ * The offset must be multiple of 256 to help performance.
+ */
+ NvU32 nonSecureCodeOff;
+ /*!
+ * The size of the nonSecure code part.
+ */
+ NvU32 nonSecureCodeSize;
+ /*!
+ * Offset from codeDmaBase where the secure code is located.
+ * The offset must be multiple of 256 to help performance.
+ */
+ NvU32 secureCodeOff;
+ /*!
+ * The size of the ecure code part.
+ */
+ NvU32 secureCodeSize;
+ /*!
+ * Code entry point which will be invoked by BL after code is loaded.
+ */
+ NvU32 codeEntryPoint;
+ /*!
+ * 256B aligned Physical FB Address where data is located.
+ */
+ RM_FLCN_U64 dataDmaBase;
+ /*!
+ * Size of data block. Should be multiple of 256B.
+ */
+ NvU32 dataSize;
+ /*!
+ * Arguments to be passed to the target firmware being loaded.
+ */
+ NvU32 argc;
+ /*!
+ * Number of arguments to be passed to the target firmware being loaded.
+ */
+ NvU32 argv;
+} RM_FLCN_BL_DMEM_DESC, *PRM_FLCN_BL_DMEM_DESC;
+
+/*!
+ * @brief The header used by the GPU driver to figure out code and data
+ * sections of bootloader.
+ */
+typedef struct _def_rm_flcn_bl_img_header
+{
+ /*!
+ * Offset of code section in the image.
+ */
+ NvU32 blCodeOffset;
+ /*!
+ * Size of code section in the image.
+ */
+ NvU32 blCodeSize;
+ /*!
+ * Offset of data section in the image.
+ */
+ NvU32 blDataOffset;
+ /*!
+ * Size of data section in the image.
+ */
+ NvU32 blDataSize;
+} RM_FLCN_BL_IMG_HEADER, *PRM_FLCN_BL_IMG_HEADER;
+
+/*!
+ * @brief The descriptor used by RM to figure out the requirements of boot loader.
+ */
+typedef struct _def_rm_flcn_bl_desc
+{
+ /*!
+ * Starting tag of bootloader
+ */
+ NvU32 blStartTag;
+ /*!
+ * Dmem offset where _def_rm_flcn_bl_dmem_desc to be loaded
+ */
+ NvU32 blDmemDescLoadOff;
+ /*!
+ * Description of the image
+ */
+ RM_FLCN_BL_IMG_HEADER blImgHeader;
+} RM_FLCN_BL_DESC, *PRM_FLCN_BL_DESC;
+
+#endif // RMFLCNBL_H
diff --git a/userspace/sdks/nv570/nvalloc/common/inc/rmgspseq.h b/userspace/sdks/nv570/nvalloc/common/inc/rmgspseq.h
new file mode 100644
index 0000000..5d130d6
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/common/inc/rmgspseq.h
@@ -0,0 +1,66 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2019-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/*!
+ * Top-level header-file that defines the GSP data structures used to request
+ * firmware load/execution by the CPU.
+ */
+
+#ifndef _RMGSPSEQ_H_
+#define _RMGSPSEQ_H_
+
+#include "rmflcnbl.h"
+
+/*!
+ * Structure for loading/executing generic bootloader
+ */
+typedef struct GspLoadExecGenericBootloaderParams
+{
+ RM_FLCN_BL_DMEM_DESC dmemDesc;
+ NvU32 dmemDescSize;
+ NvU32 addrSpace;
+ NvU32 cpuCacheAttrib;
+ NvU32 reserved[4];
+} GspLoadExecGenericBootloaderParams;
+
+/*!
+ * Structure for loading/executing HS binary
+ */
+typedef struct GspLoadExecHsBinaryParams
+{
+ NvU64 imemPhysAddr;
+ NvU64 dmemPhysAddr;
+ NvU64 reserved64[2];
+ NvU32 ucodeImemVA;
+ NvU32 ucodeImemPA;
+ NvU32 ucodeImemSize;
+ NvU32 ucodeDmemVA;
+ NvU32 ucodeDmemPA;
+ NvU32 ucodeDmemSize;
+ NvU32 hsSigDmemAddr;
+ NvU32 engineIdMask;
+ NvU32 ucodeId;
+ NvU32 reserved32[3];
+} GspLoadExecHsBinaryParams;
+
+#endif // _RMGSPSEQ_H_
diff --git a/userspace/sdks/nv570/nvalloc/common/inc/rmifrif.h b/userspace/sdks/nv570/nvalloc/common/inc/rmifrif.h
new file mode 100644
index 0000000..b774d02
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/common/inc/rmifrif.h
@@ -0,0 +1,123 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2020-2012 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _RMIFRIF_H_
+#define _RMIFRIF_H_
+
+/*!
+ * @file rmifrif.h
+ * @brief Defines structures and interfaces common between RM and
+ * Init-From-Rom (IFR).
+ *
+ * For systems supporting GC6 that have on-board VBIOS ROMs, IFR is used
+ * to expedite several parts of GC6 exit in parallel with PEX init.
+ *
+ * After running devinit using a PMU ucode image loaded from the ROM itself,
+ * parts of RM stateLoad can be done using RM's ucode image. This is
+ * achieved by loading RM PMU ucode directly from FB. The primary difficulties
+ * are how to find RM's PMU ucode and how to bootstrap it.
+ *
+ * We use the simple approach of allocating a fixed buffer near the
+ * top of FB that contains the information required to bootstrap RM's PMU
+ * image. This buffer is called the RM_IFR_GC6_CTX.
+ *
+ * The buffer is allocated within RM's reserved memory space, directly before
+ * the VBIOS workspace (if any is present). Since the VBIOS workspace is
+ * always a multiple of 64K, RM enforces that the offset between top of memory
+ * and the end of the buffer is 64K. This way the IFR code can start
+ * from the top of memory and search downwards in 64K decrements.
+ *
+ * A small header is placed at the end of the buffer which contains a
+ * string signature identifying the buffer and other data needed to find the
+ * remaining context data.
+ *
+ * Top_Of-FB /---------------------\ <-
+ * | | \
+ * | (VBIOS_Workspace) | | END_OFFSET
+ * | | /
+ * |---------------------| <-
+ | | \
+ * | GSP FW (if present) | | pFbHalPvtInfo->gspFwSizeBytes
+ * | | /
+ * |---------------------| <-
+ * | RM_IFR_GC6_CTX_HDR | \
+ * |---------------------| |
+ * | (Padding) | | RM_IFR_GC6_CTX_HDR.bufferSize
+ * |---------------------| |
+ * | Sequence Data | /
+ * |---------------------| <-
+ * | |
+ * | |
+ * | |
+ * | |
+ * 0x00000000 \---------------------/
+ *
+ * To simplify the RM PMU bootstrap process and decrease IFR maintainence
+ * cost, the bootstrap process is encoded as a sequence script, leveraging
+ * a small subset of RM's PMU_SEQ_INST interface (see pmuseqinst.h).
+ * Register writes are captured during the initial (CPU-driven) RM PMU bootstrap
+ * and saved into a sequence for replay during GC6 exit.
+ *
+ * Only the following opcodes are supported currently:
+ * NV_PMU_SEQ_WRITE_REG_OPC - (multi-)register write
+ * NV_PMU_SEQ_EXIT_OPC - sequence done
+ *
+ */
+
+/*!
+ * Header structure which identifies the GC6 context buffer.
+ */
+typedef struct
+{
+ NvU8 signature[12]; // RM_IFR_GC6_CTX_SIGNATURE
+ NvU32 bufferSize; // Size of the entire context buffer in bytes
+ NvU32 seqSizeWords; // Number of 32-bit words of sequence data
+ NvU32 checksum; // 32-bit chunk checksum of the sequence data
+} RM_IFR_GC6_CTX_HDR, *PRM_IFR_GC6_CTX_HDR;
+
+/*!
+ * String signature that IFR searches for to find the GC6 context buffer.
+ */
+#define RM_IFR_GC6_CTX_SIGNATURE "GC6_CTX_HDR" // 12 bytes
+
+/*!
+ * Alignment of the offset between top of memory and the end of the
+ * GC6 context buffer (which is also the end of the header).
+ */
+#define RM_IFR_GC6_CTX_END_OFFSET_ALIGNMENT 0x10000 // 64KB
+
+/*!
+ * Maximum offset between top of memory and the end of the
+ * GC6 context buffer. This is meant to be a loose upper bound preventing
+ * scanning of the whole of memory (e.g. when something goes wrong).
+ */
+#define RM_IFR_GC6_CTX_END_OFFSET_MAX 0x1000000 // 16MB
+
+/*!
+ * Maximum size of the context data in bytes.
+ * This is limited by FECS falcon DMEM size (4K on Kepler).
+ * The buffer must fit within DMEM together with stack and other global data.
+ */
+#define RM_IFR_GC6_CTX_DATA_MAX_SIZE 2048 // 2KB
+
+#endif // _RMIFRIF_H_
diff --git a/userspace/sdks/nv570/nvalloc/common/inc/rmlsfm.h b/userspace/sdks/nv570/nvalloc/common/inc/rmlsfm.h
new file mode 100644
index 0000000..ca91911
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/common/inc/rmlsfm.h
@@ -0,0 +1,579 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2011-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef RMLSFM_H
+#define RMLSFM_H
+
+/*****************************************************************************/
+/* This file is shared between ACR, SEC2 Binaries */
+/* Do not update this file without updating ACR/SEC2 */
+/*****************************************************************************/
+
+/*!
+ * @file rmlsfm.h
+ * @brief Top-level header-file that defines Light Secure Falcon Managment
+ SW shared interfaces.
+ */
+
+/*!
+ * READ/WRITE masks for WPR region
+ */
+#define LSF_WPR_REGION_RMASK (0xCU) // Readable only from level 2 and 3 client
+#define LSF_WPR_REGION_WMASK (0xCU) // Writable only from level 2 and 3 client
+#define LSF_WPR_REGION_RMASK_SUB_WPR_ENABLED (0x8) // Readable only from level 3 client
+#define LSF_WPR_REGION_WMASK_SUB_WPR_ENABLED (0x8) // Writable only from level 3 client
+#define LSF_WPR_REGION_ALLOW_READ_MISMATCH_NO (0x0) // Disallow read mis-match for all clients
+#define LSF_WPR_REGION_ALLOW_WRITE_MISMATCH_NO (0x0) // Disallow write mis-match for all clients
+
+/*!
+ * READ mask for WPR region on Tegra
+ * This is required until we update tegra binaries, Bug 200281517
+ * TODO: dgoyal - Remove this once tegra binaries are updated
+ */
+#define LSF_WPR_REGION_RMASK_FOR_TEGRA (0xFU)
+
+/*!
+ * Expected REGION ID to be used for the unprotected FB region (region that
+ * does not have read or write protections)
+ */
+#define LSF_UNPROTECTED_REGION_ID (0x0U)
+
+/*!
+ * Expected REGION ID to be used for the WPR region for the falcon microcode (includes data).
+ * ACR allots client requests to each region based on read/write masks and it is supposed
+ * to provide first priority to requests from LSFM. Providing first priority will naturally assign
+ * region ID 1 to LSFM and this define will provide a way for different parties to sanity check
+ * this fact. Also there are other falcons (FECS/video falcons) which depends on this define, so please
+ * be aware while modifying this.
+ */
+#define LSF_WPR_EXPECTED_REGION_ID (0x1U)
+
+/*!
+ * Expected REGION ID to be used for the unused WPR region.
+ */
+#define LSF_WPR_UNUSED_REGION_ID (0x2U)
+
+/*!
+ * Invalid LS falcon subWpr ID
+ */
+#define LSF_SUB_WPR_ID_INVALID (0xFFFFFFFFU)
+
+/*!
+ * Expected REGION ID to be used for the VPR region.
+ */
+#define LSF_VPR_REGION_ID (0x3U)
+
+/*!
+ * Expected REGION ID to be used for the CPR region with conf compute.
+ */
+#define LSF_CPR_REGION_ID (0x3U)
+
+/*!
+ * Size of the separate bootloader data that could be present in WPR region.
+ */
+#define LSF_LS_BLDATA_EXPECTED_SIZE (0x100U)
+
+/*!
+ * since we dont check signatures in GC6 exit, we need to hardcode the WPR offset
+ */
+#define LSF_WPR_EXPECTED_OFFSET (0x0U)
+
+/*!
+ * CTXDMA to be used while loading code/data in target falcons
+ */
+#define LSF_BOOTSTRAP_CTX_DMA_FECS (0x0)
+
+/*!
+ * Context DMA ID 6 is reserved for Video UCODE
+ */
+#define LSF_BOOTSTRAP_CTX_DMA_VIDEO (0x6)
+#define LSF_BOOTSTRAP_CTX_DMA_BOOTSTRAP_OWNER (0x0)
+#define LSF_BOOTSTRAP_CTX_DMA_FBFLCN (0x0)
+
+/*!
+ * Falcon Id Defines
+ * Defines a common Light Secure Falcon identifier.
+ * Codesigning infra. assumes LSF_FALCON_ID_ prefix for units,
+ * Changes to the define needs to be reflected in path [1]
+ * For new Falcon Id adding, we need to append to the end;
+ * don't insert the new falcon Id in the middle.
+ *
+ * @note If a newly added Falcon has multiple instances sharing
+ * the same Falcon Id, the LSF_FALCON_USES_INSTANCE macro
+ * need to be updated.
+ */
+#define LSF_FALCON_ID_PMU (0U)
+#define LSF_FALCON_ID_DPU (1U)
+#define LSF_FALCON_ID_GSPLITE LSF_FALCON_ID_DPU
+#define LSF_FALCON_ID_FECS (2U)
+#define LSF_FALCON_ID_GPCCS (3U)
+#define LSF_FALCON_ID_NVDEC (4U)
+#define LSF_FALCON_ID_NVENC (5U)
+#define LSF_FALCON_ID_NVENC0 (5U)
+#define LSF_FALCON_ID_NVENC1 (6U)
+#define LSF_FALCON_ID_SEC2 (7U)
+#define LSF_FALCON_ID_NVENC2 (8U)
+#define LSF_FALCON_ID_MINION (9U)
+#define LSF_FALCON_ID_FBFALCON (10U)
+#define LSF_FALCON_ID_XUSB (11U)
+#define LSF_FALCON_ID_GSP_RISCV (12U)
+#define LSF_FALCON_ID_PMU_RISCV (13U)
+#define LSF_FALCON_ID_SOE (14U)
+#define LSF_FALCON_ID_NVDEC1 (15U)
+#define LSF_FALCON_ID_OFA (16U)
+#define LSF_FALCON_ID_SEC2_RISCV (17U)
+#define LSF_FALCON_ID_NVDEC_RISCV (18U)
+#define LSF_FALCON_ID_NVDEC_RISCV_EB (19U)
+#define LSF_FALCON_ID_NVJPG (20U)
+#define LSF_FALCON_ID_FECS_RISCV (21U)
+#define LSF_FALCON_ID_GPCCS_RISCV (22U)
+#define LSF_FALCON_ID_NVJPG_RISCV_EB (23U)
+#define LSF_FALCON_ID_OFA_RISCV_EB (24U)
+#define LSF_FALCON_ID_NVENC_RISCV_EB (25U)
+#define LSF_FALCON_ID_PMU_RISCV_EB (26U)
+#define LSF_FALCON_ID_NVDEC0_RISCV_EB (27U)
+#define LSF_FALCON_ID_GSPLITE_RISCV_EB (28U)
+#define LSF_FALCON_ID_DISPLAY_RISCV_EB (29U)
+#define LSF_FALCON_ID_FBFALCON_RISCV_EB (30U)
+#define LSF_FALCON_ID_LPSEC (31U)
+#define LSF_FALCON_ID_END (32U)
+
+#define LSF_FALCON_ID_INVALID (0xFFFFFFFFU)
+
+//
+// TODO: Remove below Alias and add _EB Patching to macro LSF_FALCON_ID_FECS_RISCV, similarly for GPCCS,
+// and similar cleanups in RM since RISCV based CTXSW engines are to be booted externally.
+// Tracking in Bug 3808599
+//
+#define LSF_FALCON_ID_FECS_RISCV_EB (LSF_FALCON_ID_FECS_RISCV)
+#define LSF_FALCON_ID_GPCCS_RISCV_EB (LSF_FALCON_ID_GPCCS_RISCV)
+
+//
+// ************************ NOTIFICATION *********************************
+// In case anyone needs to add new LSF falconId, please must calculate
+// WPR header size per LSF_FALCON_ID_END. RM needs to call lsfmGetWprHeaderSizeMax_HAL
+// to align with acrReadSubWprHeader_HAL in ACR. Otherwise, ACR can't get correct
+// address to read sub wpr headers.
+// We observer in case LSF_FALCON_ID_END > 32 will cause SEC2 IMEM tag missing error;
+// but don't get the root cause yet.
+//
+#define LSF_FALCON_ID_END_15 (15U)
+#define LSF_FALCON_ID_END_17 (17U)
+#define LSF_FALCON_ID_END_18 (18U)
+#define LSF_FALCON_ID_END_21 (21U)
+#define LSF_FALCON_ID_END_30 (30U)
+
+#define LSF_FALCON_INSTANCE_DEFAULT_0 (0x0U)
+#define LSF_FALCON_INSTANCE_DEFAULT_3 (0x3U)
+#define LSF_FALCON_INSTANCE_DEFAULT_4 (0x4U)
+#define LSF_FALCON_INSTANCE_COUNT_DEFAULT_1 (0x1U)
+
+// Currently max supported instance is 24 for FECS/GPCCS SMC
+#define LSF_FALCON_INSTANCE_FECS_GPCCS_MAX (0x18U)
+#define LSF_FALCON_INSTANCE_INVALID (0xFFFFFFFFU)
+#define LSF_FALCON_INDEX_MASK_DEFAULT_0 (0x0U)
+
+/*!
+ * Checks if the LSF Falcon specified by falconId uses a falconInstance to uniquely identify itself.
+ * Some Falcons (eg: NVENC) use separate FalconId for each instance while some (eg: NVJPG)
+ * shares the same falconId across all instances of that engine. Those engines require a falconInstance
+ * to uniquely identify it.
+ * @note this macro should be updated as needed whenever LSF_FALCON_ID* defines are added. See Bug: 3833461
+ */
+#define LSF_FALCON_USES_INSTANCE(falconId) ((falconId == LSF_FALCON_ID_NVDEC_RISCV_EB) || \
+ (falconId == LSF_FALCON_ID_NVJPG) || \
+ (falconId == LSF_FALCON_ID_NVJPG_RISCV_EB) || \
+ (falconId == LSF_FALCON_ID_NVENC_RISCV_EB) || \
+ (falconId == LSF_FALCON_ID_FECS_RISCV_EB) || \
+ (falconId == LSF_FALCON_ID_GPCCS_RISCV_EB) || \
+ (falconId == LSF_FALCON_ID_GSPLITE_RISCV_EB) || \
+ (falconId == LSF_FALCON_ID_OFA_RISCV_EB) || \
+ (falconId == LSF_FALCON_ID_LPSEC))
+
+
+/*!
+ * Size in entries of the ucode descriptor's dependency map.
+ * This used to be LSF_FALCON_ID_END, but since that had to grow and we did not want to break any
+ * existing binaries, they had to be split.
+ *
+ * Increasing this number should be done with care.
+ */
+#define LSF_FALCON_DEPMAP_SIZE (11U)
+
+/*!
+ * Falcon Binaries version defines
+ */
+#define LSF_FALCON_BIN_VERSION_INVALID (0xFFFFFFFFU)
+
+
+/*!
+ * Light Secure Falcon Ucode Description Defines
+ * This stucture is prelim and may change as the ucode signing flow evolves.
+ */
+typedef struct
+{
+ NvU8 prdKeys[2][16];
+ NvU8 dbgKeys[2][16];
+ NvU32 bPrdPresent;
+ NvU32 bDbgPresent;
+ NvU32 falconId;
+ NvU32 bSupportsVersioning;
+ NvU32 version;
+ NvU32 depMapCount;
+ NvU8 depMap[LSF_FALCON_DEPMAP_SIZE * 2 * 4];
+ NvU8 kdf[16];
+} LSF_UCODE_DESC, *PLSF_UCODE_DESC;
+
+/*!
+ * Light Secure WPR Header
+ * Defines state allowing Light Secure Falcon bootstrapping.
+ *
+ * falconId - LS falcon ID
+ * lsbOffset - Offset into WPR region holding LSB header
+ * bootstrapOwner - Bootstrap OWNER (either PMU or SEC2)
+ * bLazyBootstrap - Skip bootstrapping by ACR
+ * status - Bootstrapping status
+ */
+typedef struct
+{
+ NvU32 falconId;
+ NvU32 lsbOffset;
+ NvU32 bootstrapOwner;
+ NvU32 bLazyBootstrap;
+ NvU32 binVersion;
+ NvU32 status;
+} LSF_WPR_HEADER, *PLSF_WPR_HEADER;
+
+/*!
+ * LSF shared SubWpr Header
+ *
+ * useCaseId - Shared SubWpr se case ID (updated by RM)
+ * startAddr - start address of subWpr (updated by RM)
+ * size4K - size of subWpr in 4K (updated by RM)
+ */
+typedef struct
+{
+ NvU32 useCaseId;
+ NvU32 startAddr;
+ NvU32 size4K;
+} LSF_SHARED_SUB_WPR_HEADER, *PLSF_SHARED_SUB_WPR_HEADER;
+
+// Shared SubWpr use case IDs
+typedef enum
+{
+ LSF_SHARED_DATA_SUB_WPR_USE_CASE_ID_FRTS_VBIOS_TABLES = 1,
+ LSF_SHARED_DATA_SUB_WPR_USE_CASE_ID_PLAYREADY_SHARED_DATA = 2,
+ LSF_SHARED_DATA_SUB_WPR_USE_CASE_ID_APM_RTS = 3
+} LSF_SHARED_DATA_SUB_WPR_USE_CASE_ID_ENUM;
+
+#define LSF_SHARED_DATA_SUB_WPR_USE_CASE_ID_MAX LSF_SHARED_DATA_SUB_WPR_USE_CASE_ID_APM_RTS
+#define LSF_SHARED_DATA_SUB_WPR_USE_CASE_ID_INVALID (0xFFFFFFFFU)
+
+#define MAX_SUPPORTED_SHARED_SUB_WPR_USE_CASES LSF_SHARED_DATA_SUB_WPR_USE_CASE_ID_MAX
+
+//
+// Static sizes of shared subWPRs
+// Minimum granularity supported is 4K
+//
+#define LSF_SHARED_DATA_SUB_WPR_FRTS_VBIOS_TABLES_SIZE_IN_4K (0x100) // 1MB in 4K
+#define LSF_SHARED_DATA_SUB_WPR_PLAYREADY_SHARED_DATA_SIZE_IN_4K (0x1) // 4K
+#define LSF_SHARED_DATA_SUB_WPR_APM_RTS_SIZE_IN_4K (0x1) // 4K
+
+/*!
+ * Bootstrap Owner Defines
+ */
+#define LSF_BOOTSTRAP_OWNER_PMU (LSF_FALCON_ID_PMU)
+#define LSF_BOOTSTRAP_OWNER_SEC2 (LSF_FALCON_ID_SEC2)
+#define LSF_BOOTSTRAP_OWNER_GSPLITE (LSF_FALCON_ID_GSPLITE)
+#define LSF_BOOTSTRAP_OWNER_DEFAULT LSF_BOOTSTRAP_OWNER_PMU
+
+/*!
+ * Image Status Defines
+ */
+#define LSF_IMAGE_STATUS_NONE (0U)
+#define LSF_IMAGE_STATUS_COPY (1U)
+#define LSF_IMAGE_STATUS_VALIDATION_CODE_FAILED (2U)
+#define LSF_IMAGE_STATUS_VALIDATION_DATA_FAILED (3U)
+#define LSF_IMAGE_STATUS_VALIDATION_DONE (4U)
+#define LSF_IMAGE_STATUS_VALIDATION_SKIPPED (5U)
+#define LSF_IMAGE_STATUS_BOOTSTRAP_READY (6U)
+#define LSF_IMAGE_STATUS_REVOCATION_CHECK_FAILED (7U)
+
+/*!
+ * Light Secure Bootstrap Header
+ * Defines state allowing Light Secure Falcon bootstrapping.
+ *
+ * signature - Code/data signature details for this LS falcon
+ * ucodeOffset - Offset into WPR region where UCODE is located
+ * ucodeSize - Size of ucode
+ * dataSize - Size of ucode data
+ * blCodeSize - Size of bootloader that needs to be loaded by bootstrap owner
+ * blImemOffset - BL starting virtual address. Need for tagging.
+ * blDataOffset - Offset into WPR region holding the BL data
+ * blDataSize - Size of BL data
+ * appCodeOffset - Offset into WPR region where Application UCODE is located
+ * appCodeSize - Size of Application UCODE
+ * appDataOffset - Offset into WPR region where Application DATA is located
+ * appDataSize - Size of Application DATA
+ * blLoadCodeAt0 - Load BL at 0th IMEM offset
+ * bSetVACtx - Make sure to set the code/data loading CTX DMA to be virtual before exiting
+ * bDmaReqCtx - This falcon requires a ctx before issuing DMAs
+ * bForcePrivLoad- Use priv loading method instead of bootloader/DMAs
+ */
+
+#define NV_FLCN_ACR_LSF_FLAG_LOAD_CODE_AT_0 0:0
+#define NV_FLCN_ACR_LSF_FLAG_LOAD_CODE_AT_0_FALSE 0
+#define NV_FLCN_ACR_LSF_FLAG_LOAD_CODE_AT_0_TRUE 1
+#define NV_FLCN_ACR_LSF_FLAG_SET_VA_CTX 1:1
+#define NV_FLCN_ACR_LSF_FLAG_SET_VA_CTX_FALSE 0
+#define NV_FLCN_ACR_LSF_FLAG_SET_VA_CTX_TRUE 1
+#define NV_FLCN_ACR_LSF_FLAG_DMACTL_REQ_CTX 2:2
+#define NV_FLCN_ACR_LSF_FLAG_DMACTL_REQ_CTX_FALSE 0
+#define NV_FLCN_ACR_LSF_FLAG_DMACTL_REQ_CTX_TRUE 1
+#define NV_FLCN_ACR_LSF_FLAG_FORCE_PRIV_LOAD 3:3
+#define NV_FLCN_ACR_LSF_FLAG_FORCE_PRIV_LOAD_FALSE 0
+#define NV_FLCN_ACR_LSF_FLAG_FORCE_PRIV_LOAD_TRUE 1
+typedef struct
+{
+ LSF_UCODE_DESC signature;
+ NvU32 ucodeOffset;
+ NvU32 ucodeSize;
+ NvU32 dataSize;
+ NvU32 blCodeSize;
+ NvU32 blImemOffset;
+ NvU32 blDataOffset;
+ NvU32 blDataSize;
+ NvU32 appCodeOffset;
+ NvU32 appCodeSize;
+ NvU32 appDataOffset;
+ NvU32 appDataSize;
+ NvU32 flags;
+ /*
+ * TODO: Uncomment this once Sanket's changes
+ * of HALifying is done
+ NvU32 monitorCodeOffset;
+ NvU32 monitorDataOffset;
+ NvU32 manifestOffset;
+ */
+} LSF_LSB_HEADER, *PLSF_LSB_HEADER;
+
+
+/*!
+ * Light Secure WPR Content Alignments
+ */
+#define LSF_WPR_HEADER_ALIGNMENT (256U)
+#define LSF_SUB_WPR_HEADER_ALIGNMENT (256U)
+#define LSF_LSB_HEADER_ALIGNMENT (256U)
+#define LSF_BL_DATA_ALIGNMENT (256U)
+#define LSF_BL_DATA_SIZE_ALIGNMENT (256U)
+#define LSF_BL_CODE_SIZE_ALIGNMENT (256U)
+#define LSF_DATA_SIZE_ALIGNMENT (256U)
+#define LSF_CODE_SIZE_ALIGNMENT (256U)
+
+// MMU excepts subWpr sizes in units of 4K
+#define SUB_WPR_SIZE_ALIGNMENT (4096U)
+
+/*!
+ * Maximum WPR Header size
+ */
+#define LSF_WPR_HEADERS_TOTAL_SIZE_MAX (NV_ALIGN_UP((sizeof(LSF_WPR_HEADER) * LSF_FALCON_ID_END), LSF_WPR_HEADER_ALIGNMENT))
+#define LSF_LSB_HEADER_TOTAL_SIZE_MAX (NV_ALIGN_UP(sizeof(LSF_LSB_HEADER), LSF_LSB_HEADER_ALIGNMENT))
+
+//
+// PMU OBJACR_ALIGNED_256 size will vary with LSF_FALCON_ID_END.
+// PMU could run out of DMEM in case we increase LSF_FALCON_ID_END more and more.
+// The PMU supports the ACR task on GM20X_thru_VOLTA profiles only.
+// In order to prevent LSF_FALCON_ID_END changes to affect older / shipped PMU ucodes (increase of DMEM footprint)
+// adding PMU specific ***_END define capturing value covering all PMU profiles that this with the ACR task.
+//
+#define LSF_FALCON_ID_END_PMU (LSF_FALCON_ID_FBFALCON + 1)
+#define LSF_WPR_HEADERS_TOTAL_SIZE_MAX_PMU (NV_ALIGN_UP((sizeof(LSF_WPR_HEADER) * LSF_FALCON_ID_END_PMU), LSF_WPR_HEADER_ALIGNMENT))
+
+//
+// In order to prevent LSF_FALCON_ID_END changes to affect older / shipped SEC2/ACR ucodes (increase of DMEM footprint)
+// adding SEC2/ACR specific ***_END define covering all supported falcons in pre-hopper SEC2-RTOS/ACR ucode.
+//
+#define LSF_FALCON_ID_END_ACR_ON_SEC2 (LSF_FALCON_ID_NVJPG + 1)
+#define LSF_WPR_HEADERS_TOTAL_SIZE_MAX_ACR_ON_SEC2 (NV_ALIGN_UP((sizeof(LSF_WPR_HEADER) * LSF_FALCON_ID_END_ACR_ON_SEC2), LSF_WPR_HEADER_ALIGNMENT))
+
+// Maximum SUB WPR header size
+#define LSF_SUB_WPR_HEADERS_TOTAL_SIZE_MAX (NV_ALIGN_UP((sizeof(LSF_SHARED_SUB_WPR_HEADER) * LSF_SHARED_DATA_SUB_WPR_USE_CASE_ID_MAX), LSF_SUB_WPR_HEADER_ALIGNMENT))
+
+/*!
+ * For the ucode surface alignment, We align to RM_PAGE_SIZE because of
+ * busMapRmAperture issues, not because of Falcon ucode alignment requirements
+ * which currently are that it be at least 256.
+ */
+#define LSF_UCODE_DATA_ALIGNMENT RM_PAGE_SIZE
+
+/*!
+ * ACR Descriptors used by ACR UC
+ */
+
+/*!
+ * Supporting maximum of 2 regions.
+ * This is needed to pre-allocate space in DMEM
+ */
+#define RM_FLCN_ACR_MAX_REGIONS (2)
+#define LSF_BOOTSTRAP_OWNER_RESERVED_DMEM_SIZE (0x200)
+
+/*!
+ * startAddress - Starting address of region
+ * endAddress - Ending address of region
+ * regionID - Region ID
+ * readMask - Read Mask
+ * writeMask - WriteMask
+ * clientMask - Bit map of all clients currently using this region
+ * shadowMemStartAddress- FB location from where contents need to be copied to startAddress
+ */
+typedef struct _def_acr_dmem_region_prop
+{
+ NvU32 startAddress;
+ NvU32 endAddress;
+ NvU32 regionID;
+ NvU32 readMask;
+ NvU32 writeMask;
+ NvU32 clientMask;
+ NvU32 shadowMemStartAddress;
+} RM_FLCN_ACR_REGION_PROP, *PRM_FLCN_ACR_REGION_PROP;
+
+
+/*!
+ * noOfRegions - Number of regions used by RM.
+ * regionProps - Region properties
+ */
+typedef struct _def_acr_regions
+{
+ NvU32 noOfRegions;
+ RM_FLCN_ACR_REGION_PROP regionProps[RM_FLCN_ACR_MAX_REGIONS];
+} RM_FLCN_ACR_REGIONS, *PRM_FLCN_ACR_REGIONS;
+
+/*!
+ * bVprEnabled : When set, ACR_LOCKDOWN phase programs VPR range. Needs to be
+ : NvU32 because of alignment
+ * vprStartAddress : Start address of VPR region. SEC2 binary updates this value
+ * vprEndAddress : End address of VPR region. SEC2 binary updates this value
+ * hdcpPolicies : VPR display policies. SEC2 binary updates this value
+ */
+typedef struct _def_acr_vpr_dmem_desc
+{
+ NvU32 bVprEnabled;
+ NvU32 vprStartAddress;
+ NvU32 vprEndAddress;
+ NvU32 hdcpPolicies;
+} ACR_BSI_VPR_DESC, *PACR_BSI_VPR_DESC;
+
+/*!
+ * reservedDmem - When the bootstrap owner has done bootstrapping other falcons,
+ * and need to switch into LS mode, it needs to have its own actual
+ * DMEM image copied into DMEM as part of LS setup. If ACR desc is at
+ * location 0, it will definitely get overwritten causing data corruption.
+ * Hence we are reserving 0x200 bytes to give room for any loading data.
+ * NOTE: This has to be the first member always
+ * signature - Signature of ACR ucode.
+ * wprRegionID - Region ID holding the WPR header and its details
+ * wprOffset - Offset from the WPR region holding the wpr header
+ * regions - Region descriptors
+ * ucodeBlobBase- Used for Tegra, stores non-WPR start address where kernel stores ucode blob
+ * ucodeBlobSize- Used for Tegra, stores the size of the ucode blob
+ */
+typedef struct _def_acr_dmem_desc
+{
+ NvU32 signatures[4];
+ NvU32 wprRegionID;
+ NvU32 wprOffset;
+ NvU32 mmuMemoryRange;
+ RM_FLCN_ACR_REGIONS regions;
+ NvU32 ucodeBlobSize;
+ // uCodeBlobBase is moved after ucodeBlobSize to inherently align to qword (8 bytes)
+ NvU64 NV_DECLARE_ALIGNED(ucodeBlobBase, 8);
+
+ /*!
+ * Do not change the offset of this descriptor as it shared between
+ * ACR_REGION_LOCKDOWN HS binary and SEC2. Any change in this structure
+ * need recompilation of SEC2 and ACR_LOCKDOWN HS binary
+ */
+ ACR_BSI_VPR_DESC vprDesc;
+} RM_FLCN_ACR_DESC, *PRM_FLCN_ACR_DESC;
+
+/*!
+* Hub keys/nonce Structure in BSI
+*/
+#define MAX_SFBHUB_ENCRYPTION_REGION_KEY_SIZE 4
+
+typedef struct _def_acr_hub_scratch_data
+{
+ NvU32 key[MAX_SFBHUB_ENCRYPTION_REGION_KEY_SIZE];
+ NvU32 nonce[MAX_SFBHUB_ENCRYPTION_REGION_KEY_SIZE];
+} ACR_BSI_HUB_DESC, *PACR_BSI_HUB_DESC;
+
+#define MAX_HUB_ENCRYPTION_REGION_COUNT 3
+typedef struct _def_acr_hub_scratch_array
+{
+ ACR_BSI_HUB_DESC entries[MAX_HUB_ENCRYPTION_REGION_COUNT];
+} ACR_BSI_HUB_DESC_ARRAY, *PACR_BSI_HUB_DESC_ARRAY;
+
+typedef struct _def_acr_reserved_dmem
+{
+ NvU32 reservedDmem[(LSF_BOOTSTRAP_OWNER_RESERVED_DMEM_SIZE/4)]; // Always first..
+} ACR_RESERVED_DMEM, *PACR_RESERVED_DMEM;
+
+typedef struct _def_booter_reserved_dmem
+{
+ NvU32 reservedDmem[(LSF_BOOTSTRAP_OWNER_RESERVED_DMEM_SIZE/4)]; // Always first..
+} BOOTER_RESERVED_DMEM;
+
+#define NV_FLCN_ACR_DESC_FLAGS_SIG_VERIF 0:0
+#define NV_FLCN_ACR_DESC_FLAGS_SIG_VERIF_DISABLE 0
+#define NV_FLCN_ACR_DESC_FLAGS_SIG_VERIF_ENABLE 1
+
+// Macro defines to be consumed by RM to get GH100 GSP Inst_in_sys FMC boot status.
+#define GSP_INST_IN_SYS_COMPLETION_STATUS_OK 0x55
+#define GSP_INST_IN_SYS_COMPLETION_STATUS_ERROR 0xAA
+#define GSP_INST_IN_SYS_COMPLETION_STATUS_IN_PROGRESS 0x00
+
+/*!
+ * Size of ACR phase in dword
+ */
+#define ACR_PHASE_SIZE_DWORD sizeof(RM_FLCN_ACR_DESC)/sizeof(NvU32)
+
+/*!
+ * Falcon Mode Tokens
+ * This is the value logged to a mailbox register to indicate that the
+ * falcon isn't booted in secure mode.
+ */
+#define LSF_FALCON_MODE_TOKEN_FLCN_INSECURE (0xDEADDEADU)
+
+
+// LS encryption context, to store data to decrypt LS images.
+#define LS_ENCRYPTION_AES128_CBC_IV_SIZE_BYTE (16)
+
+typedef struct
+{
+ NvU8 bLsEncrypted;
+ NvU8 rsvd[3];
+ NvU8 lsEncIV[LS_ENCRYPTION_AES128_CBC_IV_SIZE_BYTE];
+} LSF_ENCRYPTION_CONTEXT, *PLSF_ENCRYPTION_CONTEXT;
+
+#endif // RMLSFM_H
+
diff --git a/userspace/sdks/nv570/nvalloc/common/inc/rmpbicmdif.h b/userspace/sdks/nv570/nvalloc/common/inc/rmpbicmdif.h
new file mode 100644
index 0000000..cd4d092
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/common/inc/rmpbicmdif.h
@@ -0,0 +1,140 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2009-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/*!
+ * Shared postbox interface defines for RM and PMU.
+ */
+
+#ifndef RMPBICMDIF_H
+#define RMPBICMDIF_H
+
+/*
+ * Define the status of postbox interface at different instances.
+ *
+ * The values should be in accordance to the spec and must not be changed.
+ * A new PBI command must be submitted with the status NV_PBI_COMMAND_STATUS_UNDEFINED.
+ */
+
+#define NV_PBI_COMMAND_STATUS 7:0
+#define NV_PBI_COMMAND_STATUS_UNDEFINED 0x00 // command submitted to PMU
+#define NV_PBI_COMMAND_STATUS_SUCCESS 0x01 // command successfully completed by PMU
+#define NV_PBI_COMMAND_STATUS_PENDING 0x02 // command accepted by PMU
+#define NV_PBI_COMMAND_STATUS_BUSY 0x03 // command processing in PMU
+#define NV_PBI_COMMAND_STATUS_UNSPECIFIED_FAILURE 0x04 // unknown failure or hang
+#define NV_PBI_COMMAND_STATUS_INVALID_ADDRESS 0x05 // invalid address submitted to PMU
+#define NV_PBI_COMMAND_STATUS_MORE_DATA 0x06 // user needs to send more data to PMU
+#define NV_PBI_COMMAND_STATUS_INVALID_COMMAND 0x07 // invalid command submitted
+
+/*
+ * This corresponds to reserved bits of command register
+ */
+#define NV_PBI_COMMAND_RSVD_0 15:8
+#define NV_PBI_COMMAND_RSVD_0_VAL 0x00
+
+/*
+ * This specifies the dword index if client is sending multiple dwords
+ * for single Dword this should be zero
+ */
+#define NV_PBI_COMMAND_BUFFER_INDEX 19:16
+
+/*
+ * This specifies the total no. of dwords passed by client
+ */
+#define NV_PBI_COMMAND_BUFFER_SIZE 23:20
+
+/*
+ * These corresponds the different function ID's supported out of PBI
+ */
+#define NV_PBI_COMMAND_FUNC_ID 27:24
+#define NV_PBI_COMMAND_FUNC_ID_GET_CAPABILITIES (0)
+#define NV_PBI_COMMAND_FUNC_ID_EXECUTE_ROUTINE (11)
+
+//
+// Definitions for common 'Execute Routine' calls that are
+// shared across all GPUs.
+//
+// Common routine IDs must be in the range 0x80 to 0xff.
+//
+// Get GID:
+#define NV_PBI_EXECUTE_ROUTINE_GET_GID 0x80
+// Get Feature:
+#define NV_PBI_EXECUTE_ROUTINE_GET_FEATURE 0x81
+#define NV_PBI_EXECUTE_ROUTINE_GET_FEATURE_EXCLUSION 5:0
+#define NV_PBI_EXECUTE_ROUTINE_GET_FEATURE_EXCLUSION_ALLOWED 0x2
+
+/*
+ * This corresponds to reserved field of command register
+ */
+#define NV_PBI_COMMAND_RSVD_1 28:28
+#define NV_PBI_COMMAND_RSVD_1_VAL 0x00
+
+/*
+ * If this bit is set system will be notified on command completion
+ */
+#define NV_PBI_COMMAND_SYS_NOTIFY 29:29
+#define NV_PBI_COMMAND_SYS_NOTIFY_TRUE 0x01
+#define NV_PBI_COMMAND_SYS_NOTIFY_FALSE 0x00
+
+/*
+ * If this bit is set driver will be notified of command completion status
+ */
+#define NV_PBI_COMMAND_DRV_NOTIFY 30:30
+#define NV_PBI_COMMAND_DRV_NOTIFY_TRUE 0x01
+#define NV_PBI_COMMAND_DRV_NOTIFY_FALSE 0x00
+
+/*
+ * Defines the interrupt state of the PBI command
+ */
+#define NV_PBI_COMMAND_INTERRUPT 31:31
+#define NV_PBI_COMMAND_INTERRUPT_TRUE 0x01
+#define NV_PBI_COMMAND_INTERRUPT_FALSE 0x00
+
+/*
+ * This sets the different fields of command register
+ */
+#define PBI_SET_COMMAND_PARAMS(status, r0, index, sz, cmd, r1, sys, \
+ drv, intr, val) \
+{ \
+ val = DRF_NUM(_PBI, _COMMAND, _STATUS, status) | \
+ DRF_NUM(_PBI, _COMMAND, _RSVD_0, r0) | \
+ DRF_NUM(_PBI, _COMMAND, _BUFFER_INDEX, index) | \
+ DRF_NUM(_PBI, _COMMAND, _BUFFER_SIZE, sz) | \
+ DRF_NUM(_PBI, _COMMAND, _FUNC_ID, cmd) | \
+ DRF_NUM(_PBI, _COMMAND, _RSVD_1, r1) | \
+ DRF_NUM(_PBI, _COMMAND, _SYS_NOTIFY, sys) | \
+ DRF_NUM(_PBI, _COMMAND, _DRV_NOTIFY, drv) | \
+ DRF_NUM(_PBI, _COMMAND, _INTERRUPT, intr); \
+}
+
+/*
+ * postbox_clients_mutex_id
+ *
+ * Define the Mutex ID for different PBI clients
+ */
+enum postbox_clients_mutex_id
+{
+ PBI_CLIENT_NONE = 0x00,
+ PBI_CLIENT_DRIVER_PCIPBI_SHIM = 0x15
+};
+
+#endif /* RMPBICMDIF_H */
diff --git a/userspace/sdks/nv570/nvalloc/common/inc/sec2/nvdm_payload_cmd_response.h b/userspace/sdks/nv570/nvalloc/common/inc/sec2/nvdm_payload_cmd_response.h
new file mode 100644
index 0000000..fa117aa
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/common/inc/sec2/nvdm_payload_cmd_response.h
@@ -0,0 +1,44 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/*
+ * @file nvdm_payload_cmd_response.h
+ * @brief Header file containing the definition for the
+ * NVDM_PAYLOAD_COMMAND_RESPONSE structure, which
+ * is required for SMBPBI-specific payloads and needs
+ * to be visible by bothe the PMU and the driver sides.
+ */
+
+#ifndef _NVDM_PAYLOAD_CMD_RESPONSE_H
+#define _NVDM_PAYLOAD_CMD_RESPONSE_H
+
+#pragma pack(1)
+typedef struct
+{
+ NvU32 taskId;
+ NvU32 commandNvdmType;
+ NvU32 errorCode;
+} NVDM_PAYLOAD_COMMAND_RESPONSE;
+#pragma pack()
+
+#endif // _NVDM_PAYLOAD_CMD_RESPONSE_H
diff --git a/userspace/sdks/nv570/nvalloc/common/inc/sec2/sec2_emem_channels.h b/userspace/sdks/nv570/nvalloc/common/inc/sec2/sec2_emem_channels.h
new file mode 100644
index 0000000..3681f24
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/common/inc/sec2/sec2_emem_channels.h
@@ -0,0 +1,39 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _SEC2_EMEM_CHANNELS_H_
+#define _SEC2_EMEM_CHANNELS_H_
+
+//
+// NVDM (NVIDIA Data Model) overlayed on MCTP (Management Component Transport
+// Protocol) and sent over EMEM is the communication mechanism used between SEC2
+// management partition and CPU-RM/other uprocs.
+//
+
+// RM uses channel 0 for SEC2 EMEM.
+#define SEC2_EMEM_CHANNEL_RM 0x0
+
+// EMEM channel 0 (RM) is allocated 1K bytes.
+#define SEC2_EMEM_CHANNEL_RM_SIZE 1024
+
+#endif // _SEC2_EMEM_CHANNELS_H_
diff --git a/userspace/sdks/nv570/nvalloc/common/inc/spdm/rmspdmrsakeys.h b/userspace/sdks/nv570/nvalloc/common/inc/spdm/rmspdmrsakeys.h
new file mode 100644
index 0000000..882497b
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/common/inc/spdm/rmspdmrsakeys.h
@@ -0,0 +1,160 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/*!
+ * @file rmspdmrsakeys.h
+ * @brief SPDM Interfaces - RSA keys
+ */
+
+#ifndef _RM_SPDM_RSA_KEYS_H_
+#define _RM_SPDM_RSA_KEYS_H_
+
+//
+// Note !!
+// All key components order must be big-endian(network order).
+// If any change for these key components, need to rebuild GSP/RM code as well.
+//
+#ifndef USE_MBEDTLS
+
+const NvU8 g_rsa3k_modulus_mutual_authentication_prod[] =
+{
+ 0xcd, 0x65, 0xd2, 0xca, 0x74, 0xd1, 0x76, 0x76, 0x9f, 0x18, 0x23, 0x64, 0x55, 0x84, 0x98, 0x60,
+ 0x71, 0xeb, 0x42, 0x6d, 0xa4, 0x98, 0xf9, 0x92, 0xea, 0x83, 0x5b, 0x9b, 0xe2, 0x66, 0x8b, 0x43,
+ 0x14, 0x4d, 0x5a, 0xb8, 0xdb, 0x68, 0x2b, 0xfa, 0x5f, 0xdf, 0x7f, 0xf4, 0xfd, 0x5e, 0x42, 0x34,
+ 0x09, 0x98, 0xa1, 0x21, 0x98, 0x4c, 0x8d, 0xbc, 0x99, 0xdb, 0xea, 0xc1, 0xe3, 0x42, 0xe6, 0x67,
+ 0x26, 0x86, 0x2c, 0xd0, 0xdb, 0xf3, 0x9c, 0x12, 0xad, 0xb3, 0x82, 0x93, 0x9c, 0xb9, 0xae, 0x98,
+ 0x82, 0xeb, 0x59, 0xb6, 0x5c, 0x09, 0x9f, 0xa6, 0x15, 0x30, 0xa0, 0xc6, 0x77, 0xd5, 0xae, 0xa2,
+ 0x91, 0x65, 0x24, 0xc3, 0x7d, 0x9b, 0xa4, 0x2c, 0x31, 0x73, 0x41, 0x26, 0x72, 0xe7, 0x2f, 0xb8,
+ 0x60, 0xd8, 0xce, 0xb8, 0xd8, 0x4b, 0x90, 0x6c, 0xa3, 0x19, 0x7e, 0x2b, 0xd5, 0xf6, 0x05, 0x8a,
+ 0x2b, 0xb9, 0x9e, 0x27, 0xba, 0x2e, 0x16, 0x81, 0x9a, 0x9e, 0xf5, 0x6c, 0x38, 0x0a, 0x01, 0xea,
+ 0xd6, 0xe1, 0xa4, 0x83, 0x76, 0xd0, 0x68, 0xbb, 0x90, 0x63, 0xce, 0x1c, 0x8c, 0x6f, 0x0f, 0x6b,
+ 0x65, 0x5b, 0x12, 0xe2, 0x92, 0x60, 0x79, 0x88, 0x99, 0x5e, 0x17, 0x89, 0x4d, 0x54, 0xb1, 0x87,
+ 0x9c, 0xe6, 0x6d, 0x3c, 0x56, 0x1c, 0x3a, 0x3e, 0xb9, 0x16, 0x2c, 0xc8, 0xda, 0x1a, 0xfb, 0x5c,
+ 0xd7, 0x16, 0x3c, 0x74, 0xda, 0x78, 0xf1, 0x53, 0xd7, 0x66, 0x97, 0x8a, 0x57, 0x0b, 0x86, 0x57,
+ 0x2c, 0x45, 0xa1, 0x5e, 0xae, 0x39, 0x39, 0xde, 0xe0, 0x40, 0x6f, 0xdb, 0x4c, 0xd8, 0xc1, 0x8c,
+ 0xdb, 0xce, 0xea, 0x05, 0xc0, 0xbc, 0x89, 0x72, 0x15, 0xfd, 0xbf, 0xb2, 0xb7, 0xf2, 0x5d, 0x05,
+ 0xdd, 0x2b, 0x53, 0xa4, 0x03, 0x1e, 0x11, 0x67, 0xa7, 0x0f, 0x87, 0xfb, 0x57, 0x48, 0x91, 0xc8,
+ 0x02, 0xb7, 0x46, 0x3d, 0x82, 0xcd, 0x06, 0x4a, 0x79, 0x0f, 0xa5, 0x8a, 0xac, 0xfb, 0xb7, 0xc2,
+ 0xf0, 0x95, 0x19, 0x4c, 0x78, 0x7a, 0xc7, 0xd7, 0x70, 0xee, 0x6e, 0x59, 0xaf, 0x51, 0x9b, 0x11,
+ 0x03, 0xd3, 0x56, 0xb3, 0x05, 0x5a, 0xbb, 0x1f, 0xbd, 0xc2, 0x0e, 0x89, 0x77, 0xb4, 0xc1, 0x02,
+ 0xf9, 0x97, 0x56, 0x07, 0x2e, 0x4e, 0x2d, 0x01, 0x73, 0x89, 0x7d, 0xf3, 0xc9, 0x8c, 0x88, 0x2c,
+ 0x79, 0xd9, 0x47, 0x34, 0x9e, 0x32, 0x51, 0xd4, 0xa6, 0x7e, 0xd1, 0x08, 0xda, 0xc0, 0x76, 0x24,
+ 0x8e, 0x25, 0x73, 0x14, 0x30, 0xd2, 0x17, 0x37, 0xbc, 0xe0, 0x3e, 0xa2, 0x47, 0xff, 0xe2, 0x4e,
+ 0x9b, 0x31, 0x6c, 0xe6, 0x54, 0xaf, 0x62, 0x3a, 0xcd, 0xfa, 0x2f, 0xaf, 0x73, 0x2e, 0x73, 0x4a,
+ 0x3a, 0x60, 0xa8, 0xa9, 0xfc, 0x77, 0xb2, 0x57, 0xdd, 0x3a, 0xfa, 0xce, 0x35, 0xc3, 0xea, 0xa9
+};
+
+const NvU8 g_rsa3k_public_exponent_mutual_authentication_prod[] = {0x00, 0x01, 0x00, 0x01};
+
+const NvU8 g_rsa3k_private_exponent_mutual_authentication_prod[] =
+{
+ 0x04, 0x85, 0xc0, 0x6d, 0x6a, 0xc3, 0x0d, 0xeb, 0xb0, 0xb7, 0x14, 0x58, 0x6a, 0x35, 0xa0, 0x31,
+ 0x47, 0x70, 0xd9, 0xa6, 0x96, 0x60, 0x33, 0xe6, 0x93, 0x39, 0x4f, 0x34, 0x10, 0x79, 0x17, 0x89,
+ 0xe3, 0x91, 0x8c, 0x74, 0xd3, 0x87, 0xe8, 0xa7, 0xfb, 0xa2, 0x6d, 0x2b, 0xd4, 0xc4, 0x55, 0x8a,
+ 0xd5, 0xc7, 0x41, 0x8c, 0xfe, 0xd0, 0x78, 0xb2, 0x75, 0x64, 0xcd, 0x37, 0x75, 0xac, 0x8c, 0x6c,
+ 0x2b, 0x01, 0xfb, 0x4c, 0xa1, 0xfb, 0x2c, 0x2d, 0x91, 0x1b, 0x89, 0xbd, 0x7c, 0x4e, 0xee, 0x54,
+ 0x37, 0x55, 0xbd, 0x44, 0xf1, 0xa3, 0xd8, 0x9b, 0x0c, 0x8e, 0x64, 0x8b, 0xda, 0x29, 0x9f, 0x4d,
+ 0xbf, 0x0b, 0xce, 0x12, 0x6b, 0xda, 0x98, 0x73, 0xcc, 0xa6, 0xf0, 0x01, 0x4b, 0xb8, 0x61, 0x69,
+ 0x9a, 0xe0, 0x4b, 0x34, 0xf0, 0xb6, 0x41, 0x38, 0xd3, 0x22, 0x85, 0x8f, 0xab, 0x87, 0x5e, 0x39,
+ 0xdb, 0x9a, 0x9b, 0xab, 0xde, 0x42, 0x93, 0x86, 0x49, 0x04, 0x44, 0xfd, 0x1c, 0x02, 0xc4, 0x66,
+ 0x0a, 0x53, 0x2f, 0x8f, 0x21, 0x77, 0x97, 0x46, 0xc1, 0xf8, 0x20, 0x9a, 0xaa, 0x50, 0xeb, 0xb2,
+ 0xfe, 0xa9, 0x51, 0xb2, 0x21, 0x6c, 0xf4, 0x60, 0x18, 0x98, 0x64, 0xc6, 0x46, 0x28, 0x9e, 0x3c,
+ 0x11, 0x2d, 0x55, 0xac, 0x65, 0x6c, 0xfb, 0xaf, 0x53, 0xdd, 0xf4, 0x20, 0x7c, 0x04, 0xea, 0x11,
+ 0xe8, 0x25, 0x65, 0x15, 0x32, 0x8e, 0x08, 0x84, 0xc7, 0x41, 0x13, 0x58, 0x73, 0x61, 0x63, 0x1f,
+ 0xef, 0x30, 0x1d, 0x3d, 0x36, 0x08, 0x3a, 0xb2, 0xf7, 0x25, 0x56, 0xfc, 0x03, 0x78, 0xb5, 0x45,
+ 0xf4, 0x60, 0x47, 0x95, 0x1c, 0x6a, 0x2b, 0xfa, 0xe3, 0x1c, 0x2f, 0x0d, 0x2a, 0x90, 0x43, 0x65,
+ 0x09, 0xbe, 0x63, 0x71, 0x33, 0xd3, 0x29, 0x31, 0xd5, 0x29, 0x26, 0xa3, 0x15, 0xc2, 0x46, 0x70,
+ 0xb4, 0x3e, 0x23, 0xaf, 0xb6, 0xfb, 0x87, 0x8f, 0x39, 0xf0, 0xd2, 0x3e, 0x35, 0x3c, 0xec, 0x7a,
+ 0xd2, 0x0f, 0xd8, 0xa4, 0x0c, 0x19, 0xc8, 0xee, 0x47, 0x7c, 0x1e, 0xd6, 0x67, 0x31, 0xe2, 0x9d,
+ 0xc0, 0x65, 0x64, 0x60, 0xe7, 0xd2, 0xeb, 0xe1, 0x02, 0xd5, 0x92, 0x7c, 0x51, 0xf1, 0x3b, 0x12,
+ 0x00, 0x65, 0xfd, 0x2b, 0x13, 0x15, 0xfa, 0x6d, 0x99, 0x1d, 0xd3, 0x03, 0x77, 0xb1, 0xb0, 0xf0,
+ 0x39, 0x7c, 0x27, 0x13, 0x30, 0xba, 0xff, 0x4d, 0x2e, 0xda, 0xe0, 0x37, 0xad, 0xf4, 0x49, 0x0a,
+ 0xdd, 0x1e, 0x87, 0x8c, 0xc9, 0x6b, 0xf8, 0xc6, 0xb3, 0x05, 0xeb, 0x6c, 0x5f, 0x84, 0x64, 0x62,
+ 0x1c, 0xf6, 0x04, 0x6f, 0xd7, 0xa9, 0xbc, 0x22, 0x97, 0xdb, 0x8d, 0xa5, 0xe1, 0x3a, 0x5c, 0x0d,
+ 0x7b, 0x78, 0x25, 0x98, 0x04, 0x7f, 0x2b, 0x59, 0x5b, 0x7c, 0xf7, 0x73, 0x37, 0x7f, 0x92, 0x8d
+};
+
+#else
+
+const NvU8 g_rsa3k_modulus_mutual_authentication_prod[] =
+{
+ 0xa9, 0xea, 0xc3, 0x35, 0xce, 0xfa, 0x3a, 0xdd, 0x57, 0xb2, 0x77, 0xfc, 0xa9, 0xa8, 0x60, 0x3a,
+ 0x4a, 0x73, 0x2e, 0x73, 0xaf, 0x2f, 0xfa, 0xcd, 0x3a, 0x62, 0xaf, 0x54, 0xe6, 0x6c, 0x31, 0x9b,
+ 0x4e, 0xe2, 0xff, 0x47, 0xa2, 0x3e, 0xe0, 0xbc, 0x37, 0x17, 0xd2, 0x30, 0x14, 0x73, 0x25, 0x8e,
+ 0x24, 0x76, 0xc0, 0xda, 0x08, 0xd1, 0x7e, 0xa6, 0xd4, 0x51, 0x32, 0x9e, 0x34, 0x47, 0xd9, 0x79,
+ 0x2c, 0x88, 0x8c, 0xc9, 0xf3, 0x7d, 0x89, 0x73, 0x01, 0x2d, 0x4e, 0x2e, 0x07, 0x56, 0x97, 0xf9,
+ 0x02, 0xc1, 0xb4, 0x77, 0x89, 0x0e, 0xc2, 0xbd, 0x1f, 0xbb, 0x5a, 0x05, 0xb3, 0x56, 0xd3, 0x03,
+ 0x11, 0x9b, 0x51, 0xaf, 0x59, 0x6e, 0xee, 0x70, 0xd7, 0xc7, 0x7a, 0x78, 0x4c, 0x19, 0x95, 0xf0,
+ 0xc2, 0xb7, 0xfb, 0xac, 0x8a, 0xa5, 0x0f, 0x79, 0x4a, 0x06, 0xcd, 0x82, 0x3d, 0x46, 0xb7, 0x02,
+ 0xc8, 0x91, 0x48, 0x57, 0xfb, 0x87, 0x0f, 0xa7, 0x67, 0x11, 0x1e, 0x03, 0xa4, 0x53, 0x2b, 0xdd,
+ 0x05, 0x5d, 0xf2, 0xb7, 0xb2, 0xbf, 0xfd, 0x15, 0x72, 0x89, 0xbc, 0xc0, 0x05, 0xea, 0xce, 0xdb,
+ 0x8c, 0xc1, 0xd8, 0x4c, 0xdb, 0x6f, 0x40, 0xe0, 0xde, 0x39, 0x39, 0xae, 0x5e, 0xa1, 0x45, 0x2c,
+ 0x57, 0x86, 0x0b, 0x57, 0x8a, 0x97, 0x66, 0xd7, 0x53, 0xf1, 0x78, 0xda, 0x74, 0x3c, 0x16, 0xd7,
+ 0x5c, 0xfb, 0x1a, 0xda, 0xc8, 0x2c, 0x16, 0xb9, 0x3e, 0x3a, 0x1c, 0x56, 0x3c, 0x6d, 0xe6, 0x9c,
+ 0x87, 0xb1, 0x54, 0x4d, 0x89, 0x17, 0x5e, 0x99, 0x88, 0x79, 0x60, 0x92, 0xe2, 0x12, 0x5b, 0x65,
+ 0x6b, 0x0f, 0x6f, 0x8c, 0x1c, 0xce, 0x63, 0x90, 0xbb, 0x68, 0xd0, 0x76, 0x83, 0xa4, 0xe1, 0xd6,
+ 0xea, 0x01, 0x0a, 0x38, 0x6c, 0xf5, 0x9e, 0x9a, 0x81, 0x16, 0x2e, 0xba, 0x27, 0x9e, 0xb9, 0x2b,
+ 0x8a, 0x05, 0xf6, 0xd5, 0x2b, 0x7e, 0x19, 0xa3, 0x6c, 0x90, 0x4b, 0xd8, 0xb8, 0xce, 0xd8, 0x60,
+ 0xb8, 0x2f, 0xe7, 0x72, 0x26, 0x41, 0x73, 0x31, 0x2c, 0xa4, 0x9b, 0x7d, 0xc3, 0x24, 0x65, 0x91,
+ 0xa2, 0xae, 0xd5, 0x77, 0xc6, 0xa0, 0x30, 0x15, 0xa6, 0x9f, 0x09, 0x5c, 0xb6, 0x59, 0xeb, 0x82,
+ 0x98, 0xae, 0xb9, 0x9c, 0x93, 0x82, 0xb3, 0xad, 0x12, 0x9c, 0xf3, 0xdb, 0xd0, 0x2c, 0x86, 0x26,
+ 0x67, 0xe6, 0x42, 0xe3, 0xc1, 0xea, 0xdb, 0x99, 0xbc, 0x8d, 0x4c, 0x98, 0x21, 0xa1, 0x98, 0x09,
+ 0x34, 0x42, 0x5e, 0xfd, 0xf4, 0x7f, 0xdf, 0x5f, 0xfa, 0x2b, 0x68, 0xdb, 0xb8, 0x5a, 0x4d, 0x14,
+ 0x43, 0x8b, 0x66, 0xe2, 0x9b, 0x5b, 0x83, 0xea, 0x92, 0xf9, 0x98, 0xa4, 0x6d, 0x42, 0xeb, 0x71,
+ 0x60, 0x98, 0x84, 0x55, 0x64, 0x23, 0x18, 0x9f, 0x76, 0x76, 0xd1, 0x74, 0xca, 0xd2, 0x65, 0xcd,
+ 0x00
+};
+
+const NvU8 g_rsa3k_public_exponent_mutual_authentication_prod[] = {0x01, 0x00, 0x01, 0x00};
+
+const NvU8 g_rsa3k_private_exponent_mutual_authentication_prod[] =
+{
+ 0x8d, 0x92, 0x7f, 0x37, 0x73, 0xf7, 0x7c, 0x5b, 0x59, 0x2b, 0x7f, 0x04, 0x98, 0x25, 0x78, 0x7b,
+ 0x0d, 0x5c, 0x3a, 0xe1, 0xa5, 0x8d, 0xdb, 0x97, 0x22, 0xbc, 0xa9, 0xd7, 0x6f, 0x04, 0xf6, 0x1c,
+ 0x62, 0x64, 0x84, 0x5f, 0x6c, 0xeb, 0x05, 0xb3, 0xc6, 0xf8, 0x6b, 0xc9, 0x8c, 0x87, 0x1e, 0xdd,
+ 0x0a, 0x49, 0xf4, 0xad, 0x37, 0xe0, 0xda, 0x2e, 0x4d, 0xff, 0xba, 0x30, 0x13, 0x27, 0x7c, 0x39,
+ 0xf0, 0xb0, 0xb1, 0x77, 0x03, 0xd3, 0x1d, 0x99, 0x6d, 0xfa, 0x15, 0x13, 0x2b, 0xfd, 0x65, 0x00,
+ 0x12, 0x3b, 0xf1, 0x51, 0x7c, 0x92, 0xd5, 0x02, 0xe1, 0xeb, 0xd2, 0xe7, 0x60, 0x64, 0x65, 0xc0,
+ 0x9d, 0xe2, 0x31, 0x67, 0xd6, 0x1e, 0x7c, 0x47, 0xee, 0xc8, 0x19, 0x0c, 0xa4, 0xd8, 0x0f, 0xd2,
+ 0x7a, 0xec, 0x3c, 0x35, 0x3e, 0xd2, 0xf0, 0x39, 0x8f, 0x87, 0xfb, 0xb6, 0xaf, 0x23, 0x3e, 0xb4,
+ 0x70, 0x46, 0xc2, 0x15, 0xa3, 0x26, 0x29, 0xd5, 0x31, 0x29, 0xd3, 0x33, 0x71, 0x63, 0xbe, 0x09,
+ 0x65, 0x43, 0x90, 0x2a, 0x0d, 0x2f, 0x1c, 0xe3, 0xfa, 0x2b, 0x6a, 0x1c, 0x95, 0x47, 0x60, 0xf4,
+ 0x45, 0xb5, 0x78, 0x03, 0xfc, 0x56, 0x25, 0xf7, 0xb2, 0x3a, 0x08, 0x36, 0x3d, 0x1d, 0x30, 0xef,
+ 0x1f, 0x63, 0x61, 0x73, 0x58, 0x13, 0x41, 0xc7, 0x84, 0x08, 0x8e, 0x32, 0x15, 0x65, 0x25, 0xe8,
+ 0x11, 0xea, 0x04, 0x7c, 0x20, 0xf4, 0xdd, 0x53, 0xaf, 0xfb, 0x6c, 0x65, 0xac, 0x55, 0x2d, 0x11,
+ 0x3c, 0x9e, 0x28, 0x46, 0xc6, 0x64, 0x98, 0x18, 0x60, 0xf4, 0x6c, 0x21, 0xb2, 0x51, 0xa9, 0xfe,
+ 0xb2, 0xeb, 0x50, 0xaa, 0x9a, 0x20, 0xf8, 0xc1, 0x46, 0x97, 0x77, 0x21, 0x8f, 0x2f, 0x53, 0x0a,
+ 0x66, 0xc4, 0x02, 0x1c, 0xfd, 0x44, 0x04, 0x49, 0x86, 0x93, 0x42, 0xde, 0xab, 0x9b, 0x9a, 0xdb,
+ 0x39, 0x5e, 0x87, 0xab, 0x8f, 0x85, 0x22, 0xd3, 0x38, 0x41, 0xb6, 0xf0, 0x34, 0x4b, 0xe0, 0x9a,
+ 0x69, 0x61, 0xb8, 0x4b, 0x01, 0xf0, 0xa6, 0xcc, 0x73, 0x98, 0xda, 0x6b, 0x12, 0xce, 0x0b, 0xbf,
+ 0x4d, 0x9f, 0x29, 0xda, 0x8b, 0x64, 0x8e, 0x0c, 0x9b, 0xd8, 0xa3, 0xf1, 0x44, 0xbd, 0x55, 0x37,
+ 0x54, 0xee, 0x4e, 0x7c, 0xbd, 0x89, 0x1b, 0x91, 0x2d, 0x2c, 0xfb, 0xa1, 0x4c, 0xfb, 0x01, 0x2b,
+ 0x6c, 0x8c, 0xac, 0x75, 0x37, 0xcd, 0x64, 0x75, 0xb2, 0x78, 0xd0, 0xfe, 0x8c, 0x41, 0xc7, 0xd5,
+ 0x8a, 0x55, 0xc4, 0xd4, 0x2b, 0x6d, 0xa2, 0xfb, 0xa7, 0xe8, 0x87, 0xd3, 0x74, 0x8c, 0x91, 0xe3,
+ 0x89, 0x17, 0x79, 0x10, 0x34, 0x4f, 0x39, 0x93, 0xe6, 0x33, 0x60, 0x96, 0xa6, 0xd9, 0x70, 0x47,
+ 0x31, 0xa0, 0x35, 0x6a, 0x58, 0x14, 0xb7, 0xb0, 0xeb, 0x0d, 0xc3, 0x6a, 0x6d, 0xc0, 0x85, 0x04
+};
+
+#endif
+
+#endif // _RM_SPDM_RSA_KEYS_H_
diff --git a/userspace/sdks/nv570/nvalloc/common/inc/spdm/rmspdmtransport.h b/userspace/sdks/nv570/nvalloc/common/inc/spdm/rmspdmtransport.h
new file mode 100644
index 0000000..9440ed8
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/common/inc/spdm/rmspdmtransport.h
@@ -0,0 +1,97 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2021-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _RM_SPDM_TRANSPORT_H_
+#define _RM_SPDM_TRANSPORT_H_
+
+/* ------------------------- Macros and Defines ----------------------------- */
+//
+// The following defines and macros are shared for any message-related constants
+// shared between RM and endpoint.
+//
+
+// Defines used for polling-based communication between Kernel-RM and GSP.
+#define NV_SPDM_PARTITION_BOOT_SUCCESS (0x59D3B007)
+#define NV_SPDM_REQUESTER_SECRETS_DERIVED (0x59D35DED)
+#define NV_SPDM_NO_MESSAGE_PENDING_TOKEN (0x00000000)
+#define NV_SPDM_REQUESTER_MESSAGE_PENDING_TOKEN (0xAFAFAFAF)
+#define NV_SPDM_RESPONDER_MESSAGE_PENDING_TOKEN (0xFAFAFAFA)
+#define NV_SPDM_SECRET_TEARDOWN_SUCCESS (0x59D35EDE)
+#define NV_SPDM_SECRET_TEARDOWN_FAILURE (0x59D35EFA)
+#define NV_SPDM_SECRET_TEARDOWN_ACK (0x59D35EAC)
+
+// TDISP Defines for polling-based communication between Kernel-RM and GSP.
+#define NV_TDISP_PARTITION_BOOT_SUCCESS (0x59D4B001)
+
+//
+// The SPDM communication between Kernel-RM and GSP utilizes a buffer in sysmem accessible
+// to both endpoints. The sysmem buffer will contain both a custom NV-defined header
+// describing the message type and size, and the SPDM payload itself.
+//
+
+//
+// Size of the full transportation buffer (header + SPDM payload) allocated in sysmem.
+// We need to align sysmem allocations with page size, but need less space. So we
+// over-allocate and tell GSP we only have the size we actually need.
+//
+#define NV_SPDM_SYSMEM_SURFACE_SIZE_PAGE_ALIGNED (0x2000)
+#define NV_SPDM_SYSMEM_SURFACE_SIZE_IN_BYTES (0x1200)
+#define NV_SPDM_SYSMEM_SURFACE_ALIGNMENT_IN_BYTES (256)
+
+// Struct and defines for the header which prepends the SPDM payload.
+#pragma pack(1)
+typedef struct _NV_SPDM_DESC_HEADER
+{
+ NvU32 msgType;
+ NvU32 msgSizeByte;
+ NvU32 version;
+} NV_SPDM_DESC_HEADER, *PNV_SPDM_DESC_HEADER;
+#pragma pack()
+
+#define NV_SPDM_MESSAGE_TYPE_NORMAL (0)
+#define NV_SPDM_MESSAGE_TYPE_SECURED (1)
+#define NV_SPDM_MESSAGE_TYPE_APPLICATION (2)
+#define NV_SPDM_DESC_HEADER_VERSION_1_0 (0x10)
+#define NV_SPDM_DESC_HEADER_VERSION_CURRENT (NV_SPDM_DESC_HEADER_VERSION_1_0)
+#define NV_SPDM_DESC_HEADER_ALIGNMENT_IN_BYTES (NV_SPDM_SYSMEM_SURFACE_ALIGNMENT_IN_BYTES)
+
+// Define utilized to determine size available for SPDM payload
+#define NV_SPDM_MAX_SPDM_PAYLOAD_SIZE (NV_SPDM_SYSMEM_SURFACE_SIZE_IN_BYTES - sizeof(NV_SPDM_DESC_HEADER))
+#define NV_SPDM_MAX_TRANSCRIPT_BUFFER_SIZE (2 * NV_SPDM_MAX_SPDM_PAYLOAD_SIZE)
+
+// Limited by the transport size, do not increase without increasing transport buffer.
+#define NV_SPDM_MAX_RANDOM_MSG_BYTES (0x0)
+
+#ifdef NVRM
+#include "gpu/mem_mgr/mem_desc.h"
+#else
+#ifndef ADDR_SYSMEM
+// System memory (PCI)
+#define ADDR_SYSMEM (1)
+#endif // ADDR_SYSMEM
+#endif //NVRM
+
+#define NV_SPDM_DMA_ADDR_SPACE_DEFAULT (ADDR_SYSMEM)
+#define NV_SPDM_DMA_REGION_ID_DEFAULT (0)
+
+#endif // _RM_SPDM_TRANSPORT_H_
diff --git a/userspace/sdks/nv570/nvalloc/common/inc/spdm/rmspdmvendordef.h b/userspace/sdks/nv570/nvalloc/common/inc/spdm/rmspdmvendordef.h
new file mode 100644
index 0000000..76eec37
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/common/inc/spdm/rmspdmvendordef.h
@@ -0,0 +1,161 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2021-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _RMSPDMVENDORDEF_H_
+#define _RMSPDMVENDORDEF_H_
+#include <nvtypes.h>
+
+/*!
+ * In NVIDIA's implementation of SPDM, we will support application messages
+ * which are payloads delivered encrypted in SPDM secured messages,
+ * sent across the SPDM channel, but do not contain SPDM messages.
+ * Instead, these messages are for NVIDIA-application purposes.
+ * These messages and relevant structs are defined here.
+ */
+
+/* ------------------------- Application Payloads ------------------------ */
+/*!
+ * All application messages will follow a simple header format in order to
+ * simplify the parsing and forwarding of application messages to the
+ * relevant recipient endpoint. This format is defined as follows:
+ *
+ * +----------------------------------+
+ * | RM_SPDM_NV_CMD |
+ * | Command Type | Command Payload |
+ * | (4 bytes) (n - 4 - 4 bytes) |
+ * +----------------------------------+
+ *
+ * The Command Type value defines the expected structure of the payload,
+ * and how it should be interpreted.
+ *
+ * There are two major categories of commands - requests and responses.
+ * The values of 0x00000000-0x7FFFFFFF are reserved for requests.
+ * The values of 0x80000000-0xFFFFFFFF are reserved for responses.
+ */
+
+typedef enum
+{
+ // Request commands.
+ RM_SPDM_NV_CMD_TYPE_REQ_KEYMGR_NVLE = 0x00000000,
+ // 0x00000001 - 0x7FFFFFFF reserved.
+
+ // Response commands.
+ RM_SPDM_NV_CMD_TYPE_RSP_SUCCESS = 0x80000000,
+ // 0x80000001 - 0xFFFFFFFF reserved.
+ RM_SPDM_NV_CMD_TYPE_RSP_ERROR = 0xFFFFFFFF,
+} RM_SPDM_NV_CMD_TYPE;
+
+typedef struct
+{
+ NvU32 cmdType;
+} RM_SPDM_NV_CMD_HDR;
+
+/* ------------------------- NVIDIA Requests -------------------------------- */
+/*!
+ * Request Command: Key Manager NVLE Command
+ * Command Type: 0x00000000
+ *
+ * Fields:
+ * Payload - Variable size opaque data blob containing command meant for Key manager
+ *
+ * This command is a generic wrapper around all commands that must be forwarded to Key Manager for NvLink Encryption.
+ * The command structure itself is opaque, as SPDM need not process any of the message itself. This limits coupling
+ * between the two command interfaces.
+ */
+typedef struct
+{
+ RM_SPDM_NV_CMD_HDR hdr;
+
+ NvU8 payload[];
+} RM_SPDM_NV_CMD_REQ_KEYMGR_NVLE;
+
+/*!
+ * Union of all known requests, so responder can allocate enough space for all possible requests.
+ */
+typedef union {
+ RM_SPDM_NV_CMD_HDR hdr;
+
+ RM_SPDM_NV_CMD_REQ_KEYMGR_NVLE keyMgrNvle;
+} RM_SPDM_NV_CMD_REQ;
+
+/* ------------------------- NVIDIA Responses ------------------------------- */
+/*!
+ * Response Command: Success
+ * Command Type: 0x80000000
+ *
+ * This command is a simple payload for the responding endpoint to
+ * return success. It has no Command Payload.
+ */
+typedef struct
+{
+ RM_SPDM_NV_CMD_HDR hdr;
+} RM_SPDM_NV_CMD_RSP_SUCCESS;
+
+/*!
+ * Response Command: Error
+ * Command Type: 0xFFFFFFFF
+ *
+ * This command is a generic placeholder error response to return specific
+ * failure code to application endpoint. This is used to return an error
+ * back to the original application which sent the message, rather than
+ * suggesting that there was some SPDM or transport layer error.
+ */
+typedef struct
+{
+ RM_SPDM_NV_CMD_HDR hdr;
+ NV_STATUS status;
+} RM_SPDM_NV_CMD_RSP_ERROR;
+
+/*!
+ * Union of all known responses, so requester can allocate enough space for all possible responses.
+ */
+typedef union {
+ RM_SPDM_NV_CMD_HDR hdr;
+
+ RM_SPDM_NV_CMD_RSP_SUCCESS success;
+ RM_SPDM_NV_CMD_RSP_ERROR error;
+} RM_SPDM_NV_CMD_RSP;
+
+#pragma pack()
+
+/* ------------------------- Macros ----------------------------------------- */
+#define SPDM_MAX_MEASUREMENT_BLOCK_COUNT (64)
+#define SPDM_CERT_DEFAULT_SLOT_ID (0)
+#define SPDM_CAPABILITIES_CT_EXPONENT_MAX (0x1F)
+#define SPDM_DEFAULT_HEARTBEAT_PERIOD_IN_SEC (4)
+
+#define NV_BYTE_TO_BIT_OVERFLOW_MASK_UINT32 (0xE0000000)
+#define IS_BYTE_TO_BIT_OVERFLOW_UINT32(a) \
+ ((a & NV_BYTE_TO_BIT_OVERFLOW_MASK_UINT32) != 0)
+
+/* ---------------------- Public defines ------------------------------------- */
+#define NV_KEY_UPDATE_TRIGGER_THRESHOLD (0x10000000)
+
+#define NV_KEY_UPDATE_TRIGGER_ID_INVALID (0)
+#define NV_KEY_UPDATE_TRIGGER_ID_GET_MEASUREMENTS (1)
+#define NV_KEY_UPDATE_TRIGGER_ID_HEARTBEAT (2)
+#define NV_KEY_UPDATE_TRIGGER_ID_LAST (3)
+
+#define NV_SPDM_ENCAP_CERT_SIZE_IN_BYTE (578)
+
+#endif // _RMSPDMVENDORDEF_H_
diff --git a/userspace/sdks/nv570/nvalloc/unix/include/nv-caps.h b/userspace/sdks/nv570/nvalloc/unix/include/nv-caps.h
new file mode 100644
index 0000000..35bbf7c
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/include/nv-caps.h
@@ -0,0 +1,94 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2019 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _NV_CAPS_H_
+#define _NV_CAPS_H_
+
+#include <nv-kernel-interface-api.h>
+
+/*
+ * Opaque OS-specific struct; on Linux, this has member
+ * 'struct proc_dir_entry'.
+ */
+typedef struct nv_cap nv_cap_t;
+
+/*
+ * Creates directory named "capabilities" under the provided path.
+ *
+ * @param[in] path Absolute path
+ *
+ * Returns a valid nv_cap_t upon success. Otherwise, returns NULL.
+ */
+nv_cap_t* NV_API_CALL nv_cap_init(const char *path);
+
+/*
+ * Creates capability directory entry
+ *
+ * @param[in] parent_cap Parent capability directory
+ * @param[in] name Capability directory's name
+ * @param[in] mode Capability directory's access mode
+ *
+ * Returns a valid nv_cap_t upon success. Otherwise, returns NULL.
+ */
+nv_cap_t* NV_API_CALL nv_cap_create_dir_entry(nv_cap_t *parent_cap, const char *name, int mode);
+
+/*
+ * Creates capability file entry
+ *
+ * @param[in] parent_cap Parent capability directory
+ * @param[in] name Capability file's name
+ * @param[in] mode Capability file's access mode
+ *
+ * Returns a valid nv_cap_t upon success. Otherwise, returns NULL.
+ */
+nv_cap_t* NV_API_CALL nv_cap_create_file_entry(nv_cap_t *parent_cap, const char *name, int mode);
+
+/*
+ * Destroys capability entry
+ *
+ * @param[in] cap Capability entry
+ */
+void NV_API_CALL nv_cap_destroy_entry(nv_cap_t *cap);
+
+/*
+ * Validates and duplicates the provided file descriptor
+ *
+ * @param[in] cap Capability entry
+ * @param[in] fd File descriptor to be validated
+ *
+ * Returns duplicate fd upon success. Otherwise, returns -1.
+ */
+int NV_API_CALL nv_cap_validate_and_dup_fd(const nv_cap_t *cap, int fd);
+
+/*
+ * Closes file descriptor
+ *
+ * This function should be used to close duplicate file descriptors
+ * returned by nv_cap_validate_and_dup_fd.
+ *
+ * @param[in] fd File descriptor to be validated
+ *
+ */
+void NV_API_CALL nv_cap_close_fd(int fd);
+
+#endif /* _NV_CAPS_H_ */
diff --git a/userspace/sdks/nv570/nvalloc/unix/include/nv-chardev-numbers.h b/userspace/sdks/nv570/nvalloc/unix/include/nv-chardev-numbers.h
new file mode 100644
index 0000000..54ca547
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/include/nv-chardev-numbers.h
@@ -0,0 +1,43 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+
+#ifndef _NV_CHARDEV_NUMBERS_H_
+#define _NV_CHARDEV_NUMBERS_H_
+
+// NVIDIA's reserved major character device number (Linux).
+#define NV_MAJOR_DEVICE_NUMBER 195
+
+// Minor numbers 0 to 247 reserved for regular devices
+#define NV_MINOR_DEVICE_NUMBER_REGULAR_MAX 247
+
+// Minor numbers 248 to 253 currently unused
+
+// Minor number 254 reserved for the modeset device (provided by NVKMS)
+#define NV_MINOR_DEVICE_NUMBER_MODESET_DEVICE 254
+
+// Minor number 255 reserved for the control device
+#define NV_MINOR_DEVICE_NUMBER_CONTROL_DEVICE 255
+
+#endif // _NV_CHARDEV_NUMBERS_H_
+
diff --git a/userspace/sdks/nv570/nvalloc/unix/include/nv-gpu-info.h b/userspace/sdks/nv570/nvalloc/unix/include/nv-gpu-info.h
new file mode 100644
index 0000000..1b79320
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/include/nv-gpu-info.h
@@ -0,0 +1,47 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2015 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _NV_GPU_INFO_H_
+#define _NV_GPU_INFO_H_
+
+typedef struct {
+ NvU32 gpu_id;
+
+ struct {
+ NvU32 domain;
+ NvU8 bus, slot, function;
+ } pci_info;
+
+ NvBool needs_numa_setup;
+ NvBool is_soc_disp;
+
+ /*
+ * opaque OS-specific pointer; on Linux, this is a pointer to the
+ * 'struct device' for the GPU.
+ */
+ void *os_device_ptr;
+} nv_gpu_info_t;
+
+#define NV_MAX_GPUS 32
+
+#endif /* _NV_GPU_INFO_H_ */
diff --git a/userspace/sdks/nv570/nvalloc/unix/include/nv-ioctl-lockless-diag.h b/userspace/sdks/nv570/nvalloc/unix/include/nv-ioctl-lockless-diag.h
new file mode 100644
index 0000000..84e3fa7
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/include/nv-ioctl-lockless-diag.h
@@ -0,0 +1,43 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 1993-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#if !defined(NV_IOCTL_LOCKLESS_DIAG)
+#define NV_IOCTL_LOCKLESS_DIAG
+
+#include <nvtypes.h>
+#include "ctrl/ctrl0000/ctrl0000nvd.h"
+
+typedef struct
+{
+ NvU32 cmd; // in
+ NvU32 status; // out
+ union // in/out
+ {
+ NV0000_CTRL_NVD_GET_NVLOG_INFO_PARAMS getNvlogInfo;
+ NV0000_CTRL_NVD_GET_NVLOG_BUFFER_INFO_PARAMS getNvlogBufferInfo;
+ NV0000_CTRL_NVD_GET_NVLOG_PARAMS getNvlog;
+ } params;
+} NV_LOCKLESS_DIAGNOSTIC_PARAMS;
+
+#endif
+
diff --git a/userspace/sdks/nv570/nvalloc/unix/include/nv-ioctl-numa.h b/userspace/sdks/nv570/nvalloc/unix/include/nv-ioctl-numa.h
new file mode 100644
index 0000000..0af5267
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/include/nv-ioctl-numa.h
@@ -0,0 +1,81 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2020 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+
+#ifndef NV_IOCTL_NUMA_H
+#define NV_IOCTL_NUMA_H
+
+#include <nv-ioctl-numbers.h>
+
+#if defined(NV_KERNEL_INTERFACE_LAYER) && defined(NV_LINUX)
+#include <linux/types.h>
+#elif defined (NV_KERNEL_INTERFACE_LAYER) && defined(NV_BSD)
+#include <sys/stdint.h>
+#else
+
+#include <stdint.h>
+
+#if !defined(__aligned)
+#define __aligned(n) __attribute__((aligned(n)))
+#endif
+
+#endif
+
+#define NV_ESC_NUMA_INFO (NV_IOCTL_BASE + 15)
+#define NV_ESC_SET_NUMA_STATUS (NV_IOCTL_BASE + 16)
+
+#define NV_IOCTL_NUMA_INFO_MAX_OFFLINE_ADDRESSES 64
+typedef struct offline_addresses
+{
+ uint64_t addresses[NV_IOCTL_NUMA_INFO_MAX_OFFLINE_ADDRESSES] __aligned(8);
+ uint32_t numEntries;
+} nv_offline_addresses_t;
+
+
+/* per-device NUMA memory info as assigned by the system */
+typedef struct nv_ioctl_numa_info
+{
+ int32_t nid;
+ int32_t status;
+ uint64_t memblock_size __aligned(8);
+ uint64_t numa_mem_addr __aligned(8);
+ uint64_t numa_mem_size __aligned(8);
+ uint8_t use_auto_online;
+ nv_offline_addresses_t offline_addresses __aligned(8);
+} nv_ioctl_numa_info_t;
+
+/* set the status of the device NUMA memory */
+typedef struct nv_ioctl_set_numa_status
+{
+ int32_t status;
+} nv_ioctl_set_numa_status_t;
+
+#define NV_IOCTL_NUMA_STATUS_DISABLED 0
+#define NV_IOCTL_NUMA_STATUS_OFFLINE 1
+#define NV_IOCTL_NUMA_STATUS_ONLINE_IN_PROGRESS 2
+#define NV_IOCTL_NUMA_STATUS_ONLINE 3
+#define NV_IOCTL_NUMA_STATUS_ONLINE_FAILED 4
+#define NV_IOCTL_NUMA_STATUS_OFFLINE_IN_PROGRESS 5
+#define NV_IOCTL_NUMA_STATUS_OFFLINE_FAILED 6
+
+#endif
diff --git a/userspace/sdks/nv570/nvalloc/unix/include/nv-ioctl-numbers.h b/userspace/sdks/nv570/nvalloc/unix/include/nv-ioctl-numbers.h
new file mode 100644
index 0000000..e266368
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/include/nv-ioctl-numbers.h
@@ -0,0 +1,48 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2020-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+
+#ifndef NV_IOCTL_NUMBERS_H
+#define NV_IOCTL_NUMBERS_H
+
+/* NOTE: using an ioctl() number > 55 will overflow! */
+/*
+ * NOTE: Any new ioctls added here should also be added to nv_validate_ioctls() in nv.c or
+ * rm_validate_ioctls() in osapi.c
+ */
+#define NV_IOCTL_MAGIC 'F'
+#define NV_IOCTL_BASE 200
+#define NV_ESC_CARD_INFO (NV_IOCTL_BASE + 0)
+#define NV_ESC_REGISTER_FD (NV_IOCTL_BASE + 1)
+#define NV_ESC_ALLOC_OS_EVENT (NV_IOCTL_BASE + 6)
+#define NV_ESC_FREE_OS_EVENT (NV_IOCTL_BASE + 7)
+#define NV_ESC_STATUS_CODE (NV_IOCTL_BASE + 9)
+#define NV_ESC_CHECK_VERSION_STR (NV_IOCTL_BASE + 10)
+#define NV_ESC_IOCTL_XFER_CMD (NV_IOCTL_BASE + 11)
+#define NV_ESC_ATTACH_GPUS_TO_FD (NV_IOCTL_BASE + 12)
+#define NV_ESC_QUERY_DEVICE_INTR (NV_IOCTL_BASE + 13)
+#define NV_ESC_SYS_PARAMS (NV_IOCTL_BASE + 14)
+#define NV_ESC_EXPORT_TO_DMABUF_FD (NV_IOCTL_BASE + 17)
+#define NV_ESC_WAIT_OPEN_COMPLETE (NV_IOCTL_BASE + 18)
+
+#endif
diff --git a/userspace/sdks/nv570/nvalloc/unix/include/nv-ioctl.h b/userspace/sdks/nv570/nvalloc/unix/include/nv-ioctl.h
new file mode 100644
index 0000000..8ca1642
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/include/nv-ioctl.h
@@ -0,0 +1,158 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2020-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+
+#ifndef NV_IOCTL_H
+#define NV_IOCTL_H
+
+#include <nv-ioctl-numbers.h>
+#include <nv-ioctl-numa.h>
+#include <nvtypes.h>
+
+
+typedef struct {
+ NvU32 domain; /* PCI domain number */
+ NvU8 bus; /* PCI bus number */
+ NvU8 slot; /* PCI slot number */
+ NvU8 function; /* PCI function number */
+ NvU16 vendor_id; /* PCI vendor ID */
+ NvU16 device_id; /* PCI device ID */
+} nv_pci_info_t;
+
+/*
+ * ioctl()'s with parameter structures too large for the
+ * _IOC cmd layout use the nv_ioctl_xfer_t structure
+ * and the NV_ESC_IOCTL_XFER_CMD ioctl() to pass the actual
+ * size and user argument pointer into the RM, which
+ * will then copy it to/from kernel space in separate steps.
+ */
+typedef struct nv_ioctl_xfer
+{
+ NvU32 cmd;
+ NvU32 size;
+ NvP64 ptr NV_ALIGN_BYTES(8);
+} nv_ioctl_xfer_t;
+
+typedef struct nv_ioctl_card_info
+{
+ NvBool valid;
+ nv_pci_info_t pci_info; /* PCI config information */
+ NvU32 gpu_id;
+ NvU16 interrupt_line;
+ NvU64 reg_address NV_ALIGN_BYTES(8);
+ NvU64 reg_size NV_ALIGN_BYTES(8);
+ NvU64 fb_address NV_ALIGN_BYTES(8);
+ NvU64 fb_size NV_ALIGN_BYTES(8);
+ NvU32 minor_number;
+ NvU8 dev_name[10]; /* device names such as vmgfx[0-32] for vmkernel */
+} nv_ioctl_card_info_t;
+
+/* alloc event */
+typedef struct nv_ioctl_alloc_os_event
+{
+ NvHandle hClient;
+ NvHandle hDevice;
+ NvU32 fd;
+ NvU32 Status;
+} nv_ioctl_alloc_os_event_t;
+
+/* free event */
+typedef struct nv_ioctl_free_os_event
+{
+ NvHandle hClient;
+ NvHandle hDevice;
+ NvU32 fd;
+ NvU32 Status;
+} nv_ioctl_free_os_event_t;
+
+/* status code */
+typedef struct nv_ioctl_status_code
+{
+ NvU32 domain;
+ NvU8 bus;
+ NvU8 slot;
+ NvU32 status;
+} nv_ioctl_status_code_t;
+
+/* check version string */
+#define NV_RM_API_VERSION_STRING_LENGTH 64
+
+typedef struct nv_ioctl_rm_api_version
+{
+ NvU32 cmd;
+ NvU32 reply;
+ char versionString[NV_RM_API_VERSION_STRING_LENGTH];
+} nv_ioctl_rm_api_version_t;
+
+#define NV_RM_API_VERSION_CMD_STRICT 0
+#define NV_RM_API_VERSION_CMD_RELAXED '1'
+#define NV_RM_API_VERSION_CMD_QUERY '2'
+
+#define NV_RM_API_VERSION_REPLY_UNRECOGNIZED 0
+#define NV_RM_API_VERSION_REPLY_RECOGNIZED 1
+
+typedef struct nv_ioctl_query_device_intr
+{
+ NvU32 intrStatus NV_ALIGN_BYTES(4);
+ NvU32 status;
+} nv_ioctl_query_device_intr_t;
+
+/* system parameters that the kernel driver may use for configuration */
+typedef struct nv_ioctl_sys_params
+{
+ NvU64 memblock_size NV_ALIGN_BYTES(8);
+} nv_ioctl_sys_params_t;
+
+typedef struct nv_ioctl_register_fd
+{
+ int ctl_fd;
+} nv_ioctl_register_fd_t;
+
+#define NV_DMABUF_EXPORT_MAX_HANDLES 128
+
+#define NV_DMABUF_EXPORT_MAPPING_TYPE_DEFAULT 0
+#define NV_DMABUF_EXPORT_MAPPING_TYPE_FORCE_PCIE 1
+
+typedef struct nv_ioctl_export_to_dma_buf_fd
+{
+ int fd;
+ NvHandle hClient;
+ NvU32 totalObjects;
+ NvU32 numObjects;
+ NvU32 index;
+ NvU64 totalSize NV_ALIGN_BYTES(8);
+ NvU8 mappingType;
+ NvBool bAllowMmap;
+ NvHandle handles[NV_DMABUF_EXPORT_MAX_HANDLES];
+ NvU64 offsets[NV_DMABUF_EXPORT_MAX_HANDLES] NV_ALIGN_BYTES(8);
+ NvU64 sizes[NV_DMABUF_EXPORT_MAX_HANDLES] NV_ALIGN_BYTES(8);
+ NvU32 status;
+} nv_ioctl_export_to_dma_buf_fd_t;
+
+typedef struct nv_ioctl_wait_open_complete
+{
+ int rc;
+ NvU32 adapterStatus;
+} nv_ioctl_wait_open_complete_t;
+
+#endif
diff --git a/userspace/sdks/nv570/nvalloc/unix/include/nv-kernel-rmapi-ops.h b/userspace/sdks/nv570/nvalloc/unix/include/nv-kernel-rmapi-ops.h
new file mode 100644
index 0000000..d50a1e4
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/include/nv-kernel-rmapi-ops.h
@@ -0,0 +1,61 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2015-2019 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _NV_KERNEL_RMAPI_OPS_H_
+#define _NV_KERNEL_RMAPI_OPS_H_
+
+/*
+ * Define the RMAPI provided to kernel-level RM clients.
+ *
+ * Kernel-level RM clients should populate nvidia_kernel_rmapi_ops_t
+ * by assigning nvidia_kernel_rmapi_ops_t::op and the corresponding
+ * parameter structure in nvidia_kernel_rmapi_ops_t's params union.
+ * Then, pass a pointer to the nvidia_kernel_rmapi_ops_t to
+ * rm_kernel_rmapi_op().
+ */
+
+#include "nvtypes.h"
+#include "nvos.h"
+
+typedef struct {
+ NvU32 op; /* One of the NV0[14]_XXXX operations listed below. */
+
+ union {
+ NVOS00_PARAMETERS free; /* NV01_FREE */
+ NVOS02_PARAMETERS allocMemory64; /* NV01_ALLOC_MEMORY */
+ NVOS64_PARAMETERS alloc; /* NV04_ALLOC */
+ NVOS32_PARAMETERS *pVidHeapControl; /* NV04_VID_HEAP_CONTROL */
+ NVOS33_PARAMETERS mapMemory; /* NV04_MAP_MEMORY */
+ NVOS34_PARAMETERS unmapMemory; /* NV04_UNMAP_MEMORY */
+ NVOS39_PARAMETERS allocContextDma2; /* NV04_ALLOC_CONTEXT_DMA */
+ NVOS46_PARAMETERS mapMemoryDma; /* NV04_MAP_MEMORY_DMA */
+ NVOS47_PARAMETERS unmapMemoryDma; /* NV04_UNMAP_MEMORY_DMA */
+ NVOS49_PARAMETERS bindContextDma; /* NV04_BIND_CONTEXT_DMA */
+ NVOS54_PARAMETERS control; /* NV04_CONTROL*/
+ NVOS55_PARAMETERS dupObject; /* NV04_DUP_OBJECT */
+ NVOS57_PARAMETERS share; /* NV04_SHARE */
+ NVOS61_PARAMETERS addVblankCallback; /* NV04_ADD_VBLANK_CALLBACK */
+ } params;
+} nvidia_kernel_rmapi_ops_t;
+
+#endif /* _NV_KERNEL_RMAPI_OPS_H_ */
diff --git a/userspace/sdks/nv570/nvalloc/unix/include/nv-nb-regs.h b/userspace/sdks/nv570/nvalloc/unix/include/nv-nb-regs.h
new file mode 100644
index 0000000..6282b35
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/include/nv-nb-regs.h
@@ -0,0 +1,65 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2007-2018 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _NV_NB_REGS_H_
+#define _NV_NB_REGS_H_
+
+#include "nvdevid.h"
+
+typedef struct
+{
+ NvU32 subsystem_vendor_id;
+ NvU32 subsystem_device_id;
+ NvU16 gpu_device_id;
+} nv_nb_id_t;
+
+typedef struct
+{
+ NvU32 vendor_id;
+ const char *name;
+ NvU32 data;
+} nv_nb_reg_t;
+
+/*
+ * nb_id_table contains the OEM vendor ID, the subsystem ID and the
+ * GPU device ID of the notebooks for which we need to enable
+ * vendor specific registry keys. nb_reg_table contains the vendor
+ * specific registry key values. The initVendorSpecificRegistry()
+ * function compares the present notebooks OEM subsystem ID and the
+ * GPU device ID with the values present in id_tables. If a match
+ * is found, initVendorSpecificRegistry() extracts the vendor
+ * ID and sets any associated registry key listed in nb_reg_table.
+ */
+
+static nv_nb_id_t nb_id_table[] = {
+ { PCI_VENDOR_ID_PC_PARTNER, 0x0620, 0x1284 }, // Acer GT 630
+ { PCI_VENDOR_ID_PC_PARTNER, 0x0620, 0x124b }, // Acer GT 640
+ { 0, 0, 0 }
+};
+
+static nv_nb_reg_t nb_reg_table[] = {
+ { PCI_VENDOR_ID_PC_PARTNER, "RmOverrideSupportChipsetAspm", 2 },
+ { 0, NULL, 0 }
+};
+
+#endif //_NV_NB_REGS_H_
diff --git a/userspace/sdks/nv570/nvalloc/unix/include/nv-priv.h b/userspace/sdks/nv570/nvalloc/unix/include/nv-priv.h
new file mode 100644
index 0000000..a3dcebf
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/include/nv-priv.h
@@ -0,0 +1,357 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 1999-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _NV_PRIV_H_
+#define _NV_PRIV_H_
+
+#include <nv.h>
+#include <os/os.h>
+#include <ctrl/ctrl402c.h>
+#include <gpu/disp/kern_disp_max.h>
+#include <gpu/disp/kern_disp_type.h>
+
+#define NV_PRIV_REG_WR08(b,o,d) (*((volatile NvV8*)&(b)->Reg008[(o)/1])=(NvV8)(d))
+#define NV_PRIV_REG_WR16(b,o,d) (*((volatile NvV16*)&(b)->Reg016[(o)/2])=(NvV16)(d))
+#define NV_PRIV_REG_WR32(b,o,d) (*((volatile NvV32*)&(b)->Reg032[(o)/4])=(NvV32)(d))
+
+#define NV_PRIV_REG_RD08(b,o) ((b)->Reg008[(o)/1])
+#define NV_PRIV_REG_RD16(b,o) ((b)->Reg016[(o)/2])
+#define NV_PRIV_REG_RD32(b,o) ((b)->Reg032[(o)/4])
+
+struct OBJGPU;
+
+typedef struct
+{
+ NvBool baseValid;
+ VGAADDRDESC base;
+ NvBool workspaceBaseValid;
+ VGAADDRDESC workspaceBase;
+ NvU32 vesaMode;
+} nv_vga_t;
+
+/*
+* device state during Power Management
+*/
+typedef struct nv_pm_state_s
+{
+ NvU32 IntrEn;
+ NvBool InHibernate;
+} nv_pm_state_t;
+
+/*
+* data structure for the UNIX workqueues
+*/
+typedef struct nv_work_item_s
+{
+ OsQueueWorkItemFlags flags;
+ NvU32 gpuInstance;
+ union
+ {
+ OSWorkItemFunction *pGpuFunction;
+ OSSystemWorkItemFunction *pSystemFunction;
+ } func;
+ void *pData;
+} nv_work_item_t;
+
+#define INVALID_DISP_ID 0xFFFFFFFF
+#define MAX_DISP_ID_PER_ADAPTER 0x2
+
+typedef struct nv_i2c_adapter_entry_s
+{
+ void *pOsAdapter;
+ NvU32 port;
+ NvU32 displayId[MAX_DISP_ID_PER_ADAPTER];
+} nv_i2c_adapter_entry_t;
+
+#define NV_INIT_FLAG_HAL 0x0001
+#define NV_INIT_FLAG_HAL_COMPONENTS 0x0002
+#define NV_INIT_FLAG_GPU_STATE 0x0004
+#define NV_INIT_FLAG_GPU_STATE_LOAD 0x0008
+#define NV_INIT_FLAG_FIFO_WATCHDOG 0x0010
+#define NV_INIT_FLAG_CORE_LOGIC 0x0020
+#define NV_INIT_FLAG_GPUMGR_ATTACH 0x0040
+#define NV_INIT_FLAG_PUBLIC_I2C 0x0080
+#define NV_INIT_FLAG_SCALABILITY 0x0100
+#define NV_INIT_FLAG_DMA 0x0200
+
+#define MAX_I2C_ADAPTERS NV402C_CTRL_NUM_I2C_PORTS
+
+/*
+ * GPU dynamic power state machine.
+ *
+ * The GPU is in exactly one of these states at at time. Only certain state
+ * transitions are valid, as documented by the DAGs below.
+ *
+ * When in "instant idle" or COARSE mode:
+ *
+ * +----------------------+
+ * v |
+ * +---------+ +----------------+ +--------+
+ * | UNKNOWN | --> | IDLE_INDICATED | --> | IN_USE |
+ * +---------+ +----------------+ +--------+
+ *
+ * The transition from UNKNOWN to IDLE_INDICATED happens in
+ * rm_init_dynamic_power_management().
+ *
+ * Thereafter, transitions from IDLE_INDICATED to IN_USE happen when
+ * os_ref_dynamic_power() is called and the refcount transitions from 0 to 1;
+ * transitions from IN_USE to IDLE_INDICATED happen when
+ * os_unref_dynamic_power() is called and the refcount transitions from 1 to 0.
+ * Note that only calls to os_(un)ref_dynamic_power() with the mode == COARSE
+ * are considered in this mode; calls with mode == FINE are ignored. Since
+ * COARSE calls are placed only in rm_init_adapter/rm_shutdown_adapter, the GPU
+ * effectively stays in the IN_USE state any time any client has initialized
+ * it.
+ *
+ *
+ * When in "deferred idle" or FINE mode:
+ *
+ * +----------------------------------------------------------------+
+ * | |
+ * | |
+ * | +-------------------------------------------+----------------------+
+ * | | | v
+ * | +---------+ +----------------+ +--------------+ +----------------+ +--------+
+ * | | UNKNOWN | --> | IDLE_INDICATED | --> | | --> | IDLE_SUSTAINED | --> | IN_USE | -+
+ * | +---------+ +----------------+ | | +----------------+ +--------+ |
+ * | ^ | | | ^ |
+ * +--------------------+ | IDLE_INSTANT | ------+----------------------+ |
+ * | | | |
+ * | | | |
+ * | | <-----+ |
+ * +--------------+ |
+ * ^ |
+ * +-----------------------------------------------------+
+ *
+ * As before, the transition from UNKNOWN to IDLE_INDICATED happens in
+ * rm_init_dynamic_power_management(). This is not ideal: it means the GPU may
+ * be powered down immediately upon loading the RM module, even if
+ * rm_init_adapter() is going to be called soon thereafter. However, we can't
+ * rely on deferred idle callbacks yet, since those currently rely on core RM
+ * being initialized.
+ *
+ * At the beginning of rm_init_adapter(), the GPU transitions to the IN_USE
+ * state; during the rm_init_adapter() sequence,
+ * RmInitDeferredDynamicPowerManagement() will be called which will schedule
+ * timer callbacks and set the "deferred_idle_enabled" boolean.
+ *
+ * While in "deferred idle" mode, one of the callbacks
+ * timerCallbackForIdlePreConditions(), timerCallbackToIndicateIdle(), or
+ * RmIndicateIdle() should be scheduled when in the states:
+ * - IN_USE
+ * - IDLE_INSTANT
+ * - IDLE_SUSTAINED
+ * Note that since we may transition from IN_USE to IDLE_INSTANT rapidly (e.g.,
+ * for a series of RM calls), we don't attempt to schedule the callbacks and
+ * cancel them on each of these transitions. The
+ * timerCallbackForIdlePreConditions() callback will simply exit early if in
+ * the IN_USE state.
+ *
+ * As before, the GPU will remain in the IN_USE state until
+ * os_unref_dynamic_power() is called and the count transitions from 1 to 0
+ * (calls with mode == FINE are honored, in this mode, and these transitions
+ * can happen frequently). When the refcount reaches 0, rather than going
+ * directly to the IDLE_INDICATED state, it transitions to the IDLE_INSTANT
+ * state.
+ *
+ * Then, when the next timerCallbackForIdlePreConditions() callback executes,
+ * if all preconditions are met, the state will transition to IDLE_SUSTAINED.
+ *
+ * If, when in the IDLE_SUSTAINED state, os_ref_dynamic_power() is called, the
+ * GPU will transition back to the IN_USE state and return to the IDLE_INSTANT
+ * state. This ensures that there is a suitable delay between any activity
+ * that requires bumping the refcount and indicating idleness.
+ *
+ * If the timerCallbackForIdlePreConditions() callback executes again and the
+ * GPU is still in the IDLE_SUSTAINED state, userspace mappings will be revoked
+ * and the timerCallbackToIndicateIdle() callback will be scheduled.
+ *
+ * If, before the timerCallbackToIndicateIdle() callback executes, either
+ * os_ref_dynamic_power() is called or a mapping which has been revoked is
+ * accessed (which triggers the RmForceGpuNotIdle() callback), the GPU will
+ * transition back to the IN_USE or IDLE_INSTANT state, respectively.
+ *
+ * Then, when the timerCallbackToIndicateIdle() callback executes, if all
+ * mappings are still revoked, and the GPU is still in the IDLE_SUSTAINED
+ * state, and all GPU idleness preconditions remain satisfied, the
+ * RmIndicateIdle() work item will be enqueued. (Else, the GPU will transition
+ * back to the IDLE_INSTANT state and the callback for preconditions is
+ * scheduled again.)
+ *
+ * Finally, once the RmIndicateIdle() work item is called, if all of the same
+ * conditions still hold, the state will transition to IDLE_INDICATED. No
+ * callbacks will be scheduled from here; the callbacks for preconditions
+ * should be re-scheduled when transitioning out of the IDLE_INDICATED state.
+ *
+ * Once in the IDLE_INDICATED state, the kernel is free to call the RM to
+ * perform the GC6 entry sequence then turn off power to the GPU (although it
+ * may not, if the audio function is being used for example).
+ *
+ * There are two paths to exit the IDLE_INDICATED state:
+ * (a) If os_ref_dynamic_power() is called, in which case it transitions
+ * directly to the IN_USE state;
+ * (b) If RmForceGpuNotIdle() is called, in which case it transitions back to
+ * the IDLE_INSTANT state.
+ */
+typedef enum
+{
+ NV_DYNAMIC_POWER_STATE_UNKNOWN = 0,
+
+ NV_DYNAMIC_POWER_STATE_IN_USE,
+
+ NV_DYNAMIC_POWER_STATE_IDLE_INSTANT,
+ NV_DYNAMIC_POWER_STATE_IDLE_SUSTAINED,
+ NV_DYNAMIC_POWER_STATE_IDLE_INDICATED,
+} nv_dynamic_power_state_t;
+
+typedef struct nv_dynamic_power_s
+{
+ /*
+ * mode is read without the mutex -- should be read-only outside of
+ * rm_init_dynamic_power_management, called during probe only.
+ */
+ nv_dynamic_power_mode_t mode;
+ /*
+ * Whether to indicate idle immediately when the refcount reaches 0, or
+ * only go to the IDLE_INSTANT state, and expect timer callbacks to
+ * transition through IDLE_SUSTAINED -> IDLE_INDICATED.
+ */
+ NvBool deferred_idle_enabled;
+
+ PORT_ATOMIC nv_dynamic_power_state_t state;
+ NvS32 refcount;
+
+ /*
+ * A word on lock ordering. These locks must be taken in the order:
+ *
+ * RM API lock > this dynamic_power mutex > RM GPUs lock
+ *
+ * Skipping any of those locks is fine (if they aren't required to protect
+ * whatever state is being accessed or modified), so long as the order is
+ * not violated.
+ */
+ PORT_MUTEX *mutex;
+
+ /*
+ * callback handles for deferred dynamic power management.
+ */
+ NvP64 idle_precondition_check_event;
+ NvP64 indicate_idle_event;
+ NvBool idle_precondition_check_callback_scheduled;
+
+ /*
+ * callback handle for kernel initiated gc6 entry/exit.
+ * these will be protected by the gpu lock.
+ */
+ NvP64 remove_idle_holdoff;
+ NvBool b_idle_holdoff;
+
+ /*
+ * flag set if the platform does not support fine grain dynamic power
+ * management.
+ */
+ NvBool b_fine_not_supported;
+
+ /*
+ * This flag is used to check if a workitem is queued for
+ * RmQueueIdleSustainedWorkitem().
+ */
+ NvBool b_idle_sustained_workitem_queued;
+
+ /*
+ * Counter to track clients disallowing GCOFF.
+ */
+ NvU32 clients_gcoff_disallow_refcount;
+
+ /*
+ * Maximum FB allocation size which can be saved in system memory
+ * while doing GCOFF based dynamic PM.
+ */
+ NvU64 gcoff_max_fb_size;
+
+ /*
+ * NVreg_DynamicPowerManagement regkey value set by the user
+ */
+ NvU32 dynamic_power_regkey;
+} nv_dynamic_power_t;
+
+typedef struct
+{
+ OBJGPU *pGpu;
+
+ NvU32 pmc_boot_0;
+
+ nv_vga_t vga;
+
+ NvU32 flags;
+ NvU32 status;
+
+ nv_i2c_adapter_entry_t i2c_adapters[MAX_I2C_ADAPTERS];
+
+ void *pVbiosCopy;
+ NvU32 vbiosSize;
+
+ nv_pm_state_t pm_state;
+
+ nv_reg_entry_t *pRegistry;
+
+ nv_dynamic_power_t dynamic_power;
+
+ /* Flag to check if GPU mobile config is enabled */
+ NvBool b_mobile_config_enabled;
+
+ /* Flag to check if S0ix-based power management is enabled. */
+ NvBool s0ix_pm_enabled;
+
+ /* Variable to track Dynamic Boost support */
+ int db_supported;
+
+ /*
+ * Maximum FB allocation size which can be saved in system memory
+ * during system supened with S0ix-based power management.
+ */
+ NvU64 s0ix_gcoff_max_fb_size;
+
+ NvU32 pmc_boot_1;
+ NvU32 pmc_boot_42;
+
+ /*
+ * This flag is set if the upstream port has been configured ("D3cold Aux Power Limit" and
+ * "PERST# Assertion Delay") for GC6. This configuration is needed only for desktops.
+ */
+ NvBool gc6_upstream_port_configured;
+
+ /* This flag is set if _PR3 ACPI method is available to support RTD3. */
+ NvBool pr3_acpi_method_present;
+} nv_priv_t;
+
+#define NV_SET_NV_PRIV(nv,p) ((nv)->priv = (p))
+#define NV_GET_NV_PRIV(nv) ((nv) ? (nv)->priv : NULL)
+
+/*
+ * Make sure that your stack has taken API Lock before using this macro.
+ */
+#define NV_GET_NV_PRIV_PGPU(nv) \
+ (NV_GET_NV_PRIV(nv) ? ((nv_priv_t *)NV_GET_NV_PRIV(nv))->pGpu : NULL)
+
+#endif // _NV_PRIV_H_
diff --git a/userspace/sdks/nv570/nvalloc/unix/include/nv-reg.h b/userspace/sdks/nv570/nvalloc/unix/include/nv-reg.h
new file mode 100644
index 0000000..93999d4
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/include/nv-reg.h
@@ -0,0 +1,1137 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2006-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+//
+// This file holds Unix-specific NVIDIA driver options
+//
+
+#ifndef _RM_REG_H_
+#define _RM_REG_H_
+
+#include "nvtypes.h"
+#include "nv-firmware-registry.h"
+
+/*
+ * use NV_REG_STRING to stringify a registry key when using that registry key
+ */
+
+#define __NV_REG_STRING(regkey) #regkey
+#define NV_REG_STRING(regkey) __NV_REG_STRING(regkey)
+
+/*
+ * use NV_DEFINE_REG_ENTRY and NV_DEFINE_PARAMS_TABLE_ENTRY to simplify definition
+ * of registry keys in the kernel module source code.
+ */
+
+#define __NV_REG_VAR(regkey) NVreg_##regkey
+
+#if defined(NV_MODULE_PARAMETER)
+#define NV_DEFINE_REG_ENTRY(regkey, default_value) \
+ static NvU32 __NV_REG_VAR(regkey) = (default_value); \
+ NV_MODULE_PARAMETER(__NV_REG_VAR(regkey))
+#define NV_DEFINE_REG_ENTRY_GLOBAL(regkey, default_value) \
+ NvU32 __NV_REG_VAR(regkey) = (default_value); \
+ NV_MODULE_PARAMETER(__NV_REG_VAR(regkey))
+#else
+#define NV_DEFINE_REG_ENTRY(regkey, default_value) \
+ static NvU32 __NV_REG_VAR(regkey) = (default_value)
+#define NV_DEFINE_REG_ENTRY_GLOBAL(regkey, default_value) \
+ NvU32 __NV_REG_VAR(regkey) = (default_value)
+#endif
+
+#if defined(NV_MODULE_STRING_PARAMETER)
+#define NV_DEFINE_REG_STRING_ENTRY(regkey, default_value) \
+ char *__NV_REG_VAR(regkey) = (default_value); \
+ NV_MODULE_STRING_PARAMETER(__NV_REG_VAR(regkey))
+#else
+#define NV_DEFINE_REG_STRING_ENTRY(regkey, default_value) \
+ char *__NV_REG_VAR(regkey) = (default_value)
+#endif
+
+#define NV_DEFINE_PARAMS_TABLE_ENTRY(regkey) \
+ { NV_REG_STRING(regkey), &__NV_REG_VAR(regkey) }
+
+/*
+ * Like NV_DEFINE_PARMS_TABLE_ENTRY, but allows a mismatch between the name of
+ * the regkey and the name of the module parameter. When using this macro, the
+ * name of the parameter is passed to the extra "parameter" argument, and it is
+ * this name that must be used in the NV_DEFINE_REG_ENTRY() macro.
+ */
+
+#define NV_DEFINE_PARAMS_TABLE_ENTRY_CUSTOM_NAME(regkey, parameter) \
+ { NV_REG_STRING(regkey), &__NV_REG_VAR(parameter)}
+
+/*
+ *----------------- registry key definitions--------------------------
+ */
+
+/*
+ * Option: ModifyDeviceFiles
+ *
+ * Description:
+ *
+ * When this option is enabled, the NVIDIA driver will verify the validity
+ * of the NVIDIA device files in /dev and attempt to dynamically modify
+ * and/or (re-)create them, if necessary. If you don't wish for the NVIDIA
+ * driver to touch the device files, you can use this registry key.
+ *
+ * This module parameter is only honored by the NVIDIA GPU driver and NVIDIA
+ * capability driver. Furthermore, the NVIDIA capability driver provides
+ * modifiable /proc file entry (DeviceFileModify=0/1) to alter the behavior of
+ * this module parameter per device file.
+ *
+ * Possible Values:
+ * 0 = disable dynamic device file management
+ * 1 = enable dynamic device file management (default)
+ */
+
+#define __NV_MODIFY_DEVICE_FILES ModifyDeviceFiles
+#define NV_REG_MODIFY_DEVICE_FILES NV_REG_STRING(__NV_MODIFY_DEVICE_FILES)
+
+/*
+ * Option: DeviceFileUID
+ *
+ * Description:
+ *
+ * This registry key specifies the UID assigned to the NVIDIA device files
+ * created and/or modified by the NVIDIA driver when dynamic device file
+ * management is enabled.
+ *
+ * This module parameter is only honored by the NVIDIA GPU driver.
+ *
+ * The default UID is 0 ('root').
+ */
+
+#define __NV_DEVICE_FILE_UID DeviceFileUID
+#define NV_REG_DEVICE_FILE_UID NV_REG_STRING(__NV_DEVICE_FILE_UID)
+
+/*
+ * Option: DeviceFileGID
+ *
+ * Description:
+ *
+ * This registry key specifies the GID assigned to the NVIDIA device files
+ * created and/or modified by the NVIDIA driver when dynamic device file
+ * management is enabled.
+ *
+ * This module parameter is only honored by the NVIDIA GPU driver.
+ *
+ * The default GID is 0 ('root').
+ */
+
+#define __NV_DEVICE_FILE_GID DeviceFileGID
+#define NV_REG_DEVICE_FILE_GID NV_REG_STRING(__NV_DEVICE_FILE_GID)
+
+/*
+ * Option: DeviceFileMode
+ *
+ * Description:
+ *
+ * This registry key specifies the device file mode assigned to the NVIDIA
+ * device files created and/or modified by the NVIDIA driver when dynamic
+ * device file management is enabled.
+ *
+ * This module parameter is only honored by the NVIDIA GPU driver.
+ *
+ * The default mode is 0666 (octal, rw-rw-rw-).
+ */
+
+#define __NV_DEVICE_FILE_MODE DeviceFileMode
+#define NV_REG_DEVICE_FILE_MODE NV_REG_STRING(__NV_DEVICE_FILE_MODE)
+
+/*
+ * Option: ResmanDebugLevel
+ *
+ * Default value: ~0
+ */
+
+#define __NV_RESMAN_DEBUG_LEVEL ResmanDebugLevel
+#define NV_REG_RESMAN_DEBUG_LEVEL NV_REG_STRING(__NV_RESMAN_DEBUG_LEVEL)
+
+/*
+ * Option: RmLogonRC
+ *
+ * Default value: 1
+ */
+
+#define __NV_RM_LOGON_RC RmLogonRC
+#define NV_REG_RM_LOGON_RC NV_REG_STRING(__NV_RM_LOGON_RC)
+
+/*
+ * Option: InitializeSystemMemoryAllocations
+ *
+ * Description:
+ *
+ * The NVIDIA Linux driver normally clears system memory it allocates
+ * for use with GPUs or within the driver stack. This is to ensure
+ * that potentially sensitive data is not rendered accessible by
+ * arbitrary user applications.
+ *
+ * Owners of single-user systems or similar trusted configurations may
+ * choose to disable the aforementioned clears using this option and
+ * potentially improve performance.
+ *
+ * Possible values:
+ *
+ * 1 = zero out system memory allocations (default)
+ * 0 = do not perform memory clears
+ */
+
+#define __NV_INITIALIZE_SYSTEM_MEMORY_ALLOCATIONS \
+ InitializeSystemMemoryAllocations
+#define NV_REG_INITIALIZE_SYSTEM_MEMORY_ALLOCATIONS \
+ NV_REG_STRING(__NV_INITIALIZE_SYSTEM_MEMORY_ALLOCATIONS)
+
+/*
+ * Option: RegistryDwords
+ *
+ * Description:
+ *
+ * This option accepts a semicolon-separated list of key=value pairs. Each
+ * key name is checked against the table of static options; if a match is
+ * found, the static option value is overridden, but invalid options remain
+ * invalid. Pairs that do not match an entry in the static option table
+ * are passed on to the RM directly.
+ *
+ * Format:
+ *
+ * NVreg_RegistryDwords="<key=value>;<key=value>;..."
+ */
+
+#define __NV_REGISTRY_DWORDS RegistryDwords
+#define NV_REG_REGISTRY_DWORDS NV_REG_STRING(__NV_REGISTRY_DWORDS)
+
+/*
+ * Option: RegistryDwordsPerDevice
+ *
+ * Description:
+ *
+ * This option allows to specify registry keys per GPU device. It helps to
+ * control registry at GPU level of granularity. It accepts a semicolon
+ * separated list of key=value pairs. The first key value pair MUST be
+ * "pci=DDDD:BB:DD.F;" where DDDD is Domain, BB is Bus Id, DD is device slot
+ * number and F is the Function. This PCI BDF is used to identify which GPU to
+ * assign the registry keys that follows next.
+ * If a GPU corresponding to the value specified in "pci=DDDD:BB:DD.F;" is NOT
+ * found, then all the registry keys that follows are skipped, until we find next
+ * valid pci identified "pci=DDDD:BB:DD.F;". Following are the valid formats for
+ * the value of the "pci" string:
+ * 1) bus:slot : Domain and function defaults to 0.
+ * 2) domain:bus:slot : Function defaults to 0.
+ * 3) domain:bus:slot.func : Complete PCI dev id string.
+ *
+ * For each of the registry keys that follows, key name is checked against the
+ * table of static options; if a match is found, the static option value is
+ * overridden, but invalid options remain invalid. Pairs that do not match an
+ * entry in the static option table are passed on to the RM directly.
+ *
+ * Format:
+ *
+ * NVreg_RegistryDwordsPerDevice="pci=DDDD:BB:DD.F;<key=value>;<key=value>;..; \
+ * pci=DDDD:BB:DD.F;<key=value>;..;"
+ */
+
+#define __NV_REGISTRY_DWORDS_PER_DEVICE RegistryDwordsPerDevice
+#define NV_REG_REGISTRY_DWORDS_PER_DEVICE NV_REG_STRING(__NV_REGISTRY_DWORDS_PER_DEVICE)
+
+#define __NV_RM_MSG RmMsg
+#define NV_RM_MSG NV_REG_STRING(__NV_RM_MSG)
+
+/*
+ * Option: EnableMSI
+ *
+ * Description:
+ *
+ * When this option is enabled and the host kernel supports the MSI feature,
+ * the NVIDIA driver will enable the PCI-E MSI capability of GPUs with the
+ * support for this feature instead of using PCI-E wired interrupt.
+ *
+ * Possible Values:
+ *
+ * 0 = disable MSI interrupt
+ * 1 = enable MSI interrupt (default)
+ *
+ */
+
+#define __NV_ENABLE_MSI EnableMSI
+#define NV_REG_ENABLE_MSI NV_REG_STRING(__NV_ENABLE_MSI)
+
+/*
+ * Option: EnablePCIeGen3
+ *
+ * Description:
+ *
+ * Due to interoperability problems seen with Kepler PCIe Gen3 capable GPUs
+ * when configured on SandyBridge E desktop platforms, NVIDIA feels that
+ * delivering a reliable, high-quality experience is not currently possible in
+ * PCIe Gen3 mode on all PCIe Gen3 platforms. Therefore, Quadro, Tesla and
+ * NVS Kepler products operate in PCIe Gen2 mode by default. You may use this
+ * option to enable PCIe Gen3 support.
+ *
+ * This is completely unsupported!
+ *
+ * Possible Values:
+ *
+ * 0: disable PCIe Gen3 support (default)
+ * 1: enable PCIe Gen3 support
+ */
+
+#define __NV_ENABLE_PCIE_GEN3 EnablePCIeGen3
+#define NV_REG_ENABLE_PCIE_GEN3 NV_REG_STRING(__NV_ENABLE_PCIE_GEN3)
+
+/*
+ * Option: MemoryPoolSize
+ *
+ * Description:
+ *
+ * When set to a non-zero value, this option specifies the size of the
+ * memory pool, given as a multiple of 1 GB, created on VMware ESXi to
+ * satisfy any system memory allocations requested by the NVIDIA kernel
+ * module.
+ */
+
+#define __NV_MEMORY_POOL_SIZE MemoryPoolSize
+#define NV_REG_MEMORY_POOL_SIZE NV_REG_STRING(__NV_MEMORY_POOL_SIZE)
+
+/*
+ * Option: KMallocHeapMaxSize
+ *
+ * Description:
+ *
+ * When set to a non-zero value, this option specifies the maximum size of the
+ * heap memory space reserved for kmalloc operations. Given as a
+ * multiple of 1 MB created on VMware ESXi to satisfy any system memory
+ * allocations requested by the NVIDIA kernel module.
+ */
+
+#define __NV_KMALLOC_HEAP_MAX_SIZE KMallocHeapMaxSize
+#define NV_KMALLOC_HEAP_MAX_SIZE NV_REG_STRING(__NV_KMALLOC_HEAP_MAX_SIZE)
+
+/*
+ * Option: VMallocHeapMaxSize
+ *
+ * Description:
+ *
+ * When set to a non-zero value, this option specifies the maximum size of the
+ * heap memory space reserved for vmalloc operations. Given as a
+ * multiple of 1 MB created on VMware ESXi to satisfy any system memory
+ * allocations requested by the NVIDIA kernel module.
+ */
+
+#define __NV_VMALLOC_HEAP_MAX_SIZE VMallocHeapMaxSize
+#define NV_VMALLOC_HEAP_MAX_SIZE NV_REG_STRING(__NV_VMALLOC_HEAP_MAX_SIZE)
+
+/*
+ * Option: IgnoreMMIOCheck
+ *
+ * Description:
+ *
+ * When this option is enabled, the NVIDIA kernel module will ignore
+ * MMIO limit check during device probe on VMWare ESXi kernel. This is
+ * typically necessary when VMware ESXi MMIO limit differs between any
+ * base version and its updates. Customer using updates can set regkey
+ * to avoid probe failure.
+ */
+
+#define __NV_IGNORE_MMIO_CHECK IgnoreMMIOCheck
+#define NV_REG_IGNORE_MMIO_CHECK NV_REG_STRING(__NV_IGNORE_MMIO_CHECK)
+
+/*
+ * Option: pci
+ *
+ * Description:
+ *
+ * On Unix platforms, per GPU based registry key can be specified as:
+ * NVreg_RegistryDwordsPerDevice="pci=DDDD:BB:DD.F,<per-gpu registry keys>".
+ * where DDDD:BB:DD.F refers to Domain:Bus:Device.Function.
+ * We need this key "pci" to identify what follows next is a PCI BDF identifier,
+ * for which the registry keys are to be applied.
+ *
+ * This define is not used on non-UNIX platforms.
+ *
+ * Possible Formats for value:
+ *
+ * 1) bus:slot : Domain and function defaults to 0.
+ * 2) domain:bus:slot : Function defaults to 0.
+ * 3) domain:bus:slot.func : Complete PCI BDF identifier string.
+ */
+#define __NV_PCI_DEVICE_BDF pci
+#define NV_REG_PCI_DEVICE_BDF NV_REG_STRING(__NV_PCI_DEVICE_BDF)
+
+/*
+ * Option: EnableStreamMemOPs
+ *
+ * Description:
+ *
+ * When this option is enabled, the CUDA driver will enable support for
+ * CUDA Stream Memory Operations in user-mode applications, which are so
+ * far required to be disabled by default due to limited support in
+ * devtools.
+ *
+ * Note: this is treated as a hint. MemOPs may still be left disabled by CUDA
+ * driver for other reasons.
+ *
+ * Possible Values:
+ *
+ * 0 = disable feature (default)
+ * 1 = enable feature
+ */
+#define __NV_ENABLE_STREAM_MEMOPS EnableStreamMemOPs
+#define NV_REG_ENABLE_STREAM_MEMOPS NV_REG_STRING(__NV_ENABLE_STREAM_MEMOPS)
+
+/*
+ * Option: EnableUserNUMAManagement
+ *
+ * Description:
+ *
+ * When this option is enabled, the NVIDIA kernel module will require the
+ * user-mode NVIDIA Persistence daemon to manage the onlining and offlining
+ * of its NUMA device memory.
+ *
+ * This option has no effect on platforms that do not support onlining
+ * device memory to a NUMA node (this feature is only supported on certain
+ * POWER9 systems).
+ *
+ * Possible Values:
+ *
+ * 0: disable user-mode NUMA management
+ * 1: enable user-mode NUMA management (default)
+ */
+#define __NV_ENABLE_USER_NUMA_MANAGEMENT EnableUserNUMAManagement
+#define NV_REG_ENABLE_USER_NUMA_MANAGEMENT NV_REG_STRING(__NV_ENABLE_USER_NUMA_MANAGEMENT)
+
+/*
+ * Option: CoherentGPUMemoryMode
+ *
+ * Description:
+ *
+ * This option can be set to control how GPU Memory is accessed through
+ * the coherent link.
+ *
+ * This option has no effect on platforms that do not support onlining
+ * device memory to a NUMA node.
+ *
+ * Possible string values:
+ *
+ * "driver" : disable onlining coherent memory to the OS as a NUMA node. The driver
+ * will manage it in this case
+ * "numa" (or unset) : enable onlining coherent memory to the OS as a NUMA node (default)
+ */
+#define __NV_COHERENT_GPU_MEMORY_MODE CoherentGPUMemoryMode
+#define NV_REG_COHERENT_GPU_MEMORY_MODE NV_REG_STRING(__NV_COHERENT_GPU_MEMORY_MODE)
+
+/*
+ * Option: GpuBlacklist
+ *
+ * Description:
+ *
+ * This option accepts a list of blacklisted GPUs, separated by commas, that
+ * cannot be attached or used. Each blacklisted GPU is identified by a UUID in
+ * the ASCII format with leading "GPU-". An exact match is required; no partial
+ * UUIDs. This regkey is deprecated and will be removed in the future. Use
+ * NV_REG_EXCLUDED_GPUS instead.
+ */
+#define __NV_GPU_BLACKLIST GpuBlacklist
+#define NV_REG_GPU_BLACKLIST NV_REG_STRING(__NV_GPU_BLACKLIST)
+
+/*
+ * Option: ExcludedGpus
+ *
+ * Description:
+ *
+ * This option accepts a list of excluded GPUs, separated by commas, that
+ * cannot be attached or used. Each excluded GPU is identified by a UUID in
+ * the ASCII format with leading "GPU-". An exact match is required; no partial
+ * UUIDs.
+ */
+#define __NV_EXCLUDED_GPUS ExcludedGpus
+#define NV_REG_EXCLUDED_GPUS NV_REG_STRING(__NV_EXCLUDED_GPUS)
+
+/*
+ * Option: NVreg_ExcludeAllGpus
+ *
+ * Description:
+ *
+ * This option allows the user to exclude all GPUs. If used in conjunction with
+ * UUID based GPU exclusion, all GPUs will be excluded
+ *
+ * Possible values:
+ * 1 - Excludes all GPUs from being attached or used
+ * 0 - No effect (default)
+ */
+ #define __NV_EXCLUDE_ALL_GPUS ExcludeAllGpus
+ #define NV_EXCLUDE_ALL_GPUS NV_REG_STRING(__NV_EXCLUDE_ALL_GPUS)
+ #define NV_EXCLUDE_ALL_GPUS_DEFAULT 0
+
+/*
+ * Option: NvLinkDisable
+ *
+ * Description:
+ *
+ * When this option is enabled, the NVIDIA kernel module will not attempt to
+ * initialize or train NVLink connections for any GPUs. System reboot is required
+ * for changes to take affect.
+ *
+ * This option has no effect if no GPUs support NVLink.
+ *
+ * Possible Values:
+ *
+ * 0: Do not disable NVLink (default)
+ * 1: Disable NVLink
+ */
+#define __NV_NVLINK_DISABLE NvLinkDisable
+#define NV_REG_NVLINK_DISABLE NV_REG_STRING(__NV_NVLINK_DISABLE)
+
+/*
+ * Option: RestrictProfilingToAdminUsers
+ *
+ * Description:
+ *
+ * When this option is enabled, the NVIDIA kernel module will prevent users
+ * without administrative access (i.e., the CAP_SYS_ADMIN capability) from
+ * using GPU performance counters.
+ *
+ * Possible Values:
+ *
+ * 0: Do not restrict GPU counters (default)
+ * 1: Restrict GPU counters to system administrators only
+ */
+
+#define __NV_RM_PROFILING_ADMIN_ONLY RmProfilingAdminOnly
+#define __NV_RM_PROFILING_ADMIN_ONLY_PARAMETER RestrictProfilingToAdminUsers
+#define NV_REG_RM_PROFILING_ADMIN_ONLY NV_REG_STRING(__NV_RM_PROFILING_ADMIN_ONLY)
+
+
+/*
+* Option: EnableDebuggerInterface
+*
+* Description:
+*
+* When this option is enabled, the NVIDIA kernel module will allow non-administrator users to
+* create a non-preemptable debugger session for non-CILP contexts.
+*
+* Possible Values:
+*
+* 0: Do not allow non-administrator users to create non-preemptable debugger sessions (default)
+* 1: Allow non-administrator users to create non-preemptable debugger sessions
+*/
+#define __NV_ENABLE_NON_PREEMTABLE_DEBUGGER_SESSION EnableDebuggerInterface
+#define NV_REG_ENABLE_NON_PREEMTABLE_DEBUGGER_SESSION NV_REG_STRING(__NV_ENABLE_NON_PREEMTABLE_DEBUGGER_SESSION)
+
+/*
+ * Option: TemporaryFilePath
+ *
+ * Description:
+ *
+ * When specified, this option changes the location in which the
+ * NVIDIA kernel module will create unnamed temporary files (e.g. to
+ * save the contents of video memory in). The indicated file must
+ * be a directory. By default, temporary files are created in /tmp.
+ */
+#define __NV_TEMPORARY_FILE_PATH TemporaryFilePath
+#define NV_REG_TEMPORARY_FILE_PATH NV_REG_STRING(__NV_TEMPORARY_FILE_PATH)
+
+/*
+ * Option: PreserveVideoMemoryAllocations
+ *
+ * If enabled, this option prompts the NVIDIA kernel module to save and
+ * restore all video memory allocations across system power management
+ * cycles, i.e. suspend/resume and hibernate/restore. Otherwise,
+ * only select allocations are preserved.
+ *
+ * Possible Values:
+ *
+ * 0: Preserve only select video memory allocations
+ * 1: Preserve all video memory allocations
+ * 2: Automatically enable video memory allocations when
+ * NVreg_UseKernelSuspendNotifiers is enabled (default)
+ */
+#define __NV_PRESERVE_VIDEO_MEMORY_ALLOCATIONS PreserveVideoMemoryAllocations
+#define NV_REG_PRESERVE_VIDEO_MEMORY_ALLOCATIONS \
+ NV_REG_STRING(__NV_PRESERVE_VIDEO_MEMORY_ALLOCATIONS)
+
+#define NV_REG_PRESERVE_VIDEO_MEMORY_ALLOCATIONS_DISABLED 0
+#define NV_REG_PRESERVE_VIDEO_MEMORY_ALLOCATIONS_ENABLED 1
+#define NV_REG_PRESERVE_VIDEO_MEMORY_ALLOCATIONS_AUTO 2
+
+/*
+ * Option: UseKernelSuspendNotifiers
+ *
+ * If enabled, this option prompts the NVIDIA kernel module to register a
+ * notifier that saves and restores all video memory allocations across system
+ * power management cycles if PreserveVideoMemoryAllocations is enabled.
+ *
+ * Possible Values:
+ *
+ * 0: Suspend notifiers are not used (default)
+ * 1: Suspend notifiers are used when available
+ */
+
+#define __NV_USE_KERNEL_SUSPEND_NOTIFIERS UseKernelSuspendNotifiers
+#define NV_REG_USE_KERNEL_SUSPEND_NOTIFIERS \
+ NV_REG_STRING(__NV_USE_KERNEL_SUSPEND_NOTIFIERS)
+
+/*
+ * Option: EnableS0ixPowerManagement
+ *
+ * When this option is enabled, the NVIDIA driver will use S0ix-based
+ * power management for system suspend/resume, if both the platform and
+ * the GPU support S0ix.
+ *
+ * During system suspend, if S0ix is enabled and
+ * video memory usage is above the threshold configured by
+ * 'S0ixPowerManagementVideoMemoryThreshold', video memory will be kept
+ * in self-refresh mode while the rest of the GPU is powered down.
+ *
+ * Otherwise, the driver will copy video memory contents to system memory
+ * and power off the video memory along with the GPU.
+ *
+ * Possible Values:
+ *
+ * 0: Disable S0ix based power management (default)
+ * 1: Enable S0ix based power management
+ */
+
+#define __NV_ENABLE_S0IX_POWER_MANAGEMENT EnableS0ixPowerManagement
+#define NV_REG_ENABLE_S0IX_POWER_MANAGEMENT \
+ NV_REG_STRING(__NV_ENABLE_S0IX_POWER_MANAGEMENT)
+
+/*
+ * Option: S0ixPowerManagementVideoMemoryThreshold
+ *
+ * This option controls the threshold that the NVIDIA driver will use during
+ * S0ix-based system power management.
+ *
+ * When S0ix is enabled and the system is suspended, the driver will
+ * compare the amount of video memory in use with this threshold,
+ * to decide whether to keep video memory in self-refresh or copy video
+ * memory content to system memory.
+ *
+ * See the 'EnableS0ixPowerManagement' option.
+ *
+ * Values are expressed in Megabytes (1048576 bytes).
+ *
+ * Default value for this option is 256MB.
+ *
+ */
+#define __NV_S0IX_POWER_MANAGEMENT_VIDEO_MEMORY_THRESHOLD \
+ S0ixPowerManagementVideoMemoryThreshold
+#define NV_REG_S0IX_POWER_MANAGEMENT_VIDEO_MEMORY_THRESHOLD \
+ NV_REG_STRING(__NV_S0IX_POWER_MANAGEMENT_VIDEO_MEMORY_THRESHOLD)
+
+/*
+ * Option: DynamicPowerManagement
+ *
+ * This option controls how aggressively the NVIDIA kernel module will manage
+ * GPU power through kernel interfaces.
+ *
+ * Possible Values:
+ *
+ * 0: Never allow the GPU to be powered down (default).
+ * 1: Power down the GPU when it is not initialized.
+ * 2: Power down the GPU after it has been inactive for some time.
+ * 3: (Default) Power down the GPU after a period of inactivity (i.e.,
+ * mode 2) on Ampere or later notebooks. Otherwise, do not power down
+ * the GPU.
+ */
+#define __NV_DYNAMIC_POWER_MANAGEMENT DynamicPowerManagement
+#define NV_REG_DYNAMIC_POWER_MANAGEMENT \
+ NV_REG_STRING(__NV_DYNAMIC_POWER_MANAGEMENT)
+
+#define NV_REG_DYNAMIC_POWER_MANAGEMENT_NEVER 0
+#define NV_REG_DYNAMIC_POWER_MANAGEMENT_COARSE 1
+#define NV_REG_DYNAMIC_POWER_MANAGEMENT_FINE 2
+#define NV_REG_DYNAMIC_POWER_MANAGEMENT_DEFAULT 3
+
+/*
+ * Option: DynamicPowerManagementVideoMemoryThreshold
+ *
+ * This option controls the threshold that the NVIDIA driver will use
+ * when selecting the dynamic power management scheme.
+ *
+ * When the driver detects that the GPU is idle, it will compare the amount
+ * of video memory in use with this threshold.
+ *
+ * If the current video memory usage is less than the threshold, the
+ * driver may preserve video memory contents in system memory and power off
+ * the video memory along with the GPU itself, if supported. Otherwise,
+ * the video memory will be kept in self-refresh mode while powering down
+ * the rest of the GPU, if supported.
+ *
+ * Values are expressed in Megabytes (1048576 bytes).
+ *
+ * If the requested value is greater than 200MB (the default), then it
+ * will be capped to 200MB.
+ */
+#define __NV_DYNAMIC_POWER_MANAGEMENT_VIDEO_MEMORY_THRESHOLD \
+ DynamicPowerManagementVideoMemoryThreshold
+#define NV_REG_DYNAMIC_POWER_MANAGEMENT_VIDEO_MEMORY_THRESHOLD \
+ NV_REG_STRING(__NV_DYNAMIC_POWER_MANAGEMENT_VIDEO_MEMORY_THRESHOLD)
+
+/*
+ * Option: TegraGpuPgMask
+ *
+ * This option controls the TPC/GPC/FBP power-gating mask for Tegra iGPU.
+ *
+ */
+#define __NV_TEGRA_GPU_PG_MASK TegraGpuPgMask
+#define NV_REG_TEGRA_GPU_PG_MASK \
+ NV_REG_STRING(__NV_TEGRA_GPU_PG_MASK)
+
+/*
+ * Option: RegisterPCIDriver
+ *
+ * Description:
+ *
+ * When this option is enabled, the NVIDIA driver will register with
+ * PCI subsystem.
+ *
+ * Possible values:
+ *
+ * 1 - register as PCI driver (default)
+ * 0 - do not register as PCI driver
+ */
+
+#define __NV_REGISTER_PCI_DRIVER RegisterPCIDriver
+#define NV_REG_REGISTER_PCI_DRIVER NV_REG_STRING(__NV_REGISTER_PCI_DRIVER)
+
+/*
+ * Option: RegisterPlatformDeviceDriver
+ *
+ * Description:
+ *
+ * When this option is enabled, the NVIDIA driver will register with
+ * platform subsystem.
+ *
+ * Possible values:
+ *
+ * 1 - register as platform driver (default)
+ * 0 - do not register as platform driver
+ */
+
+#define __NV_REGISTER_PLATFORM_DEVICE_DRIVER RegisterPlatformDeviceDriver
+#define NV_REG_REGISTER_PLATFORM_DEVICE_DRIVER NV_REG_STRING(__NV_REGISTER_PLATFORM_DEVICE_DRIVER)
+
+/*
+ * Option: EnablePCIERelaxedOrderingMode
+ *
+ * Description:
+ *
+ * When this option is enabled, the registry key RmSetPCIERelaxedOrdering will
+ * be set to NV_REG_STR_RM_SET_PCIE_TLP_RELAXED_ORDERING_FORCE_ENABLE, causing
+ * every device to set the relaxed ordering bit to 1 in all outbound MWr
+ * transaction-layer packets. This is equivalent to setting the regkey to
+ * FORCE_ENABLE as a non-per-device registry key.
+ *
+ * Possible values:
+ * 0 - Do not enable PCIe TLP relaxed ordering bit-setting (default)
+ * 1 - Enable PCIe TLP relaxed ordering bit-setting
+ */
+#define __NV_ENABLE_PCIE_RELAXED_ORDERING_MODE EnablePCIERelaxedOrderingMode
+#define NV_REG_ENABLE_PCIE_RELAXED_ORDERING_MODE \
+ NV_REG_STRING(__NV_ENABLE_PCIE_RELAXED_ORDERING_MODE)
+
+/*
+ * Option: EnableResizableBar
+ *
+ * Description:
+ *
+ * When this option is enabled, the NVIDIA driver will attempt to resize
+ * BAR1 to match framebuffer size, or the next largest available size on
+ * supported machines. This is currently only implemented for Linux.
+ *
+ * Possible values:
+ * 0 - Do not enable PCI BAR resizing
+ * 1 - Enable PCI BAR resizing
+ */
+#define __NV_ENABLE_RESIZABLE_BAR EnableResizableBar
+#define NV_REG_ENABLE_RESIZABLE_BAR NV_REG_STRING(__NV_ENABLE_RESIZABLE_BAR)
+
+/*
+ * Option: EnableGpuFirmware
+ *
+ * Description:
+ *
+ * When this option is enabled, the NVIDIA driver will enable use of GPU
+ * firmware.
+ *
+ * If this key is set globally to the system, the driver may still attempt
+ * to apply some policies to maintain uniform firmware modes across all
+ * GPUS. This may result in the driver failing initialization on some GPUs
+ * to maintain such a policy.
+ *
+ * If this key is set using NVreg_RegistryDwordsPerDevice, then the driver
+ * will attempt to honor whatever configuration is specified without applying
+ * additional policies. This may also result in failed GPU initialzations if
+ * the configuration is not possible (for example if the firmware is missing
+ * from the filesystem, or the GPU is not capable).
+ *
+ * NOTE: More details for this regkey can be found in nv-firmware-registry.h
+ */
+#define __NV_ENABLE_GPU_FIRMWARE EnableGpuFirmware
+#define NV_REG_ENABLE_GPU_FIRMWARE NV_REG_STRING(__NV_ENABLE_GPU_FIRMWARE)
+
+/*
+ * Option: EnableGpuFirmwareLogs
+ *
+ * When this option is enabled, the NVIDIA driver will send GPU firmware logs
+ * to the system log, when possible.
+ *
+ * NOTE: More details for this regkey can be found in nv-firmware-registry.h
+ */
+#define __NV_ENABLE_GPU_FIRMWARE_LOGS EnableGpuFirmwareLogs
+#define NV_REG_ENABLE_GPU_FIRMWARE_LOGS NV_REG_STRING(__NV_ENABLE_GPU_FIRMWARE_LOGS)
+
+/*
+ * Option: EnableDbgBreakpoint
+ *
+ * When this option is set to a non-zero value, and the kernel is configured
+ * appropriately, assertions within resman will trigger a CPU breakpoint (e.g.,
+ * INT3 on x86_64), assumed to be caught by an attached debugger.
+ *
+ * When this option is set to the value zero (the default), assertions within
+ * resman will print to the system log, but no CPU breakpoint will be triggered.
+ */
+#define __NV_ENABLE_DBG_BREAKPOINT EnableDbgBreakpoint
+
+
+/*
+ * Option: OpenRmEnableUnsupportedGpus
+ *
+ * This option to require opt in for use of Open RM on non-Data Center
+ * GPUs is deprecated and no longer required. The kernel module parameter
+ * is left here, though ignored, for backwards compatibility.
+ */
+#define __NV_OPENRM_ENABLE_UNSUPPORTED_GPUS OpenRmEnableUnsupportedGpus
+
+/*
+ * Option: NVreg_DmaRemapPeerMmio
+ *
+ * Description:
+ *
+ * When this option is enabled, the NVIDIA driver will use device driver
+ * APIs provided by the Linux kernel for DMA-remapping part of a device's
+ * MMIO region to another device, creating e.g., IOMMU mappings as necessary.
+ * When this option is disabled, the NVIDIA driver will instead only apply a
+ * fixed offset, which may be zero, to CPU physical addresses to produce the
+ * DMA address for the peer's MMIO region, and no IOMMU mappings will be
+ * created.
+ *
+ * This option only affects peer MMIO DMA mappings, and not system memory
+ * mappings.
+ *
+ * Possible Values:
+ * 0 = disable dynamic DMA remapping of peer MMIO regions
+ * 1 = enable dynamic DMA remapping of peer MMIO regions (default)
+ */
+#define __NV_DMA_REMAP_PEER_MMIO DmaRemapPeerMmio
+#define NV_DMA_REMAP_PEER_MMIO NV_REG_STRING(__NV_DMA_REMAP_PEER_MMIO)
+#define NV_DMA_REMAP_PEER_MMIO_DISABLE 0x00000000
+#define NV_DMA_REMAP_PEER_MMIO_ENABLE 0x00000001
+
+/*
+ * Option: NVreg_RmNvlinkBandwidthLinkCount
+ *
+ * Description:
+ *
+ * This option allows user to reduce the GPU nvlink bandwidth to save power.
+ *
+ * This option is only for Blackwell+ GPU with NVLINK version 5.0.
+ */
+#define __NV_RM_NVLINK_BW_LINK_COUNT RmNvlinkBandwidthLinkCount
+#define NV_RM_NVLINK_BW_LINK_COUNT NV_REG_STRING(__NV_RM_NVLINK_BW_LINK_COUNT)
+
+/*
+ * Option: NVreg_RmNvlinkBandwidth
+ *
+ * Description:
+ *
+ * This option allows user to reduce the NVLINK P2P bandwidth to save power.
+ * The option is in the string format.
+ *
+ * Possible string values:
+ * OFF: 0% bandwidth
+ * MIN: 15%-25% bandwidth depending on the system's NVLink topology
+ * HALF: 50% bandwidth
+ * 3QUARTER: 75% bandwidth
+ * FULL: 100% bandwidth (default)
+ *
+ * This option is only for Hopper+ GPU with NVLINK version 4.0.
+ */
+#define __NV_RM_NVLINK_BW RmNvlinkBandwidth
+#define NV_RM_NVLINK_BW NV_REG_STRING(__NV_RM_NVLINK_BW)
+
+/*
+ * Option: NVreg_EnableNonblockingOpen
+ *
+ * Description:
+ *
+ * When this option is enabled, the NVIDIA driver will try to perform any
+ * required device initialization in the background when /dev/nvidiaN devices
+ * are opened with the flag O_NONBLOCK.
+ *
+ * Possible Values:
+ * 0 = O_NONBLOCK flag when opening devices is ignored
+ * 1 = O_NONBLOCK flag when opening devices results in background device
+ * initialization (default)
+ */
+#define __NV_ENABLE_NONBLOCKING_OPEN EnableNonblockingOpen
+#define NV_ENABLE_NONBLOCKING_OPEN NV_REG_STRING(__NV_ENABLE_NONBLOCKING_OPEN)
+
+/*
+ * Option: NVreg_ImexChannelCount
+ *
+ * Description:
+ *
+ * This option allows users to specify the number of IMEX (import/export)
+ * channels. Within an IMEX domain, the channels allow sharing memory
+ * securely in a multi-user environment using the CUDA driver's fabric handle
+ * based APIs.
+ *
+ * An IMEX domain is either an OS instance or a group of securely
+ * connected OS instances using the NVIDIA IMEX daemon. The option must
+ * be set to the same value on each OS instance within the IMEX domain.
+ *
+ * An IMEX channel is a logical entity that is represented by a /dev node.
+ * The IMEX channels are global resources within the IMEX domain. When
+ * exporter and importer CUDA processes have been granted access to the
+ * same IMEX channel, they can securely share memory.
+ *
+ * Note that the NVIDIA driver will not attempt to create the /dev nodes. Thus,
+ * the related CUDA APIs will fail with an insufficient permission error until
+ * the /dev nodes are set up. The creation of these /dev nodes,
+ * /dev/nvidia-caps-imex-channels/channelN, must be handled by the
+ * administrator, where N is the minor number. The major number can be
+ * queried from /proc/devices.
+ *
+ * nvidia-modprobe CLI support is available to set up the /dev nodes.
+ * NVreg_ModifyDeviceFiles, NVreg_DeviceFileGID, NVreg_DeviceFileUID
+ * and NVreg_DeviceFileMode will be honored by nvidia-modprobe.
+ *
+ * Also, refer to the NVreg_CreateImexChannel0 option.
+ *
+ * Possible values:
+ * 0 - Disable IMEX using CUDA driver's fabric handles.
+ * N - N IMEX channels will be enabled in the driver to facilitate N
+ * concurrent users. Default value is 2048 channels, and the current
+ * maximum value is 20-bit, same as Linux dev_t's minor number limit.
+ */
+#define __NV_IMEX_CHANNEL_COUNT ImexChannelCount
+#define NV_REG_IMEX_CHANNEL_COUNT NV_REG_STRING(__NV_IMEX_CHANNEL_COUNT)
+
+/*
+ * Option: NVreg_CreateImexChannel0
+ *
+ * Description:
+ *
+ * This option allows users to specify whether the NVIDIA driver must create
+ * the IMEX channel 0 by default. The channel will be created automatically
+ * when the NVIDIA open GPU kernel module is loaded.
+ *
+ * Note that users are advised to enable this option only in trusted
+ * environments where it is acceptable for applications to share the same
+ * IMEX channel.
+ *
+ * For more details on IMEX channels, refer to the NVreg_ImexChannelCount
+ * option.
+ *
+ * Possible values:
+ * 0 - Do not create IMEX channel 0 (default).
+ * 1 - Create IMEX channel 0.
+ */
+#define __NV_CREATE_IMEX_CHANNEL_0 CreateImexChannel0
+#define NV_CREATE_IMEX_CHANNEL_0 NV_REG_STRING(__CREATE_IMEX_CHANNEL_0)
+
+/*
+ * Option: NVreg_EnableSystemMemoryPools
+ *
+ * Description:
+ *
+ * This option controls system memory page pools creation for different page sizes
+ * Pool for pageSize is enabled by setting bit (pageSize >> NV_ENABLE_SYSTEM_MEMORY_POOLS_SHIFT)
+ * The pools keep memory cached once freed to speed-up reallocation
+ * Pools are shared by all adapters
+ *
+ * This feature is only supported by OpenRM driver
+ *
+ * By default 4K, 64K, 2M page size pools are enabled
+ */
+#define __NV_ENABLE_SYSTEM_MEMORY_POOLS EnableSystemMemoryPools
+#define NV_ENABLE_SYSTEM_MEMORY_POOLS NV_REG_STRING(__NV_ENABLE_SYSTEM_MEMORY_POOLS)
+#define NV_ENABLE_SYSTEM_MEMORY_POOLS_DEFAULT 0x00000211
+#define NV_ENABLE_SYSTEM_MEMORY_POOLS_SHIFT 12
+
+/*
+ * Option: NVreg_OsEnableCxlSupport
+ *
+ * Description:
+ *
+ * When this option is enabled, the driver will enable support for
+ * CXL at the OS layer.
+ *
+ * This option has no effect on platforms that do not support CXL or on
+ * GPUs without CXL capability.
+ *
+ * Possible Values:
+ *
+ * 0: disable CXL support
+ * 1: enable CXL support (default)
+ */
+#define __NV_OS_ENABLE_CXL_SUPPORT OsEnableCxlSupport
+#define NV_REG_OS_ENABLE_CXL_SUPPORT NV_REG_STRING(__NV_OS_ENABLE_CXL_SUPPORT)
+
+/*
+ * Option: NVreg_GpuInitOnProbe
+ *
+ * Description:
+ *
+ * This option allows the user to control initialization of the GPU at PCI probe time
+ *
+ * Possible values:
+ * 0 - Disable initializing the GPUs on PCI probe
+ * 1 - Initialize GPUs on PCI probe
+ */
+ #define __NV_GPU_INIT_ON_PROBE GpuInitOnProbe
+ #define NV_GPU_INIT_ON_PROBE NV_REG_STRING(__NV_GPU_INIT_ON_PROBE)
+ #define NV_GPU_INIT_ON_PROBE_DEFAULT 0
+
+#if defined(NV_DEFINE_REGISTRY_KEY_TABLE)
+
+/*
+ *---------registry key parameter declarations--------------
+ */
+
+NV_DEFINE_REG_ENTRY(__NV_RESMAN_DEBUG_LEVEL, ~0);
+NV_DEFINE_REG_ENTRY(__NV_RM_LOGON_RC, 1);
+NV_DEFINE_REG_ENTRY_GLOBAL(__NV_MODIFY_DEVICE_FILES, 1);
+NV_DEFINE_REG_ENTRY(__NV_DEVICE_FILE_UID, 0);
+NV_DEFINE_REG_ENTRY(__NV_DEVICE_FILE_GID, 0);
+NV_DEFINE_REG_ENTRY(__NV_DEVICE_FILE_MODE, 0666);
+NV_DEFINE_REG_ENTRY(__NV_INITIALIZE_SYSTEM_MEMORY_ALLOCATIONS, 1);
+NV_DEFINE_REG_ENTRY(__NV_ENABLE_PCIE_GEN3, 0);
+NV_DEFINE_REG_ENTRY(__NV_ENABLE_MSI, 1);
+NV_DEFINE_REG_ENTRY(__NV_ENABLE_STREAM_MEMOPS, 0);
+NV_DEFINE_REG_ENTRY(__NV_RM_PROFILING_ADMIN_ONLY_PARAMETER, 1);
+NV_DEFINE_REG_ENTRY(__NV_PRESERVE_VIDEO_MEMORY_ALLOCATIONS,
+ NV_REG_PRESERVE_VIDEO_MEMORY_ALLOCATIONS_AUTO);
+NV_DEFINE_REG_ENTRY(__NV_ENABLE_S0IX_POWER_MANAGEMENT, 0);
+NV_DEFINE_REG_ENTRY(__NV_S0IX_POWER_MANAGEMENT_VIDEO_MEMORY_THRESHOLD, 256);
+NV_DEFINE_REG_ENTRY(__NV_DYNAMIC_POWER_MANAGEMENT, 3);
+NV_DEFINE_REG_ENTRY(__NV_DYNAMIC_POWER_MANAGEMENT_VIDEO_MEMORY_THRESHOLD, 200);
+NV_DEFINE_REG_ENTRY(__NV_ENABLE_GPU_FIRMWARE, NV_REG_ENABLE_GPU_FIRMWARE_DEFAULT_VALUE);
+NV_DEFINE_REG_ENTRY(__NV_ENABLE_GPU_FIRMWARE_LOGS, NV_REG_ENABLE_GPU_FIRMWARE_LOGS_ENABLE_ON_DEBUG);
+NV_DEFINE_REG_ENTRY(__NV_OPENRM_ENABLE_UNSUPPORTED_GPUS, 1);
+
+NV_DEFINE_REG_ENTRY_GLOBAL(__NV_ENABLE_USER_NUMA_MANAGEMENT, 1);
+NV_DEFINE_REG_ENTRY_GLOBAL(__NV_MEMORY_POOL_SIZE, 0);
+NV_DEFINE_REG_ENTRY_GLOBAL(__NV_KMALLOC_HEAP_MAX_SIZE, 0);
+NV_DEFINE_REG_ENTRY_GLOBAL(__NV_VMALLOC_HEAP_MAX_SIZE, 0);
+NV_DEFINE_REG_ENTRY_GLOBAL(__NV_IGNORE_MMIO_CHECK, 0);
+NV_DEFINE_REG_ENTRY_GLOBAL(__NV_NVLINK_DISABLE, 0);
+NV_DEFINE_REG_ENTRY_GLOBAL(__NV_ENABLE_PCIE_RELAXED_ORDERING_MODE, 0);
+NV_DEFINE_REG_ENTRY_GLOBAL(__NV_REGISTER_PCI_DRIVER, 1);
+NV_DEFINE_REG_ENTRY_GLOBAL(__NV_REGISTER_PLATFORM_DEVICE_DRIVER, 1);
+NV_DEFINE_REG_ENTRY_GLOBAL(__NV_ENABLE_RESIZABLE_BAR, 0);
+NV_DEFINE_REG_ENTRY_GLOBAL(__NV_ENABLE_DBG_BREAKPOINT, 0);
+NV_DEFINE_REG_ENTRY_GLOBAL(__NV_TEGRA_GPU_PG_MASK, 0);
+NV_DEFINE_REG_ENTRY_GLOBAL(__NV_ENABLE_NONBLOCKING_OPEN, 1);
+NV_DEFINE_REG_ENTRY_GLOBAL(__NV_EXCLUDE_ALL_GPUS, NV_EXCLUDE_ALL_GPUS_DEFAULT);
+NV_DEFINE_REG_ENTRY_GLOBAL(__NV_GPU_INIT_ON_PROBE, NV_GPU_INIT_ON_PROBE_DEFAULT);
+
+NV_DEFINE_REG_STRING_ENTRY(__NV_COHERENT_GPU_MEMORY_MODE, NULL);
+NV_DEFINE_REG_STRING_ENTRY(__NV_REGISTRY_DWORDS, NULL);
+NV_DEFINE_REG_STRING_ENTRY(__NV_REGISTRY_DWORDS_PER_DEVICE, NULL);
+NV_DEFINE_REG_STRING_ENTRY(__NV_RM_MSG, NULL);
+NV_DEFINE_REG_STRING_ENTRY(__NV_GPU_BLACKLIST, NULL);
+NV_DEFINE_REG_STRING_ENTRY(__NV_TEMPORARY_FILE_PATH, NULL);
+NV_DEFINE_REG_STRING_ENTRY(__NV_EXCLUDED_GPUS, NULL);
+NV_DEFINE_REG_ENTRY(__NV_DMA_REMAP_PEER_MMIO, NV_DMA_REMAP_PEER_MMIO_ENABLE);
+NV_DEFINE_REG_STRING_ENTRY(__NV_RM_NVLINK_BW, NULL);
+NV_DEFINE_REG_ENTRY(__NV_RM_NVLINK_BW_LINK_COUNT, 0);
+NV_DEFINE_REG_ENTRY_GLOBAL(__NV_IMEX_CHANNEL_COUNT, 2048);
+NV_DEFINE_REG_ENTRY_GLOBAL(__NV_CREATE_IMEX_CHANNEL_0, 0);
+NV_DEFINE_REG_ENTRY_GLOBAL(__NV_ENABLE_SYSTEM_MEMORY_POOLS, NV_ENABLE_SYSTEM_MEMORY_POOLS_DEFAULT);
+NV_DEFINE_REG_ENTRY_GLOBAL(__NV_OS_ENABLE_CXL_SUPPORT, 1);
+NV_DEFINE_REG_ENTRY_GLOBAL(__NV_USE_KERNEL_SUSPEND_NOTIFIERS, 0);
+NV_DEFINE_REG_ENTRY(__NV_ENABLE_NON_PREEMTABLE_DEBUGGER_SESSION, 0);
+/*
+ *----------------registry database definition----------------------
+ */
+
+/*
+ * You can enable any of the registry options disabled by default by
+ * editing their respective entries in the table below. The last field
+ * determines if the option is considered valid - in order for the
+ * changes to take effect, you need to recompile and reload the NVIDIA
+ * kernel module.
+ */
+nv_parm_t nv_parms[] = {
+ NV_DEFINE_PARAMS_TABLE_ENTRY(__NV_RESMAN_DEBUG_LEVEL),
+ NV_DEFINE_PARAMS_TABLE_ENTRY(__NV_RM_LOGON_RC),
+ NV_DEFINE_PARAMS_TABLE_ENTRY(__NV_MODIFY_DEVICE_FILES),
+ NV_DEFINE_PARAMS_TABLE_ENTRY(__NV_DEVICE_FILE_UID),
+ NV_DEFINE_PARAMS_TABLE_ENTRY(__NV_DEVICE_FILE_GID),
+ NV_DEFINE_PARAMS_TABLE_ENTRY(__NV_DEVICE_FILE_MODE),
+ NV_DEFINE_PARAMS_TABLE_ENTRY(__NV_INITIALIZE_SYSTEM_MEMORY_ALLOCATIONS),
+ NV_DEFINE_PARAMS_TABLE_ENTRY(__NV_ENABLE_MSI),
+ NV_DEFINE_PARAMS_TABLE_ENTRY(__NV_ENABLE_PCIE_GEN3),
+ NV_DEFINE_PARAMS_TABLE_ENTRY(__NV_MEMORY_POOL_SIZE),
+ NV_DEFINE_PARAMS_TABLE_ENTRY(__NV_KMALLOC_HEAP_MAX_SIZE),
+ NV_DEFINE_PARAMS_TABLE_ENTRY(__NV_VMALLOC_HEAP_MAX_SIZE),
+ NV_DEFINE_PARAMS_TABLE_ENTRY(__NV_IGNORE_MMIO_CHECK),
+ NV_DEFINE_PARAMS_TABLE_ENTRY(__NV_ENABLE_STREAM_MEMOPS),
+ NV_DEFINE_PARAMS_TABLE_ENTRY(__NV_ENABLE_USER_NUMA_MANAGEMENT),
+ NV_DEFINE_PARAMS_TABLE_ENTRY(__NV_NVLINK_DISABLE),
+ NV_DEFINE_PARAMS_TABLE_ENTRY_CUSTOM_NAME(__NV_RM_PROFILING_ADMIN_ONLY,
+ __NV_RM_PROFILING_ADMIN_ONLY_PARAMETER),
+ NV_DEFINE_PARAMS_TABLE_ENTRY(__NV_PRESERVE_VIDEO_MEMORY_ALLOCATIONS),
+ NV_DEFINE_PARAMS_TABLE_ENTRY(__NV_USE_KERNEL_SUSPEND_NOTIFIERS),
+ NV_DEFINE_PARAMS_TABLE_ENTRY(__NV_ENABLE_S0IX_POWER_MANAGEMENT),
+ NV_DEFINE_PARAMS_TABLE_ENTRY(__NV_S0IX_POWER_MANAGEMENT_VIDEO_MEMORY_THRESHOLD),
+ NV_DEFINE_PARAMS_TABLE_ENTRY(__NV_DYNAMIC_POWER_MANAGEMENT),
+ NV_DEFINE_PARAMS_TABLE_ENTRY(__NV_DYNAMIC_POWER_MANAGEMENT_VIDEO_MEMORY_THRESHOLD),
+ NV_DEFINE_PARAMS_TABLE_ENTRY(__NV_TEGRA_GPU_PG_MASK),
+ NV_DEFINE_PARAMS_TABLE_ENTRY(__NV_REGISTER_PCI_DRIVER),
+ NV_DEFINE_PARAMS_TABLE_ENTRY(__NV_ENABLE_PCIE_RELAXED_ORDERING_MODE),
+ NV_DEFINE_PARAMS_TABLE_ENTRY(__NV_ENABLE_RESIZABLE_BAR),
+ NV_DEFINE_PARAMS_TABLE_ENTRY(__NV_ENABLE_GPU_FIRMWARE),
+ NV_DEFINE_PARAMS_TABLE_ENTRY(__NV_ENABLE_GPU_FIRMWARE_LOGS),
+ NV_DEFINE_PARAMS_TABLE_ENTRY(__NV_RM_NVLINK_BW_LINK_COUNT),
+ NV_DEFINE_PARAMS_TABLE_ENTRY(__NV_ENABLE_DBG_BREAKPOINT),
+ NV_DEFINE_PARAMS_TABLE_ENTRY(__NV_OPENRM_ENABLE_UNSUPPORTED_GPUS),
+ NV_DEFINE_PARAMS_TABLE_ENTRY(__NV_DMA_REMAP_PEER_MMIO),
+ NV_DEFINE_PARAMS_TABLE_ENTRY(__NV_IMEX_CHANNEL_COUNT),
+ NV_DEFINE_PARAMS_TABLE_ENTRY(__NV_CREATE_IMEX_CHANNEL_0),
+ NV_DEFINE_PARAMS_TABLE_ENTRY(__NV_ENABLE_SYSTEM_MEMORY_POOLS),
+ NV_DEFINE_PARAMS_TABLE_ENTRY(__NV_OS_ENABLE_CXL_SUPPORT),
+ NV_DEFINE_PARAMS_TABLE_ENTRY(__NV_ENABLE_NON_PREEMTABLE_DEBUGGER_SESSION),
+ {NULL, NULL}
+};
+
+#elif defined(NVRM)
+
+extern nv_parm_t nv_parms[];
+
+#endif /* NV_DEFINE_REGISTRY_KEY_TABLE */
+
+#endif /* _RM_REG_H_ */
diff --git a/userspace/sdks/nv570/nvalloc/unix/include/nv-unix-nvos-params-wrappers.h b/userspace/sdks/nv570/nvalloc/unix/include/nv-unix-nvos-params-wrappers.h
new file mode 100644
index 0000000..02b0156
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/include/nv-unix-nvos-params-wrappers.h
@@ -0,0 +1,49 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2017 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _NV_UNIX_NVOS_PARAMS_WRAPPERS_H_
+#define _NV_UNIX_NVOS_PARAMS_WRAPPERS_H_
+
+#include <nvos.h>
+
+/*
+ * This is a wrapper for NVOS02_PARAMETERS with file descriptor
+ */
+
+typedef struct
+{
+ NVOS02_PARAMETERS params;
+ int fd;
+} nv_ioctl_nvos02_parameters_with_fd;
+
+/*
+ * This is a wrapper for NVOS33_PARAMETERS with file descriptor
+ */
+typedef struct
+{
+ NVOS33_PARAMETERS params;
+ int fd;
+} nv_ioctl_nvos33_parameters_with_fd;
+
+#endif // _NV_UNIX_NVOS_PARAMS_WRAPPERS_H_
+
diff --git a/userspace/sdks/nv570/nvalloc/unix/include/nv.h b/userspace/sdks/nv570/nvalloc/unix/include/nv.h
new file mode 100644
index 0000000..d8db166
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/include/nv.h
@@ -0,0 +1,1367 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 1999-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+
+#ifndef _NV_H_
+#define _NV_H_
+
+
+
+#include <nvlimits.h>
+
+#if defined(NV_KERNEL_INTERFACE_LAYER) && defined(__FreeBSD__)
+ #include <sys/stddef.h> // NULL
+#elif defined(NV_KERNEL_INTERFACE_LAYER) && defined(NV_LINUX)
+ #include <linux/stddef.h> // NULL
+#else
+ #include <stddef.h> // NULL
+#endif
+
+#include <nvstatus.h>
+#include "nv_stdarg.h"
+#include <nv-caps.h>
+#include <nv-firmware.h>
+#include <nv-ioctl.h>
+#include <nv-ioctl-numa.h>
+#include <nvmisc.h>
+#include <os/nv_memory_area.h>
+
+#if !defined(NV_KERNEL_INTERFACE_LAYER) && defined(NVRM) && !defined(NV_DRM_FREEBSD_LKPI)
+#include <nvport/nvport.h>
+#else
+#define PORT_ATOMIC
+#endif
+
+extern nv_cap_t *nvidia_caps_root;
+
+extern const NvBool nv_is_rm_firmware_supported_os;
+
+#include <nvi2c.h>
+#include <nvimpshared.h>
+
+#include <nv-kernel-interface-api.h>
+
+#define GPU_UUID_LEN (16)
+
+/*
+ * Buffer size for an ASCII UUID: We need 2 digits per byte, plus space
+ * for "GPU", 5 dashes, and '\0' termination:
+ */
+#define GPU_UUID_ASCII_LEN (GPU_UUID_LEN * 2 + 9)
+
+/*
+ * #define an absolute maximum used as a sanity check for the
+ * NV_ESC_IOCTL_XFER_CMD ioctl() size argument.
+ */
+#define NV_ABSOLUTE_MAX_IOCTL_SIZE 16384
+
+/*
+ * Solaris provides no more than 8 bits for the argument size in
+ * the ioctl() command encoding; make sure we don't exceed this
+ * limit.
+ */
+#define __NV_IOWR_ASSERT(type) ((sizeof(type) <= NV_PLATFORM_MAX_IOCTL_SIZE) ? 1 : -1)
+#define __NV_IOWR(nr, type) ({ \
+ typedef char __NV_IOWR_TYPE_SIZE_ASSERT[__NV_IOWR_ASSERT(type)]; \
+ _IOWR(NV_IOCTL_MAGIC, (nr), type); \
+})
+
+#define NV_PCI_DEV_FMT "%04x:%02x:%02x.%x"
+#define NV_PCI_DEV_FMT_ARGS(nv) (nv)->pci_info.domain, (nv)->pci_info.bus, \
+ (nv)->pci_info.slot, (nv)->pci_info.function
+
+#define NV_RM_DEVICE_INTR_ADDRESS 0x100
+
+#define NV_TEGRA_PCI_IGPU_PG_MASK_DEFAULT 0xFFFFFFFF
+
+/*
+ * Clock domain identifier, which is used for fetching the engine
+ * load backed by the specified clock domain for Tegra platforms
+ * conforming linux devfreq framework to realize dynamic frequency
+ * scaling.
+ */
+typedef enum _TEGRASOC_DEVFREQ_CLK
+{
+ TEGRASOC_DEVFREQ_CLK_GPC,
+ TEGRASOC_DEVFREQ_CLK_NVD,
+} TEGRASOC_DEVFREQ_CLK;
+
+/*!
+ * @brief The order of the display clocks in the below defined enum
+ * should be synced with below mapping array and macro.
+ * All four should be updated simultaneously in case
+ * of removal or addition of clocks in below order.
+ * Also, TEGRASOC_WHICH_CLK_MAX is used in various places
+ * in below mentioned files.
+ * arch/nvalloc/unix/Linux/nv-linux.h
+ *
+ * arch/nvalloc/unix/src/os.c
+ * dispClkMapRmToOsArr[] = {...};
+ *
+ * arch/nvalloc/unix/Linux/nv-clk.c
+ * osMapClk[] = {...};
+ *
+ */
+typedef enum _TEGRASOC_WHICH_CLK
+{
+ TEGRASOC_WHICH_CLK_NVDISPLAYHUB,
+ TEGRASOC_WHICH_CLK_NVDISPLAY_DISP,
+ TEGRASOC_WHICH_CLK_NVDISPLAY_P0,
+ TEGRASOC_WHICH_CLK_NVDISPLAY_P1,
+ TEGRASOC_WHICH_CLK_NVDISPLAY_P2,
+ TEGRASOC_WHICH_CLK_NVDISPLAY_P3,
+ TEGRASOC_WHICH_CLK_NVDISPLAY_P4,
+ TEGRASOC_WHICH_CLK_NVDISPLAY_P5,
+ TEGRASOC_WHICH_CLK_NVDISPLAY_P6,
+ TEGRASOC_WHICH_CLK_NVDISPLAY_P7,
+ TEGRASOC_WHICH_CLK_DPAUX0,
+ TEGRASOC_WHICH_CLK_FUSE,
+ TEGRASOC_WHICH_CLK_DSIPLL_VCO,
+ TEGRASOC_WHICH_CLK_DSIPLL_CLKOUTPN,
+ TEGRASOC_WHICH_CLK_DSIPLL_CLKOUTA,
+ TEGRASOC_WHICH_CLK_SPPLL0_VCO,
+ TEGRASOC_WHICH_CLK_SPPLL0_CLKOUTA,
+ TEGRASOC_WHICH_CLK_SPPLL0_CLKOUTB,
+ TEGRASOC_WHICH_CLK_SPPLL0_CLKOUTPN,
+ TEGRASOC_WHICH_CLK_SPPLL1_CLKOUTPN,
+ TEGRASOC_WHICH_CLK_SPPLL0_DIV27,
+ TEGRASOC_WHICH_CLK_SPPLL1_DIV27,
+ TEGRASOC_WHICH_CLK_SPPLL0_DIV10,
+ TEGRASOC_WHICH_CLK_SPPLL0_DIV25,
+ TEGRASOC_WHICH_CLK_SPPLL1_VCO,
+ TEGRASOC_WHICH_CLK_VPLL0_REF,
+ TEGRASOC_WHICH_CLK_VPLL0,
+ TEGRASOC_WHICH_CLK_VPLL1,
+ TEGRASOC_WHICH_CLK_VPLL2,
+ TEGRASOC_WHICH_CLK_VPLL3,
+ TEGRASOC_WHICH_CLK_VPLL4,
+ TEGRASOC_WHICH_CLK_VPLL5,
+ TEGRASOC_WHICH_CLK_VPLL6,
+ TEGRASOC_WHICH_CLK_VPLL7,
+ TEGRASOC_WHICH_CLK_NVDISPLAY_P0_REF,
+ TEGRASOC_WHICH_CLK_RG0,
+ TEGRASOC_WHICH_CLK_RG1,
+ TEGRASOC_WHICH_CLK_RG2,
+ TEGRASOC_WHICH_CLK_RG3,
+ TEGRASOC_WHICH_CLK_RG4,
+ TEGRASOC_WHICH_CLK_RG5,
+ TEGRASOC_WHICH_CLK_RG6,
+ TEGRASOC_WHICH_CLK_RG7,
+ TEGRASOC_WHICH_CLK_DISPPLL,
+ TEGRASOC_WHICH_CLK_DISPHUBPLL,
+ TEGRASOC_WHICH_CLK_DSI_LP,
+ TEGRASOC_WHICH_CLK_DSI_CORE,
+ TEGRASOC_WHICH_CLK_DSI_PIXEL,
+ TEGRASOC_WHICH_CLK_PRE_SOR0,
+ TEGRASOC_WHICH_CLK_PRE_SOR1,
+ TEGRASOC_WHICH_CLK_PRE_SOR2,
+ TEGRASOC_WHICH_CLK_PRE_SOR3,
+ TEGRASOC_WHICH_CLK_DP_LINKA_REF,
+ TEGRASOC_WHICH_CLK_DP_LINKB_REF,
+ TEGRASOC_WHICH_CLK_DP_LINKC_REF,
+ TEGRASOC_WHICH_CLK_DP_LINKD_REF,
+ TEGRASOC_WHICH_CLK_SOR_LINKA_INPUT,
+ TEGRASOC_WHICH_CLK_SOR_LINKB_INPUT,
+ TEGRASOC_WHICH_CLK_SOR_LINKC_INPUT,
+ TEGRASOC_WHICH_CLK_SOR_LINKD_INPUT,
+ TEGRASOC_WHICH_CLK_SOR_LINKA_AFIFO,
+ TEGRASOC_WHICH_CLK_SOR_LINKB_AFIFO,
+ TEGRASOC_WHICH_CLK_SOR_LINKC_AFIFO,
+ TEGRASOC_WHICH_CLK_SOR_LINKD_AFIFO,
+ TEGRASOC_WHICH_CLK_SOR_LINKA_AFIFO_M,
+ TEGRASOC_WHICH_CLK_RG0_M,
+ TEGRASOC_WHICH_CLK_RG1_M,
+ TEGRASOC_WHICH_CLK_SOR0_M,
+ TEGRASOC_WHICH_CLK_SOR1_M,
+ TEGRASOC_WHICH_CLK_PLLHUB,
+ TEGRASOC_WHICH_CLK_SOR0,
+ TEGRASOC_WHICH_CLK_SOR1,
+ TEGRASOC_WHICH_CLK_SOR2,
+ TEGRASOC_WHICH_CLK_SOR3,
+ TEGRASOC_WHICH_CLK_SOR_PADA_INPUT,
+ TEGRASOC_WHICH_CLK_SOR_PADB_INPUT,
+ TEGRASOC_WHICH_CLK_SOR_PADC_INPUT,
+ TEGRASOC_WHICH_CLK_SOR_PADD_INPUT,
+ TEGRASOC_WHICH_CLK_SOR0_PAD,
+ TEGRASOC_WHICH_CLK_SOR1_PAD,
+ TEGRASOC_WHICH_CLK_SOR2_PAD,
+ TEGRASOC_WHICH_CLK_SOR3_PAD,
+ TEGRASOC_WHICH_CLK_PRE_SF0,
+ TEGRASOC_WHICH_CLK_SF0,
+ TEGRASOC_WHICH_CLK_SF1,
+ TEGRASOC_WHICH_CLK_SF2,
+ TEGRASOC_WHICH_CLK_SF3,
+ TEGRASOC_WHICH_CLK_SF4,
+ TEGRASOC_WHICH_CLK_SF5,
+ TEGRASOC_WHICH_CLK_SF6,
+ TEGRASOC_WHICH_CLK_SF7,
+ TEGRASOC_WHICH_CLK_DSI_PAD_INPUT,
+ TEGRASOC_WHICH_CLK_PRE_SOR0_REF,
+ TEGRASOC_WHICH_CLK_PRE_SOR1_REF,
+ TEGRASOC_WHICH_CLK_SOR0_PLL_REF,
+ TEGRASOC_WHICH_CLK_SOR1_PLL_REF,
+ TEGRASOC_WHICH_CLK_SOR2_PLL_REF,
+ TEGRASOC_WHICH_CLK_SOR3_PLL_REF,
+ TEGRASOC_WHICH_CLK_SOR0_REF,
+ TEGRASOC_WHICH_CLK_SOR1_REF,
+ TEGRASOC_WHICH_CLK_SOR2_REF,
+ TEGRASOC_WHICH_CLK_SOR3_REF,
+ TEGRASOC_WHICH_CLK_OSC,
+ TEGRASOC_WHICH_CLK_DSC,
+ TEGRASOC_WHICH_CLK_MAUD,
+ TEGRASOC_WHICH_CLK_AZA_2XBIT,
+ TEGRASOC_WHICH_CLK_AZA_BIT,
+ TEGRASOC_WHICH_CLK_MIPI_CAL,
+ TEGRASOC_WHICH_CLK_UART_FST_MIPI_CAL,
+ TEGRASOC_WHICH_CLK_SOR0_DIV,
+ TEGRASOC_WHICH_CLK_DISP_ROOT,
+ TEGRASOC_WHICH_CLK_HUB_ROOT,
+ TEGRASOC_WHICH_CLK_PLLA_DISP,
+ TEGRASOC_WHICH_CLK_PLLA_DISPHUB,
+ TEGRASOC_WHICH_CLK_PLLA,
+ TEGRASOC_WHICH_CLK_VPLLX_SOR0_MUXED,
+ TEGRASOC_WHICH_CLK_VPLLX_SOR1_MUXED,
+ TEGRASOC_WHICH_CLK_VPLLX_SOR2_MUXED,
+ TEGRASOC_WHICH_CLK_VPLLX_SOR3_MUXED,
+ TEGRASOC_WHICH_CLK_SF0_SOR,
+ TEGRASOC_WHICH_CLK_SF1_SOR,
+ TEGRASOC_WHICH_CLK_SF2_SOR,
+ TEGRASOC_WHICH_CLK_SF3_SOR,
+ TEGRASOC_WHICH_CLK_SF4_SOR,
+ TEGRASOC_WHICH_CLK_SF5_SOR,
+ TEGRASOC_WHICH_CLK_SF6_SOR,
+ TEGRASOC_WHICH_CLK_SF7_SOR,
+ TEGRASOC_WHICH_CLK_EMC,
+ TEGRASOC_WHICH_CLK_GPU_FIRST,
+ TEGRASOC_WHICH_CLK_GPU_SYS = TEGRASOC_WHICH_CLK_GPU_FIRST,
+ TEGRASOC_WHICH_CLK_GPU_NVD,
+ TEGRASOC_WHICH_CLK_GPU_UPROC,
+ TEGRASOC_WHICH_CLK_GPU_GPC0,
+ TEGRASOC_WHICH_CLK_GPU_GPC1,
+ TEGRASOC_WHICH_CLK_GPU_GPC2,
+ TEGRASOC_WHICH_CLK_GPU_LAST = TEGRASOC_WHICH_CLK_GPU_GPC2,
+ TEGRASOC_WHICH_CLK_MAX, // TEGRASOC_WHICH_CLK_MAX is defined for boundary checks only.
+} TEGRASOC_WHICH_CLK;
+
+#ifdef NVRM
+
+extern const char *pNVRM_ID;
+
+/*
+ * ptr arithmetic convenience
+ */
+
+typedef union
+{
+ volatile NvV8 Reg008[1];
+ volatile NvV16 Reg016[1];
+ volatile NvV32 Reg032[1];
+} nv_hwreg_t, * nv_phwreg_t;
+
+
+#define NVRM_PCICFG_NUM_BARS 6
+#define NVRM_PCICFG_BAR_OFFSET(i) (0x10 + (i) * 4)
+#define NVRM_PCICFG_BAR_REQTYPE_MASK 0x00000001
+#define NVRM_PCICFG_BAR_REQTYPE_MEMORY 0x00000000
+#define NVRM_PCICFG_BAR_MEMTYPE_MASK 0x00000006
+#define NVRM_PCICFG_BAR_MEMTYPE_64BIT 0x00000004
+#define NVRM_PCICFG_BAR_ADDR_MASK 0xfffffff0
+
+#define NVRM_PCICFG_NUM_DWORDS 16
+
+#define NV_GPU_NUM_BARS 3
+#define NV_GPU_BAR_INDEX_REGS 0
+#define NV_GPU_BAR_INDEX_FB 1
+#define NV_GPU_BAR_INDEX_IMEM 2
+
+typedef struct
+{
+ NvU64 cpu_address;
+ NvU64 size;
+ NvU32 offset;
+ NvU32 *map;
+ nv_phwreg_t map_u;
+} nv_aperture_t;
+
+typedef struct
+{
+ char *name;
+ NvU32 *data;
+} nv_parm_t;
+
+#define NV_RM_PAGE_SHIFT 12
+#define NV_RM_PAGE_SIZE (1 << NV_RM_PAGE_SHIFT)
+#define NV_RM_PAGE_MASK (NV_RM_PAGE_SIZE - 1)
+
+#define NV_RM_TO_OS_PAGE_SHIFT (os_page_shift - NV_RM_PAGE_SHIFT)
+#define NV_RM_PAGES_TO_OS_PAGES(count) \
+ ((((NvUPtr)(count)) >> NV_RM_TO_OS_PAGE_SHIFT) + \
+ ((((count) & ((1 << NV_RM_TO_OS_PAGE_SHIFT) - 1)) != 0) ? 1 : 0))
+
+// for dynamic granularity page array feature.
+// Notice: dst_granu should be larger than src_granu.
+#define NV_SRC_TO_DST_PAGE_SHIFT(src_granu, dst_granu) (GET_PAGE_SHIFT(dst_granu) - GET_PAGE_SHIFT(src_granu))
+#define NV_SRC_TO_DST_PAGE_COUNT(src_page_count,src_granu, dst_granu) \
+ ((((NvUPtr)(src_page_count)) >> NV_SRC_TO_DST_PAGE_SHIFT(src_granu, dst_granu)) + \
+ ((((src_page_count) & ((1 << NV_SRC_TO_DST_PAGE_SHIFT(src_granu, dst_granu)) - 1)) != 0) ? 1 : 0))
+
+#if defined(NVCPU_X86_64)
+#define NV_STACK_SIZE (NV_RM_PAGE_SIZE * 3)
+#else
+#define NV_STACK_SIZE (NV_RM_PAGE_SIZE * 2)
+#endif
+
+typedef struct nvidia_stack_s
+{
+ NvU32 size;
+ void *top;
+ NvU8 stack[NV_STACK_SIZE-16] __attribute__ ((aligned(16)));
+} nvidia_stack_t;
+
+/*
+ * TODO: Remove once all UNIX layers have been converted to use nvidia_stack_t
+ */
+typedef nvidia_stack_t nv_stack_t;
+
+typedef struct nv_file_private_t nv_file_private_t;
+
+/*
+ * this is a wrapper for unix events
+ * unlike the events that will be returned to clients, this includes
+ * kernel-specific data, such as file pointer, etc..
+ */
+typedef struct nv_event_s
+{
+ NvHandle hParent;
+ NvHandle hObject;
+ NvU32 index;
+ NvU32 info32;
+ NvU16 info16;
+ nv_file_private_t *nvfp; /* per file-descriptor data pointer */
+ NvU32 fd;
+ PORT_ATOMIC NvS32 active; /* whether the event should be signaled */
+ NvU32 refcount; /* count of associated RM events */
+ struct nv_event_s *next;
+} nv_event_t;
+
+typedef struct nv_kern_mapping_s
+{
+ void *addr;
+ NvU64 size;
+ NvU32 modeFlag;
+ struct nv_kern_mapping_s *next;
+} nv_kern_mapping_t;
+
+typedef struct nv_usermap_access_params_s
+{
+ NvU64 addr;
+ NvU64 size;
+ NvU64 offset;
+ NvU64 *page_array;
+ NvU64 num_pages;
+ MemoryArea memArea;
+ NvU64 access_start;
+ NvU64 access_size;
+ NvBool contig;
+ NvU32 caching;
+} nv_usermap_access_params_t;
+
+/*
+ * It stores mapping context per mapping
+ */
+typedef struct nv_alloc_mapping_context_s {
+ void *alloc;
+ NvU64 page_index;
+ NvU64 *page_array;
+ NvU64 num_pages;
+ MemoryArea memArea;
+ NvU64 access_start;
+ NvU64 access_size;
+ NvU32 prot;
+ NvBool valid;
+ NvU32 caching;
+} nv_alloc_mapping_context_t;
+
+struct nv_alloc_mapping_list_node_s;
+
+typedef struct nv_alloc_mapping_list_node_s {
+ nv_alloc_mapping_context_t context;
+ MemoryRange fileRange;
+ struct nv_alloc_mapping_list_node_s *pNext;
+ struct nv_alloc_mapping_list_node_s *pPrev;
+} nv_alloc_mapping_list_node_t;
+
+typedef enum
+{
+ NV_SOC_IRQ_DISPLAY_TYPE = 0x1,
+ NV_SOC_IRQ_DPAUX_TYPE,
+ NV_SOC_IRQ_GPIO_TYPE,
+ NV_SOC_IRQ_HDACODEC_TYPE,
+ NV_SOC_IRQ_TCPC2DISP_TYPE,
+ NV_SOC_IRQ_INVALID_TYPE
+} nv_soc_irq_type_t;
+
+/*
+ * It stores interrupt numbers and interrupt type and private data
+ */
+typedef struct nv_soc_irq_info_s {
+ NvU32 irq_num;
+ nv_soc_irq_type_t irq_type;
+ NvBool bh_pending;
+ union {
+ NvU32 gpio_num;
+ NvU32 dpaux_instance;
+ } irq_data;
+ NvS32 ref_count;
+} nv_soc_irq_info_t;
+
+#define NV_MAX_SOC_IRQS 10
+#define NV_MAX_DPAUX_NUM_DEVICES 4
+#define NV_MAX_DPAUX_DEV_NAME_SIZE 10
+
+#define NV_MAX_SOC_DPAUX_NUM_DEVICES 4
+
+/*
+ * per device state
+ */
+
+/* DMA-capable device data, defined by kernel interface layer */
+typedef struct nv_dma_device nv_dma_device_t;
+
+typedef struct nv_phys_addr_range
+{
+ NvU64 addr;
+ NvU64 len;
+} nv_phys_addr_range_t;
+
+typedef struct
+{
+ char vbios_version[15];
+ char firmware_version[64];
+} nv_cached_gpu_info_t;
+
+typedef struct nv_state_t
+{
+ void *priv; /* private data */
+ void *os_state; /* os-specific device state */
+
+ int flags;
+
+ /* PCI config info */
+ nv_pci_info_t pci_info;
+ NvU16 subsystem_id;
+ NvU16 subsystem_vendor;
+ NvU32 gpu_id;
+ NvU32 iovaspace_id;
+ struct
+ {
+ NvBool valid;
+ NvU8 uuid[GPU_UUID_LEN];
+ NvBool pci_uuid_read_attempted;
+ NV_STATUS pci_uuid_status;
+ } nv_uuid_cache;
+ void *handle;
+
+ NvU32 pci_cfg_space[NVRM_PCICFG_NUM_DWORDS];
+
+ /* physical characteristics */
+ nv_aperture_t bars[NV_GPU_NUM_BARS];
+ nv_aperture_t *regs;
+ nv_aperture_t *dpaux[NV_MAX_DPAUX_NUM_DEVICES];
+ nv_aperture_t *hdacodec_regs;
+ nv_aperture_t *mipical_regs;
+ nv_aperture_t *fb, ud;
+ nv_aperture_t *simregs;
+
+ NvU32 num_dpaux_instance;
+ NvU32 interrupt_line;
+ NvU32 dpaux_irqs[NV_MAX_DPAUX_NUM_DEVICES];
+ char dpaux_devname[NV_MAX_DPAUX_NUM_DEVICES][NV_MAX_DPAUX_DEV_NAME_SIZE];
+ nv_soc_irq_info_t soc_irq_info[NV_MAX_SOC_IRQS];
+ NvS32 current_soc_irq;
+ NvU32 num_soc_irqs;
+ NvU32 hdacodec_irq;
+ NvU32 tcpc2disp_irq;
+ NvU8 *soc_dcb_blob;
+ NvU32 soc_dcb_size;
+ NvU32 disp_sw_soc_chip_id;
+ NvBool soc_is_dpalt_mode_supported;
+ NvBool soc_is_hfrp_supported;
+ NvBool soc_is_external_phy_supported;
+ NvU64 dma_mask;
+
+ NvBool is_tegra_pci_igpu;
+ NvBool supports_tegra_igpu_rg;
+ NvBool is_tegra_pci_igpu_rg_enabled;
+ NvU32 tegra_pci_igpu_pg_mask;
+
+ NvBool primary_vga;
+
+ NvU32 sim_env;
+
+ NvU32 rc_timer_enabled;
+
+ /* list of events allocated for this device */
+ nv_event_t *event_list;
+
+ /* lock to protect event_list */
+ void *event_spinlock;
+
+ nv_kern_mapping_t *kern_mappings;
+
+ /* Kernel interface DMA device data */
+ nv_dma_device_t *dma_dev;
+ nv_dma_device_t *niso_dma_dev;
+
+ /*
+ * Per-GPU queue. The actual queue object is usually allocated in the
+ * arch-specific parent structure (e.g. nv_linux_state_t), and this
+ * pointer just points to it.
+ */
+ struct os_work_queue *queue;
+
+ /* For loading RM as a firmware (DCE or GSP) client */
+ NvBool request_firmware; /* request firmware from the OS */
+ NvBool request_fw_client_rm; /* attempt to init RM as FW a client */
+ NvBool allow_fallback_to_monolithic_rm; /* allow fallback to monolithic RM if FW client RM doesn't work out */
+ NvBool enable_firmware_logs; /* attempt to enable firmware log decoding/printing */
+
+ /* Variable to track, if nvidia_remove is called */
+ NvBool removed;
+
+ NvBool console_device;
+
+ /* Variable to track, if GPU is external GPU */
+ NvBool is_external_gpu;
+
+ /* Variable to track, if regkey PreserveVideoMemoryAllocations is set */
+ NvBool preserve_vidmem_allocations;
+
+ /* Variable to force allocation of 32-bit addressable memory */
+ NvBool force_dma32_alloc;
+
+ /* PCI power state should be D0 during system suspend */
+ NvBool d0_state_in_suspend;
+
+ /* Current cyclestats client and context */
+ NvU32 profiler_owner;
+ void *profiler_context;
+
+ /*
+ * RMAPI objects to use in the OS layer to talk to core RM.
+ *
+ * Note that we only need to store one subdevice handle: in SLI, we will
+ * have a separate nv_state_t per physical GPU.
+ */
+ struct {
+ NvHandle hClient;
+ NvHandle hDevice;
+ NvHandle hSubDevice;
+ NvHandle hI2C;
+ NvHandle hDisp;
+ } rmapi;
+
+ /* Bool to check if dma-buf is supported */
+ NvBool dma_buf_supported;
+
+ /* Bool to check if the device received a shutdown notification */
+ NvBool is_shutdown;
+
+ /* Bool to check if the GPU has a coherent sysmem link */
+ NvBool coherent;
+
+ /*
+ * Bool to check if GPU memory is backed by struct page.
+ * False for non-coherent platforms. May also be false
+ * on coherent platforms if GPU memory is not onlined to the kernel.
+ */
+ NvBool mem_has_struct_page;
+
+ /*
+ * Coherent GPU Memory Mode, one of:
+ * NV_COHERENT_GPU_MEM_MODE_NONE
+ * NV_COHERENT_GPU_MEM_MODE_NUMA
+ * NV_COHERENT_GPU_MEM_MODE_DRIVER
+ */
+ NvBool coherent_gpu_mem_mode;
+
+ /* OS detected GPU has ATS capability */
+ NvBool ats_support;
+ /*
+ * NUMA node ID of the CPU to which the GPU is attached.
+ * Holds NUMA_NO_NODE on platforms that don't support NUMA configuration.
+ */
+ NvS32 cpu_numa_node_id;
+
+ struct {
+ /* Bool to check if ISO iommu enabled */
+ NvBool iso_iommu_present;
+ /* Bool to check if NISO iommu enabled */
+ NvBool niso_iommu_present;
+ /* Display SMMU Stream IDs */
+ NvU32 dispIsoStreamId;
+ NvU32 dispNisoStreamId;
+ } iommus;
+
+ struct {
+ NvU32 max_dispclk_rate_using_disppllkhz;
+ NvU32 max_dispclk_rate_using_sppll0clkoutakhz;
+ NvU32 max_hubclk_rate_using_sppll0clkoutbkhz;
+ } clocks;
+
+ /* Console is managed by drm drivers or NVKMS */
+ NvBool client_managed_console;
+
+ /* Console is mapped to sysmem instead of GPU PCIe BAR1 or BAR2 */
+ NvBool sysmem_mapped_console;
+
+ /* Struct to cache the gpu info details */
+ nv_cached_gpu_info_t cached_gpu_info;
+
+ /* Bool to check if power management is supported */
+ NvBool is_pm_unsupported;
+
+ /* Bool to check if the GPU is a CXL device */
+ NvBool is_cxl_dev;
+} nv_state_t;
+
+#define NVFP_TYPE_NONE ((NvU32)0x0)
+#define NVFP_TYPE_REFCOUNTED ((NvU32)0x1)
+#define NVFP_TYPE_REGISTERED ((NvU32)0x2)
+
+struct nv_file_private_t
+{
+ NvHandle *handles;
+ NvU16 maxHandles;
+ NvU32 deviceInstance;
+ NvU32 gpuInstanceId;
+ NvU8 metadata[64];
+
+ nv_file_private_t * PORT_ATOMIC ctl_nvfp;
+ void *ctl_nvfp_priv;
+ PORT_ATOMIC NvU32 register_or_refcount;
+ // In-flight nv_post_event() calls using this file private.
+ PORT_ATOMIC NvS32 event_posting_refcount;
+
+ //
+ // True if a client or an event was ever allocated on this fd.
+ // If false, RMAPI cleanup is skipped.
+ //
+ NvBool bCleanupRmapi;
+};
+
+static inline NvS32 nv_event_posting_refcount_read(nv_file_private_t *nvfp)
+{
+ return *((volatile NvS32 *)&nvfp->event_posting_refcount);
+}
+
+// Forward define the gpu ops structures
+typedef struct gpuSession *nvgpuSessionHandle_t;
+typedef struct gpuDevice *nvgpuDeviceHandle_t;
+typedef struct gpuAddressSpace *nvgpuAddressSpaceHandle_t;
+typedef struct gpuTsg *nvgpuTsgHandle_t;
+typedef struct UvmGpuTsgAllocParams_tag nvgpuTsgAllocParams_t;
+typedef struct gpuChannel *nvgpuChannelHandle_t;
+typedef struct UvmGpuChannelInfo_tag *nvgpuChannelInfo_t;
+typedef struct UvmGpuChannelAllocParams_tag nvgpuChannelAllocParams_t;
+typedef struct UvmGpuCaps_tag *nvgpuCaps_t;
+typedef struct UvmGpuCopyEnginesCaps_tag *nvgpuCesCaps_t;
+typedef struct UvmGpuAddressSpaceInfo_tag *nvgpuAddressSpaceInfo_t;
+typedef struct UvmGpuAllocInfo_tag *nvgpuAllocInfo_t;
+typedef struct UvmGpuP2PCapsParams_tag *nvgpuP2PCapsParams_t;
+typedef struct UvmGpuFbInfo_tag *nvgpuFbInfo_t;
+typedef struct UvmGpuNvlinkInfo_tag *nvgpuNvlinkInfo_t;
+typedef struct UvmGpuEccInfo_tag *nvgpuEccInfo_t;
+typedef struct UvmGpuFaultInfo_tag *nvgpuFaultInfo_t;
+typedef struct UvmGpuAccessCntrInfo_tag *nvgpuAccessCntrInfo_t;
+typedef struct UvmGpuAccessCntrConfig_tag nvgpuAccessCntrConfig_t;
+typedef struct UvmGpuInfo_tag nvgpuInfo_t;
+typedef struct UvmGpuClientInfo_tag nvgpuClientInfo_t;
+typedef struct UvmPmaAllocationOptions_tag *nvgpuPmaAllocationOptions_t;
+typedef struct UvmPmaStatistics_tag *nvgpuPmaStatistics_t;
+typedef struct UvmGpuMemoryInfo_tag *nvgpuMemoryInfo_t;
+typedef struct UvmGpuExternalMappingInfo_tag *nvgpuExternalMappingInfo_t;
+typedef struct UvmGpuExternalPhysAddrInfo_tag *nvgpuExternalPhysAddrInfo_t;
+typedef struct UvmGpuChannelResourceInfo_tag *nvgpuChannelResourceInfo_t;
+typedef struct UvmGpuChannelInstanceInfo_tag *nvgpuChannelInstanceInfo_t;
+typedef struct UvmGpuChannelResourceBindParams_tag *nvgpuChannelResourceBindParams_t;
+typedef struct UvmGpuPagingChannelAllocParams_tag nvgpuPagingChannelAllocParams_t;
+typedef struct UvmGpuPagingChannel_tag *nvgpuPagingChannelHandle_t;
+typedef struct UvmGpuPagingChannelInfo_tag *nvgpuPagingChannelInfo_t;
+typedef enum UvmPmaGpuMemoryType_tag nvgpuGpuMemoryType_t;
+typedef NV_STATUS (*nvPmaEvictPagesCallback)(void *, NvU64, NvU64 *, NvU32, NvU64, NvU64, nvgpuGpuMemoryType_t);
+typedef NV_STATUS (*nvPmaEvictRangeCallback)(void *, NvU64, NvU64, nvgpuGpuMemoryType_t);
+typedef struct UvmGpuAccessBitsBufferAlloc_tag *nvgpuAccessBitBufferAlloc_t;
+/*
+ * flags
+ */
+
+#define NV_FLAG_INITIALIZED 0x0001
+#define NV_FLAG_EXCLUDE 0x0002
+#define NV_FLAG_CONTROL 0x0004
+#define NV_FLAG_PCI_P2P_UNSUPPORTED_CHIPSET 0x0008
+#define NV_FLAG_SOC_DISPLAY 0x0010
+#define NV_FLAG_USES_MSI 0x0020
+#define NV_FLAG_USES_MSIX 0x0040
+#define NV_FLAG_PASSTHRU 0x0080
+#define NV_FLAG_SUSPENDED 0x0100
+#define NV_FLAG_HAS_CONSOLE_IN_SYSMEM_CARVEOUT 0x0200
+/* To be set when an FLR needs to be triggered after device shut down. */
+#define NV_FLAG_TRIGGER_FLR 0x0400
+#define NV_FLAG_PERSISTENT_SW_STATE 0x0800
+#define NV_FLAG_IN_RECOVERY 0x1000
+// Unused 0x2000
+#define NV_FLAG_UNBIND_LOCK 0x4000
+/* To be set when GPU is not present on the bus, to help device teardown */
+#define NV_FLAG_IN_SURPRISE_REMOVAL 0x8000
+
+typedef enum
+{
+ NV_PM_ACTION_HIBERNATE,
+ NV_PM_ACTION_STANDBY,
+ NV_PM_ACTION_RESUME
+} nv_pm_action_t;
+
+typedef enum
+{
+ NV_PM_ACTION_DEPTH_DEFAULT,
+ NV_PM_ACTION_DEPTH_MODESET,
+ NV_PM_ACTION_DEPTH_UVM
+} nv_pm_action_depth_t;
+
+typedef enum
+{
+ NV_DYNAMIC_PM_NEVER,
+ NV_DYNAMIC_PM_COARSE,
+ NV_DYNAMIC_PM_FINE
+} nv_dynamic_power_mode_t;
+
+typedef enum
+{
+ NV_POWER_STATE_IN_HIBERNATE,
+ NV_POWER_STATE_IN_STANDBY,
+ NV_POWER_STATE_RUNNING
+} nv_power_state_t;
+
+typedef struct
+{
+ const char *vidmem_power_status;
+ const char *dynamic_power_status;
+ const char *gc6_support;
+ const char *gcoff_support;
+ const char *s0ix_status;
+ const char *db_support;
+} nv_power_info_t;
+
+typedef enum
+{
+ NV_MEMORY_TYPE_SYSTEM, /* Memory mapped for ROM, SBIOS and physical RAM. */
+ NV_MEMORY_TYPE_REGISTERS,
+ NV_MEMORY_TYPE_FRAMEBUFFER,
+ NV_MEMORY_TYPE_DEVICE_MMIO, /* All kinds of MMIO referred by NVRM e.g. BARs and MCFG of device */
+} nv_memory_type_t;
+
+#define NV_PRIMARY_VGA(nv) ((nv)->primary_vga)
+
+#define NV_IS_CTL_DEVICE(nv) ((nv)->flags & NV_FLAG_CONTROL)
+#define NV_IS_SOC_DISPLAY_DEVICE(nv) \
+ ((nv)->flags & NV_FLAG_SOC_DISPLAY)
+
+#define NV_IS_DEVICE_IN_SURPRISE_REMOVAL(nv) \
+ (((nv)->flags & NV_FLAG_IN_SURPRISE_REMOVAL) != 0)
+
+#define NV_HAS_CONSOLE_IN_SYSMEM_CARVEOUT(nv) \
+ (((nv)->flags & NV_FLAG_HAS_CONSOLE_IN_SYSMEM_CARVEOUT) != 0)
+
+/*
+ * For console setup by EFI GOP, the base address is BAR1.
+ * For console setup by VBIOS, the base address is BAR2 + 16MB.
+ */
+#define NV_IS_CONSOLE_MAPPED(nv, addr) \
+ (((addr) == (nv)->bars[NV_GPU_BAR_INDEX_FB].cpu_address) || \
+ ((addr) == ((nv)->bars[NV_GPU_BAR_INDEX_IMEM].cpu_address + 0x1000000)))
+
+#define NV_SOC_IS_ISO_IOMMU_PRESENT(nv) \
+ ((nv)->iommus.iso_iommu_present)
+
+#define NV_SOC_IS_NISO_IOMMU_PRESENT(nv) \
+ ((nv)->iommus.niso_iommu_present)
+/*
+ * GPU add/remove events
+ */
+#define NV_SYSTEM_GPU_ADD_EVENT 0x9001
+#define NV_SYSTEM_GPU_REMOVE_EVENT 0x9002
+
+/*
+ * NVIDIA ACPI sub-event IDs (event types) to be passed into
+ * to core NVIDIA driver for ACPI events.
+ */
+#define NV_SYSTEM_ACPI_EVENT_VALUE_DISPLAY_SWITCH_DEFAULT 0
+#define NV_SYSTEM_ACPI_EVENT_VALUE_DOCK_EVENT_UNDOCKED 0
+#define NV_SYSTEM_ACPI_EVENT_VALUE_DOCK_EVENT_DOCKED 1
+
+#define NV_ACPI_NVIF_HANDLE_PRESENT 0x01
+#define NV_ACPI_DSM_HANDLE_PRESENT 0x02
+#define NV_ACPI_WMMX_HANDLE_PRESENT 0x04
+
+#define NV_EVAL_ACPI_METHOD_NVIF 0x01
+#define NV_EVAL_ACPI_METHOD_WMMX 0x02
+
+/*
+ * Coherent GPU Memory Mode
+ */
+#define NV_COHERENT_GPU_MEM_MODE_NONE 0
+#define NV_COHERENT_GPU_MEM_MODE_NUMA 1
+#define NV_COHERENT_GPU_MEM_MODE_DRIVER 2
+
+typedef enum {
+ NV_I2C_CMD_READ = 1,
+ NV_I2C_CMD_WRITE,
+ NV_I2C_CMD_SMBUS_READ,
+ NV_I2C_CMD_SMBUS_WRITE,
+ NV_I2C_CMD_SMBUS_QUICK_WRITE,
+ NV_I2C_CMD_SMBUS_QUICK_READ,
+ NV_I2C_CMD_SMBUS_BLOCK_READ,
+ NV_I2C_CMD_SMBUS_BLOCK_WRITE,
+ NV_I2C_CMD_BLOCK_READ,
+ NV_I2C_CMD_BLOCK_WRITE
+} nv_i2c_cmd_t;
+
+// Flags needed by osAllocPagesNode / os_alloc_pages_node
+#define NV_ALLOC_PAGES_NODE_NONE 0x0
+#define NV_ALLOC_PAGES_NODE_SKIP_RECLAIM 0x1
+
+/*
+** where we hide our nv_state_t * ...
+*/
+#define NV_SET_NV_STATE(pgpu,p) ((pgpu)->pOsGpuInfo = (p))
+#define NV_GET_NV_STATE(pGpu) \
+ (nv_state_t *)((pGpu) ? (pGpu)->pOsGpuInfo : NULL)
+
+static inline NvBool IS_REG_OFFSET(nv_state_t *nv, NvU64 offset, NvU64 length)
+{
+ return ((offset >= nv->regs->cpu_address) &&
+ ((offset + (length - 1)) >= offset) &&
+ ((offset + (length - 1)) <= (nv->regs->cpu_address + (nv->regs->size - 1))));
+}
+
+static inline NvBool IS_FB_OFFSET(nv_state_t *nv, NvU64 offset, NvU64 length)
+{
+ return ((nv->fb) && (nv->fb->size != 0) &&
+ (offset >= nv->fb->cpu_address) &&
+ ((offset + (length - 1)) >= offset) &&
+ ((offset + (length - 1)) <= (nv->fb->cpu_address + (nv->fb->size - 1))));
+}
+
+static inline NvBool IS_UD_OFFSET(nv_state_t *nv, NvU64 offset, NvU64 length)
+{
+ return ((nv->ud.cpu_address != 0) && (nv->ud.size != 0) &&
+ (offset >= nv->ud.cpu_address) &&
+ ((offset + (length - 1)) >= offset) &&
+ ((offset + (length - 1)) <= (nv->ud.cpu_address + (nv->ud.size - 1))));
+}
+
+static inline NvBool IS_IMEM_OFFSET(nv_state_t *nv, NvU64 offset, NvU64 length)
+{
+ return ((nv->bars[NV_GPU_BAR_INDEX_IMEM].cpu_address != 0) &&
+ (nv->bars[NV_GPU_BAR_INDEX_IMEM].size != 0) &&
+ (offset >= nv->bars[NV_GPU_BAR_INDEX_IMEM].cpu_address) &&
+ ((offset + (length - 1)) >= offset) &&
+ ((offset + (length - 1)) <= (nv->bars[NV_GPU_BAR_INDEX_IMEM].cpu_address +
+ (nv->bars[NV_GPU_BAR_INDEX_IMEM].size - 1))));
+}
+
+#define NV_RM_MAX_MSIX_LINES 8
+
+#define NV_MAX_ISR_DELAY_US 20000
+#define NV_MAX_ISR_DELAY_MS (NV_MAX_ISR_DELAY_US / 1000)
+
+#define NV_TIMERCMP(a, b, CMP) \
+ (((a)->tv_sec == (b)->tv_sec) ? \
+ ((a)->tv_usec CMP (b)->tv_usec) : ((a)->tv_sec CMP (b)->tv_sec))
+
+#define NV_TIMERADD(a, b, result) \
+ { \
+ (result)->tv_sec = (a)->tv_sec + (b)->tv_sec; \
+ (result)->tv_usec = (a)->tv_usec + (b)->tv_usec; \
+ if ((result)->tv_usec >= 1000000) \
+ { \
+ ++(result)->tv_sec; \
+ (result)->tv_usec -= 1000000; \
+ } \
+ }
+
+#define NV_TIMERSUB(a, b, result) \
+ { \
+ (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
+ (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
+ if ((result)->tv_usec < 0) \
+ { \
+ --(result)->tv_sec; \
+ (result)->tv_usec += 1000000; \
+ } \
+ }
+
+#define NV_TIMEVAL_TO_US(tv) ((NvU64)(tv).tv_sec * 1000000 + (tv).tv_usec)
+
+#ifndef NV_ALIGN_UP
+#define NV_ALIGN_UP(v,g) (((v) + ((g) - 1)) & ~((g) - 1))
+#endif
+#ifndef NV_ALIGN_DOWN
+#define NV_ALIGN_DOWN(v,g) ((v) & ~((g) - 1))
+#endif
+
+
+/*
+ * driver internal interfaces
+ */
+
+/*
+ * ---------------------------------------------------------------------------
+ *
+ * Function prototypes for UNIX specific OS interface.
+ *
+ * ---------------------------------------------------------------------------
+ */
+
+NvU32 NV_API_CALL nv_get_dev_minor (nv_state_t *);
+void* NV_API_CALL nv_alloc_kernel_mapping (nv_state_t *, void *, NvU64, NvU32, NvU64, void **);
+void NV_API_CALL nv_free_kernel_mapping (nv_state_t *, void *, void *, void *);
+NV_STATUS NV_API_CALL nv_alloc_user_mapping (nv_state_t *, void *, NvU64, NvU32, NvU64, NvU32, NvU64 *, void **);
+void NV_API_CALL nv_free_user_mapping (nv_state_t *, void *, NvU64, void *);
+NV_STATUS NV_API_CALL nv_add_mapping_context_to_file (nv_state_t *, nv_usermap_access_params_t*, NvU32, void *, NvU64, NvU32);
+
+NvU64 NV_API_CALL nv_get_kern_phys_address (NvU64);
+NvU64 NV_API_CALL nv_get_user_phys_address (NvU64);
+nv_state_t* NV_API_CALL nv_get_adapter_state (NvU32, NvU8, NvU8);
+nv_state_t* NV_API_CALL nv_get_ctl_state (void);
+
+void NV_API_CALL nv_set_dma_address_size (nv_state_t *, NvU32 );
+
+NV_STATUS NV_API_CALL nv_alias_pages (nv_state_t *, NvU32, NvU64, NvU32, NvU32, NvU64, NvU64 *, NvBool, void **);
+NV_STATUS NV_API_CALL nv_alloc_pages (nv_state_t *, NvU32, NvU64, NvBool, NvU32, NvBool, NvBool, NvS32, NvU64 *, void **);
+NV_STATUS NV_API_CALL nv_free_pages (nv_state_t *, NvU32, NvBool, NvU32, void *);
+
+NV_STATUS NV_API_CALL nv_register_user_pages (nv_state_t *, NvU64, NvU64 *, void *, void **, NvBool);
+void NV_API_CALL nv_unregister_user_pages (nv_state_t *, NvU64, void **, void **);
+
+NV_STATUS NV_API_CALL nv_register_peer_io_mem (nv_state_t *, NvU64 *, NvU64, void **);
+void NV_API_CALL nv_unregister_peer_io_mem(nv_state_t *, void *);
+
+struct sg_table;
+
+NV_STATUS NV_API_CALL nv_register_sgt (nv_state_t *, NvU64 *, NvU64, NvU32, void **,
+ struct sg_table *, void *, NvBool);
+void NV_API_CALL nv_unregister_sgt (nv_state_t *, struct sg_table **, void **, void *);
+NV_STATUS NV_API_CALL nv_register_phys_pages (nv_state_t *, NvU64 *, NvU64, NvU32, void **);
+void NV_API_CALL nv_unregister_phys_pages (nv_state_t *, void *);
+
+NV_STATUS NV_API_CALL nv_dma_map_sgt (nv_dma_device_t *, NvU64, NvU64 *, NvU32, NvBool, void **);
+
+NV_STATUS NV_API_CALL nv_dma_map_alloc (nv_dma_device_t *, NvU64, NvU64 *, NvBool, NvBool, void **);
+NV_STATUS NV_API_CALL nv_dma_unmap_alloc (nv_dma_device_t *, NvU64, NvU64 *, void **);
+
+NV_STATUS NV_API_CALL nv_dma_map_peer (nv_dma_device_t *, nv_dma_device_t *, NvU8, NvU64, NvU64 *);
+void NV_API_CALL nv_dma_unmap_peer (nv_dma_device_t *, NvU64, NvU64);
+
+NV_STATUS NV_API_CALL nv_dma_map_mmio (nv_dma_device_t *, NvU64, NvU64 *);
+void NV_API_CALL nv_dma_unmap_mmio (nv_dma_device_t *, NvU64, NvU64);
+
+void NV_API_CALL nv_dma_cache_invalidate (nv_dma_device_t *, void *);
+void* NV_API_CALL nv_dma_get_dev_pagemap (NvU64);
+void NV_API_CALL nv_dma_put_dev_pagemap (void *);
+NvBool NV_API_CALL nv_grdma_pci_topology_supported(nv_state_t *, nv_dma_device_t *);
+
+NvS32 NV_API_CALL nv_start_rc_timer (nv_state_t *);
+NvS32 NV_API_CALL nv_stop_rc_timer (nv_state_t *);
+
+void NV_API_CALL nv_post_event (nv_event_t *, NvHandle, NvU32, NvU32, NvU16, NvBool);
+NvS32 NV_API_CALL nv_get_event (nv_file_private_t *, nv_event_t *, NvU32 *);
+
+void* NV_API_CALL nv_i2c_add_adapter (nv_state_t *, NvU32);
+void NV_API_CALL nv_i2c_del_adapter (nv_state_t *, void *);
+
+void NV_API_CALL nv_acpi_methods_init (NvU32 *);
+void NV_API_CALL nv_acpi_methods_uninit (void);
+
+NV_STATUS NV_API_CALL nv_acpi_method (NvU32, NvU32, NvU32, void *, NvU16, NvU32 *, void *, NvU16 *);
+NV_STATUS NV_API_CALL nv_acpi_d3cold_dsm_for_upstream_port (nv_state_t *, NvU8 *, NvU32, NvU32, NvU32 *);
+NV_STATUS NV_API_CALL nv_acpi_dsm_method (nv_state_t *, NvU8 *, NvU32, NvBool, NvU32, void *, NvU16, NvU32 *, void *, NvU16 *);
+NV_STATUS NV_API_CALL nv_acpi_ddc_method (nv_state_t *, void *, NvU32 *, NvBool);
+NV_STATUS NV_API_CALL nv_acpi_dod_method (nv_state_t *, NvU32 *, NvU32 *);
+NV_STATUS NV_API_CALL nv_acpi_rom_method (nv_state_t *, NvU32 *, NvU32 *);
+NV_STATUS NV_API_CALL nv_acpi_get_powersource (NvU32 *);
+NvBool NV_API_CALL nv_acpi_is_battery_present(void);
+
+NV_STATUS NV_API_CALL nv_acpi_mux_method (nv_state_t *, NvU32 *, NvU32, const char *);
+
+NV_STATUS NV_API_CALL nv_log_error (nv_state_t *, NvU32, const char *, va_list);
+
+NvBool NV_API_CALL nv_requires_dma_remap (nv_state_t *);
+
+NvBool NV_API_CALL nv_is_rm_firmware_active(nv_state_t *);
+const void*NV_API_CALL nv_get_firmware(nv_state_t *, nv_firmware_type_t, nv_firmware_chip_family_t, const void **, NvU32 *);
+void NV_API_CALL nv_put_firmware(const void *);
+
+nv_file_private_t* NV_API_CALL nv_get_file_private(NvS32, NvBool, void **);
+void NV_API_CALL nv_put_file_private(void *);
+
+NV_STATUS NV_API_CALL nv_get_device_memory_config(nv_state_t *, NvU64 *, NvU64 *, NvU64 *, NvU64 *, NvU32 *, NvS32 *);
+NV_STATUS NV_API_CALL nv_get_egm_info(nv_state_t *, NvU64 *, NvU64 *, NvS32 *);
+
+void NV_API_CALL nv_p2p_free_platform_data(void *data);
+
+NV_STATUS NV_API_CALL nv_revoke_gpu_mappings (nv_state_t *);
+void NV_API_CALL nv_acquire_mmap_lock (nv_state_t *);
+void NV_API_CALL nv_release_mmap_lock (nv_state_t *);
+NvBool NV_API_CALL nv_get_all_mappings_revoked_locked (nv_state_t *);
+void NV_API_CALL nv_set_safe_to_mmap_locked (nv_state_t *, NvBool);
+
+nv_alloc_mapping_list_node_t** NV_API_CALL nv_acquire_file_va(nv_file_private_t *, NvBool);
+void NV_API_CALL nv_release_file_va(nv_file_private_t *, NvBool);
+
+NV_STATUS NV_API_CALL nv_indicate_idle (nv_state_t *);
+NV_STATUS NV_API_CALL nv_indicate_not_idle (nv_state_t *);
+void NV_API_CALL nv_idle_holdoff (nv_state_t *);
+
+NvBool NV_API_CALL nv_dynamic_power_available (nv_state_t *);
+void NV_API_CALL nv_audio_dynamic_power (nv_state_t *);
+
+void NV_API_CALL nv_control_soc_irqs (nv_state_t *, NvBool bEnable);
+NV_STATUS NV_API_CALL nv_get_current_irq_priv_data(nv_state_t *, NvU32 *);
+
+NV_STATUS NV_API_CALL nv_acquire_fabric_mgmt_cap (int, int*);
+int NV_API_CALL nv_cap_drv_init(void);
+void NV_API_CALL nv_cap_drv_exit(void);
+NvBool NV_API_CALL nv_is_gpu_accessible(nv_state_t *);
+NvBool NV_API_CALL nv_match_gpu_os_info(nv_state_t *, void *);
+
+void NV_API_CALL nv_get_updated_emu_seg(NvU32 *start, NvU32 *end);
+void NV_API_CALL nv_get_screen_info(nv_state_t *, NvU64 *, NvU32 *, NvU32 *, NvU32 *, NvU32 *, NvU64 *);
+void NV_API_CALL nv_set_gpu_pg_mask(nv_state_t *);
+
+struct dma_buf;
+typedef struct nv_dma_buf nv_dma_buf_t;
+struct drm_gem_object;
+
+NV_STATUS NV_API_CALL nv_dma_import_sgt (nv_dma_device_t *, struct sg_table *, struct drm_gem_object *);
+void NV_API_CALL nv_dma_release_sgt(struct sg_table *, struct drm_gem_object *);
+NV_STATUS NV_API_CALL nv_dma_import_dma_buf (nv_dma_device_t *, struct dma_buf *, NvBool, NvU32 *, struct sg_table **, nv_dma_buf_t **);
+NV_STATUS NV_API_CALL nv_dma_import_from_fd (nv_dma_device_t *, NvS32, NvBool, NvU32 *, struct sg_table **, nv_dma_buf_t **);
+void NV_API_CALL nv_dma_release_dma_buf (nv_dma_buf_t *);
+
+void NV_API_CALL nv_schedule_uvm_isr (nv_state_t *);
+
+NV_STATUS NV_API_CALL nv_schedule_uvm_drain_p2p (NvU8 *);
+void NV_API_CALL nv_schedule_uvm_resume_p2p (NvU8 *);
+
+NvBool NV_API_CALL nv_platform_supports_s0ix (void);
+NvBool NV_API_CALL nv_s2idle_pm_configured (void);
+
+NvBool NV_API_CALL nv_pci_tegra_register_power_domain (nv_state_t *, NvBool);
+NvBool NV_API_CALL nv_pci_tegra_pm_init (nv_state_t *);
+void NV_API_CALL nv_pci_tegra_pm_deinit (nv_state_t *);
+
+NvBool NV_API_CALL nv_is_chassis_notebook (void);
+void NV_API_CALL nv_allow_runtime_suspend (nv_state_t *nv);
+void NV_API_CALL nv_disallow_runtime_suspend (nv_state_t *nv);
+
+typedef void (*nvTegraDceClientIpcCallback)(NvU32, NvU32, NvU32, void *, void *);
+
+NV_STATUS NV_API_CALL nv_get_num_phys_pages (void *, NvU32 *);
+NV_STATUS NV_API_CALL nv_get_phys_pages (void *, void *, NvU32 *);
+void NV_API_CALL nv_get_disp_smmu_stream_ids (nv_state_t *, NvU32 *, NvU32 *);
+
+typedef struct TEGRA_IMP_IMPORT_DATA TEGRA_IMP_IMPORT_DATA;
+typedef struct nv_i2c_msg_s nv_i2c_msg_t;
+
+NV_STATUS NV_API_CALL nv_bpmp_send_mrq (nv_state_t *, NvU32, const void *, NvU32, void *, NvU32, NvS32 *, NvS32 *);
+NV_STATUS NV_API_CALL nv_i2c_transfer(nv_state_t *, NvU32, NvU8, nv_i2c_msg_t *, int);
+void NV_API_CALL nv_i2c_unregister_clients(nv_state_t *);
+NV_STATUS NV_API_CALL nv_i2c_bus_status(nv_state_t *, NvU32, NvS32 *, NvS32 *);
+NV_STATUS NV_API_CALL nv_imp_get_import_data (TEGRA_IMP_IMPORT_DATA *);
+NV_STATUS NV_API_CALL nv_imp_get_uefi_data (nv_state_t *nv, NvU32 *iso_bw_kbps, NvU32 *floor_bw_kbps);
+NV_STATUS NV_API_CALL nv_imp_enable_disable_rfl (nv_state_t *nv, NvBool bEnable);
+NV_STATUS NV_API_CALL nv_imp_icc_set_bw (nv_state_t *nv, NvU32 avg_bw_kbps, NvU32 floor_bw_kbps);
+NV_STATUS NV_API_CALL nv_get_num_dpaux_instances(nv_state_t *nv, NvU32 *num_instances);
+NV_STATUS NV_API_CALL nv_get_tegra_brightness_level(nv_state_t *, NvU32 *);
+NV_STATUS NV_API_CALL nv_set_tegra_brightness_level(nv_state_t *, NvU32);
+
+NV_STATUS NV_API_CALL nv_soc_device_reset (nv_state_t *);
+NV_STATUS NV_API_CALL nv_soc_pm_powergate (nv_state_t *);
+NV_STATUS NV_API_CALL nv_soc_pm_unpowergate (nv_state_t *);
+NV_STATUS NV_API_CALL nv_gpio_get_pin_state(nv_state_t *, NvU32, NvU32 *);
+void NV_API_CALL nv_gpio_set_pin_state(nv_state_t *, NvU32, NvU32);
+NV_STATUS NV_API_CALL nv_gpio_set_pin_direction(nv_state_t *, NvU32, NvU32);
+NV_STATUS NV_API_CALL nv_gpio_get_pin_direction(nv_state_t *, NvU32, NvU32 *);
+NV_STATUS NV_API_CALL nv_gpio_get_pin_number(nv_state_t *, NvU32, NvU32 *);
+NvBool NV_API_CALL nv_gpio_get_pin_interrupt_status(nv_state_t *, NvU32, NvU32);
+NV_STATUS NV_API_CALL nv_gpio_set_pin_interrupt(nv_state_t *, NvU32, NvU32);
+NvU32 NV_API_CALL nv_tegra_get_rm_interface_type(NvU32);
+NV_STATUS NV_API_CALL nv_tegra_dce_register_ipc_client(NvU32, void *, nvTegraDceClientIpcCallback, NvU32 *);
+NV_STATUS NV_API_CALL nv_tegra_dce_client_ipc_send_recv(NvU32, void *, NvU32);
+NV_STATUS NV_API_CALL nv_tegra_dce_unregister_ipc_client(NvU32);
+NV_STATUS NV_API_CALL nv_dsi_parse_panel_props(nv_state_t *, void *);
+NvBool NV_API_CALL nv_dsi_is_panel_connected(nv_state_t *);
+NV_STATUS NV_API_CALL nv_dsi_panel_enable(nv_state_t *, void *);
+NV_STATUS NV_API_CALL nv_dsi_panel_reset(nv_state_t *, void *);
+void NV_API_CALL nv_dsi_panel_disable(nv_state_t *, void *);
+void NV_API_CALL nv_dsi_panel_cleanup(nv_state_t *, void *);
+NV_STATUS NV_API_CALL nv_soc_mipi_cal_reset(nv_state_t *);
+NvU32 NV_API_CALL nv_soc_fuse_register_read (NvU32 addr);
+NvBool NV_API_CALL nv_get_hdcp_enabled(nv_state_t *nv);
+NV_STATUS NV_API_CALL nv_get_valid_window_head_mask(nv_state_t *nv, NvU64 *);
+NV_STATUS NV_API_CALL nv_dp_uphy_pll_init(nv_state_t *, NvU32, NvU32);
+NV_STATUS NV_API_CALL nv_dp_uphy_pll_deinit(nv_state_t *);
+NV_STATUS NV_API_CALL nv_soc_i2c_hsp_semaphore_acquire(NvU32 ownerId, NvBool bAcquire, NvU64 timeout);
+typedef void (*nv_soc_tsec_cb_func_t)(void*, void*);
+NvU32 NV_API_CALL nv_soc_tsec_send_cmd(void* cmd, nv_soc_tsec_cb_func_t cb_func, void* cb_context);
+NvU32 NV_API_CALL nv_soc_tsec_event_register(nv_soc_tsec_cb_func_t cb_func, void* cb_context, NvBool is_init_event);
+NvU32 NV_API_CALL nv_soc_tsec_event_unregister(NvBool is_init_event);
+void* NV_API_CALL nv_soc_tsec_alloc_mem_desc(NvU32 num_bytes, NvU32 *flcn_addr);
+void NV_API_CALL nv_soc_tsec_free_mem_desc(void *mem_desc);
+NvBool NV_API_CALL nv_is_clk_enabled (nv_state_t *, TEGRASOC_WHICH_CLK);
+NV_STATUS NV_API_CALL nv_set_parent (nv_state_t *, TEGRASOC_WHICH_CLK, TEGRASOC_WHICH_CLK);
+NV_STATUS NV_API_CALL nv_get_parent (nv_state_t *, TEGRASOC_WHICH_CLK, TEGRASOC_WHICH_CLK*);
+NV_STATUS NV_API_CALL nv_clk_get_handles (nv_state_t *);
+void NV_API_CALL nv_clk_clear_handles (nv_state_t *);
+NV_STATUS NV_API_CALL nv_enable_clk (nv_state_t *, TEGRASOC_WHICH_CLK);
+void NV_API_CALL nv_disable_clk (nv_state_t *, TEGRASOC_WHICH_CLK);
+NV_STATUS NV_API_CALL nv_get_curr_freq (nv_state_t *, TEGRASOC_WHICH_CLK, NvU32 *);
+NV_STATUS NV_API_CALL nv_get_max_freq (nv_state_t *, TEGRASOC_WHICH_CLK, NvU32 *);
+NV_STATUS NV_API_CALL nv_get_min_freq (nv_state_t *, TEGRASOC_WHICH_CLK, NvU32 *);
+NV_STATUS NV_API_CALL nv_set_freq (nv_state_t *, TEGRASOC_WHICH_CLK, NvU32);
+
+void NV_API_CALL nv_pci_cxl_set_caching(nv_state_t *, NvBool);
+
+/*
+ * ---------------------------------------------------------------------------
+ *
+ * Function prototypes for Resource Manager interface.
+ *
+ * ---------------------------------------------------------------------------
+ */
+
+NvBool NV_API_CALL rm_init_rm (nvidia_stack_t *);
+void NV_API_CALL rm_shutdown_rm (nvidia_stack_t *);
+NvBool NV_API_CALL rm_init_private_state (nvidia_stack_t *, nv_state_t *);
+void NV_API_CALL rm_free_private_state (nvidia_stack_t *, nv_state_t *);
+NvBool NV_API_CALL rm_init_adapter (nvidia_stack_t *, nv_state_t *);
+void NV_API_CALL rm_disable_adapter (nvidia_stack_t *, nv_state_t *);
+void NV_API_CALL rm_shutdown_adapter (nvidia_stack_t *, nv_state_t *);
+NV_STATUS NV_API_CALL rm_exclude_adapter (nvidia_stack_t *, nv_state_t *);
+NV_STATUS NV_API_CALL rm_acquire_api_lock (nvidia_stack_t *);
+NV_STATUS NV_API_CALL rm_release_api_lock (nvidia_stack_t *);
+NV_STATUS NV_API_CALL rm_acquire_gpu_lock (nvidia_stack_t *, nv_state_t *);
+NV_STATUS NV_API_CALL rm_release_gpu_lock (nvidia_stack_t *, nv_state_t *);
+NV_STATUS NV_API_CALL rm_acquire_all_gpus_lock (nvidia_stack_t *);
+NV_STATUS NV_API_CALL rm_release_all_gpus_lock (nvidia_stack_t *);
+NV_STATUS NV_API_CALL rm_ioctl (nvidia_stack_t *, nv_state_t *, nv_file_private_t *, NvU32, void *, NvU32);
+NV_STATUS NV_API_CALL rm_validate_ioctls (NvU32, NvU32);
+NvBool NV_API_CALL rm_isr (nvidia_stack_t *, nv_state_t *, NvU32 *);
+void NV_API_CALL rm_isr_bh (nvidia_stack_t *, nv_state_t *);
+void NV_API_CALL rm_isr_bh_unlocked (nvidia_stack_t *, nv_state_t *);
+NvBool NV_API_CALL rm_is_msix_allowed (nvidia_stack_t *, nv_state_t *);
+NvBool NV_API_CALL rm_wait_for_bar_firewall (nvidia_stack_t *, NvU32 domain, NvU8 bus, NvU8 device, NvU8 function, NvU16 devId, NvU16 subsystemId);
+NV_STATUS NV_API_CALL rm_pmu_perfmon_get_load (nvidia_stack_t *, nv_state_t *, NvU32 *, TEGRASOC_DEVFREQ_CLK);
+NV_STATUS NV_API_CALL rm_power_management (nvidia_stack_t *, nv_state_t *, nv_pm_action_t);
+NV_STATUS NV_API_CALL rm_stop_user_channels (nvidia_stack_t *, nv_state_t *);
+NV_STATUS NV_API_CALL rm_restart_user_channels (nvidia_stack_t *, nv_state_t *);
+NV_STATUS NV_API_CALL rm_save_low_res_mode (nvidia_stack_t *, nv_state_t *);
+char* NV_API_CALL rm_get_gpu_uuid (nvidia_stack_t *, nv_state_t *);
+const NvU8* NV_API_CALL rm_get_gpu_uuid_raw (nvidia_stack_t *, nv_state_t *);
+void NV_API_CALL rm_set_rm_firmware_requested(nvidia_stack_t *, nv_state_t *);
+void NV_API_CALL rm_cleanup_file_private (nvidia_stack_t *, nv_state_t *, nv_file_private_t *);
+void NV_API_CALL rm_unbind_lock (nvidia_stack_t *, nv_state_t *);
+NV_STATUS NV_API_CALL rm_read_registry_dword (nvidia_stack_t *, nv_state_t *, const char *, NvU32 *);
+NV_STATUS NV_API_CALL rm_write_registry_dword (nvidia_stack_t *, nv_state_t *, const char *, NvU32);
+NV_STATUS NV_API_CALL rm_write_registry_binary (nvidia_stack_t *, nv_state_t *, const char *, NvU8 *, NvU32);
+NV_STATUS NV_API_CALL rm_write_registry_string (nvidia_stack_t *, nv_state_t *, const char *, const char *, NvU32);
+void NV_API_CALL rm_parse_option_string (nvidia_stack_t *, const char *);
+char* NV_API_CALL rm_remove_spaces (const char *);
+char* NV_API_CALL rm_string_token (char **, const char);
+void NV_API_CALL rm_vgpu_vfio_set_driver_vm(nvidia_stack_t *, NvBool);
+NV_STATUS NV_API_CALL rm_get_adapter_status_external(nvidia_stack_t *, nv_state_t *);
+
+NV_STATUS NV_API_CALL rm_run_rc_callback (nvidia_stack_t *, nv_state_t *);
+void NV_API_CALL rm_execute_work_item (nvidia_stack_t *, void *);
+const char* NV_API_CALL rm_get_device_name (NvU16, NvU16, NvU16);
+
+NV_STATUS NV_API_CALL rm_is_supported_device (nvidia_stack_t *, nv_state_t *);
+NvBool NV_API_CALL rm_is_supported_pci_device(NvU8 pci_class,
+ NvU8 pci_subclass,
+ NvU16 vendor,
+ NvU16 device,
+ NvU16 subsystem_vendor,
+ NvU16 subsystem_device,
+ NvBool print_legacy_warning);
+
+void NV_API_CALL rm_i2c_remove_adapters (nvidia_stack_t *, nv_state_t *);
+NvBool NV_API_CALL rm_i2c_is_smbus_capable (nvidia_stack_t *, nv_state_t *, void *);
+NV_STATUS NV_API_CALL rm_i2c_transfer (nvidia_stack_t *, nv_state_t *, void *, nv_i2c_cmd_t, NvU8, NvU8, NvU32, NvU8 *);
+
+NV_STATUS NV_API_CALL rm_perform_version_check (nvidia_stack_t *, void *, NvU32);
+
+void NV_API_CALL rm_power_source_change_event (nvidia_stack_t *, NvU32);
+
+void NV_API_CALL rm_request_dnotifier_state (nvidia_stack_t *, nv_state_t *);
+
+void NV_API_CALL rm_disable_gpu_state_persistence (nvidia_stack_t *sp, nv_state_t *);
+NV_STATUS NV_API_CALL rm_p2p_init_mapping (nvidia_stack_t *, NvU64, NvU64 *, NvU64 *, NvU64 *, NvU64 *, NvU64, NvU64, NvU64, NvU64, void (*)(void *), void *);
+NV_STATUS NV_API_CALL rm_p2p_destroy_mapping (nvidia_stack_t *, NvU64);
+NV_STATUS NV_API_CALL rm_p2p_get_pages (nvidia_stack_t *, NvU64, NvU32, NvU64, NvU64, NvU64 *, NvU32 *, NvU32 *, NvU32 *, NvU8 **, void *, NvBool *);
+NV_STATUS NV_API_CALL rm_p2p_get_gpu_info (nvidia_stack_t *, NvU64, NvU64, NvU8 **, void **);
+NV_STATUS NV_API_CALL rm_p2p_get_pages_persistent (nvidia_stack_t *, NvU64, NvU64, void **, NvU64 *, NvU32 *, NvBool, void *, void *, void **, NvBool *);
+NV_STATUS NV_API_CALL rm_p2p_register_callback (nvidia_stack_t *, NvU64, NvU64, NvU64, void *, void (*)(void *), void *);
+NV_STATUS NV_API_CALL rm_p2p_put_pages (nvidia_stack_t *, NvU64, NvU32, NvU64, void *);
+NV_STATUS NV_API_CALL rm_p2p_put_pages_persistent(nvidia_stack_t *, void *, void *, void *);
+NV_STATUS NV_API_CALL rm_p2p_dma_map_pages (nvidia_stack_t *, nv_dma_device_t *, NvU8 *, NvU64, NvU32, NvU64 *, void **);
+NV_STATUS NV_API_CALL rm_dma_buf_dup_mem_handle (nvidia_stack_t *, nv_state_t *, NvHandle, NvHandle, NvHandle,
+ NvHandle, void *, NvHandle, NvU64, NvU64, NvU8, NvHandle *, void **,
+ NvBool *, NvU32 *, NvBool *, nv_memory_type_t *);
+void NV_API_CALL rm_dma_buf_undup_mem_handle(nvidia_stack_t *, nv_state_t *, NvHandle, NvHandle);
+NV_STATUS NV_API_CALL rm_dma_buf_map_mem_handle (nvidia_stack_t *, nv_state_t *,
+ NvHandle, NvHandle, MemoryRange,
+ NvU8, void *, NvBool, MemoryArea *);
+void NV_API_CALL rm_dma_buf_unmap_mem_handle(nvidia_stack_t *, nv_state_t *,
+ NvHandle, NvHandle, NvU8, void *,
+ NvBool, MemoryArea);
+NV_STATUS NV_API_CALL rm_dma_buf_get_client_and_device(nvidia_stack_t *,
+ nv_state_t *, NvHandle, NvHandle,
+ NvU8, NvHandle *, NvHandle *,
+ NvHandle *, void **, NvBool *, NvBool *);
+void NV_API_CALL rm_dma_buf_put_client_and_device(nvidia_stack_t *, nv_state_t *, NvHandle, NvHandle, NvHandle, void *);
+
+void NV_API_CALL rm_kernel_rmapi_op(nvidia_stack_t *sp, void *ops_cmd);
+NvBool NV_API_CALL rm_get_device_remove_flag(nvidia_stack_t *sp, NvU32 gpu_id);
+NV_STATUS NV_API_CALL rm_gpu_copy_mmu_faults(nvidia_stack_t *, nv_state_t *, NvU32 *);
+NV_STATUS NV_API_CALL rm_gpu_handle_mmu_faults(nvidia_stack_t *, nv_state_t *, NvU32 *);
+NvBool NV_API_CALL rm_is_chipset_io_coherent(nv_stack_t *);
+NvBool NV_API_CALL rm_init_event_locks(nvidia_stack_t *, nv_state_t *);
+void NV_API_CALL rm_destroy_event_locks(nvidia_stack_t *, nv_state_t *);
+NV_STATUS NV_API_CALL rm_get_gpu_numa_info(nvidia_stack_t *, nv_state_t *, nv_ioctl_numa_info_t *);
+NV_STATUS NV_API_CALL rm_gpu_numa_online(nvidia_stack_t *, nv_state_t *);
+NV_STATUS NV_API_CALL rm_gpu_numa_offline(nvidia_stack_t *, nv_state_t *);
+NvBool NV_API_CALL rm_is_device_sequestered(nvidia_stack_t *, nv_state_t *);
+void NV_API_CALL rm_check_for_gpu_surprise_removal(nvidia_stack_t *, nv_state_t *);
+NV_STATUS NV_API_CALL rm_set_external_kernel_client_count(nvidia_stack_t *, nv_state_t *, NvBool);
+NV_STATUS NV_API_CALL rm_schedule_gpu_wakeup(nvidia_stack_t *, nv_state_t *);
+NvBool NV_API_CALL rm_disable_iomap_wc(void);
+
+void NV_API_CALL rm_init_tegra_dynamic_power_management(nvidia_stack_t *, nv_state_t *);
+void NV_API_CALL rm_init_dynamic_power_management(nvidia_stack_t *, nv_state_t *, NvBool);
+void NV_API_CALL rm_cleanup_dynamic_power_management(nvidia_stack_t *, nv_state_t *);
+void NV_API_CALL rm_enable_dynamic_power_management(nvidia_stack_t *, nv_state_t *);
+NV_STATUS NV_API_CALL rm_ref_dynamic_power(nvidia_stack_t *, nv_state_t *, nv_dynamic_power_mode_t);
+void NV_API_CALL rm_unref_dynamic_power(nvidia_stack_t *, nv_state_t *, nv_dynamic_power_mode_t);
+NV_STATUS NV_API_CALL rm_transition_dynamic_power(nvidia_stack_t *, nv_state_t *, NvBool, NvBool *);
+void NV_API_CALL rm_get_power_info(nvidia_stack_t *, nv_state_t *, nv_power_info_t *);
+
+void NV_API_CALL rm_acpi_notify(nvidia_stack_t *, nv_state_t *, NvU32);
+void NV_API_CALL rm_acpi_nvpcf_notify(nvidia_stack_t *);
+
+NvBool NV_API_CALL rm_is_altstack_in_use(void);
+
+void NV_API_CALL rm_notify_gpu_addition(nvidia_stack_t *, nv_state_t *);
+void NV_API_CALL rm_notify_gpu_removal(nvidia_stack_t *, nv_state_t *);
+
+/* vGPU VFIO specific functions */
+NV_STATUS NV_API_CALL nv_vgpu_create_request(nvidia_stack_t *, nv_state_t *, const NvU8 *, NvU32, NvU16 *,
+ NvU32 *, NvU32 *, NvU32);
+NV_STATUS NV_API_CALL nv_vgpu_delete(nvidia_stack_t *, const NvU8 *, NvU16);
+NV_STATUS NV_API_CALL nv_vgpu_get_type_ids(nvidia_stack_t *, nv_state_t *, NvU32 *, NvU32 *, NvBool, NvU8, NvBool);
+NV_STATUS NV_API_CALL nv_vgpu_get_type_info(nvidia_stack_t *, nv_state_t *, NvU32, char *, int, NvU8);
+NV_STATUS NV_API_CALL nv_vgpu_get_bar_info(nvidia_stack_t *, nv_state_t *, const NvU8 *, NvU64 *,
+ NvU64 *, NvU64 *, NvU32 *, NvBool *, NvU8 *);
+NV_STATUS NV_API_CALL nv_vgpu_update_sysfs_info(nvidia_stack_t *, nv_state_t *, const NvU8 *, NvU32, NvU32 *);
+NV_STATUS NV_API_CALL nv_vgpu_get_hbm_info(nvidia_stack_t *, nv_state_t *, const NvU8 *, NvU64 *, NvU64 *);
+NV_STATUS NV_API_CALL nv_vgpu_process_vf_info(nvidia_stack_t *, nv_state_t *, NvU8, NvU32, NvU8, NvU8, NvU8, NvBool, void *);
+NV_STATUS NV_API_CALL nv_gpu_bind_event(nvidia_stack_t *, NvU32, NvBool *);
+NV_STATUS NV_API_CALL nv_gpu_unbind_event(nvidia_stack_t *, NvU32, NvBool *);
+
+nv_soc_irq_type_t NV_API_CALL nv_get_current_irq_type(nv_state_t*);
+void NV_API_CALL nv_flush_coherent_cpu_cache_range(nv_state_t *nv, NvU64 cpu_virtual, NvU64 size);
+
+/* Callbacks should occur roughly every 10ms. */
+#define NV_SNAPSHOT_TIMER_HZ 100
+void NV_API_CALL nv_start_snapshot_timer(void (*snapshot_callback)(void *context));
+void NV_API_CALL nv_flush_snapshot_timer(void);
+void NV_API_CALL nv_stop_snapshot_timer(void);
+
+static inline const NvU8 *nv_get_cached_uuid(nv_state_t *nv)
+{
+ return nv->nv_uuid_cache.valid ? nv->nv_uuid_cache.uuid : NULL;
+}
+
+/* nano second resolution timer callback structure */
+typedef struct nv_nano_timer nv_nano_timer_t;
+
+/* nano timer functions */
+void NV_API_CALL nv_create_nano_timer(nv_state_t *, void *pTmrEvent, nv_nano_timer_t **);
+void NV_API_CALL nv_start_nano_timer(nv_state_t *nv, nv_nano_timer_t *, NvU64 timens);
+NV_STATUS NV_API_CALL rm_run_nano_timer_callback(nvidia_stack_t *, nv_state_t *, void *pTmrEvent);
+void NV_API_CALL nv_cancel_nano_timer(nv_state_t *, nv_nano_timer_t *);
+void NV_API_CALL nv_destroy_nano_timer(nv_state_t *nv, nv_nano_timer_t *);
+
+// Host1x specific functions.
+NV_STATUS NV_API_CALL nv_get_syncpoint_aperture(NvU32, NvU64 *, NvU64 *, NvU32 *);
+
+#if defined(NVCPU_X86_64)
+
+static inline NvU64 nv_rdtsc(void)
+{
+ NvU64 val;
+ __asm__ __volatile__ ("rdtsc \t\n"
+ "shlq $0x20,%%rdx \t\n"
+ "orq %%rdx,%%rax \t\n"
+ : "=A" (val));
+ return val;
+}
+
+#endif
+
+static inline NvBool nv_dev_needs_vidmem_preservation(const nv_state_t *nv)
+{
+ /*
+ * Tegra iGPUs and SoC display devices don't need vidmem preservation.
+ */
+ return !nv->is_tegra_pci_igpu && !NV_IS_SOC_DISPLAY_DEVICE(nv);
+}
+
+#endif /* NVRM */
+
+static inline int nv_count_bits(NvU64 word)
+{
+ NvU64 bits;
+
+ bits = (word & 0x5555555555555555ULL) + ((word >> 1) & 0x5555555555555555ULL);
+ bits = (bits & 0x3333333333333333ULL) + ((bits >> 2) & 0x3333333333333333ULL);
+ bits = (bits & 0x0f0f0f0f0f0f0f0fULL) + ((bits >> 4) & 0x0f0f0f0f0f0f0f0fULL);
+ bits = (bits & 0x00ff00ff00ff00ffULL) + ((bits >> 8) & 0x00ff00ff00ff00ffULL);
+ bits = (bits & 0x0000ffff0000ffffULL) + ((bits >> 16) & 0x0000ffff0000ffffULL);
+ bits = (bits & 0x00000000ffffffffULL) + ((bits >> 32) & 0x00000000ffffffffULL);
+
+ return (int)(bits);
+}
+
+#endif
diff --git a/userspace/sdks/nv570/nvalloc/unix/include/nv_escape.h b/userspace/sdks/nv570/nvalloc/unix/include/nv_escape.h
new file mode 100644
index 0000000..601d9de
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/include/nv_escape.h
@@ -0,0 +1,55 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 1999-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef NV_ESCAPE_H_INCLUDED
+#define NV_ESCAPE_H_INCLUDED
+
+/*
+ * NOTE: Any new ioctls added here should also be added to RmValidateIoctl() in escape.c
+ * or rm_validate_ioctls() in osapi.c
+ */
+#define NV_ESC_RM_ALLOC_MEMORY 0x27
+#define NV_ESC_RM_ALLOC_OBJECT 0x28
+#define NV_ESC_RM_FREE 0x29
+#define NV_ESC_RM_CONTROL 0x2A
+#define NV_ESC_RM_ALLOC 0x2B
+#define NV_ESC_RM_DUP_OBJECT 0x34
+#define NV_ESC_RM_SHARE 0x35
+#define NV_ESC_RM_I2C_ACCESS 0x39
+#define NV_ESC_RM_IDLE_CHANNELS 0x41
+#define NV_ESC_RM_VID_HEAP_CONTROL 0x4A
+#define NV_ESC_RM_ACCESS_REGISTRY 0x4D
+#define NV_ESC_RM_MAP_MEMORY 0x4E
+#define NV_ESC_RM_UNMAP_MEMORY 0x4F
+#define NV_ESC_RM_GET_EVENT_DATA 0x52
+#define NV_ESC_RM_ALLOC_CONTEXT_DMA2 0x54
+#define NV_ESC_RM_ADD_VBLANK_CALLBACK 0x56
+#define NV_ESC_RM_MAP_MEMORY_DMA 0x57
+#define NV_ESC_RM_UNMAP_MEMORY_DMA 0x58
+#define NV_ESC_RM_BIND_CONTEXT_DMA 0x59
+#define NV_ESC_RM_EXPORT_OBJECT_TO_FD 0x5C
+#define NV_ESC_RM_IMPORT_OBJECT_FROM_FD 0x5D
+#define NV_ESC_RM_UPDATE_DEVICE_MAPPING_INFO 0x5E
+#define NV_ESC_RM_LOCKLESS_DIAGNOSTIC 0x5F
+
+#endif // NV_ESCAPE_H_INCLUDED
diff --git a/userspace/sdks/nv570/nvalloc/unix/include/os-interface.h b/userspace/sdks/nv570/nvalloc/unix/include/os-interface.h
new file mode 100644
index 0000000..2a80c50
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/include/os-interface.h
@@ -0,0 +1,298 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 1999-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+
+/*
+ * Os interface definitions needed by os-interface.c
+ */
+
+#ifndef OS_INTERFACE_H
+#define OS_INTERFACE_H
+
+/******************* Operating System Interface Routines *******************\
+* *
+* Operating system wrapper functions used to abstract the OS. *
+* *
+\***************************************************************************/
+
+#include <nvtypes.h>
+#include <nvstatus.h>
+#include "nv_stdarg.h"
+#include <nv-kernel-interface-api.h>
+#include <os/nv_memory_type.h>
+#include <os/nv_memory_area.h>
+#include <nv-caps.h>
+
+#include "rs_access.h"
+
+
+
+typedef struct
+{
+ NvU32 os_major_version;
+ NvU32 os_minor_version;
+ NvU32 os_build_number;
+ const char * os_build_version_str;
+ const char * os_build_date_plus_str;
+}os_version_info;
+
+/* Each OS defines its own version of this opaque type */
+struct os_work_queue;
+
+/* Each OS defines its own version of this opaque type */
+typedef struct os_wait_queue os_wait_queue;
+
+/* Flags needed by os_get_current_proccess_flags */
+#define OS_CURRENT_PROCESS_FLAG_NONE 0x0
+#define OS_CURRENT_PROCESS_FLAG_KERNEL_THREAD 0x1
+#define OS_CURRENT_PROCESS_FLAG_EXITING 0x2
+
+/*
+ * ---------------------------------------------------------------------------
+ *
+ * Function prototypes for OS interface.
+ *
+ * ---------------------------------------------------------------------------
+ */
+
+NV_STATUS NV_API_CALL os_alloc_mem (void **, NvU64);
+void NV_API_CALL os_free_mem (void *);
+NV_STATUS NV_API_CALL os_get_system_time (NvU32 *, NvU32 *);
+NvU64 NV_API_CALL os_get_monotonic_time_ns (void);
+NvU64 NV_API_CALL os_get_monotonic_time_ns_hr (void);
+NvU64 NV_API_CALL os_get_monotonic_tick_resolution_ns (void);
+NV_STATUS NV_API_CALL os_delay (NvU32);
+NV_STATUS NV_API_CALL os_delay_us (NvU32);
+NvU64 NV_API_CALL os_get_cpu_frequency (void);
+NvU32 NV_API_CALL os_get_current_process (void);
+void NV_API_CALL os_get_current_process_name (char *, NvU32);
+NV_STATUS NV_API_CALL os_get_current_thread (NvU64 *);
+char* NV_API_CALL os_string_copy (char *, const char *);
+NvU32 NV_API_CALL os_string_length (const char *);
+NvU32 NV_API_CALL os_strtoul (const char *, char **, NvU32);
+NvS32 NV_API_CALL os_string_compare (const char *, const char *);
+NvS32 NV_API_CALL os_snprintf (char *, NvU32, const char *, ...);
+NvS32 NV_API_CALL os_vsnprintf (char *, NvU32, const char *, va_list);
+void NV_API_CALL os_log_error (const char *, va_list);
+void* NV_API_CALL os_mem_copy (void *, const void *, NvU32);
+NV_STATUS NV_API_CALL os_memcpy_from_user (void *, const void *, NvU32);
+NV_STATUS NV_API_CALL os_memcpy_to_user (void *, const void *, NvU32);
+void* NV_API_CALL os_mem_set (void *, NvU8, NvU32);
+NvS32 NV_API_CALL os_mem_cmp (const NvU8 *, const NvU8 *, NvU32);
+void* NV_API_CALL os_pci_init_handle (NvU32, NvU8, NvU8, NvU8, NvU16 *, NvU16 *);
+NV_STATUS NV_API_CALL os_pci_read_byte (void *, NvU32, NvU8 *);
+NV_STATUS NV_API_CALL os_pci_read_word (void *, NvU32, NvU16 *);
+NV_STATUS NV_API_CALL os_pci_read_dword (void *, NvU32, NvU32 *);
+NV_STATUS NV_API_CALL os_pci_write_byte (void *, NvU32, NvU8);
+NV_STATUS NV_API_CALL os_pci_write_word (void *, NvU32, NvU16);
+NV_STATUS NV_API_CALL os_pci_write_dword (void *, NvU32, NvU32);
+NvBool NV_API_CALL os_pci_remove_supported (void);
+void NV_API_CALL os_pci_remove (void *);
+void* NV_API_CALL os_map_kernel_space (NvU64, NvU64, NvU32);
+void NV_API_CALL os_unmap_kernel_space (void *, NvU64);
+NV_STATUS NV_API_CALL os_flush_cpu_cache_all (void);
+NV_STATUS NV_API_CALL os_flush_user_cache (void);
+void NV_API_CALL os_flush_cpu_write_combine_buffer(void);
+NvU8 NV_API_CALL os_io_read_byte (NvU32);
+NvU16 NV_API_CALL os_io_read_word (NvU32);
+NvU32 NV_API_CALL os_io_read_dword (NvU32);
+void NV_API_CALL os_io_write_byte (NvU32, NvU8);
+void NV_API_CALL os_io_write_word (NvU32, NvU16);
+void NV_API_CALL os_io_write_dword (NvU32, NvU32);
+NvBool NV_API_CALL os_is_administrator (void);
+NvBool NV_API_CALL os_check_access (RsAccessRight accessRight);
+void NV_API_CALL os_dbg_init (void);
+void NV_API_CALL os_dbg_breakpoint (void);
+void NV_API_CALL os_dbg_set_level (NvU32);
+NvU32 NV_API_CALL os_get_cpu_count (void);
+NvU32 NV_API_CALL os_get_cpu_number (void);
+void NV_API_CALL os_disable_console_access (void);
+void NV_API_CALL os_enable_console_access (void);
+NV_STATUS NV_API_CALL os_registry_init (void);
+NvU64 NV_API_CALL os_get_max_user_va (void);
+NV_STATUS NV_API_CALL os_schedule (void);
+NV_STATUS NV_API_CALL os_alloc_spinlock (void **);
+void NV_API_CALL os_free_spinlock (void *);
+NvU64 NV_API_CALL os_acquire_spinlock (void *);
+void NV_API_CALL os_release_spinlock (void *, NvU64);
+NV_STATUS NV_API_CALL os_queue_work_item (struct os_work_queue *, void *);
+NV_STATUS NV_API_CALL os_flush_work_queue (struct os_work_queue *, NvBool);
+NvBool NV_API_CALL os_is_queue_flush_ongoing (struct os_work_queue *);
+NV_STATUS NV_API_CALL os_alloc_mutex (void **);
+void NV_API_CALL os_free_mutex (void *);
+NV_STATUS NV_API_CALL os_acquire_mutex (void *);
+NV_STATUS NV_API_CALL os_cond_acquire_mutex (void *);
+void NV_API_CALL os_release_mutex (void *);
+void* NV_API_CALL os_alloc_semaphore (NvU32);
+void NV_API_CALL os_free_semaphore (void *);
+NV_STATUS NV_API_CALL os_acquire_semaphore (void *);
+NV_STATUS NV_API_CALL os_cond_acquire_semaphore (void *);
+NV_STATUS NV_API_CALL os_release_semaphore (void *);
+void* NV_API_CALL os_alloc_rwlock (void);
+void NV_API_CALL os_free_rwlock (void *);
+NV_STATUS NV_API_CALL os_acquire_rwlock_read (void *);
+NV_STATUS NV_API_CALL os_acquire_rwlock_write (void *);
+NV_STATUS NV_API_CALL os_cond_acquire_rwlock_read (void *);
+NV_STATUS NV_API_CALL os_cond_acquire_rwlock_write (void *);
+void NV_API_CALL os_release_rwlock_read (void *);
+void NV_API_CALL os_release_rwlock_write (void *);
+NvBool NV_API_CALL os_semaphore_may_sleep (void);
+NV_STATUS NV_API_CALL os_get_version_info (os_version_info*);
+NV_STATUS NV_API_CALL os_get_is_openrm (NvBool *);
+NvBool NV_API_CALL os_is_bif_reset_supported (void *);
+NvBool NV_API_CALL os_is_isr (void);
+void NV_API_CALL os_dump_stack (void);
+NvBool NV_API_CALL os_is_efi_enabled (void);
+NvBool NV_API_CALL os_is_xen_dom0 (void);
+NvBool NV_API_CALL os_is_vgx_hyper (void);
+NV_STATUS NV_API_CALL os_inject_vgx_msi (NvU16, NvU64, NvU32);
+NvBool NV_API_CALL os_is_grid_supported (void);
+NvU32 NV_API_CALL os_get_grid_csp_support (void);
+void NV_API_CALL os_bug_check (NvU32, const char *);
+NV_STATUS NV_API_CALL os_lock_user_pages (void *, NvU64, void **, NvU32);
+NV_STATUS NV_API_CALL os_lookup_user_io_memory (void *, NvU64, NvU64 **);
+NV_STATUS NV_API_CALL os_unlock_user_pages (NvU64, void *, NvU32);
+NV_STATUS NV_API_CALL os_match_mmap_offset (void *, NvU64, NvU64 *);
+NV_STATUS NV_API_CALL os_get_euid (NvU32 *);
+NV_STATUS NV_API_CALL os_get_smbios_header (NvU64 *pSmbsAddr);
+NV_STATUS NV_API_CALL os_get_acpi_rsdp_from_uefi (NvU32 *);
+void NV_API_CALL os_add_record_for_crashLog (void *, NvU32);
+void NV_API_CALL os_delete_record_for_crashLog (void *);
+NV_STATUS NV_API_CALL os_call_vgpu_vfio (void *, NvU32);
+NV_STATUS NV_API_CALL os_device_vm_present (void);
+NV_STATUS NV_API_CALL os_numa_memblock_size (NvU64 *);
+NV_STATUS NV_API_CALL os_alloc_pages_node (NvS32, NvU32, NvU32, NvU64 *);
+NV_STATUS NV_API_CALL os_get_page (NvU64 address);
+NV_STATUS NV_API_CALL os_put_page (NvU64 address);
+NvU32 NV_API_CALL os_get_page_refcount (NvU64 address);
+NvU32 NV_API_CALL os_count_tail_pages (NvU64 address);
+void NV_API_CALL os_free_pages_phys (NvU64, NvU32);
+NV_STATUS NV_API_CALL os_open_temporary_file (void **);
+void NV_API_CALL os_close_file (void *);
+NV_STATUS NV_API_CALL os_write_file (void *, NvU8 *, NvU64, NvU64);
+NV_STATUS NV_API_CALL os_read_file (void *, NvU8 *, NvU64, NvU64);
+NV_STATUS NV_API_CALL os_open_readonly_file (const char *, void **);
+NV_STATUS NV_API_CALL os_open_and_read_file (const char *, NvU8 *, NvU64);
+NvBool NV_API_CALL os_is_nvswitch_present (void);
+NV_STATUS NV_API_CALL os_get_random_bytes (NvU8 *, NvU16);
+NvU32 NV_API_CALL os_get_current_process_flags (void);
+NV_STATUS NV_API_CALL os_alloc_wait_queue (os_wait_queue **);
+void NV_API_CALL os_free_wait_queue (os_wait_queue *);
+void NV_API_CALL os_wait_uninterruptible (os_wait_queue *);
+void NV_API_CALL os_wait_interruptible (os_wait_queue *);
+void NV_API_CALL os_wake_up (os_wait_queue *);
+nv_cap_t* NV_API_CALL os_nv_cap_init (const char *);
+nv_cap_t* NV_API_CALL os_nv_cap_create_dir_entry (nv_cap_t *, const char *, int);
+nv_cap_t* NV_API_CALL os_nv_cap_create_file_entry (nv_cap_t *, const char *, int);
+void NV_API_CALL os_nv_cap_destroy_entry (nv_cap_t *);
+int NV_API_CALL os_nv_cap_validate_and_dup_fd (const nv_cap_t *, int);
+void NV_API_CALL os_nv_cap_close_fd (int);
+NvS32 NV_API_CALL os_imex_channel_get (NvU64);
+NvS32 NV_API_CALL os_imex_channel_count (void);
+NV_STATUS NV_API_CALL os_tegra_igpu_perf_boost (void *, NvBool, NvU32);
+
+NV_STATUS NV_API_CALL os_get_tegra_platform (NvU32 *);
+enum os_pci_req_atomics_type {
+ OS_INTF_PCIE_REQ_ATOMICS_32BIT,
+ OS_INTF_PCIE_REQ_ATOMICS_64BIT,
+ OS_INTF_PCIE_REQ_ATOMICS_128BIT
+};
+NV_STATUS NV_API_CALL os_enable_pci_req_atomics (void *, enum os_pci_req_atomics_type);
+void NV_API_CALL os_pci_trigger_flr(void *handle);
+NV_STATUS NV_API_CALL os_get_numa_node_memory_usage (NvS32, NvU64 *, NvU64 *);
+NV_STATUS NV_API_CALL os_numa_add_gpu_memory (void *, NvU64, NvU64, NvU32 *);
+NV_STATUS NV_API_CALL os_numa_remove_gpu_memory (void *, NvU64, NvU64, NvU32);
+NV_STATUS NV_API_CALL os_offline_page_at_address(NvU64 address);
+void* NV_API_CALL os_get_pid_info(void);
+void NV_API_CALL os_put_pid_info(void *pid_info);
+NV_STATUS NV_API_CALL os_find_ns_pid(void *pid_info, NvU32 *ns_pid);
+NvBool NV_API_CALL os_is_init_ns(void);
+NV_STATUS NV_API_CALL os_iommu_sva_bind(void *arg, void **handle, NvU32 *pasid);
+void NV_API_CALL os_iommu_sva_unbind(void *handle);
+NvBool NV_API_CALL os_supports_kernel_suspend_notifiers(void);
+
+extern NvU64 os_page_size;
+extern NvU64 os_max_page_size;
+extern NvU64 os_page_mask;
+extern NvU8 os_page_shift;
+extern NvBool os_cc_enabled;
+extern NvBool os_cc_sev_snp_enabled;
+extern NvBool os_cc_sme_enabled;
+extern NvBool os_cc_snp_vtom_enabled;
+extern NvBool os_cc_tdx_enabled;
+extern NvBool os_dma_buf_enabled;
+extern NvBool os_imex_channel_is_supported;
+
+/*
+ * ---------------------------------------------------------------------------
+ *
+ * Debug macros.
+ *
+ * ---------------------------------------------------------------------------
+ */
+
+#define NV_DBG_INFO 0x0
+#define NV_DBG_SETUP 0x1
+#define NV_DBG_USERERRORS 0x2
+#define NV_DBG_WARNINGS 0x3
+#define NV_DBG_ERRORS 0x4
+
+
+void NV_API_CALL out_string(const char *str);
+int NV_API_CALL nv_printf(NvU32 debuglevel, const char *printf_format, ...);
+
+#define NV_DEV_PRINTF(debuglevel, nv, format, ... ) \
+ nv_printf(debuglevel, "NVRM: GPU " NV_PCI_DEV_FMT ": " format, NV_PCI_DEV_FMT_ARGS(nv), ## __VA_ARGS__)
+
+#define NV_DEV_PRINTF_STATUS(debuglevel, nv, status, format, ... ) \
+ nv_printf(debuglevel, "NVRM: GPU " NV_PCI_DEV_FMT ": " format " (0x%x)\n", NV_PCI_DEV_FMT_ARGS(nv), ## __VA_ARGS__, status)
+
+/*
+ * Fields for os_lock_user_pages flags parameter
+ */
+#define NV_LOCK_USER_PAGES_FLAGS_WRITE 0:0
+#define NV_LOCK_USER_PAGES_FLAGS_WRITE_NO 0x00000000
+#define NV_LOCK_USER_PAGES_FLAGS_WRITE_YES 0x00000001
+
+// NV OS Tegra platform type defines
+#define NV_OS_TEGRA_PLATFORM_SIM 0
+#define NV_OS_TEGRA_PLATFORM_FPGA 1
+#define NV_OS_TEGRA_PLATFORM_SILICON 2
+
+/*
+ * Plumbing through cgroup dmem api
+ */
+#define OS_CGROUP_IMPL_NONE 0
+#define OS_CGROUP_IMPL_MISC 1
+#define OS_CGROUP_IMPL_DMEM 2
+NvU32 NV_API_CALL os_cgroup_implementation(void);
+void* NV_API_CALL os_dmem_cgroup_register_region(NvU64 size, const char *name);
+void NV_API_CALL os_dmem_cgroup_unregister_region(void *region);
+NV_STATUS NV_API_CALL os_dmem_cgroup_try_charge(void *region, NvU64 size, void **ret_pool, void **ret_limit_pool);
+void NV_API_CALL os_dmem_cgroup_uncharge(void *pool, NvU64 size);
+
+void* NV_API_CALL os_cgroup_for_pid(int pid, void *pidInfo);
+void* NV_API_CALL os_cgroup_get_from_fd(NvU32 fd);
+void NV_API_CALL os_cgroup_put(void *cgroup);
+
+#endif /* OS_INTERFACE_H */
diff --git a/userspace/sdks/nv570/nvalloc/unix/include/os_custom.h b/userspace/sdks/nv570/nvalloc/unix/include/os_custom.h
new file mode 100644
index 0000000..1effaf7
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/include/os_custom.h
@@ -0,0 +1,60 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 1999-2018 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _OS_CUSTOM_H_
+#define _OS_CUSTOM_H_
+
+/*!
+ * @file os_custom.h
+ * @brief OS module specific definitions for this OS
+ */
+
+#include <os-interface.h>
+
+// File modes, added for NVIDIA capabilities.
+#define OS_RUSR 00400 // read permission, owner
+#define OS_WUSR 00200 // write permission, owner
+#define OS_XUSR 00100 // execute/search permission, owner
+#define OS_RWXU (OS_RUSR | OS_WUSR | OS_XUSR) // read, write, execute/search, owner
+#define OS_RGRP 00040 // read permission, group
+#define OS_WGRP 00020 // write permission, group
+#define OS_XGRP 00010 // execute/search permission, group
+#define OS_RWXG (OS_RGRP | OS_WGRP | OS_XGRP) // read, write, execute/search, group
+#define OS_ROTH 00004 // read permission, other
+#define OS_WOTH 00002 // write permission, other
+#define OS_XOTH 00001 // execute/search permission, other
+#define OS_RWXO (OS_ROTH | OS_WOTH | OS_XOTH) // read, write, execute/search, other
+#define OS_RUGO (OS_RUSR | OS_RGRP | OS_ROTH)
+#define OS_WUGO (OS_WUSR | OS_WGRP | OS_WOTH)
+#define OS_XUGO (OS_XUSR | OS_XGRP | OS_XOTH)
+
+// Trigger for collecting GPU state for later extraction.
+void RmLogGpuCrash(OBJGPU *);
+
+// This is callback function in the miniport.
+// The argument is a device extension, and must be cast as such to be useful.
+typedef void (*MINIPORT_CALLBACK)(void*);
+
+NV_STATUS osPackageRegistry(OBJGPU *pGpu, PACKED_REGISTRY_TABLE *, NvU32 *);
+
+#endif // _OS_CUSTOM_H_
diff --git a/userspace/sdks/nv570/nvalloc/unix/include/osapi.h b/userspace/sdks/nv570/nvalloc/unix/include/osapi.h
new file mode 100644
index 0000000..6402bdb
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/include/osapi.h
@@ -0,0 +1,203 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 1999-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _OSAPI_H_
+#define _OSAPI_H_
+
+#include "core/system.h"
+#include "gpu/gpu.h"
+
+#include <os-interface.h> // NV_DBG_ERRORS
+#include <rmapi/rmapi.h>
+#include <core/thread_state.h>
+
+#if defined(__use_altstack__)
+#if defined(QA_BUILD)
+//---------------------------------------------------------------------------
+//
+// 32 bit debug marker values.
+//
+//---------------------------------------------------------------------------
+
+#define NV_MARKER1 (NvU32)(('M' << 24) | ('R' << 16) | ('V' << 8) | 'N')
+#define NV_MARKER2 (NvU32)(('N' << 24) | ('V' << 16) | ('R' << 8) | 'M')
+
+//
+// The two macros below implement a simple alternate stack usage sanity
+// check for QA_BUILD RM builds. NV_ALTSTACK_WRITE_MARKERS() fills
+// altstacks with NV_MARKER1, which enables NV_ALTSTACK_CHECK_MARKERS()
+// to determine the stack usage fairly reliably by looking for the
+// first clobbered marker. If more than 7/8 of the alternate stack were
+// used, NV_ALTSTACK_CHECK_MARKERS() prints an error and asserts.
+//
+#define NV_ALTSTACK_WRITE_MARKERS(sp) \
+{ \
+ NvU32 i, *stack = (void *)(sp)->stack; \
+ for (i = 0; i < ((sp)->size / sizeof(NvU32)); i++) \
+ stack[i] = NV_MARKER1; \
+}
+
+#define NV_ALTSTACK_CHECK_MARKERS(sp) \
+{ \
+ NvU32 i, *stack = (void *)(sp)->stack; \
+ for (i = 0; i < ((sp)->size / sizeof(NvU32)); i++) \
+ { \
+ if (stack[i] != NV_MARKER1) \
+ break; \
+ } \
+ if ((i * sizeof(NvU32)) < ((sp)->size / 8)) \
+ { \
+ nv_printf(NV_DBG_ERRORS, "NVRM: altstack: used %d of %d bytes!\n", \
+ ((sp)->size - (i * (NvU32)sizeof(NvU32))), (sp)->size); \
+ NV_ASSERT_PRECOMP((i * sizeof(NvU32)) >= ((sp)->size / 8)); \
+ } \
+}
+#else
+#define NV_ALTSTACK_WRITE_MARKERS(sp)
+#define NV_ALTSTACK_CHECK_MARKERS(sp)
+#endif
+#if defined(NVCPU_X86_64)
+#define NV_ENTER_RM_RUNTIME(sp,fp) \
+{ \
+ NV_ALTSTACK_WRITE_MARKERS(sp); \
+ __asm__ __volatile__ ("movq %%rbp,%0" : "=r" (fp)); /* save %rbp */ \
+ __asm__ __volatile__ ("movq %0,%%rbp" :: "r" ((sp)->top)); \
+}
+
+#define NV_EXIT_RM_RUNTIME(sp,fp) \
+{ \
+ register void *__rbp __asm__ ("rbp"); \
+ if (__rbp != (sp)->top) \
+ { \
+ nv_printf(NV_DBG_ERRORS, "NVRM: detected corrupted runtime stack!\n"); \
+ NV_ASSERT_PRECOMP(__rbp == (sp)->top); \
+ } \
+ NV_ALTSTACK_CHECK_MARKERS(sp); \
+ __asm__ __volatile__ ("movq %0,%%rbp" :: "r" (fp)); /* restore %rbp */ \
+}
+#else
+#error "gcc \"altstacks\" support is not implemented on this platform!"
+#endif
+#else
+#define NV_ENTER_RM_RUNTIME(sp,fp) { (void)sp; (void)fp; }
+#define NV_EXIT_RM_RUNTIME(sp,fp)
+#endif
+
+void RmShutdownRm (void);
+
+NvBool RmInitPrivateState (nv_state_t *);
+void RmFreePrivateState (nv_state_t *);
+
+NvBool RmInitAdapter (nv_state_t *);
+NvBool RmPartiallyInitAdapter (nv_state_t *);
+void RmShutdownAdapter (nv_state_t *);
+void RmDisableAdapter (nv_state_t *);
+void RmPartiallyDisableAdapter(nv_state_t *);
+NV_STATUS RmGetAdapterStatus (nv_state_t *, NvU32 *);
+NV_STATUS RmExcludeAdapter (nv_state_t *);
+
+NvBool RmGpuHasIOSpaceEnabled (nv_state_t *);
+
+void RmFreeUnusedClients (nv_state_t *, nv_file_private_t *);
+NV_STATUS RmIoctl (nv_state_t *, nv_file_private_t *, NvU32, void *, NvU32);
+NV_STATUS RmValidateIoctl (NvU32, NvU32);
+
+void RmI2cAddGpuPorts(nv_state_t *);
+
+NV_STATUS RmInitX86EmuState(OBJGPU *);
+void RmFreeX86EmuState(OBJGPU *);
+NV_STATUS RmPowerSourceChangeEvent(nv_state_t *, NvU32);
+
+void RmRequestDNotifierState(nv_state_t *);
+
+const NvU8 *RmGetGpuUuidRaw(nv_state_t *);
+
+NV_STATUS nv_vbios_call(OBJGPU *, NvU32 *, NvU32 *);
+
+int amd_adv_spec_cache_feature(OBJOS *);
+int amd_msr_c0011022_incompatible(OBJOS *);
+
+NV_STATUS rm_get_adapter_status (nv_state_t *, NvU32 *);
+
+void rm_client_free_os_events (NvHandle);
+
+NV_STATUS rm_create_mmap_context (NvHandle, NvHandle, NvHandle, NvP64, NvU64, NvU64, NvU32, NvU32);
+NV_STATUS rm_update_device_mapping_info (NvHandle, NvHandle, NvHandle, void *, void *);
+
+NV_STATUS rm_access_registry (NvHandle, NvHandle, NvU32, NvP64, NvU32, NvP64, NvU32, NvP64, NvU32 *, NvU32 *, NvU32 *);
+
+// registry management
+NV_STATUS RmInitRegistry (void);
+NV_STATUS RmDestroyRegistry (nv_state_t *);
+
+NV_STATUS RmWriteRegistryDword (nv_state_t *, const char *, NvU32 );
+NV_STATUS RmReadRegistryDword (nv_state_t *, const char *, NvU32 *);
+NV_STATUS RmWriteRegistryString (nv_state_t *, const char *, const char *, NvU32);
+NV_STATUS RmReadRegistryBinary (nv_state_t *, const char *, NvU8 *, NvU32 *);
+NV_STATUS RmWriteRegistryBinary (nv_state_t *, const char *, NvU8 *, NvU32);
+NV_STATUS RmReadRegistryString (nv_state_t *, const char *, NvU8 *, NvU32 *);
+
+NV_STATUS RmPackageRegistry (nv_state_t *, PACKED_REGISTRY_TABLE *, NvU32 *);
+
+NvBool RmIsNvifFunctionSupported(NvU32, NvU32);
+void RmInitAcpiMethods (OBJOS *, OBJSYS *, OBJGPU *);
+void RmUnInitAcpiMethods (OBJSYS *);
+
+void RmInflateOsToRmPageArray (RmPhysAddr *, NvU64);
+void RmDeflateRmToOsPageArray (RmPhysAddr *, NvU64);
+
+void convertPageArrayBetweenOsAndRm(
+ RmPhysAddr *pteArray,
+ NvU64 pageCountFrom,
+ NvU64 pageSizeFrom,
+ NvU64 pageCountTo,
+ NvU64 pageSizeTo,
+ NvU64 *newPageCountTo);
+
+#define IS_DISCONTIG_AND_DYNGRAN_ENABLED(pMemDesc) \
+ (SYS_GET_INSTANCE()->bEnableDynamicGranularityPageArrays && !memdescGetContiguity(pMemDesc, AT_CPU))
+
+void RmInitPowerManagement (nv_state_t *);
+void RmDestroyPowerManagement (nv_state_t *);
+
+NV_STATUS RmPowerManagementTegra (OBJGPU *pGpu, nv_pm_action_t pmAction);
+
+NV_STATUS os_ref_dynamic_power (nv_state_t *, nv_dynamic_power_mode_t);
+void os_unref_dynamic_power (nv_state_t *, nv_dynamic_power_mode_t);
+void RmHandleDisplayChange (nvidia_stack_t *, nv_state_t *);
+void RmUpdateGc6ConsoleRefCount (nv_state_t *, NvBool);
+
+NvBool rm_get_uefi_console_status (nv_state_t *);
+NvU64 rm_get_uefi_console_size (nv_state_t *, NvU64 *);
+
+void rm_check_s0ix_regkey_and_platform_support(void);
+
+RM_API *RmUnixRmApiPrologue (nv_state_t *, THREAD_STATE_NODE *, NvU32 module);
+void RmUnixRmApiEpilogue (nv_state_t *, THREAD_STATE_NODE *);
+
+static inline NvBool rm_is_system_notebook(void)
+{
+ return (nv_is_chassis_notebook() || nv_acpi_is_battery_present());
+}
+
+#endif // _OSAPI_H_
diff --git a/userspace/sdks/nv570/nvalloc/unix/include/rmobjexportimport.h b/userspace/sdks/nv570/nvalloc/unix/include/rmobjexportimport.h
new file mode 100644
index 0000000..a070c4e
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/include/rmobjexportimport.h
@@ -0,0 +1,40 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2016-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _RMOBJEXPORTIMPORT_H_
+#define _RMOBJEXPORTIMPORT_H_
+
+#include "nvstatus.h"
+
+typedef NvHandle RmObjExportHandle;
+
+NV_STATUS RmExportObject(NvHandle hSrcClient, NvHandle hSrcObject,
+ RmObjExportHandle *pDstObject, NvU32 *pDeviceInstance);
+
+void RmFreeObjExportHandle(RmObjExportHandle hObject);
+
+NV_STATUS RmImportObject(NvHandle hDstClient, NvHandle hDstParent,
+ NvHandle *phDstObject, RmObjExportHandle hSrcObject,
+ NvU8 *pObjectType);
+#endif // _RMOBJEXPORTIMPORT_H_
+
diff --git a/userspace/sdks/nv570/nvalloc/unix/include/x86emu/debug.h b/userspace/sdks/nv570/nvalloc/unix/include/x86emu/debug.h
new file mode 100644
index 0000000..6a37dfa
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/include/x86emu/debug.h
@@ -0,0 +1,211 @@
+/****************************************************************************
+*
+* Realmode X86 Emulator Library
+*
+* Copyright (C) 1996-1999 SciTech Software, Inc.
+* Copyright (C) David Mosberger-Tang
+* Copyright (C) 1999 Egbert Eich
+*
+* ========================================================================
+*
+* Permission to use, copy, modify, distribute, and sell this software and
+* its documentation for any purpose is hereby granted without fee,
+* provided that the above copyright notice appear in all copies and that
+* both that copyright notice and this permission notice appear in
+* supporting documentation, and that the name of the authors not be used
+* in advertising or publicity pertaining to distribution of the software
+* without specific, written prior permission. The authors makes no
+* representations about the suitability of this software for any purpose.
+* It is provided "as is" without express or implied warranty.
+*
+* THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+* EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+* PERFORMANCE OF THIS SOFTWARE.
+*
+* ========================================================================
+*
+* Language: ANSI C
+* Environment: Any
+* Developer: Kendall Bennett
+*
+* Description: Header file for debug definitions.
+*
+****************************************************************************/
+
+#ifndef __X86EMU_DEBUG_H
+#define __X86EMU_DEBUG_H
+
+/*---------------------- Macros and type definitions ----------------------*/
+
+/* checks to be enabled for "runtime" */
+
+#define CHECK_IP_FETCH_F 0x1
+#define CHECK_SP_ACCESS_F 0x2
+#define CHECK_MEM_ACCESS_F 0x4 /*using regular linear pointer */
+#define CHECK_DATA_ACCESS_F 0x8 /*using segment:offset*/
+
+#ifdef X86EMU_DEBUG
+# define CHECK_IP_FETCH() (M.x86.check & CHECK_IP_FETCH_F)
+# define CHECK_SP_ACCESS() (M.x86.check & CHECK_SP_ACCESS_F)
+# define CHECK_MEM_ACCESS() (M.x86.check & CHECK_MEM_ACCESS_F)
+# define CHECK_DATA_ACCESS() (M.x86.check & CHECK_DATA_ACCESS_F)
+#else
+# define CHECK_IP_FETCH() 0
+# define CHECK_SP_ACCESS() 0
+# define CHECK_MEM_ACCESS() 0
+# define CHECK_DATA_ACCESS() 0
+#endif
+
+#ifdef X86EMU_DEBUG
+# define DEBUG_INSTRUMENT() (M.x86.debug & DEBUG_INSTRUMENT_F)
+# define DEBUG_DECODE() (M.x86.debug & DEBUG_DECODE_F)
+# define DEBUG_TRACE() (M.x86.debug & DEBUG_TRACE_F)
+# define DEBUG_STEP() (M.x86.debug & DEBUG_STEP_F)
+# define DEBUG_DISASSEMBLE() (M.x86.debug & DEBUG_DISASSEMBLE_F)
+# define DEBUG_BREAK() (M.x86.debug & DEBUG_BREAK_F)
+# define DEBUG_SVC() (M.x86.debug & DEBUG_SVC_F)
+# define DEBUG_SAVE_IP_CS() (M.x86.debug & DEBUG_SAVE_IP_CS_F)
+
+# define DEBUG_FS() (M.x86.debug & DEBUG_FS_F)
+# define DEBUG_PROC() (M.x86.debug & DEBUG_PROC_F)
+# define DEBUG_SYSINT() (M.x86.debug & DEBUG_SYSINT_F)
+# define DEBUG_TRACECALL() (M.x86.debug & DEBUG_TRACECALL_F)
+# define DEBUG_TRACECALLREGS() (M.x86.debug & DEBUG_TRACECALL_REGS_F)
+# define DEBUG_SYS() (M.x86.debug & DEBUG_SYS_F)
+# define DEBUG_MEM_TRACE() (M.x86.debug & DEBUG_MEM_TRACE_F)
+# define DEBUG_IO_TRACE() (M.x86.debug & DEBUG_IO_TRACE_F)
+# define DEBUG_DECODE_NOPRINT() (M.x86.debug & DEBUG_DECODE_NOPRINT_F)
+#else
+# define DEBUG_INSTRUMENT() 0
+# define DEBUG_DECODE() 0
+# define DEBUG_TRACE() 0
+# define DEBUG_STEP() 0
+# define DEBUG_DISASSEMBLE() 0
+# define DEBUG_BREAK() 0
+# define DEBUG_SVC() 0
+# define DEBUG_SAVE_IP_CS() 0
+# define DEBUG_FS() 0
+# define DEBUG_PROC() 0
+# define DEBUG_SYSINT() 0
+# define DEBUG_TRACECALL() 0
+# define DEBUG_TRACECALLREGS() 0
+# define DEBUG_SYS() 0
+# define DEBUG_MEM_TRACE() 0
+# define DEBUG_IO_TRACE() 0
+# define DEBUG_DECODE_NOPRINT() 0
+#endif
+
+#ifdef X86EMU_DEBUG
+
+# define DECODE_PRINTF(x) if (DEBUG_DECODE()) \
+ x86emu_decode_printf(x)
+# define DECODE_PRINTF2(x,y) if (DEBUG_DECODE()) \
+ x86emu_decode_printf2(x,y)
+
+/*
+ * The following allow us to look at the bytes of an instruction. The
+ * first INCR_INSTRN_LEN, is called everytime bytes are consumed in
+ * the decoding process. The SAVE_IP_CS is called initially when the
+ * major opcode of the instruction is accessed.
+ */
+#define INC_DECODED_INST_LEN(x) \
+ if (DEBUG_DECODE()) \
+ x86emu_inc_decoded_inst_len(x)
+
+#define SAVE_IP_CS(x,y) \
+ if (DEBUG_DECODE() | DEBUG_TRACECALL() | DEBUG_BREAK() \
+ | DEBUG_IO_TRACE() | DEBUG_SAVE_IP_CS()) { \
+ M.x86.saved_cs = x; \
+ M.x86.saved_ip = y; \
+ }
+#else
+# define INC_DECODED_INST_LEN(x)
+# define DECODE_PRINTF(x)
+# define DECODE_PRINTF2(x,y)
+# define SAVE_IP_CS(x,y)
+#endif
+
+#ifdef X86EMU_DEBUG
+#define TRACE_REGS() \
+ if (DEBUG_DISASSEMBLE()) { \
+ x86emu_just_disassemble(); \
+ goto EndOfTheInstructionProcedure; \
+ } \
+ if (DEBUG_TRACE() || DEBUG_DECODE()) X86EMU_trace_regs()
+#else
+# define TRACE_REGS()
+#endif
+
+#ifdef X86EMU_DEBUG
+# define SINGLE_STEP() if (DEBUG_STEP()) x86emu_single_step()
+#else
+# define SINGLE_STEP()
+#endif
+
+#define TRACE_AND_STEP() \
+ TRACE_REGS(); \
+ SINGLE_STEP()
+
+#ifdef X86EMU_DEBUG
+# define START_OF_INSTR()
+# define END_OF_INSTR() EndOfTheInstructionProcedure: x86emu_end_instr();
+# define END_OF_INSTR_NO_TRACE() x86emu_end_instr();
+#else
+# define START_OF_INSTR()
+# define END_OF_INSTR()
+# define END_OF_INSTR_NO_TRACE()
+#endif
+
+#ifdef X86EMU_DEBUG
+#include <os/os.h>
+# define CALL_TRACE(u,v,w,x,s) \
+ if (DEBUG_TRACECALLREGS()) \
+ x86emu_dump_regs(); \
+ if (DEBUG_TRACECALL()) \
+ NV_PRINTF(LEVEL_INFO, "%04x:%04x: CALL %s%04x:%04x\n", u , v, s, w, x);
+# define RETURN_TRACE(n,u,v) \
+ if (DEBUG_TRACECALLREGS()) \
+ x86emu_dump_regs(); \
+ if (DEBUG_TRACECALL()) \
+ NV_PRINTF(LEVEL_INFO, "%04x:%04x: %s\n",u,v,n);
+#else
+# define CALL_TRACE(u,v,w,x,s)
+# define RETURN_TRACE(n,u,v)
+#endif
+
+#ifdef X86EMU_DEBUG
+#define DB(x) x
+#else
+#define DB(x)
+#endif
+
+/*-------------------------- Function Prototypes --------------------------*/
+
+#ifdef __cplusplus
+extern "C" { /* Use "C" linkage when in C++ mode */
+#endif
+
+extern void x86emu_inc_decoded_inst_len (int x);
+extern void x86emu_decode_printf (const char *x);
+extern void x86emu_decode_printf2 (const char *x, int y);
+extern void x86emu_just_disassemble (void);
+extern void x86emu_single_step (void);
+extern void x86emu_end_instr (void);
+extern void x86emu_dump_regs (void);
+extern void x86emu_dump_xregs (void);
+extern void x86emu_print_int_vect (u16 iv);
+extern void x86emu_instrument_instruction (void);
+extern void x86emu_check_ip_access (void);
+extern void x86emu_check_sp_access (void);
+extern void x86emu_check_mem_access (u32 p);
+extern void x86emu_check_data_access (uint s, uint o);
+
+#ifdef __cplusplus
+} /* End of "C" linkage for C++ */
+#endif
+
+#endif /* __X86EMU_DEBUG_H */
diff --git a/userspace/sdks/nv570/nvalloc/unix/include/x86emu/decode.h b/userspace/sdks/nv570/nvalloc/unix/include/x86emu/decode.h
new file mode 100644
index 0000000..52eff18
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/include/x86emu/decode.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+*
+* Realmode X86 Emulator Library
+*
+* Copyright (C) 1996-1999 SciTech Software, Inc.
+* Copyright (C) David Mosberger-Tang
+* Copyright (C) 1999 Egbert Eich
+*
+* ========================================================================
+*
+* Permission to use, copy, modify, distribute, and sell this software and
+* its documentation for any purpose is hereby granted without fee,
+* provided that the above copyright notice appear in all copies and that
+* both that copyright notice and this permission notice appear in
+* supporting documentation, and that the name of the authors not be used
+* in advertising or publicity pertaining to distribution of the software
+* without specific, written prior permission. The authors makes no
+* representations about the suitability of this software for any purpose.
+* It is provided "as is" without express or implied warranty.
+*
+* THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+* EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+* PERFORMANCE OF THIS SOFTWARE.
+*
+* ========================================================================
+*
+* Language: ANSI C
+* Environment: Any
+* Developer: Kendall Bennett
+*
+* Description: Header file for instruction decoding logic.
+*
+****************************************************************************/
+
+#ifndef __X86EMU_DECODE_H
+#define __X86EMU_DECODE_H
+
+/*---------------------- Macros and type definitions ----------------------*/
+
+/* Instruction Decoding Stuff */
+
+#define FETCH_DECODE_MODRM(mod,rh,rl) fetch_decode_modrm(&mod,&rh,&rl)
+#define DECODE_RM_BYTE_REGISTER(r) decode_rm_byte_register(r)
+#define DECODE_RM_WORD_REGISTER(r) decode_rm_word_register(r)
+#define DECODE_RM_LONG_REGISTER(r) decode_rm_long_register(r)
+#define DECODE_CLEAR_SEGOVR() M.x86.mode &= ~SYSMODE_CLRMASK
+
+/*-------------------------- Function Prototypes --------------------------*/
+
+#ifdef __cplusplus
+extern "C" { /* Use "C" linkage when in C++ mode */
+#endif
+
+void x86emu_intr_raise (u8 type);
+void fetch_decode_modrm (int *mod,int *regh,int *regl);
+u8 fetch_byte_imm (void);
+u16 fetch_word_imm (void);
+u32 fetch_long_imm (void);
+u8 fetch_data_byte (uint offset);
+u8 fetch_data_byte_abs (uint segment, uint offset);
+u16 fetch_data_word (uint offset);
+u16 fetch_data_word_abs (uint segment, uint offset);
+u32 fetch_data_long (uint offset);
+u32 fetch_data_long_abs (uint segment, uint offset);
+void store_data_byte (uint offset, u8 val);
+void store_data_byte_abs (uint segment, uint offset, u8 val);
+void store_data_word (uint offset, u16 val);
+void store_data_word_abs (uint segment, uint offset, u16 val);
+void store_data_long (uint offset, u32 val);
+void store_data_long_abs (uint segment, uint offset, u32 val);
+u8* decode_rm_byte_register(int reg);
+u16* decode_rm_word_register(int reg);
+u32* decode_rm_long_register(int reg);
+u16* decode_rm_seg_register(int reg);
+u32 decode_rm00_address(int rm);
+u32 decode_rm01_address(int rm);
+u32 decode_rm10_address(int rm);
+u32 decode_sib_address(int sib, int mod);
+
+#ifdef __cplusplus
+} /* End of "C" linkage for C++ */
+#endif
+
+#endif /* __X86EMU_DECODE_H */
diff --git a/userspace/sdks/nv570/nvalloc/unix/include/x86emu/fpu.h b/userspace/sdks/nv570/nvalloc/unix/include/x86emu/fpu.h
new file mode 100644
index 0000000..7c4f24e
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/include/x86emu/fpu.h
@@ -0,0 +1,61 @@
+/****************************************************************************
+*
+* Realmode X86 Emulator Library
+*
+* Copyright (C) 1996-1999 SciTech Software, Inc.
+* Copyright (C) David Mosberger-Tang
+* Copyright (C) 1999 Egbert Eich
+*
+* ========================================================================
+*
+* Permission to use, copy, modify, distribute, and sell this software and
+* its documentation for any purpose is hereby granted without fee,
+* provided that the above copyright notice appear in all copies and that
+* both that copyright notice and this permission notice appear in
+* supporting documentation, and that the name of the authors not be used
+* in advertising or publicity pertaining to distribution of the software
+* without specific, written prior permission. The authors makes no
+* representations about the suitability of this software for any purpose.
+* It is provided "as is" without express or implied warranty.
+*
+* THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+* EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+* PERFORMANCE OF THIS SOFTWARE.
+*
+* ========================================================================
+*
+* Language: ANSI C
+* Environment: Any
+* Developer: Kendall Bennett
+*
+* Description: Header file for FPU instruction decoding.
+*
+****************************************************************************/
+
+#ifndef __X86EMU_FPU_H
+#define __X86EMU_FPU_H
+
+#ifdef __cplusplus
+extern "C" { /* Use "C" linkage when in C++ mode */
+#endif
+
+/* these have to be defined, whether 8087 support compiled in or not. */
+
+extern void x86emuOp_esc_coprocess_d8 (u8 op1);
+extern void x86emuOp_esc_coprocess_d9 (u8 op1);
+extern void x86emuOp_esc_coprocess_da (u8 op1);
+extern void x86emuOp_esc_coprocess_db (u8 op1);
+extern void x86emuOp_esc_coprocess_dc (u8 op1);
+extern void x86emuOp_esc_coprocess_dd (u8 op1);
+extern void x86emuOp_esc_coprocess_de (u8 op1);
+extern void x86emuOp_esc_coprocess_df (u8 op1);
+
+#ifdef __cplusplus
+} /* End of "C" linkage for C++ */
+#endif
+
+#endif /* __X86EMU_FPU_H */
diff --git a/userspace/sdks/nv570/nvalloc/unix/include/x86emu/fpu_regs.h b/userspace/sdks/nv570/nvalloc/unix/include/x86emu/fpu_regs.h
new file mode 100644
index 0000000..39ee7fe
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/include/x86emu/fpu_regs.h
@@ -0,0 +1,119 @@
+/****************************************************************************
+*
+* Realmode X86 Emulator Library
+*
+* Copyright (C) 1996-1999 SciTech Software, Inc.
+* Copyright (C) David Mosberger-Tang
+* Copyright (C) 1999 Egbert Eich
+*
+* ========================================================================
+*
+* Permission to use, copy, modify, distribute, and sell this software and
+* its documentation for any purpose is hereby granted without fee,
+* provided that the above copyright notice appear in all copies and that
+* both that copyright notice and this permission notice appear in
+* supporting documentation, and that the name of the authors not be used
+* in advertising or publicity pertaining to distribution of the software
+* without specific, written prior permission. The authors makes no
+* representations about the suitability of this software for any purpose.
+* It is provided "as is" without express or implied warranty.
+*
+* THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+* EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+* PERFORMANCE OF THIS SOFTWARE.
+*
+* ========================================================================
+*
+* Language: ANSI C
+* Environment: Any
+* Developer: Kendall Bennett
+*
+* Description: Header file for FPU register definitions.
+*
+****************************************************************************/
+
+#ifndef __X86EMU_FPU_REGS_H
+#define __X86EMU_FPU_REGS_H
+
+#ifdef X86_FPU_SUPPORT
+
+#ifdef PACK
+# pragma PACK
+#endif
+
+/* Basic 8087 register can hold any of the following values: */
+
+union x86_fpu_reg_u {
+ s8 tenbytes[10];
+ double dval;
+ float fval;
+ s16 sval;
+ s32 lval;
+ };
+
+struct x86_fpu_reg {
+ union x86_fpu_reg_u reg;
+ char tag;
+ };
+
+/*
+ * Since we are not going to worry about the problems of aliasing
+ * registers, every time a register is modified, its result type is
+ * set in the tag fields for that register. If some operation
+ * attempts to access the type in a way inconsistent with its current
+ * storage format, then we flag the operation. If common, we'll
+ * attempt the conversion.
+ */
+
+#define X86_FPU_VALID 0x80
+#define X86_FPU_REGTYP(r) ((r) & 0x7F)
+
+#define X86_FPU_WORD 0x0
+#define X86_FPU_SHORT 0x1
+#define X86_FPU_LONG 0x2
+#define X86_FPU_FLOAT 0x3
+#define X86_FPU_DOUBLE 0x4
+#define X86_FPU_LDBL 0x5
+#define X86_FPU_BSD 0x6
+
+#define X86_FPU_STKTOP 0
+
+struct x86_fpu_registers {
+ struct x86_fpu_reg x86_fpu_stack[8];
+ int x86_fpu_flags;
+ int x86_fpu_config; /* rounding modes, etc. */
+ short x86_fpu_tos, x86_fpu_bos;
+ };
+
+#ifdef END_PACK
+# pragma END_PACK
+#endif
+
+/*
+ * There are two versions of the following macro.
+ *
+ * One version is for opcode D9, for which there are more than 32
+ * instructions encoded in the second byte of the opcode.
+ *
+ * The other version, deals with all the other 7 i87 opcodes, for
+ * which there are only 32 strings needed to describe the
+ * instructions.
+ */
+
+#endif /* X86_FPU_SUPPORT */
+
+#ifdef X86EMU_DEBUG
+# define DECODE_PRINTINSTR32(t,mod,rh,rl) \
+ DECODE_PRINTF(t[(mod<<3)+(rh)]);
+# define DECODE_PRINTINSTR256(t,mod,rh,rl) \
+ DECODE_PRINTF(t[(mod<<6)+(rh<<3)+(rl)]);
+#else
+# define DECODE_PRINTINSTR32(t,mod,rh,rl)
+# define DECODE_PRINTINSTR256(t,mod,rh,rl)
+#endif
+
+#endif /* __X86EMU_FPU_REGS_H */
diff --git a/userspace/sdks/nv570/nvalloc/unix/include/x86emu/ops.h b/userspace/sdks/nv570/nvalloc/unix/include/x86emu/ops.h
new file mode 100644
index 0000000..82d2bbe
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/include/x86emu/ops.h
@@ -0,0 +1,45 @@
+/****************************************************************************
+*
+* Realmode X86 Emulator Library
+*
+* Copyright (C) 1996-1999 SciTech Software, Inc.
+* Copyright (C) David Mosberger-Tang
+* Copyright (C) 1999 Egbert Eich
+*
+* ========================================================================
+*
+* Permission to use, copy, modify, distribute, and sell this software and
+* its documentation for any purpose is hereby granted without fee,
+* provided that the above copyright notice appear in all copies and that
+* both that copyright notice and this permission notice appear in
+* supporting documentation, and that the name of the authors not be used
+* in advertising or publicity pertaining to distribution of the software
+* without specific, written prior permission. The authors makes no
+* representations about the suitability of this software for any purpose.
+* It is provided "as is" without express or implied warranty.
+*
+* THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+* EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+* PERFORMANCE OF THIS SOFTWARE.
+*
+* ========================================================================
+*
+* Language: ANSI C
+* Environment: Any
+* Developer: Kendall Bennett
+*
+* Description: Header file for operand decoding functions.
+*
+****************************************************************************/
+
+#ifndef __X86EMU_OPS_H
+#define __X86EMU_OPS_H
+
+extern void (*x86emu_optab[0x100])(u8 op1);
+extern void (*x86emu_optab2[0x100])(u8 op2);
+
+#endif /* __X86EMU_OPS_H */
diff --git a/userspace/sdks/nv570/nvalloc/unix/include/x86emu/prim_ops.h b/userspace/sdks/nv570/nvalloc/unix/include/x86emu/prim_ops.h
new file mode 100644
index 0000000..8978004
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/include/x86emu/prim_ops.h
@@ -0,0 +1,141 @@
+/****************************************************************************
+*
+* Realmode X86 Emulator Library
+*
+* Copyright (C) 1996-1999 SciTech Software, Inc.
+* Copyright (C) David Mosberger-Tang
+* Copyright (C) 1999 Egbert Eich
+*
+* ========================================================================
+*
+* Permission to use, copy, modify, distribute, and sell this software and
+* its documentation for any purpose is hereby granted without fee,
+* provided that the above copyright notice appear in all copies and that
+* both that copyright notice and this permission notice appear in
+* supporting documentation, and that the name of the authors not be used
+* in advertising or publicity pertaining to distribution of the software
+* without specific, written prior permission. The authors makes no
+* representations about the suitability of this software for any purpose.
+* It is provided "as is" without express or implied warranty.
+*
+* THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+* EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+* PERFORMANCE OF THIS SOFTWARE.
+*
+* ========================================================================
+*
+* Language: ANSI C
+* Environment: Any
+* Developer: Kendall Bennett
+*
+* Description: Header file for primitive operation functions.
+*
+****************************************************************************/
+
+#ifndef __X86EMU_PRIM_OPS_H
+#define __X86EMU_PRIM_OPS_H
+
+#ifdef __cplusplus
+extern "C" { /* Use "C" linkage when in C++ mode */
+#endif
+
+u16 aaa_word (u16 d);
+u16 aas_word (u16 d);
+u16 aad_word (u16 d);
+u16 aam_word (u8 d);
+u8 adc_byte (u8 d, u8 s);
+u16 adc_word (u16 d, u16 s);
+u32 adc_long (u32 d, u32 s);
+u8 add_byte (u8 d, u8 s);
+u16 add_word (u16 d, u16 s);
+u32 add_long (u32 d, u32 s);
+u8 and_byte (u8 d, u8 s);
+u16 and_word (u16 d, u16 s);
+u32 and_long (u32 d, u32 s);
+u8 cmp_byte (u8 d, u8 s);
+u16 cmp_word (u16 d, u16 s);
+u32 cmp_long (u32 d, u32 s);
+u8 daa_byte (u8 d);
+u8 das_byte (u8 d);
+u8 dec_byte (u8 d);
+u16 dec_word (u16 d);
+u32 dec_long (u32 d);
+u8 inc_byte (u8 d);
+u16 inc_word (u16 d);
+u32 inc_long (u32 d);
+u8 or_byte (u8 d, u8 s);
+u16 or_word (u16 d, u16 s);
+u32 or_long (u32 d, u32 s);
+u8 neg_byte (u8 s);
+u16 neg_word (u16 s);
+u32 neg_long (u32 s);
+u8 not_byte (u8 s);
+u16 not_word (u16 s);
+u32 not_long (u32 s);
+u8 rcl_byte (u8 d, u8 s);
+u16 rcl_word (u16 d, u8 s);
+u32 rcl_long (u32 d, u8 s);
+u8 rcr_byte (u8 d, u8 s);
+u16 rcr_word (u16 d, u8 s);
+u32 rcr_long (u32 d, u8 s);
+u8 rol_byte (u8 d, u8 s);
+u16 rol_word (u16 d, u8 s);
+u32 rol_long (u32 d, u8 s);
+u8 ror_byte (u8 d, u8 s);
+u16 ror_word (u16 d, u8 s);
+u32 ror_long (u32 d, u8 s);
+u8 shl_byte (u8 d, u8 s);
+u16 shl_word (u16 d, u8 s);
+u32 shl_long (u32 d, u8 s);
+u8 shr_byte (u8 d, u8 s);
+u16 shr_word (u16 d, u8 s);
+u32 shr_long (u32 d, u8 s);
+u8 sar_byte (u8 d, u8 s);
+u16 sar_word (u16 d, u8 s);
+u32 sar_long (u32 d, u8 s);
+u16 shld_word (u16 d, u16 fill, u8 s);
+u32 shld_long (u32 d, u32 fill, u8 s);
+u16 shrd_word (u16 d, u16 fill, u8 s);
+u32 shrd_long (u32 d, u32 fill, u8 s);
+u8 sbb_byte (u8 d, u8 s);
+u16 sbb_word (u16 d, u16 s);
+u32 sbb_long (u32 d, u32 s);
+u8 sub_byte (u8 d, u8 s);
+u16 sub_word (u16 d, u16 s);
+u32 sub_long (u32 d, u32 s);
+void test_byte (u8 d, u8 s);
+void test_word (u16 d, u16 s);
+void test_long (u32 d, u32 s);
+u8 xor_byte (u8 d, u8 s);
+u16 xor_word (u16 d, u16 s);
+u32 xor_long (u32 d, u32 s);
+void imul_byte (u8 s);
+void imul_word (u16 s);
+void imul_long (u32 s);
+void imul_long_direct(u32 *res_lo, u32* res_hi,u32 d, u32 s);
+void mul_byte (u8 s);
+void mul_word (u16 s);
+void mul_long (u32 s);
+void idiv_byte (u8 s);
+void idiv_word (u16 s);
+void idiv_long (u32 s);
+void div_byte (u8 s);
+void div_word (u16 s);
+void div_long (u32 s);
+void ins (int size);
+void outs (int size);
+u16 mem_access_word (int addr);
+void push_word (u16 w);
+void push_long (u32 w);
+u16 pop_word (void);
+u32 pop_long (void);
+
+#ifdef __cplusplus
+} /* End of "C" linkage for C++ */
+#endif
+
+#endif /* __X86EMU_PRIM_OPS_H */
diff --git a/userspace/sdks/nv570/nvalloc/unix/include/x86emu/regs.h b/userspace/sdks/nv570/nvalloc/unix/include/x86emu/regs.h
new file mode 100644
index 0000000..4cd0f8b
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/include/x86emu/regs.h
@@ -0,0 +1,340 @@
+/****************************************************************************
+*
+* Realmode X86 Emulator Library
+*
+* Copyright (C) 1996-1999 SciTech Software, Inc.
+* Copyright (C) David Mosberger-Tang
+* Copyright (C) 1999 Egbert Eich
+*
+* ========================================================================
+*
+* Permission to use, copy, modify, distribute, and sell this software and
+* its documentation for any purpose is hereby granted without fee,
+* provided that the above copyright notice appear in all copies and that
+* both that copyright notice and this permission notice appear in
+* supporting documentation, and that the name of the authors not be used
+* in advertising or publicity pertaining to distribution of the software
+* without specific, written prior permission. The authors makes no
+* representations about the suitability of this software for any purpose.
+* It is provided "as is" without express or implied warranty.
+*
+* THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+* EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+* PERFORMANCE OF THIS SOFTWARE.
+*
+* ========================================================================
+*
+* Language: ANSI C
+* Environment: Any
+* Developer: Kendall Bennett
+*
+* Description: Header file for x86 register definitions.
+*
+****************************************************************************/
+
+#ifndef __X86EMU_REGS_H
+#define __X86EMU_REGS_H
+
+#include "x86emu/debug.h"
+
+/*---------------------- Macros and type definitions ----------------------*/
+
+#ifdef PACK
+# pragma PACK
+#endif
+
+/*
+ * General EAX, EBX, ECX, EDX type registers. Note that for
+ * portability, and speed, the issue of byte swapping is not addressed
+ * in the registers. All registers are stored in the default format
+ * available on the host machine. The only critical issue is that the
+ * registers should line up EXACTLY in the same manner as they do in
+ * the 386. That is:
+ *
+ * EAX & 0xff === AL
+ * EAX & 0xffff == AX
+ *
+ * etc. The result is that alot of the calculations can then be
+ * done using the native instruction set fully.
+ */
+
+#ifdef __BIG_ENDIAN__
+
+typedef struct {
+ u32 e_reg;
+ } I32_reg_t;
+
+typedef struct {
+ u16 filler0, x_reg;
+ } I16_reg_t;
+
+typedef struct {
+ u8 filler0, filler1, h_reg, l_reg;
+ } I8_reg_t;
+
+#else /* !__BIG_ENDIAN__ */
+
+typedef struct {
+ u32 e_reg;
+ } I32_reg_t;
+
+typedef struct {
+ u16 x_reg;
+ } I16_reg_t;
+
+typedef struct {
+ u8 l_reg, h_reg;
+ } I8_reg_t;
+
+#endif /* __BIG_ENDIAN__ */
+
+typedef union {
+ I32_reg_t I32_reg;
+ I16_reg_t I16_reg;
+ I8_reg_t I8_reg;
+ } i386_general_register;
+
+struct i386_general_regs {
+ i386_general_register A, B, C, D;
+ };
+
+typedef struct i386_general_regs Gen_reg_t;
+
+struct i386_special_regs {
+ i386_general_register SP, BP, SI, DI, IP;
+ u32 FLAGS;
+ };
+
+/*
+ * Segment registers here represent the 16 bit quantities
+ * CS, DS, ES, SS.
+ */
+
+struct i386_segment_regs {
+ u16 CS, DS, SS, ES, FS, GS;
+ };
+
+/* 8 bit registers */
+#define R_AH gen.A.I8_reg.h_reg
+#define R_AL gen.A.I8_reg.l_reg
+#define R_BH gen.B.I8_reg.h_reg
+#define R_BL gen.B.I8_reg.l_reg
+#define R_CH gen.C.I8_reg.h_reg
+#define R_CL gen.C.I8_reg.l_reg
+#define R_DH gen.D.I8_reg.h_reg
+#define R_DL gen.D.I8_reg.l_reg
+
+/* 16 bit registers */
+#define R_AX gen.A.I16_reg.x_reg
+#define R_BX gen.B.I16_reg.x_reg
+#define R_CX gen.C.I16_reg.x_reg
+#define R_DX gen.D.I16_reg.x_reg
+
+/* 32 bit extended registers */
+#define R_EAX gen.A.I32_reg.e_reg
+#define R_EBX gen.B.I32_reg.e_reg
+#define R_ECX gen.C.I32_reg.e_reg
+#define R_EDX gen.D.I32_reg.e_reg
+
+/* special registers */
+#define R_SP spc.SP.I16_reg.x_reg
+#define R_BP spc.BP.I16_reg.x_reg
+#define R_SI spc.SI.I16_reg.x_reg
+#define R_DI spc.DI.I16_reg.x_reg
+#define R_IP spc.IP.I16_reg.x_reg
+#define R_FLG spc.FLAGS
+
+/* special registers */
+#define R_SP spc.SP.I16_reg.x_reg
+#define R_BP spc.BP.I16_reg.x_reg
+#define R_SI spc.SI.I16_reg.x_reg
+#define R_DI spc.DI.I16_reg.x_reg
+#define R_IP spc.IP.I16_reg.x_reg
+#define R_FLG spc.FLAGS
+
+/* special registers */
+#define R_ESP spc.SP.I32_reg.e_reg
+#define R_EBP spc.BP.I32_reg.e_reg
+#define R_ESI spc.SI.I32_reg.e_reg
+#define R_EDI spc.DI.I32_reg.e_reg
+#define R_EIP spc.IP.I32_reg.e_reg
+#define R_EFLG spc.FLAGS
+
+/* segment registers */
+#define R_CS seg.CS
+#define R_DS seg.DS
+#define R_SS seg.SS
+#define R_ES seg.ES
+#define R_FS seg.FS
+#define R_GS seg.GS
+
+/* flag conditions */
+#define FB_CF 0x0001 /* CARRY flag */
+#define FB_PF 0x0004 /* PARITY flag */
+#define FB_AF 0x0010 /* AUX flag */
+#define FB_ZF 0x0040 /* ZERO flag */
+#define FB_SF 0x0080 /* SIGN flag */
+#define FB_TF 0x0100 /* TRAP flag */
+#define FB_IF 0x0200 /* INTERRUPT ENABLE flag */
+#define FB_DF 0x0400 /* DIR flag */
+#define FB_OF 0x0800 /* OVERFLOW flag */
+
+/* 80286 and above always have bit#1 set */
+#define F_ALWAYS_ON (0x0002) /* flag bits always on */
+
+/*
+ * Define a mask for only those flag bits we will ever pass back
+ * (via PUSHF)
+ */
+#define F_MSK (FB_CF|FB_PF|FB_AF|FB_ZF|FB_SF|FB_TF|FB_IF|FB_DF|FB_OF)
+
+/* following bits masked in to a 16bit quantity */
+
+#define F_CF 0x0001 /* CARRY flag */
+#define F_PF 0x0004 /* PARITY flag */
+#define F_AF 0x0010 /* AUX flag */
+#define F_ZF 0x0040 /* ZERO flag */
+#define F_SF 0x0080 /* SIGN flag */
+#define F_TF 0x0100 /* TRAP flag */
+#define F_IF 0x0200 /* INTERRUPT ENABLE flag */
+#define F_DF 0x0400 /* DIR flag */
+#define F_OF 0x0800 /* OVERFLOW flag */
+
+#define TOGGLE_FLAG(flag) (M.x86.R_FLG ^= (flag))
+#define SET_FLAG(flag) (M.x86.R_FLG |= (flag))
+#define CLEAR_FLAG(flag) (M.x86.R_FLG &= ~(flag))
+#define ACCESS_FLAG(flag) (M.x86.R_FLG & (flag))
+#define CLEARALL_FLAG(m) (M.x86.R_FLG = 0)
+
+#define CONDITIONAL_SET_FLAG(COND,FLAG) \
+ if (COND) SET_FLAG(FLAG); else CLEAR_FLAG(FLAG)
+
+#define F_PF_CALC 0x010000 /* PARITY flag has been calced */
+#define F_ZF_CALC 0x020000 /* ZERO flag has been calced */
+#define F_SF_CALC 0x040000 /* SIGN flag has been calced */
+
+#define F_ALL_CALC 0xff0000 /* All have been calced */
+
+/*
+ * Emulator machine state.
+ * Segment usage control.
+ */
+#define SYSMODE_SEG_DS_SS 0x00000001
+#define SYSMODE_SEGOVR_CS 0x00000002
+#define SYSMODE_SEGOVR_DS 0x00000004
+#define SYSMODE_SEGOVR_ES 0x00000008
+#define SYSMODE_SEGOVR_FS 0x00000010
+#define SYSMODE_SEGOVR_GS 0x00000020
+#define SYSMODE_SEGOVR_SS 0x00000040
+#define SYSMODE_PREFIX_REPE 0x00000080
+#define SYSMODE_PREFIX_REPNE 0x00000100
+#define SYSMODE_PREFIX_DATA 0x00000200
+#define SYSMODE_PREFIX_ADDR 0x00000400
+#define SYSMODE_INTR_PENDING 0x10000000
+#define SYSMODE_EXTRN_INTR 0x20000000
+#define SYSMODE_HALTED 0x40000000
+
+#define SYSMODE_SEGMASK (SYSMODE_SEG_DS_SS | \
+ SYSMODE_SEGOVR_CS | \
+ SYSMODE_SEGOVR_DS | \
+ SYSMODE_SEGOVR_ES | \
+ SYSMODE_SEGOVR_FS | \
+ SYSMODE_SEGOVR_GS | \
+ SYSMODE_SEGOVR_SS)
+#define SYSMODE_CLRMASK (SYSMODE_SEG_DS_SS | \
+ SYSMODE_SEGOVR_CS | \
+ SYSMODE_SEGOVR_DS | \
+ SYSMODE_SEGOVR_ES | \
+ SYSMODE_SEGOVR_FS | \
+ SYSMODE_SEGOVR_GS | \
+ SYSMODE_SEGOVR_SS | \
+ SYSMODE_PREFIX_DATA | \
+ SYSMODE_PREFIX_ADDR)
+
+#define INTR_SYNCH 0x1
+#define INTR_ASYNCH 0x2
+#define INTR_HALTED 0x4
+
+typedef struct {
+ struct i386_general_regs gen;
+ struct i386_special_regs spc;
+ struct i386_segment_regs seg;
+ /*
+ * MODE contains information on:
+ * REPE prefix 2 bits repe,repne
+ * SEGMENT overrides 5 bits normal,DS,SS,CS,ES
+ * Delayed flag set 3 bits (zero, signed, parity)
+ * reserved 6 bits
+ * interrupt # 8 bits instruction raised interrupt
+ * BIOS video segregs 4 bits
+ * Interrupt Pending 1 bits
+ * Extern interrupt 1 bits
+ * Halted 1 bits
+ */
+ u32 mode;
+ volatile int intr; /* mask of pending interrupts */
+ int debug;
+#ifdef X86EMU_DEBUG
+ int check;
+ u16 saved_ip;
+ u16 saved_cs;
+ int enc_pos;
+ int enc_str_pos;
+ char decode_buf[32]; /* encoded byte stream */
+ char decoded_buf[256]; /* disassembled strings */
+ char debug_cmd[64]; /* input for x86emu_single_step */
+#endif
+ u8 intno;
+ u8 __pad[3];
+ } X86EMU_regs;
+
+/****************************************************************************
+REMARKS:
+Structure maintaining the emulator machine state.
+
+MEMBERS:
+mem_base - Base real mode memory for the emulator
+mem_size - Size of the real mode memory block for the emulator
+private - private data pointer
+x86 - X86 registers
+****************************************************************************/
+typedef struct {
+ unsigned long mem_base;
+ unsigned long mem_size;
+ void* private;
+ X86EMU_regs x86;
+ } X86EMU_sysEnv;
+
+#ifdef END_PACK
+# pragma END_PACK
+#endif
+
+/*----------------------------- Global Variables --------------------------*/
+
+#ifdef __cplusplus
+extern "C" { /* Use "C" linkage when in C++ mode */
+#endif
+
+/* Global emulator machine state.
+ *
+ * We keep it global to avoid pointer dereferences in the code for speed.
+ */
+
+extern X86EMU_sysEnv _X86EMU_env;
+#define M _X86EMU_env
+
+/*-------------------------- Function Prototypes --------------------------*/
+
+/* Function to log information at runtime */
+
+void printk(const char *fmt, ...);
+
+#ifdef __cplusplus
+} /* End of "C" linkage for C++ */
+#endif
+
+#endif /* __X86EMU_REGS_H */
diff --git a/userspace/sdks/nv570/nvalloc/unix/include/x86emu/types.h b/userspace/sdks/nv570/nvalloc/unix/include/x86emu/types.h
new file mode 100644
index 0000000..53c3e87
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/include/x86emu/types.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+*
+* Realmode X86 Emulator Library
+*
+* Copyright (C) 1996-1999 SciTech Software, Inc.
+* Copyright (C) David Mosberger-Tang
+* Copyright (C) 1999 Egbert Eich
+*
+* ========================================================================
+*
+* Permission to use, copy, modify, distribute, and sell this software and
+* its documentation for any purpose is hereby granted without fee,
+* provided that the above copyright notice appear in all copies and that
+* both that copyright notice and this permission notice appear in
+* supporting documentation, and that the name of the authors not be used
+* in advertising or publicity pertaining to distribution of the software
+* without specific, written prior permission. The authors makes no
+* representations about the suitability of this software for any purpose.
+* It is provided "as is" without express or implied warranty.
+*
+* THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+* EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+* PERFORMANCE OF THIS SOFTWARE.
+*
+* ========================================================================
+*
+* Language: ANSI C
+* Environment: Any
+* Developer: Kendall Bennett
+*
+* Description: Header file for x86 emulator type definitions.
+*
+****************************************************************************/
+
+
+#ifndef __X86EMU_TYPES_H
+#define __X86EMU_TYPES_H
+
+#ifndef NO_SYS_HEADERS
+#include <sys/types.h>
+#endif
+
+/*
+ * The following kludge is an attempt to work around typedef conflicts with
+ * <sys/types.h>.
+ */
+#define u8 x86emuu8
+#define u16 x86emuu16
+#define u32 x86emuu32
+#define u64 x86emuu64
+#define s8 x86emus8
+#define s16 x86emus16
+#define s32 x86emus32
+#define s64 x86emus64
+#define uint x86emuuint
+#define sint x86emusint
+
+/*---------------------- Macros and type definitions ----------------------*/
+
+/* Currently only for Linux/32bit */
+#undef __HAS_LONG_LONG__
+#if defined(__GNUC__) && !defined(NO_LONG_LONG)
+#define __HAS_LONG_LONG__
+#endif
+
+#define NUM32 int
+
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned NUM32 u32;
+#ifdef __HAS_LONG_LONG__
+typedef unsigned long long u64;
+#endif
+
+typedef char s8;
+typedef short s16;
+typedef NUM32 s32;
+#ifdef __HAS_LONG_LONG__
+typedef long long s64;
+#endif
+
+typedef unsigned int uint;
+typedef int sint;
+
+typedef u16 X86EMU_pioAddr;
+
+#undef NUM32
+
+#endif /* __X86EMU_TYPES_H */
diff --git a/userspace/sdks/nv570/nvalloc/unix/include/x86emu/x86emu.h b/userspace/sdks/nv570/nvalloc/unix/include/x86emu/x86emu.h
new file mode 100644
index 0000000..935cc70
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/include/x86emu/x86emu.h
@@ -0,0 +1,205 @@
+/****************************************************************************
+*
+* Realmode X86 Emulator Library
+*
+* Copyright (C) 1996-1999 SciTech Software, Inc.
+* Copyright (C) David Mosberger-Tang
+* Copyright (C) 1999 Egbert Eich
+*
+* ========================================================================
+*
+* Permission to use, copy, modify, distribute, and sell this software and
+* its documentation for any purpose is hereby granted without fee,
+* provided that the above copyright notice appear in all copies and that
+* both that copyright notice and this permission notice appear in
+* supporting documentation, and that the name of the authors not be used
+* in advertising or publicity pertaining to distribution of the software
+* without specific, written prior permission. The authors makes no
+* representations about the suitability of this software for any purpose.
+* It is provided "as is" without express or implied warranty.
+*
+* THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+* EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+* PERFORMANCE OF THIS SOFTWARE.
+*
+* ========================================================================
+*
+* Language: ANSI C
+* Environment: Any
+* Developer: Kendall Bennett
+*
+* Description: Header file for public specific functions.
+* Any application linking against us should only
+* include this header
+*
+****************************************************************************/
+
+#ifndef __X86EMU_X86EMU_H
+#define __X86EMU_X86EMU_H
+
+// NV
+#ifndef NO_SYS_HEADERS
+#define NO_SYS_HEADERS
+#endif
+
+#ifdef SCITECH
+#include "scitech.h"
+#define X86API _ASMAPI
+#define X86APIP _ASMAPIP
+typedef int X86EMU_pioAddr;
+#else
+#include "x86emu/types.h"
+#define X86API
+#define X86APIP *
+#endif
+#include "x86emu/regs.h"
+#include "x86emu/debug.h"
+
+/*---------------------- Macros and type definitions ----------------------*/
+
+#ifdef PACK
+# pragma PACK /* Don't pack structs with function pointers! */
+#endif
+
+/****************************************************************************
+REMARKS:
+Data structure containing ponters to programmed I/O functions used by the
+emulator. This is used so that the user program can hook all programmed
+I/O for the emulator to handled as necessary by the user program. By
+default the emulator contains simple functions that do not do access the
+hardware in any way. To allow the emualtor access the hardware, you will
+need to override the programmed I/O functions using the X86EMU_setupPioFuncs
+function.
+
+HEADER:
+x86emu.h
+
+MEMBERS:
+inb - Function to read a byte from an I/O port
+inw - Function to read a word from an I/O port
+inl - Function to read a dword from an I/O port
+outb - Function to write a byte to an I/O port
+outw - Function to write a word to an I/O port
+outl - Function to write a dword to an I/O port
+****************************************************************************/
+typedef struct {
+ u8 (X86APIP inb)(X86EMU_pioAddr addr);
+ u16 (X86APIP inw)(X86EMU_pioAddr addr);
+ u32 (X86APIP inl)(X86EMU_pioAddr addr);
+ void (X86APIP outb)(X86EMU_pioAddr addr, u8 val);
+ void (X86APIP outw)(X86EMU_pioAddr addr, u16 val);
+ void (X86APIP outl)(X86EMU_pioAddr addr, u32 val);
+ } X86EMU_pioFuncs;
+
+/****************************************************************************
+REMARKS:
+Data structure containing ponters to memory access functions used by the
+emulator. This is used so that the user program can hook all memory
+access functions as necessary for the emulator. By default the emulator
+contains simple functions that only access the internal memory of the
+emulator. If you need specialised functions to handle access to different
+types of memory (ie: hardware framebuffer accesses and BIOS memory access
+etc), you will need to override this using the X86EMU_setupMemFuncs
+function.
+
+HEADER:
+x86emu.h
+
+MEMBERS:
+rdb - Function to read a byte from an address
+rdw - Function to read a word from an address
+rdl - Function to read a dword from an address
+wrb - Function to write a byte to an address
+wrw - Function to write a word to an address
+wrl - Function to write a dword to an address
+****************************************************************************/
+typedef struct {
+ u8 (X86APIP rdb)(u32 addr);
+ u16 (X86APIP rdw)(u32 addr);
+ u32 (X86APIP rdl)(u32 addr);
+ void (X86APIP wrb)(u32 addr, u8 val);
+ void (X86APIP wrw)(u32 addr, u16 val);
+ void (X86APIP wrl)(u32 addr, u32 val);
+ } X86EMU_memFuncs;
+
+/****************************************************************************
+ Here are the default memory read and write
+ function in case they are needed as fallbacks.
+***************************************************************************/
+extern u8 X86API rdb(u32 addr);
+extern u16 X86API rdw(u32 addr);
+extern u32 X86API rdl(u32 addr);
+extern void X86API wrb(u32 addr, u8 val);
+extern void X86API wrw(u32 addr, u16 val);
+extern void X86API wrl(u32 addr, u32 val);
+
+#ifdef END_PACK
+# pragma END_PACK
+#endif
+
+/*--------------------- type definitions -----------------------------------*/
+
+typedef void (X86APIP X86EMU_intrFuncs)(int num);
+extern X86EMU_intrFuncs _X86EMU_intrTab[256];
+
+/*-------------------------- Function Prototypes --------------------------*/
+
+#ifdef __cplusplus
+extern "C" { /* Use "C" linkage when in C++ mode */
+#endif
+
+void X86EMU_setupMemFuncs(X86EMU_memFuncs *funcs);
+void X86EMU_setupPioFuncs(X86EMU_pioFuncs *funcs);
+void X86EMU_setupIntrFuncs(X86EMU_intrFuncs funcs[]);
+void X86EMU_prepareForInt(int num);
+
+/* decode.c */
+
+void X86EMU_exec(void);
+void X86EMU_halt_sys(void);
+
+#ifdef X86EMU_DEBUG
+#define HALT_SYS() do { \
+ NV_PRINTF(LEVEL_INFO, "halt_sys: file %s, line %d\n", __FILE__, __LINE__); \
+ X86EMU_halt_sys(); \
+ } while (0)
+#else
+#define HALT_SYS() X86EMU_halt_sys()
+#endif
+
+/* Debug options */
+
+#define DEBUG_DECODE_F 0x000001 /* print decoded instruction */
+#define DEBUG_TRACE_F 0x000002 /* dump regs before/after execution */
+#define DEBUG_STEP_F 0x000004
+#define DEBUG_DISASSEMBLE_F 0x000008
+#define DEBUG_BREAK_F 0x000010
+#define DEBUG_SVC_F 0x000020
+#define DEBUG_SAVE_IP_CS_F 0x000040
+#define DEBUG_FS_F 0x000080
+#define DEBUG_PROC_F 0x000100
+#define DEBUG_SYSINT_F 0x000200 /* bios system interrupts. */
+#define DEBUG_TRACECALL_F 0x000400
+#define DEBUG_INSTRUMENT_F 0x000800
+#define DEBUG_MEM_TRACE_F 0x001000
+#define DEBUG_IO_TRACE_F 0x002000
+#define DEBUG_TRACECALL_REGS_F 0x004000
+#define DEBUG_DECODE_NOPRINT_F 0x008000
+#define DEBUG_EXIT 0x010000
+#define DEBUG_SYS_F (DEBUG_SVC_F|DEBUG_FS_F|DEBUG_PROC_F)
+
+void X86EMU_trace_regs(void);
+void X86EMU_trace_xregs(void);
+void X86EMU_dump_memory(u16 seg, u16 off, u32 amt);
+int X86EMU_trace_on(void);
+int X86EMU_trace_off(void);
+
+#ifdef __cplusplus
+} /* End of "C" linkage for C++ */
+#endif
+
+#endif /* __X86EMU_X86EMU_H */
diff --git a/userspace/sdks/nv570/nvalloc/unix/include/x86emu/x86emui.h b/userspace/sdks/nv570/nvalloc/unix/include/x86emu/x86emui.h
new file mode 100644
index 0000000..5788558
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/include/x86emu/x86emui.h
@@ -0,0 +1,113 @@
+/****************************************************************************
+*
+* Realmode X86 Emulator Library
+*
+* Copyright (C) 1996-1999 SciTech Software, Inc.
+* Copyright (C) David Mosberger-Tang
+* Copyright (C) 1999 Egbert Eich
+*
+* ========================================================================
+*
+* Permission to use, copy, modify, distribute, and sell this software and
+* its documentation for any purpose is hereby granted without fee,
+* provided that the above copyright notice appear in all copies and that
+* both that copyright notice and this permission notice appear in
+* supporting documentation, and that the name of the authors not be used
+* in advertising or publicity pertaining to distribution of the software
+* without specific, written prior permission. The authors makes no
+* representations about the suitability of this software for any purpose.
+* It is provided "as is" without express or implied warranty.
+*
+* THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+* EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+* PERFORMANCE OF THIS SOFTWARE.
+*
+* ========================================================================
+*
+* Language: ANSI C
+* Environment: Any
+* Developer: Kendall Bennett
+*
+* Description: Header file for system specific functions. These functions
+* are always compiled and linked in the OS depedent libraries,
+* and never in a binary portable driver.
+*
+****************************************************************************/
+
+
+#ifndef __X86EMU_X86EMUI_H
+#define __X86EMU_X86EMUI_H
+
+/* If we are compiling in C++ mode, we can compile some functions as
+ * inline to increase performance (however the code size increases quite
+ * dramatically in this case).
+ */
+
+// NV
+#ifndef NO_SYS_HEADERS
+#define NO_SYS_HEADERS
+#endif
+#include <stddef.h> /* NULL */
+#if defined(__cplusplus) && !defined(_NO_INLINE)
+#define _INLINE inline
+#else
+#define _INLINE static
+#endif
+
+/* Get rid of unused parameters in C++ compilation mode */
+
+#ifdef __cplusplus
+#define X86EMU_UNUSED(v)
+#else
+#define X86EMU_UNUSED(v) v
+#endif
+
+#include "x86emu.h"
+#include "x86emu/regs.h"
+#include "x86emu/debug.h"
+#include "x86emu/decode.h"
+#include "x86emu/ops.h"
+#include "x86emu/prim_ops.h"
+#include "x86emu/fpu.h"
+#include "x86emu/fpu_regs.h"
+
+#ifndef NO_SYS_HEADERS
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#endif
+
+// On x86_64 abs() is not recognized. I don't understand why.
+#ifndef abs
+#define abs(i) __builtin_abs(i)
+#endif
+
+/*--------------------------- Inline Functions ----------------------------*/
+
+#ifdef __cplusplus
+extern "C" { /* Use "C" linkage when in C++ mode */
+#endif
+
+extern u8 (X86APIP sys_rdb)(u32 addr);
+extern u16 (X86APIP sys_rdw)(u32 addr);
+extern u32 (X86APIP sys_rdl)(u32 addr);
+extern void (X86APIP sys_wrb)(u32 addr,u8 val);
+extern void (X86APIP sys_wrw)(u32 addr,u16 val);
+extern void (X86APIP sys_wrl)(u32 addr,u32 val);
+
+extern u8 (X86APIP sys_inb)(X86EMU_pioAddr addr);
+extern u16 (X86APIP sys_inw)(X86EMU_pioAddr addr);
+extern u32 (X86APIP sys_inl)(X86EMU_pioAddr addr);
+extern void (X86APIP sys_outb)(X86EMU_pioAddr addr,u8 val);
+extern void (X86APIP sys_outw)(X86EMU_pioAddr addr,u16 val);
+extern void (X86APIP sys_outl)(X86EMU_pioAddr addr,u32 val);
+
+#ifdef __cplusplus
+} /* End of "C" linkage for C++ */
+#endif
+
+#endif /* __X86EMU_X86EMUI_H */
diff --git a/userspace/sdks/nv570/nvalloc/unix/src/asm/x86/nv_cpuid.c b/userspace/sdks/nv570/nvalloc/unix/src/asm/x86/nv_cpuid.c
new file mode 100644
index 0000000..fe6dfa9
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/src/asm/x86/nv_cpuid.c
@@ -0,0 +1,51 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 1999-2013 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <os/os.h>
+
+/* inline assembler routines for UNIX platforms */
+
+#if defined(NVCPU_X86_64)
+
+int osNv_cpuid(
+ int op,
+ int subop,
+ NvU32 *eax,
+ NvU32 *ebx,
+ NvU32 *ecx,
+ NvU32 *edx
+)
+{
+ asm volatile (" cpuid \n"
+ : "=a" (*eax),
+ "=b" (*ebx),
+ "=c" (*ecx),
+ "=d" (*edx)
+ : "a" (op),
+ "c" (subop)
+ : "cc");
+
+ return 1;
+}
+
+#endif
diff --git a/userspace/sdks/nv570/nvalloc/unix/src/asm/x86/nv_rdcr.c b/userspace/sdks/nv570/nvalloc/unix/src/asm/x86/nv_rdcr.c
new file mode 100644
index 0000000..6115aa4
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/src/asm/x86/nv_rdcr.c
@@ -0,0 +1,37 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 1999-2013 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <os/os.h>
+
+/* inline assembler routines for UNIX platforms */
+
+#if defined(NVCPU_X86_64)
+
+NvU32 osNv_rdcr4(void)
+{
+ NvU64 val;
+ asm volatile ("movq %%cr4,%0" : "=r" (val));
+ return (NvU32)val;
+}
+
+#endif
diff --git a/userspace/sdks/nv570/nvalloc/unix/src/dynamic-power.c b/userspace/sdks/nv570/nvalloc/unix/src/dynamic-power.c
new file mode 100644
index 0000000..fa61d94
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/src/dynamic-power.c
@@ -0,0 +1,3185 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2019-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <rmconfig.h>
+
+/*
+ * NOTE:
+ * The driver disables dynamic power management by effectively setting
+ * nv_dynamic_power_t::mode to NV_DYNAMIC_PM_NEVER at two places:
+ * 1) During module probe, when the _PRx methods are not supported
+ * by the SBIOS or when the kernel does not support runtime PM.
+ * 2) During RM Init, when the GPU is not Turing+ or when the system is not
+ * a laptop or when the VBIOS does not support RTD3/GC6.
+ *
+ * Thus, after RMInit, if the nv_dynamic_power_t::mode is still
+ * NV_DYNAMIC_PM_FINE, then we know for sure that the fine grained power
+ * control is active and running. In this case, the runtime D3 status is
+ * shown as "Enabled (fine-grained)".
+ *
+ * If the nv_dynamic_power_t::mode is NV_DYNAMIC_PM_NEVER, we have to
+ * distinguish between four cases:
+ * 1) The driver disabled dynamic power management due to lack of kernel/SBIOS
+ * support.
+ * 2) The driver disabled dynamic power management because the GPU does not
+ * support it or the system is not a laptop.
+ * 3) The user has explicitly disabled the feature.
+ * 4) Configuration is not supported by default.
+ *
+ * In order to differentiate between these four cases,
+ * we use the value of regkey NVreg_DynamicPowerManagement. If this value is
+ * set to 0, then we know that the user has explicitly disabled the
+ * feature. In this case we show the runtime D3 status as "Disabled". This
+ * handles case (3) above.
+ *
+ * For case (4), we look at the combination of nv_dynamic_power_t::mode and
+ * NVreg_DynamicPowerManagement value. If mode is never and regkey value is
+ * default, then status is shown as "Disabled by default".
+ *
+ * For remaining cases, (case (1) and (2)) we show status as "Not Supported".
+ *
+ * When the regkey is set to 0 and the driver disables the feature due to lack
+ * of some support, then precedence will be given to regkey value. Thus, when
+ * both "Not supported" and "Disabled" are possible values, precedence will be
+ * given to "Disabled" over "Not Supported".
+ *
+ * For coarse-grain power control, we show runtime D3 status as
+ * "Enabled (coarse-grained)".
+ *
+ * The runtime D3 status is shown as "?" when RM has not been initialized.
+ * This is because we do not have full knowledge regarding driver triggered
+ * disablement until RM is initialized.
+ */
+
+#include <nvlog_inc.h>
+#include <nv.h>
+#include <nv-priv.h>
+#include <nv-reg.h>
+#include <nv_ref.h>
+
+#include <osapi.h>
+
+#include <gpu/mem_mgr/mem_mgr.h>
+#include <gpu/kern_gpu_power.h>
+#include <gpu_mgr/gpu_mgr.h>
+#include <core/locks.h>
+#include <pex.h>
+#include <acpidsmguids.h>
+#include "kernel/gpu/intr/intr.h"
+
+#include <gpu/mem_sys/kern_mem_sys.h>
+#include <gpu/subdevice/subdevice.h>
+#include <ctrl/ctrl0080/ctrl0080gpu.h>
+#include <ctrl/ctrl2080/ctrl2080unix.h>
+#include <gpu/timer/objtmr.h>
+
+
+// mask holding dynamic power supported GPUs
+static NvU32 dynamicPowerSupportGpuMask = 0;
+
+//
+// Schedule timer based callback, to check for the complete GPU Idleness.
+// Windows has idle time from 70msec to 10sec, we opted for present duration
+// considering windows limit. Duration is not much aggressive or slow, hence
+// less thrashing.
+//
+#define GC6_PRECONDITION_CHECK_TIME ((NvU64)5 * 1000 * 1000 * 1000)
+
+//
+// iGPU needs a more aggressive timeout value of precondition
+// check to quickly engage the Rail-Gating state on an embedded
+// system.
+// Considering some basic scenarios like GPU monitoring which could
+// poll the GPU every 1 second, Rail-Gating cycle should not be triggered
+// in between the pollings. So the timeout value is set to 500 ms.
+// and the shortest duration to trigger Deferred-Idle would be
+// IGPU_RG_PRECONDITION_CHECK_TIME + IGPU_RG_BLOCKER_CHECK_AND_METHOD_FLUSH_TIME
+//
+#define IGPU_RG_PRECONDITION_CHECK_TIME ((NvU64)500 * 1000 * 1000)
+
+//
+// Timeout needed for back to back GC6 cycles.
+// Timeout is kept same as the timeout selected for GC6 precondition check.
+// There are cases where GPU is in GC6 and then kernel wakes GPU out of GC6
+// as part of say accessing pci tree through lspci and then again ask driver
+// to put GPU in GC6 state after access to device info is done.
+// Below are the reasons for having timeout limit for back to back GC6 cycle.
+// 1> Less chip life cycle.
+// 2> P-state is not reached to GC6 supported P-state, in some cycles.
+// P-state case returns error to kernel, resulting in corrupted sysfs entry
+// and then kernel never calls driver to put device in low power state.
+//
+#define GC6_CYCLE_IDLE_HOLDOFF_CHECK_TIME GC6_PRECONDITION_CHECK_TIME
+
+//
+// Once GPU is found to be idle, driver will schedule another callback of
+// smaller duration. Driver needs to be sure that methods that are present
+// in host pipeline are flushed to the respective engines and engines become
+// idle upon consumption.
+//
+#define GC6_BAR1_BLOCKER_CHECK_AND_METHOD_FLUSH_TIME (200 * 1000 * 1000)
+
+//
+// The purpose of this timeout value is similar to
+// GC6_BAR1_BLOCKER_CHECK_AND_METHOD_FLUSH_TIME.
+// The difference between iGPU Rail-Gating and GC6 is that iGPU RG has a more
+// aggressive timeout value of precondition check to quickly engage the
+// Rail-Gating state on an embedded system. Meanwhile, the overall duration
+// of Deferred-Idle should be larger than 1 second considering some polling
+// scenarios which happens every 1 second.
+// The value here is extended to 700 ms so the overall Deferred-Idle duration.
+// could be keep within within the range:
+// - Lower Bound: IGPU_RG_PRECONDITION_CHECK_TIME + IGPU_RG_BLOCKER_CHECK_AND_METHOD_FLUSH_TIME
+// - Upper Bound: IGPU_RG_PRECONDITION_CHECK_TIME * 2 + IGPU_RG_BLOCKER_CHECK_AND_METHOD_FLUSH_TIME
+//
+#define IGPU_RG_BLOCKER_CHECK_AND_METHOD_FLUSH_TIME (700 * 1000 * 1000)
+
+//
+// Cap Maximum FB allocation size for GCOFF. If regkey value is greater
+// than this value then it will be capped to this value.
+//
+#define GCOFF_DYNAMIC_PM_MAX_FB_SIZE_MB 1024
+
+//
+// Safe/Fallback value of PEX reset delay for GCOFF/GPUOFF.
+// Used when programming upstream port as per sku specific PEX reset delay from vbios fails
+//
+#define DEFAULT_GCOFF_PEXRST_DELAY 0
+
+static void RmScheduleCallbackForIdlePreConditions(OBJGPU *);
+static void RmScheduleCallbackForIdlePreConditionsUnderGpuLock(OBJGPU *);
+static void RmScheduleCallbackToIndicateIdle(OBJGPU *);
+static NvBool RmCheckForGcxSupportOnCurrentState(OBJGPU *);
+static void RmScheduleCallbackToRemoveIdleHoldoff(OBJGPU *);
+static void RmQueueIdleSustainedWorkitem(OBJGPU *);
+
+/*!
+ * @brief Wrapper that checks lock order for the dynamic power mutex. Locking
+ * order dictates that the GPU lock must not be taken before taking the dynamic
+ * power mutex.
+ *
+ * The GPU lock must not be held when calling this function.
+ *
+ * @param[in] nvp nv_priv_t pointer.
+ */
+static void acquireDynamicPowerMutex(nv_priv_t *nvp)
+{
+ /*
+ * Note that this may be called before nvp->pGpu has been initialized, for
+ * example at the very beginning of nv_start_device.
+ */
+ NV_ASSERT_CHECKED(!nvp->pGpu || !rmDeviceGpuLockIsOwner(nvp->pGpu->gpuInstance));
+
+ portSyncMutexAcquire(nvp->dynamic_power.mutex);
+}
+
+/*!
+ * @brief Wrapper to release the mutex, just for consistency with
+ * acquireDynamicPowerMutex() above.
+ *
+ * @param[in] nvp nv_priv_t pointer.
+ */
+static void releaseDynamicPowerMutex(nv_priv_t *nvp)
+{
+ portSyncMutexRelease(nvp->dynamic_power.mutex);
+}
+
+/*!
+ * @brief: Helper function to get a string for the given state.
+ *
+ * @param[in] state Dynamic power state.
+ *
+ * @return String for the given state.
+ */
+const char *nv_dynamic_power_state_string(
+ nv_dynamic_power_state_t state
+)
+{
+ switch (state)
+ {
+#define DPCASE(_case) \
+ case NV_DYNAMIC_POWER_STATE_ ## _case: return # _case;
+
+ DPCASE(IN_USE);
+ DPCASE(IDLE_INSTANT);
+ DPCASE(IDLE_SUSTAINED);
+ DPCASE(IDLE_INDICATED);
+ DPCASE(UNKNOWN);
+#undef DPCASE
+ }
+ NV_ASSERT(0);
+ return "UNEXPECTED";
+}
+
+/*!
+ * @brief: Helper function to transition the GPU represented by the 'nv'
+ * pointer from the power state 'old_state' to the power state 'new_state'.
+ *
+ * An atomic compare-and-swap is used; the function returns true if the
+ * operation was successful. If the function returns false, the state is
+ * unchanged.
+ *
+ * @param[in] nv nv_state_t pointer.
+ * @param[in] old_state Previous (current) state.
+ * @param[in] new_state New (requested) state.
+ *
+ * @return TRUE if the operation was successful; FALSE otherwise.
+ */
+NvBool nv_dynamic_power_state_transition(
+ nv_state_t *nv,
+ nv_dynamic_power_state_t old_state,
+ nv_dynamic_power_state_t new_state
+)
+{
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+
+ NV_ASSERT(old_state != new_state);
+
+ ct_assert(sizeof(nv_dynamic_power_state_t) == sizeof(NvS32));
+ NvBool ret = portAtomicCompareAndSwapS32((PORT_ATOMIC NvS32*)&nvp->dynamic_power.state,
+ (NvS32)new_state, (NvS32)old_state);
+
+ if (ret)
+ {
+ NV_PRINTF(LEVEL_INFO, "%s: state transition %s -> %s\n",
+ __FUNCTION__,
+ nv_dynamic_power_state_string(old_state),
+ nv_dynamic_power_state_string(new_state));
+ }
+ else
+ {
+ NV_PRINTF(LEVEL_INFO, "%s: FAILED state transition %s -> %s\n",
+ __FUNCTION__,
+ nv_dynamic_power_state_string(old_state),
+ nv_dynamic_power_state_string(new_state));
+ }
+
+ return ret;
+
+}
+
+/*!
+ * @brief: Check if the GPU hardware appears to be idle.
+ *
+ * Assumes the GPU lock is held.
+ *
+ * @param[in] pGpu OBJGPU pointer.
+ *
+ * @return TRUE if the GPU appears to be currently idle; FALSE otherwise.
+ */
+static NvBool RmCanEnterGcxUnderGpuLock(
+ OBJGPU *pGpu
+)
+{
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+
+ NV_ASSERT(rmDeviceGpuLockIsOwner(pGpu->gpuInstance));
+
+ /*
+ * If GC6 cannot be achieved (either GC6 is unsupported or the upstream port is not configured),
+ * Check for GCOFF prerequisites. Exclude the check for IGPU which has RG support.
+ */
+ if ((!pGpu->getProperty(pGpu, PDB_PROP_GPU_RTD3_GC6_SUPPORTED) ||
+ !nvp->gc6_upstream_port_configured) &&
+ (!pGpu->getProperty(pGpu, PDB_PROP_GPU_RTD3_RG_SUPPORTED)))
+ {
+ NvU64 usedFbSize = 0;
+ MemoryManager *pMemoryManager = GPU_GET_MEMORY_MANAGER(pGpu);
+
+ /*
+ * In order to enter GCOFF, the FB memory threshold should be less than gcoff_max_fb_size
+ * and clients of RM should not hold the refcount to prevent GCOFF.
+ */
+ if (!((memmgrGetUsedRamSize(pGpu, pMemoryManager, &usedFbSize) == NV_OK) &&
+ (usedFbSize <= nvp->dynamic_power.gcoff_max_fb_size) &&
+ (nvp->dynamic_power.clients_gcoff_disallow_refcount == 0)))
+ {
+ return NV_FALSE;
+ }
+ }
+
+ // Check the instantaneous engine level idleness.
+ return RmCheckForGcxSupportOnCurrentState(pGpu);
+}
+
+/*!
+ * @brief: Check the feasibility of GPU engaging in a GCx cycle.
+ *
+ * Takes the GPU lock.
+ *
+ * @param[in] pGpu OBJGPU pointer.
+ *
+ * @return TRUE if the GPU appears to be currently idle; FALSE otherwise.
+ */
+static NvBool RmCanEnterGcx(
+ OBJGPU *pGpu
+)
+{
+ NvBool result = NV_FALSE;
+ NV_STATUS status;
+ GPU_MASK gpuMask;
+
+ // LOCK: acquire per device lock
+ status = rmGpuGroupLockAcquire(pGpu->gpuInstance, GPU_LOCK_GRP_SUBDEVICE,
+ GPUS_LOCK_FLAGS_NONE, RM_LOCK_MODULES_DYN_POWER,
+ &gpuMask);
+ if (status == NV_OK)
+ {
+ result = RmCanEnterGcxUnderGpuLock(pGpu);
+ // UNLOCK: release per device lock
+ rmGpuGroupLockRelease(gpuMask, GPUS_LOCK_FLAGS_NONE);
+ }
+
+ return result;
+}
+
+/*!
+ * @brief: Force the GPU to be "not idle", if it had previously been indicated
+ * idle. This is triggered by GPU usage (i.e., writing through a revoked
+ * mapping), not tracked through the refcount maintained through
+ * os_{ref,unref}_dynamic_power. So, if we'd previously indicated the GPU was
+ * idle, we transition to the IDLE_INSTANT state.
+ *
+ * @param[in] gpuInstance GPU instance ID.
+ * @param[in] pArgs Unused callback closure.
+ */
+static void RmForceGpuNotIdle(
+ NvU32 gpuInstance,
+ void *pArgs
+)
+{
+ OBJGPU *pGpu = gpumgrGetGpu(gpuInstance);
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+ nv_dynamic_power_state_t old_state;
+ NvBool ret;
+
+ acquireDynamicPowerMutex(nvp);
+
+ old_state = nvp->dynamic_power.state;
+
+ switch (old_state)
+ {
+ case NV_DYNAMIC_POWER_STATE_IDLE_INDICATED:
+ nv_indicate_not_idle(nv);
+ NV_ASSERT(nvp->dynamic_power.deferred_idle_enabled);
+ RmScheduleCallbackForIdlePreConditions(pGpu);
+ /* fallthrough */
+ case NV_DYNAMIC_POWER_STATE_IDLE_SUSTAINED:
+ ret = nv_dynamic_power_state_transition(nv, old_state, NV_DYNAMIC_POWER_STATE_IDLE_INSTANT);
+ NV_ASSERT(ret);
+ break;
+ case NV_DYNAMIC_POWER_STATE_IDLE_INSTANT:
+ case NV_DYNAMIC_POWER_STATE_IN_USE:
+ break;
+ case NV_DYNAMIC_POWER_STATE_UNKNOWN:
+ NV_ASSERT(0);
+ break;
+ }
+
+ /*
+ * Now that the GPU is guaranteed to not be powered off, we can resume
+ * servicing mmap requests as usual.
+ */
+ nv_acquire_mmap_lock(nv);
+ nv_set_safe_to_mmap_locked(nv, NV_TRUE);
+ nv_release_mmap_lock(nv);
+
+ releaseDynamicPowerMutex(nvp);
+}
+
+/*!
+ * @brief: Work item to actually indicate the GPU is idle. This rechecks the
+ * preconditions one last time and verifies nothing has attempted to write
+ * through any mappings which were revoked.
+ *
+ * @param[in] gpuInstance GPU instance ID.
+ * @param[in] pArgs Unused callback closure.
+ */
+static void RmIndicateIdle(
+ NvU32 gpuInstance,
+ void *pArgs
+)
+{
+ OBJGPU *pGpu = gpumgrGetGpu(gpuInstance);
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+
+ acquireDynamicPowerMutex(nvp);
+
+ nv_acquire_mmap_lock(nv);
+
+ if (nv_get_all_mappings_revoked_locked(nv) &&
+ nvp->dynamic_power.state == NV_DYNAMIC_POWER_STATE_IDLE_SUSTAINED &&
+ RmCanEnterGcx(pGpu))
+ {
+ nv_set_safe_to_mmap_locked(nv, NV_FALSE);
+ nv_dynamic_power_state_transition(nv, NV_DYNAMIC_POWER_STATE_IDLE_SUSTAINED,
+ NV_DYNAMIC_POWER_STATE_IDLE_INDICATED);
+ nv_indicate_idle(nv);
+ }
+ else
+ {
+ RmScheduleCallbackForIdlePreConditions(pGpu);
+ }
+
+ nv_release_mmap_lock(nv);
+
+ releaseDynamicPowerMutex(nvp);
+}
+
+/*!
+ * @brief: Helper function to trigger the GPU to be forced indicated
+ * "non-idle", which powers it on if it had been previously powered off, and
+ * allows mmap processing to continue.
+ *
+ * Triggered when a revoked mapping is accessed.
+ *
+ * @param[in] sp nvidia_stack_t pointer.
+ * @param[in] nv nv_state_t pointer.
+ */
+NV_STATUS NV_API_CALL rm_schedule_gpu_wakeup(
+ nvidia_stack_t *sp,
+ nv_state_t *nv
+)
+{
+ void *fp;
+ NV_STATUS ret;
+ OBJGPU *pGpu = NV_GET_NV_PRIV_PGPU(nv);
+
+ NV_ENTER_RM_RUNTIME(sp, fp);
+
+ ret = osQueueWorkItem(pGpu,
+ RmForceGpuNotIdle,
+ NULL,
+ (OsQueueWorkItemFlags){0});
+
+ NV_EXIT_RM_RUNTIME(sp, fp);
+
+ return ret;
+}
+
+/*!
+ * @brief Function to increment/decrement refcount for GPU driving console.
+ *
+ * @params[in] nv nv_state_t pointer.
+ * @params[in] bIncrease If true, increase refcount else decrease.
+ */
+void
+RmUpdateGc6ConsoleRefCount
+(
+ nv_state_t *nv,
+ NvBool bIncrease
+)
+{
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+
+ if (nv->console_device == NV_FALSE)
+ {
+ return;
+ }
+
+ acquireDynamicPowerMutex(nvp);
+
+ if (bIncrease)
+ {
+ /*
+ * Here refcount value should atleast be 2 due to below:
+ * 1> Refcount increased by NV2080_CTRL_CMD_OS_UNIX_GC6_BLOCKER_REFCNT.
+ * 2> Refcount increased by the Rm entry points for current thread.
+ */
+ if (nvp->dynamic_power.refcount <= 1)
+ {
+ NV_PRINTF(LEVEL_INFO,
+ "%s: Unexpected dynamic power refcount value\n", __FUNCTION__);
+ }
+ else
+ {
+ nvp->dynamic_power.refcount++;
+ }
+ }
+ else
+ {
+ /*
+ * Here refcount value should atleast be 3 due to below:
+ * 1> Refcount set by RM at the probe time for console device.
+ * 2> Refcount increased by NV2080_CTRL_CMD_OS_UNIX_GC6_BLOCKER_REFCNT.
+ * 3> Refcount increased by the Rm entry points for current thread.
+ */
+ if (nvp->dynamic_power.refcount <= 2)
+ {
+ NV_PRINTF(LEVEL_INFO,
+ "%s: Unexpected dynamic power refcount value\n", __FUNCTION__);
+ }
+ else
+ {
+ nvp->dynamic_power.refcount--;
+ }
+ }
+
+ releaseDynamicPowerMutex(nvp);
+}
+
+/*!
+ * @brief Implements the NV2080_CTRL_CMD_OS_UNIX_GC6_BLOCKER_REFCNT RmControl
+ * request.
+ *
+ * @param[in] pSubdevice
+ * @param[in,out] pParams
+ *
+ * @return
+ * NV_OK Success
+ * NV_ERR_INVALID_ARGUMENT Invalid pParams->action
+ */
+NV_STATUS
+subdeviceCtrlCmdOsUnixGc6BlockerRefCnt_IMPL
+(
+ Subdevice *pSubdevice,
+ NV2080_CTRL_OS_UNIX_GC6_BLOCKER_REFCNT_PARAMS *pParams
+)
+{
+ OBJGPU *pGpu = GPU_RES_GET_GPU(pSubdevice);
+
+ /* TODO: keep track of inc/dec on a per-client basis, clean up after
+ * clients which are unbalanced. */
+ if (pParams->action == NV2080_CTRL_OS_UNIX_GC6_BLOCKER_REFCNT_INC)
+ {
+ return osRefGpuAccessNeeded(pGpu->pOsGpuInfo);
+ }
+ else if (pParams->action == NV2080_CTRL_OS_UNIX_GC6_BLOCKER_REFCNT_DEC)
+ {
+ osUnrefGpuAccessNeeded(pGpu->pOsGpuInfo);
+ }
+ else
+ {
+ return NV_ERR_INVALID_ARGUMENT;
+ }
+
+ return NV_OK;
+}
+
+/*!
+ * @brief Implements the NV2080_CTRL_CMD_OS_UNIX_AUDIO_DYNAMIC_POWER RmControl
+ * request. It will perform dynamic power management for GPU
+ * HDA contoller.
+ *
+ * @param[in] pSubdevice
+ * @param[in,out] pParams
+ *
+ * @return
+ * NV_OK Success
+ */
+NV_STATUS
+subdeviceCtrlCmdOsUnixAudioDynamicPower_IMPL
+(
+ Subdevice *pSubdevice,
+ NV2080_CTRL_OS_UNIX_AUDIO_DYNAMIC_POWER_PARAMS *pParams
+)
+{
+ OBJGPU *pGpu = GPU_RES_GET_GPU(pSubdevice);
+
+ /*
+ * Ideally, we need to honor pParams->bEnter. If it is true, then send the
+ * request for suspending the HDA controller and if is false, then send the
+ * request for waking up the HDA controller. Currently, for unix based OS,
+ * we don't have any proper way to do this and it is implemented with
+ * workaround. This workaround will wake up the HDA controller for few
+ * seconds and then bring it back to suspended state. We are using this
+ * workaround for both the cases (bEnter is true or false). It will help
+ * in keeping HDA controller active for the duration, when GPU is
+ * processing HDA controller commands (like writing ELD data).
+ */
+ nv_audio_dynamic_power(NV_GET_NV_STATE(pGpu));
+
+ return NV_OK;
+}
+
+/*!
+ * @brief: Function to indicate if GC6/GC-OFF is supported
+ * or not on the SKU.
+ *
+ * @param[in] pGpu OBJGPU pointer.
+ * @param[in] bGcxTypeGc6 If true, returns string indicating GC6 support
+ * otherwise returns GC-OFF support.
+ *
+ * @return String indicating GC6/GC-OFF support status.
+ */
+static const char* RmGetGpuGcxSupport(
+ OBJGPU *pGpu,
+ NvBool bGcxTypeGC6
+)
+{
+ if (!pGpu->getProperty(pGpu, PDB_PROP_GPU_UNIX_DYNAMIC_POWER_SUPPORTED))
+ {
+ return "Not Supported";
+ }
+
+ if (bGcxTypeGC6)
+ {
+ if (pGpu->getProperty(pGpu, PDB_PROP_GPU_RTD3_GC6_SUPPORTED))
+ {
+ return "Supported";
+ }
+ }
+ else
+ {
+ if ((pGpu->getProperty(pGpu, PDB_PROP_GPU_RTD3_GCOFF_SUPPORTED)) ||
+ (pGpu->getProperty(pGpu, PDB_PROP_GPU_LEGACY_GCOFF_SUPPORTED)))
+ {
+ return "Supported";
+ }
+ }
+
+ return "Not Supported";
+}
+
+/*!
+ * @brief Function to increment/decrement global Gcoff disallow refcount.
+ *
+ * @params[in] pOsGpuInfo OS specific GPU information pointer.
+ * @params[in] bIsGcoffDisallow If true, increase refcount else decrease.
+ */
+void osClientGcoffDisallowRefcount(
+ OS_GPU_INFO *pOsGpuInfo,
+ NvBool bIsGcoffDisallow
+)
+{
+ nv_priv_t *nvp = NV_GET_NV_PRIV(pOsGpuInfo);
+
+ if (nvp->dynamic_power.mode == NV_DYNAMIC_PM_NEVER)
+ {
+ return;
+ }
+
+ acquireDynamicPowerMutex(nvp);
+
+ if (bIsGcoffDisallow)
+ {
+ nvp->dynamic_power.clients_gcoff_disallow_refcount++;
+ }
+ else
+ {
+ nvp->dynamic_power.clients_gcoff_disallow_refcount--;
+ }
+
+ releaseDynamicPowerMutex(nvp);
+}
+
+/*!
+ * @brief Implements the NV2080_CTRL_CMD_OS_UNIX_ALLOW_DISALLOW_GCOFF RmControl
+ * request.
+ *
+ * @param[in] pSubdevice
+ * @param[in,out] pParams
+ *
+ * @return
+ * NV_OK Success
+ * NV_ERR_INVALID_ARGUMENT Invalid pParams->action
+ * NV_ERR_INVALID_OBJECT_HANDLE Invalid Object handle
+ * NV_ERR_OBJECT_NOT_FOUND Object not found
+ */
+NV_STATUS
+subdeviceCtrlCmdOsUnixAllowDisallowGcoff_IMPL
+(
+ Subdevice *pSubdevice,
+ NV2080_CTRL_OS_UNIX_ALLOW_DISALLOW_GCOFF_PARAMS *pParams
+)
+{
+ NV_STATUS status;
+ OBJGPU *pGpu = GPU_RES_GET_GPU(pSubdevice);
+
+ if (pParams->action == NV2080_CTRL_OS_UNIX_ALLOW_DISALLOW_GCOFF_ALLOW)
+ {
+ if (pSubdevice->bGcoffDisallowed)
+ {
+ pSubdevice->bGcoffDisallowed = NV_FALSE;
+ osClientGcoffDisallowRefcount(pGpu->pOsGpuInfo, NV_FALSE);
+ status = NV_OK;
+ }
+ else
+ {
+ NV_ASSERT(0);
+ status = NV_ERR_INVALID_ARGUMENT;
+ }
+ }
+ else if (pParams->action == NV2080_CTRL_OS_UNIX_ALLOW_DISALLOW_GCOFF_DISALLOW)
+ {
+ if (!pSubdevice->bGcoffDisallowed)
+ {
+ pSubdevice->bGcoffDisallowed = NV_TRUE;
+ osClientGcoffDisallowRefcount(pGpu->pOsGpuInfo, NV_TRUE);
+ status = NV_OK;
+ }
+ else
+ {
+ NV_ASSERT(0);
+ status = NV_ERR_INVALID_ARGUMENT;
+ }
+ }
+ else
+ {
+ status = NV_ERR_INVALID_ARGUMENT;
+ }
+
+ return status;
+}
+
+/*!
+ * @brief Read and Parse the Dynamic Power Management regkey.
+ * This function modifies the default value of regkey to either enable
+ * or disable RTD3 as per System form factor and GPU architecture.
+ *
+ * @param[in] pNv nv_state_t pointer.
+ * @param[out] pRegkeyValue Original value of regkey.
+ * @param[out] pOption Modified value of regkey.
+ *
+ * @return NV_STATUS code.
+ */
+
+#define NV_PMC_BOOT_42_CHIP_ID_GA102 0x00000172
+
+static NV_STATUS
+rmReadAndParseDynamicPowerRegkey
+(
+ nv_state_t *pNv,
+ NvU32 *pRegkeyValue,
+ NvU32 *pOption
+)
+{
+ NV_STATUS status;
+ NvU32 chipId;
+ nv_priv_t *pNvp = NV_GET_NV_PRIV(pNv);
+
+ status = osReadRegistryDword(NULL, NV_REG_DYNAMIC_POWER_MANAGEMENT, pRegkeyValue);
+
+ if (status != NV_OK)
+ return status;
+
+ // If User has set some value, honor that value
+ if (*pRegkeyValue != NV_REG_DYNAMIC_POWER_MANAGEMENT_DEFAULT)
+ {
+ *pOption = *pRegkeyValue;
+ return NV_OK;
+ }
+
+ chipId = decodePmcBoot42ChipId(pNvp->pmc_boot_42);
+
+ // From GA102+, we enable RTD3 only if system is found to be Notebook
+ if ((chipId >= NV_PMC_BOOT_42_CHIP_ID_GA102) &&
+ (rm_is_system_notebook()))
+ {
+ *pOption = NV_REG_DYNAMIC_POWER_MANAGEMENT_FINE;
+ return NV_OK;
+ }
+
+ // For Tegra PCI iGPU, support GPU Rail-Gating feature
+ if (pNv->supports_tegra_igpu_rg)
+ {
+ *pOption = NV_REG_DYNAMIC_POWER_MANAGEMENT_FINE;
+ return NV_OK;
+ }
+
+ *pOption = NV_REG_DYNAMIC_POWER_MANAGEMENT_NEVER;
+ return NV_OK;
+}
+#undef NV_PMC_BOOT_42_CHIP_ID_GA102
+
+/*!
+ * @brief Initialize state related to Tegra iGPU dynamic power management.
+ * Called once per GPU during driver initialization.
+ *
+ * @param[in] sp nvidia_stack_t pointer.
+ * @param[in] nv nv_state_t pointer.
+ */
+void NV_API_CALL rm_init_tegra_dynamic_power_management(
+ nvidia_stack_t *sp,
+ nv_state_t *nv
+)
+{
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+ void *fp;
+
+ if (!nv->supports_tegra_igpu_rg)
+ return;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+
+ portMemSet(&nvp->dynamic_power, 0, sizeof(nvp->dynamic_power));
+
+ nv->is_tegra_pci_igpu_rg_enabled = NV_FALSE;
+
+ NV_PRINTF(LEVEL_INFO,
+ "NVRM: Tegra PCI iGPU detected, Rail-Gating is supported.\n");
+
+ NV_EXIT_RM_RUNTIME(sp,fp);
+}
+
+void rm_check_s0ix_regkey_and_platform_support(void)
+{
+ OBJSYS *pSys = SYS_GET_INSTANCE();
+ NvU32 data;
+ NvBool status = ((nv_platform_supports_s0ix()) &&
+ ((osReadRegistryDword(NULL, NV_REG_ENABLE_S0IX_POWER_MANAGEMENT, &data) == NV_OK) && (data == 1)));
+
+ pSys->setProperty(pSys, PDB_PROP_SYS_SUPPORTS_S0IX, status);
+}
+
+/*!
+ * @brief Initialize state related to dynamic power management.
+ * Called once per GPU during driver initialization.
+ *
+ * @param[in] sp nvidia_stack_t pointer.
+ * @param[in] nv nv_state_t pointer.
+ */
+void NV_API_CALL rm_init_dynamic_power_management(
+ nvidia_stack_t *sp,
+ nv_state_t *nv,
+ NvBool bPr3AcpiMethodPresent
+)
+{
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+ NvU32 option = NV_REG_DYNAMIC_POWER_MANAGEMENT_NEVER;
+ NvU32 gcOffMaxFbSizeMb;
+ void *fp;
+ NvBool bUefiConsole;
+ NvU32 status;
+ NvU32 regkeyValue;
+ NvBool bIsTegraPciIgpuRgSupported = nv->supports_tegra_igpu_rg;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+
+ /*
+ * Program an impossible value so that we show correct status
+ * during procfs read of runtime D3 status.
+ */
+ nvp->dynamic_power.dynamic_power_regkey = 0xFFFFFFFFu;
+
+ /*
+ * Dynamic power management will be disabled in either of
+ * following 3 cases:
+ * 1. The driver does not support dynamic PM for this
+ * distro/kernel version.
+ * 2. _PR3 ACPI method is not supported by upstream port of GPU.
+ * 3. This feature is not enabled by regkey.
+ * Also see NOTE
+ */
+ status = rmReadAndParseDynamicPowerRegkey(nv, &regkeyValue, &option);
+
+ if (status == NV_OK)
+ {
+ nvp->dynamic_power.dynamic_power_regkey = regkeyValue;
+ }
+
+ nvp->pr3_acpi_method_present = bPr3AcpiMethodPresent;
+ if (!nv_dynamic_power_available(nv) || (status != NV_OK) ||
+ (!bPr3AcpiMethodPresent && !bIsTegraPciIgpuRgSupported))
+ {
+ NV_PRINTF(LEVEL_NOTICE,
+ "%s: Disabling dynamic power management either due to lack"
+ " of system support or due to error (%d) in reading regkey."
+ "\n", __FUNCTION__, status);
+ option = NV_REG_DYNAMIC_POWER_MANAGEMENT_NEVER;
+ }
+
+ /*
+ * Read the OS registry for Maximum FB size during GCOFF based dynamic PM.
+ * This will be capped to GCOFF_DYNAMIC_PM_MAX_FB_SIZE_MB.
+ */
+ if (osReadRegistryDword(NULL,
+ NV_REG_DYNAMIC_POWER_MANAGEMENT_VIDEO_MEMORY_THRESHOLD,
+ &gcOffMaxFbSizeMb) == NV_OK)
+ {
+ if (gcOffMaxFbSizeMb > GCOFF_DYNAMIC_PM_MAX_FB_SIZE_MB)
+ gcOffMaxFbSizeMb = GCOFF_DYNAMIC_PM_MAX_FB_SIZE_MB;
+ }
+ else
+ {
+ gcOffMaxFbSizeMb = GCOFF_DYNAMIC_PM_MAX_FB_SIZE_MB;
+ }
+
+ nvp->dynamic_power.gcoff_max_fb_size =
+ (NvU64)gcOffMaxFbSizeMb * 1024 * 1024;
+
+ nvp->dynamic_power.mutex = portSyncMutexCreate(portMemAllocatorGetGlobalNonPaged());
+ if (nvp->dynamic_power.mutex == NULL)
+ {
+ NV_PRINTF(LEVEL_ERROR,
+ "%s: failed to create power mutex\n", __FUNCTION__);
+ nvp->dynamic_power.mode = NV_DYNAMIC_PM_NEVER;
+ goto done;
+ }
+
+ switch (option)
+ {
+ case NV_REG_DYNAMIC_POWER_MANAGEMENT_FINE:
+ nvp->dynamic_power.mode = NV_DYNAMIC_PM_FINE;
+ break;
+ case NV_REG_DYNAMIC_POWER_MANAGEMENT_COARSE:
+ nvp->dynamic_power.mode = NV_DYNAMIC_PM_COARSE;
+ break;
+ default:
+ nv_printf(LEVEL_ERROR,
+ "NVRM: Unknown DynamicPowerManagement value '%u' specified; "
+ "disabling dynamic power management.\n", option);
+ // fallthrough
+ case NV_REG_DYNAMIC_POWER_MANAGEMENT_NEVER:
+ nvp->dynamic_power.mode = NV_DYNAMIC_PM_NEVER;
+ bIsTegraPciIgpuRgSupported = NV_FALSE;
+ break;
+ }
+
+ // Enable RTD3 infrastructure from OS side.
+ if ((nvp->dynamic_power.mode == NV_DYNAMIC_PM_FINE) &&
+ (nvp->dynamic_power.dynamic_power_regkey == NV_REG_DYNAMIC_POWER_MANAGEMENT_DEFAULT))
+ {
+ // Enable Dynamic Rail-Gating for Tegra PCI iGPU
+ if (bIsTegraPciIgpuRgSupported)
+ {
+ if (nv_pci_tegra_pm_init(nv))
+ {
+ nv_printf(NV_DBG_INFO, "NVRM: Tegra PCI iGPU railgating is enabled\n");
+ nv->is_tegra_pci_igpu_rg_enabled = NV_TRUE;
+
+ // Allow runtime suspend for Tegra PCI iGPU device with RG successfully enabled.
+ nv_allow_runtime_suspend(nv);
+ }
+ }
+ else
+ {
+ // Allow runtime suspend for the GPU which is not Tegra PCI iGPU device.
+ nv_allow_runtime_suspend(nv);
+ }
+ }
+
+ // UEFI case: where console is driven by GOP driver.
+ bUefiConsole = rm_get_uefi_console_status(nv);
+
+ nv->console_device = bUefiConsole || nv->primary_vga;
+
+ //
+ // Initialize refcount as 1 and state as IN_USE.
+ // rm_enable_dynamic_power_management() will decrease the refcount
+ // and change state to IDLE_INDICATED, if all prerequisites are met.
+ //
+ nvp->dynamic_power.refcount = 1;
+ nv_dynamic_power_state_transition(nv, NV_DYNAMIC_POWER_STATE_UNKNOWN,
+ NV_DYNAMIC_POWER_STATE_IN_USE);
+done:
+ NV_EXIT_RM_RUNTIME(sp,fp);
+}
+
+/*!
+ * @brief Clean up state related to dynamic power management.
+ * Called during driver removal.
+ *
+ * @param[in] sp nvidia_stack_t pointer.
+ * @param[in] nv nv_state_t pointer.
+ */
+void NV_API_CALL rm_cleanup_dynamic_power_management(
+ nvidia_stack_t *sp,
+ nv_state_t *nv
+)
+{
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+ void *fp;
+ NvBool ret;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+
+ // Disable RTD3 infrastructure from OS side.
+ if (((nvp->dynamic_power.mode == NV_DYNAMIC_PM_FINE) &&
+ (nvp->dynamic_power.dynamic_power_regkey == NV_REG_DYNAMIC_POWER_MANAGEMENT_DEFAULT)) ||
+ nv->is_tegra_pci_igpu_rg_enabled)
+ {
+ nv_disallow_runtime_suspend(nv);
+
+ // Disable Dynamic Rail-Gating for Tegra PCI iGPU
+ if (nv->is_tegra_pci_igpu_rg_enabled)
+ {
+ nv_pci_tegra_pm_deinit(nv);
+ nv->is_tegra_pci_igpu_rg_enabled = NV_FALSE;
+ nv_printf(NV_DBG_INFO, "NVRM: Tegra PCI iGPU railgating is disabled\n");
+ }
+ }
+
+ nv_dynamic_power_state_t old_state = nvp->dynamic_power.state;
+
+ switch (old_state)
+ {
+ case NV_DYNAMIC_POWER_STATE_IDLE_INDICATED:
+ nv_indicate_not_idle(nv);
+ /* fallthrough */
+ case NV_DYNAMIC_POWER_STATE_IDLE_SUSTAINED:
+ case NV_DYNAMIC_POWER_STATE_IDLE_INSTANT:
+ ret = nv_dynamic_power_state_transition(nv, old_state,
+ NV_DYNAMIC_POWER_STATE_IN_USE);
+ /*
+ * Nothing else should be running asynchronous to teardown that could
+ * change the state so this should always succeed.
+ */
+ NV_ASSERT(ret);
+ break;
+ case NV_DYNAMIC_POWER_STATE_IN_USE:
+ break;
+ case NV_DYNAMIC_POWER_STATE_UNKNOWN:
+ NV_ASSERT(0);
+ break;
+ }
+
+ if (nvp->dynamic_power.mutex)
+ {
+ portSyncMutexDestroy(nvp->dynamic_power.mutex);
+ nvp->dynamic_power.mutex = NULL;
+ }
+
+ NV_EXIT_RM_RUNTIME(sp,fp);
+}
+
+/*!
+ * @brief Initialize the dynamic power management refcount and enable GPUOFF,
+ * if all prerequisites are met.
+ * Called once per GPU during driver initialization.
+ *
+ * @param[in] sp nvidia_stack_t pointer.
+ * @param[in] nv nv_state_t pointer.
+ */
+void NV_API_CALL rm_enable_dynamic_power_management(
+ nvidia_stack_t *sp,
+ nv_state_t *nv
+)
+{
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+ void *fp;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+
+ /*
+ * If dynamic power management is enabled and device is not driving console,
+ * then dynamic power management can be engaged (since we're not
+ * using the GPU yet, so it's okay to power it off).
+ */
+ if ((nvp->dynamic_power.mode != NV_DYNAMIC_PM_NEVER) && !nv->console_device)
+ {
+ os_unref_dynamic_power(nv, NV_DYNAMIC_PM_COARSE);
+ }
+
+ NV_EXIT_RM_RUNTIME(sp,fp);
+}
+
+/*
+ * @brief Increment the dynamic power refcount to prevent the GPU from being
+ * powered off until a corresponding os_unref_dynamic_power() call is made.
+ * These two calls must always be balanced in pairs.
+ *
+ * This call may block until the GPU is powered on.
+ *
+ * The caller must not be holding the GPU lock, but may be holding the API
+ * lock.
+ *
+ * @param[in] sp nvidia_stack_t pointer.
+ * @param[in] mode Dynamic power mode this refcount bump is used for.
+ */
+NV_STATUS
+os_ref_dynamic_power(
+ nv_state_t *nv,
+ nv_dynamic_power_mode_t mode
+)
+{
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+ NV_STATUS status = NV_OK;
+ NvS32 ref;
+
+ if (nvp == NULL)
+ {
+ NV_ASSERT(nv->removed);
+ return NV_OK;
+ }
+
+ if (mode > nvp->dynamic_power.mode)
+ {
+ return NV_OK;
+ }
+
+ acquireDynamicPowerMutex(nvp);
+
+ ref = nvp->dynamic_power.refcount++;
+
+ NV_ASSERT(ref >= 0);
+
+ if (ref > 0)
+ {
+ NV_ASSERT(nvp->dynamic_power.state == NV_DYNAMIC_POWER_STATE_IN_USE);
+ }
+ else
+ {
+ /*
+ * Just transitioned from 0 -> 1.
+ * The current dynamic power state could be any of:
+ *
+ * - IDLE_INDICATED: call nv_indicate_not_idle() to ensure
+ * the GPU is at full power and ready to be used.
+ *
+ * - IDLE_INSTANT/IDLE_SUSTAINED: transition to IN_USE.
+ * Note that in these states, callbacks may be operating
+ * asynchronously, so care has to be taken to retry the write if it
+ * fails.
+ */
+
+ nv_dynamic_power_state_t old_state = nvp->dynamic_power.state;
+ NvBool ret;
+
+ switch (old_state)
+ {
+ default:
+ case NV_DYNAMIC_POWER_STATE_IN_USE:
+ NV_PRINTF(LEVEL_ERROR, "Unexpected dynamic power state 0x%x\n",
+ old_state);
+ /* fallthrough */
+ case NV_DYNAMIC_POWER_STATE_IDLE_INDICATED:
+ status = nv_indicate_not_idle(nv);
+ if (status != NV_OK)
+ {
+ nvp->dynamic_power.refcount--;
+ break;
+ }
+ if (nvp->dynamic_power.deferred_idle_enabled)
+ {
+ RmScheduleCallbackForIdlePreConditions(NV_GET_NV_PRIV_PGPU(nv));
+ }
+ /* fallthrough */
+ case NV_DYNAMIC_POWER_STATE_IDLE_SUSTAINED:
+ case NV_DYNAMIC_POWER_STATE_IDLE_INSTANT:
+ do {
+ ret = nv_dynamic_power_state_transition(nv, old_state, NV_DYNAMIC_POWER_STATE_IN_USE);
+ if (!ret)
+ {
+ old_state = nvp->dynamic_power.state;
+ NV_ASSERT(old_state == NV_DYNAMIC_POWER_STATE_IDLE_INSTANT ||
+ old_state == NV_DYNAMIC_POWER_STATE_IDLE_SUSTAINED);
+ }
+ } while (!ret);
+ break;
+ }
+ }
+
+ releaseDynamicPowerMutex(nvp);
+
+ return status;
+}
+
+/*
+ * @brief This function queries the dynamic boost support.
+ * This function returns -1 in case it failed to query the
+ * dynamic boost support. It returns 1 if dynamic boost is
+ * supported and returns 0 if dynamic boost is not supported.
+ *
+ * The caller must hold the API lock before calling this
+ * function.
+ *
+ * @param[in] nv nv_state_t pointer.
+ */
+static int os_get_dynamic_boost_support(
+ nv_state_t *nv
+)
+{
+ NV_STATUS status = NV_OK;
+ RM_API *pRmApi = rmapiGetInterface(RMAPI_GPU_LOCK_INTERNAL);
+ NV0000_CTRL_SYSTEM_NVPCF_GET_POWER_MODE_INFO_PARAMS *pNvpcfParams;
+ OBJGPU *pGpu;
+ int ret;
+
+ status = os_alloc_mem((void**)&pNvpcfParams, sizeof(*pNvpcfParams));
+ if (status != NV_OK)
+ {
+ NV_PRINTF(LEVEL_ERROR, "Failed to allocate memory\n");
+ ret = -1;
+ goto end;
+ }
+
+ pGpu = NV_GET_NV_PRIV_PGPU(nv);
+ pNvpcfParams->gpuId = pGpu->gpuId;
+ pNvpcfParams->subFunc =
+ NVPCF0100_CTRL_CONFIG_DSM_2X_FUNC_GET_SUPPORTED_CASE;
+ status = pRmApi->Control(pRmApi,
+ nv->rmapi.hClient,
+ nv->rmapi.hClient,
+ NV0000_CTRL_CMD_SYSTEM_NVPCF_GET_POWER_MODE_INFO,
+ (void*)pNvpcfParams,
+ sizeof(*pNvpcfParams));
+ if (status == NV_OK)
+ {
+ ret = 1;
+ }
+ else if (status == NV_ERR_NOT_SUPPORTED)
+ {
+ ret = 0;
+ }
+ else
+ {
+ ret = -1;
+ }
+
+ os_free_mem(pNvpcfParams);
+end:
+ return ret;
+}
+
+/*!
+ * @brief Wrapper around os_ref_dynamic_power() suitable for use from the
+ * per-OS layers.
+ *
+ * @param[in] sp nvidia_stack_t pointer.
+ * @param[in] nv nv_state_t pointer.
+ * @param[in] mode Dynamic power mode this refcount bump is used for.
+ */
+NV_STATUS NV_API_CALL rm_ref_dynamic_power(
+ nvidia_stack_t *sp,
+ nv_state_t *nv,
+ nv_dynamic_power_mode_t mode
+)
+{
+ NV_STATUS status;
+ void *fp;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+
+ status = os_ref_dynamic_power(nv, mode);
+
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return status;
+}
+
+/*!
+ * @brief Decrement the dynamic power refcount to release an earlier
+ * requirement that the GPU be powered on made by calling
+ * os_ref_dynamic_power().
+ * These two calls must always be balanced in pairs.
+ *
+ * This call may block until the GPU is powered on.
+ *
+ * The caller must not be holding the GPU lock, but may be holding the API
+ * lock.
+ *
+ * @param[in] sp nvidia_stack_t pointer.
+ * @param[in] mode Dynamic power mode this refcount bump is used for.
+ */
+void
+os_unref_dynamic_power(
+ nv_state_t *nv,
+ nv_dynamic_power_mode_t mode
+)
+{
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+ NvS32 ref;
+
+ if (nvp == NULL)
+ {
+ NV_ASSERT(nv->removed);
+ return;
+ }
+
+ if (mode > nvp->dynamic_power.mode)
+ {
+ return;
+ }
+
+ acquireDynamicPowerMutex(nvp);
+
+ ref = --nvp->dynamic_power.refcount;
+
+ NV_ASSERT(ref >= 0);
+
+ if (ref == 0) {
+ NvBool ret;
+
+ /*
+ * Just transitioned from 1 -> 0. We should have been in the IN_USE
+ * state previously; now we transition to an idle state: "instant" idle
+ * if deferred idle is enabled; otherwise indicate idle immediately.
+ *
+ * Nothing should be asynchronously changing the state from IN_USE,
+ * so the state transitions are not expected to fail.
+ */
+
+ NV_ASSERT(nvp->dynamic_power.state == NV_DYNAMIC_POWER_STATE_IN_USE);
+
+ if (nvp->dynamic_power.deferred_idle_enabled)
+ {
+ ret = nv_dynamic_power_state_transition(nv, NV_DYNAMIC_POWER_STATE_IN_USE,
+ NV_DYNAMIC_POWER_STATE_IDLE_INSTANT);
+ NV_ASSERT(ret);
+ }
+ else
+ {
+ nv_indicate_idle(nv);
+ ret = nv_dynamic_power_state_transition(nv, NV_DYNAMIC_POWER_STATE_IN_USE,
+ NV_DYNAMIC_POWER_STATE_IDLE_INDICATED);
+ NV_ASSERT(ret);
+ }
+ }
+
+ releaseDynamicPowerMutex(nvp);
+}
+
+/*!
+ * @brief Wrapper around os_unref_dynamic_power() suitable for use from the
+ * per-OS layers.
+ *
+ * @param[in] sp nvidia_stack_t pointer.
+ * @param[in] nv nv_state_t pointer.
+ * @param[in] mode Dynamic power mode this refcount bump is used for.
+ */
+void NV_API_CALL rm_unref_dynamic_power(
+ nvidia_stack_t *sp,
+ nv_state_t *nv,
+ nv_dynamic_power_mode_t mode
+)
+{
+ void *fp;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+
+ os_unref_dynamic_power(nv, mode);
+
+ NV_EXIT_RM_RUNTIME(sp,fp);
+}
+
+/*!
+ * @brief Wrapper around os_ref_dynamic_power() suitable for use from core RM.
+ *
+ * @params[in] pOsGpuInfo OS specific GPU information pointer
+ */
+NV_STATUS osRefGpuAccessNeeded(
+ OS_GPU_INFO *pOsGpuInfo
+)
+{
+ return os_ref_dynamic_power(pOsGpuInfo, NV_DYNAMIC_PM_FINE);
+}
+
+/*!
+ * @brief Wrapper around os_unref_dynamic_power() suitable for use from core RM.
+ *
+ * @params[in] pOsGpuInfo OS specific GPU information pointer
+ */
+void osUnrefGpuAccessNeeded(
+ OS_GPU_INFO *pOsGpuInfo
+)
+{
+ os_unref_dynamic_power(pOsGpuInfo, NV_DYNAMIC_PM_FINE);
+}
+
+/*!
+ * @brief Check if GCx is supported on current pstate and if engines are idle.
+ *
+ * @param[in] pGpu OBJGPU pointer.
+ */
+static NvBool RmCheckForGcxSupportOnCurrentState(
+ OBJGPU *pGpu
+)
+{
+ NV_STATUS status = NV_OK;
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ RM_API *pRmApi = rmapiGetInterface(RMAPI_GPU_LOCK_INTERNAL);
+ NV2080_CTRL_INTERNAL_GCX_ENTRY_PREREQUISITE_PARAMS entryPrerequisiteParams;
+
+ portMemSet(&entryPrerequisiteParams, 0, sizeof(entryPrerequisiteParams));
+
+ status = pRmApi->Control(pRmApi,
+ nv->rmapi.hClient,
+ nv->rmapi.hSubDevice,
+ NV2080_CTRL_CMD_INTERNAL_GCX_ENTRY_PREREQUISITE,
+ (void*)&entryPrerequisiteParams,
+ sizeof(entryPrerequisiteParams));
+
+ if (status != NV_OK)
+ {
+ NV_PRINTF(LEVEL_ERROR, "NVRM, Failed to get GCx pre-requisite, status=0x%x\n",
+ status);
+ return NV_FALSE;
+ }
+
+ return entryPrerequisiteParams.bIsGC6Satisfied || entryPrerequisiteParams.bIsGCOFFSatisfied;
+}
+
+/*!
+ * @brief: Work item to actually remove the idle holdoff which was applied
+ * on GC6 exit.
+ * This workitem is scheduled after the timeout limit for idle holdoff is
+ * finished.
+ *
+ * Queue with lock flags:
+ * bLockGpuGroupSubdevice
+ *
+ * @param[in] gpuInstance GPU instance ID.
+ * @param[in] pArgs Unused callback closure.
+ */
+static void RmRemoveIdleHoldoff(
+ NvU32 gpuInstance,
+ void *pArgs
+)
+{
+ OBJGPU *pGpu = gpumgrGetGpu(gpuInstance);
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+
+ if (nvp->dynamic_power.b_idle_holdoff == NV_TRUE)
+ {
+ if ((RmCheckForGcxSupportOnCurrentState(pGpu) == NV_TRUE) ||
+ (nvp->dynamic_power.idle_precondition_check_callback_scheduled))
+ {
+ nv_indicate_idle(nv);
+ nvp->dynamic_power.b_idle_holdoff = NV_FALSE;
+ }
+ else
+ {
+ RmScheduleCallbackToRemoveIdleHoldoff(pGpu);
+ }
+ }
+}
+
+/*!
+ * @brief Timer callback to schedule a work item to remove idle hold off
+ * that was applied after GC6 exit.
+ *
+ * @param[in] pCallbackData OBJGPU pointer (with void pointer type).
+ */
+static void timerCallbackToRemoveIdleHoldoff(
+ void *pCallbackData
+)
+{
+ NV_STATUS status = NV_OK;
+ OBJGPU *pGpu = reinterpretCast(pCallbackData, OBJGPU *);
+
+ status = osQueueWorkItem(pGpu,
+ RmRemoveIdleHoldoff,
+ NULL,
+ (OsQueueWorkItemFlags){.bLockGpuGroupSubdevice = NV_TRUE});
+
+ if (status != NV_OK)
+ {
+ NV_PRINTF(LEVEL_ERROR,
+ "Queuing of remove idle holdoff work item failed with status : 0x%x\n",
+ status);
+ }
+}
+
+/*!
+ * @brief Timer callback to check if all idle conditions remain met and
+ * if so schedule a work item to indicate the GPU is idle.
+ *
+ * @param[in] pCallbackData OBJGPU pointer (with void pointer type).
+ */
+static void timerCallbackToIndicateIdle(
+ void *pCallbackData
+)
+{
+ OBJGPU *pGpu = reinterpretCast(pCallbackData, OBJGPU *);
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+
+ nv_acquire_mmap_lock(nv);
+
+ if (nv_get_all_mappings_revoked_locked(nv) &&
+ nvp->dynamic_power.state == NV_DYNAMIC_POWER_STATE_IDLE_SUSTAINED &&
+ RmCanEnterGcxUnderGpuLock(pGpu))
+ {
+ osQueueWorkItem(pGpu,
+ RmIndicateIdle,
+ NULL,
+ (OsQueueWorkItemFlags){0});
+ }
+ else
+ {
+ if (nvp->dynamic_power.state == NV_DYNAMIC_POWER_STATE_IDLE_SUSTAINED)
+ {
+ /*
+ * Something used the GPU between when we last sampled and now.
+ * Go back to the "instant" state to start waiting from scratch.
+ */
+ nv_dynamic_power_state_transition(nv, NV_DYNAMIC_POWER_STATE_IDLE_SUSTAINED,
+ NV_DYNAMIC_POWER_STATE_IDLE_INSTANT);
+ }
+
+ RmScheduleCallbackForIdlePreConditionsUnderGpuLock(pGpu);
+ }
+
+ nv_release_mmap_lock(nv);
+}
+
+/*!
+ * @brief Timer callback to periodically check if all idle preconditions are
+ * met. If so, the dynamic power state is advanced from IDLE_INSTANT to
+ * IDLE_SUSTAINED, or (if already in the IDLE_SUSTAINED state) mappings are
+ * revoked and timerCallbackToIndicateIdle() is scheduled.
+ *
+ * @param[in] pCallbackData OBJGPU pointer (with void pointer type).
+ */
+static void timerCallbackForIdlePreConditions(
+ void *pCallbackData
+)
+{
+ OBJGPU *pGpu = reinterpretCast(pCallbackData, OBJGPU *);
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+
+ nvp->dynamic_power.idle_precondition_check_callback_scheduled = NV_FALSE;
+
+ /*
+ * Note: It is not safe to take the dynamic power mutex here.
+ * Lock ordering dictates that the dynamic power mutex must be taken before
+ * the GPU lock, and this function is called with the GPU lock held.
+ *
+ * Therefore, this function is careful about *only* triggering specific
+ * transitions:
+ * NV_DYNAMIC_POWER_STATE_IDLE_INSTANT -> NV_DYNAMIC_POWER_STATE_IDLE_SUSTAINED
+ * NV_DYNAMIC_POWER_STATE_IDLE_SUSTAINED -> NV_DYNAMIC_POWER_STATE_IDLE_INSTANT
+ *
+ * Other codepaths are resilient to these state transitions occurring
+ * asynchronously. The state transition itself is done with an atomic
+ * compare and swap, so there should be no danger of inadvertently
+ * triggering a transition from a different state due to a
+ * read-modify-write or "time of check to time of use" (TOCTTOU) race
+ * condition.
+ */
+
+ if (nvp->dynamic_power.state != NV_DYNAMIC_POWER_STATE_IN_USE)
+ {
+ if (RmCanEnterGcxUnderGpuLock(pGpu))
+ {
+ nv_dynamic_power_state_t state = nvp->dynamic_power.state;
+ switch (state)
+ {
+ case NV_DYNAMIC_POWER_STATE_UNKNOWN:
+ NV_ASSERT(0);
+ /* fallthrough */
+ case NV_DYNAMIC_POWER_STATE_IDLE_INDICATED:
+ NV_PRINTF(LEVEL_ERROR, "unexpected dynamic power state 0x%x\n",
+ nvp->dynamic_power.state);
+ /* fallthrough */
+ case NV_DYNAMIC_POWER_STATE_IN_USE:
+ break;
+ case NV_DYNAMIC_POWER_STATE_IDLE_INSTANT:
+ nv_dynamic_power_state_transition(nv, NV_DYNAMIC_POWER_STATE_IDLE_INSTANT,
+ NV_DYNAMIC_POWER_STATE_IDLE_SUSTAINED);
+ break;
+ case NV_DYNAMIC_POWER_STATE_IDLE_SUSTAINED:
+ RmQueueIdleSustainedWorkitem(pGpu);
+ return;
+ }
+
+ }
+ else
+ {
+ if (nvp->dynamic_power.state == NV_DYNAMIC_POWER_STATE_IDLE_SUSTAINED)
+ {
+ /*
+ * Something used the GPU between when we last sampled and now.
+ * Go back to the "instant" state to start waiting from scratch.
+ */
+ nv_dynamic_power_state_transition(nv, NV_DYNAMIC_POWER_STATE_IDLE_SUSTAINED,
+ NV_DYNAMIC_POWER_STATE_IDLE_INSTANT);
+ }
+ }
+ }
+ RmScheduleCallbackForIdlePreConditionsUnderGpuLock(pGpu);
+}
+
+/*!
+ * @brief Cancel any in-flight callback to remove idle holdoff.
+ *
+ * @param[in] pGpu OBJGPU pointer.
+ */
+static void RmCancelCallbackToRemoveIdleHoldoff(
+ OBJGPU *pGpu
+)
+{
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+ TMR_EVENT_GENERAL_PARAMS cancelParams;
+
+ if (NvP64_VALUE(nvp->dynamic_power.remove_idle_holdoff) != NULL)
+ {
+ portMemSet(&cancelParams, 0, sizeof(cancelParams));
+
+ cancelParams.pEvent = nvp->dynamic_power.remove_idle_holdoff;
+
+ tmrCtrlCmdEventCancel(pGpu, &cancelParams);
+ }
+}
+
+/*!
+ * @brief Cancel any in-flight timer callbacks.
+ *
+ * @param[in] pGpu OBJGPU pointer.
+ */
+static void RmCancelDynamicPowerCallbacks(
+ OBJGPU *pGpu
+)
+{
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+ TMR_EVENT_GENERAL_PARAMS cancelParams;
+
+ if (NvP64_VALUE(nvp->dynamic_power.idle_precondition_check_event) != NULL)
+ {
+ // Cancel precondition check callback.
+ portMemSet(&cancelParams, 0, sizeof(cancelParams));
+
+ cancelParams.pEvent = nvp->dynamic_power.idle_precondition_check_event;
+
+ tmrCtrlCmdEventCancel(pGpu, &cancelParams);
+ }
+
+ if (NvP64_VALUE(nvp->dynamic_power.indicate_idle_event) != NULL)
+ {
+ // Cancel callback to indicate idle
+ portMemSet(&cancelParams, 0, sizeof(cancelParams));
+
+ cancelParams.pEvent = nvp->dynamic_power.indicate_idle_event;
+
+ tmrCtrlCmdEventCancel(pGpu, &cancelParams);
+ }
+
+ RmCancelCallbackToRemoveIdleHoldoff(pGpu);
+
+ nvp->dynamic_power.idle_precondition_check_callback_scheduled = NV_FALSE;
+}
+
+/*!
+ * @brief Free timer events allocated by CreateDynamicPowerCallbacks()
+ *
+ * @param[in] pGpu OBJGPU pointer.
+ */
+static void RmDestroyDynamicPowerCallbacks(
+ OBJGPU *pGpu
+)
+{
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+ TMR_EVENT_GENERAL_PARAMS destroyParams;
+
+ if (NvP64_VALUE(nvp->dynamic_power.idle_precondition_check_event) != NULL)
+ {
+ // Destroy precondition check callback.
+ portMemSet(&destroyParams, 0, sizeof(destroyParams));
+
+ destroyParams.pEvent = nvp->dynamic_power.idle_precondition_check_event;
+
+ tmrCtrlCmdEventDestroy(pGpu, &destroyParams);
+ nvp->dynamic_power.idle_precondition_check_event = NvP64_NULL;
+ }
+
+ if (NvP64_VALUE(nvp->dynamic_power.indicate_idle_event) != NULL)
+ {
+ // Destroy callback to indicate idle
+ portMemSet(&destroyParams, 0, sizeof(destroyParams));
+
+ destroyParams.pEvent = nvp->dynamic_power.indicate_idle_event;
+
+ tmrCtrlCmdEventDestroy(pGpu, &destroyParams);
+ nvp->dynamic_power.indicate_idle_event = NvP64_NULL;
+ }
+
+ if (NvP64_VALUE(nvp->dynamic_power.remove_idle_holdoff) != NULL)
+ {
+ // Destroy callback to decrease kernel refcount
+ portMemSet(&destroyParams, 0, sizeof(destroyParams));
+
+ destroyParams.pEvent = nvp->dynamic_power.remove_idle_holdoff;
+
+ tmrCtrlCmdEventDestroy(pGpu, &destroyParams);
+ nvp->dynamic_power.remove_idle_holdoff = NvP64_NULL;
+ }
+
+ nvp->dynamic_power.deferred_idle_enabled = NV_FALSE;
+}
+
+/*
+ * @brief Adds a GPU to dynamicPowerSupportGpuMask
+ *
+ * @param[in] instance
+ */
+static void AddGpuDynamicPowerSupported
+(
+ NvU32 instance
+)
+{
+ dynamicPowerSupportGpuMask |= NVBIT(instance);
+}
+
+/*
+ * @brief Removes a GPU from dynamicPowerSupportGpuMask
+ *
+ * @param[in] instance
+ */
+static void RemoveGpuDynamicPowerSupported
+(
+ NvU32 instance
+)
+{
+ dynamicPowerSupportGpuMask &= ~NVBIT(instance);
+}
+
+/*
+ * @brief queries dynamicPowerSupportGpuMask
+ *
+ * @param[in] void
+ */
+NvU32 osGetDynamicPowerSupportMask
+(
+ void
+)
+{
+ return dynamicPowerSupportGpuMask;
+}
+
+/*!
+ * @brief Cancel any outstanding callbacks, and free RM resources allocated by
+ * RmInitDeferredDynamicPowerManagement().
+ *
+ * @param[in] nv nv_state_t pointer.
+ */
+void RmDestroyDeferredDynamicPowerManagement(
+ nv_state_t *nv
+)
+{
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+ OBJGPU *pGpu = NV_GET_NV_PRIV_PGPU(nv);
+
+ //
+ // Re-instate the dynamic power mode to fine if it was
+ // disabled due to lack of platform support
+ //
+ if (nvp->dynamic_power.b_fine_not_supported == NV_TRUE)
+ {
+ nvp->dynamic_power.mode = NV_DYNAMIC_PM_FINE;
+ nvp->dynamic_power.b_fine_not_supported = NV_FALSE;
+ }
+
+ //
+ // Before cancelling and destroying the callbacks, make sure to
+ // remove the idle holfoff that was applied during gc6 exit.
+ //
+ if (nvp->dynamic_power.b_idle_holdoff == NV_TRUE)
+ {
+ nv_indicate_idle(nv);
+ nvp->dynamic_power.b_idle_holdoff = NV_FALSE;
+ }
+
+ RmCancelDynamicPowerCallbacks(pGpu);
+ RmDestroyDynamicPowerCallbacks(pGpu);
+ RemoveGpuDynamicPowerSupported(gpuGetInstance(pGpu));
+}
+
+/*!
+ * @brief Allocate timer events to call the functions:
+ * timerCallbackForIdlePreConditions()
+ * timerCallbackToIndicateIdle()
+ *
+ * The callbacks must be scheduled separately.
+ *
+ * @param[in] pGpu OBJGPU pointer.
+ */
+static NV_STATUS CreateDynamicPowerCallbacks(
+ OBJGPU *pGpu
+)
+{
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+ TMR_EVENT_SET_PARAMS createEventParams;
+ NV_STATUS status;
+
+ // Creating PreCondition check callback.
+ portMemSet(&createEventParams, 0, sizeof(createEventParams));
+
+ createEventParams.ppEvent = &(nvp->dynamic_power.idle_precondition_check_event);
+ createEventParams.pTimeProc = NV_PTR_TO_NvP64(timerCallbackForIdlePreConditions);
+ createEventParams.pCallbackData = NV_PTR_TO_NvP64(pGpu);
+ createEventParams.flags = TMR_FLAG_USE_OS_TIMER;
+
+ status = tmrCtrlCmdEventCreate(pGpu, &createEventParams);
+
+ if (status != NV_OK)
+ {
+ NV_PRINTF(LEVEL_ERROR,
+ "Error creating dynamic power precondition check callback\n");
+ nvp->dynamic_power.idle_precondition_check_event = NvP64_NULL;
+ nvp->dynamic_power.indicate_idle_event = NvP64_NULL;
+ nvp->dynamic_power.remove_idle_holdoff = NvP64_NULL;
+ return status;
+ }
+
+ // Create callback to indicate idle..
+ portMemSet(&createEventParams, 0, sizeof(createEventParams));
+
+ createEventParams.ppEvent = &(nvp->dynamic_power.indicate_idle_event);
+ createEventParams.pTimeProc = NV_PTR_TO_NvP64(timerCallbackToIndicateIdle);
+ createEventParams.pCallbackData = NV_PTR_TO_NvP64(pGpu);
+ createEventParams.flags = TMR_FLAG_USE_OS_TIMER;
+
+ status = tmrCtrlCmdEventCreate(pGpu, &createEventParams);
+
+ if (status != NV_OK)
+ {
+ NV_PRINTF(LEVEL_ERROR,
+ "Error creating callback to indicate GPU idle\n");
+ nvp->dynamic_power.idle_precondition_check_event = NvP64_NULL;
+ nvp->dynamic_power.indicate_idle_event = NvP64_NULL;
+ nvp->dynamic_power.remove_idle_holdoff = NvP64_NULL;
+ return status;
+ }
+
+ // Create callback to remove idle holdoff
+ portMemSet(&createEventParams, 0, sizeof(createEventParams));
+
+ createEventParams.ppEvent = &(nvp->dynamic_power.remove_idle_holdoff);
+ createEventParams.pTimeProc = NV_PTR_TO_NvP64(timerCallbackToRemoveIdleHoldoff);
+ createEventParams.pCallbackData = NV_PTR_TO_NvP64(pGpu);
+ createEventParams.flags = TMR_FLAG_USE_OS_TIMER;
+
+ status = tmrCtrlCmdEventCreate(pGpu, &createEventParams);
+
+ if (status != NV_OK)
+ {
+ NV_PRINTF(LEVEL_ERROR,
+ "Error creating callback to decrease kernel refcount\n");
+ nvp->dynamic_power.idle_precondition_check_event = NvP64_NULL;
+ nvp->dynamic_power.indicate_idle_event = NvP64_NULL;
+ nvp->dynamic_power.remove_idle_holdoff = NvP64_NULL;
+ return status;
+ }
+
+ return NV_OK;
+}
+
+/*!
+ * @brief Schedule the timerCallbackForIdlePreConditions() function to be called.
+ *
+ * If it is already scheduled, the function is a noop.
+ *
+ * The GPU lock must be held when calling this function.
+ *
+ * @param[in] pGpu OBJGPU pointer.
+ */
+static void RmScheduleCallbackForIdlePreConditionsUnderGpuLock(
+ OBJGPU *pGpu
+)
+{
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+ TMR_EVENT_SCHEDULE_PARAMS scheduleEventParams;
+ NV_STATUS status;
+
+ NV_ASSERT(rmDeviceGpuLockIsOwner(pGpu->gpuInstance));
+
+ if (nvp->dynamic_power.idle_precondition_check_callback_scheduled)
+ {
+ return;
+ }
+
+ if (NvP64_VALUE(nvp->dynamic_power.idle_precondition_check_event) != NULL)
+ {
+ portMemSet(&scheduleEventParams, 0, sizeof(scheduleEventParams));
+
+ scheduleEventParams.pEvent = nvp->dynamic_power.idle_precondition_check_event;
+ scheduleEventParams.bUseTimeAbs = NV_FALSE;
+ if (pGpu->getProperty(pGpu, PDB_PROP_GPU_RTD3_RG_SUPPORTED))
+ {
+ /*
+ * iGPU which supports Rail-Gating may want shorter idleness
+ * threshold to engage the deferred-idle transition.
+ * Set the threshold for precondition check to 500 ms.
+ */
+ scheduleEventParams.timeNs = IGPU_RG_PRECONDITION_CHECK_TIME;
+ }
+ else
+ {
+ scheduleEventParams.timeNs = GC6_PRECONDITION_CHECK_TIME;
+ }
+
+ status = tmrCtrlCmdEventSchedule(pGpu, &scheduleEventParams);
+
+ if (status == NV_OK)
+ {
+ nvp->dynamic_power.idle_precondition_check_callback_scheduled = NV_TRUE;
+ }
+ else
+ {
+ NV_PRINTF(LEVEL_ERROR, "Error scheduling precondition callback\n");
+ }
+ }
+}
+
+/*!
+ * @brief Schedule the timerCallbackForIdlePreConditions() function to be called.
+ *
+ * If it is already scheduled, the function is a noop.
+ *
+ * This function takes the GPU lock.
+ *
+ * @param[in] pGpu OBJGPU pointer.
+ */
+static void RmScheduleCallbackForIdlePreConditions(
+ OBJGPU *pGpu
+)
+{
+ NV_STATUS status;
+ GPU_MASK gpuMask;
+
+ // LOCK: acquire per device lock
+ status = rmGpuGroupLockAcquire(pGpu->gpuInstance, GPU_LOCK_GRP_SUBDEVICE,
+ GPUS_LOCK_FLAGS_NONE, RM_LOCK_MODULES_DYN_POWER,
+ &gpuMask);
+ if (status == NV_OK)
+ {
+ RmScheduleCallbackForIdlePreConditionsUnderGpuLock(pGpu);
+ // UNLOCK: release per device lock
+ rmGpuGroupLockRelease(gpuMask, GPUS_LOCK_FLAGS_NONE);
+ }
+}
+
+/*!
+ * @brief Schedule the timerCallbackToIndicateIdle() function to be called.
+ *
+ * The GPU lock must be held when calling this function.
+ *
+ * @param[in] pGpu OBJGPU pointer.
+ */
+static void RmScheduleCallbackToIndicateIdle(
+ OBJGPU *pGpu
+)
+{
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+ TMR_EVENT_SCHEDULE_PARAMS scheduleEventParams;
+ NV_STATUS status;
+
+ NV_ASSERT(rmDeviceGpuLockIsOwner(pGpu->gpuInstance));
+
+ if (NvP64_VALUE(nvp->dynamic_power.indicate_idle_event) != NULL)
+ {
+ portMemSet(&scheduleEventParams, 0, sizeof(scheduleEventParams));
+
+ scheduleEventParams.pEvent = nvp->dynamic_power.indicate_idle_event;
+ scheduleEventParams.bUseTimeAbs = NV_FALSE;
+ if (pGpu->getProperty(pGpu, PDB_PROP_GPU_RTD3_RG_SUPPORTED))
+ {
+ /*
+ * iGPU which supports Rail-Gating may want shorter idleness
+ * threshold to engage the deferred-idle transition.
+ * Set the threshold for idle indicate to 700 ms.
+ */
+ scheduleEventParams.timeNs = IGPU_RG_BLOCKER_CHECK_AND_METHOD_FLUSH_TIME;
+ }
+ else
+ {
+ scheduleEventParams.timeNs = GC6_BAR1_BLOCKER_CHECK_AND_METHOD_FLUSH_TIME;
+ }
+
+ status = tmrCtrlCmdEventSchedule(pGpu, &scheduleEventParams);
+
+ if (status != NV_OK)
+ NV_PRINTF(LEVEL_ERROR, "Error scheduling indicate idle callback\n");
+ }
+}
+
+/*!
+ * @brief Schedule the timerCallbackToRemoveIdleHoldoff() function.
+ *
+ * The GPU lock must be held when calling this function.
+ *
+ * @param[in] pGpu OBJGPU pointer.
+ */
+static void RmScheduleCallbackToRemoveIdleHoldoff(
+ OBJGPU *pGpu
+)
+{
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+ TMR_EVENT_SCHEDULE_PARAMS scheduleEventParams;
+ NV_STATUS status;
+
+ NV_ASSERT(rmDeviceGpuLockIsOwner(pGpu->gpuInstance));
+
+ if (NvP64_VALUE(nvp->dynamic_power.remove_idle_holdoff) != NULL)
+ {
+ portMemSet(&scheduleEventParams, 0, sizeof(scheduleEventParams));
+
+ scheduleEventParams.pEvent = nvp->dynamic_power.remove_idle_holdoff;
+ scheduleEventParams.timeNs = GC6_CYCLE_IDLE_HOLDOFF_CHECK_TIME;
+ scheduleEventParams.bUseTimeAbs = NV_FALSE;
+
+ status = tmrCtrlCmdEventSchedule(pGpu, &scheduleEventParams);
+
+ if (status != NV_OK)
+ {
+ NV_PRINTF(LEVEL_ERROR,
+ "Error scheduling kernel refcount decrement callback\n");
+ }
+ else
+ {
+ nvp->dynamic_power.b_idle_holdoff = NV_TRUE;
+ }
+ }
+}
+
+/*!
+ * @brief Check if the system supports RTD3-GC6.
+ *
+ * @param[in] pGpu OBJGPU pointer.
+ */
+static NvBool RmCheckRtd3GcxSupport(
+ nv_state_t *pNv,
+ NvBool *bGC6Support,
+ NvBool *bGCOFFSupport
+)
+{
+ nv_priv_t *nvp = NV_GET_NV_PRIV(pNv);
+ OBJGPU *pGpu = NV_GET_NV_PRIV_PGPU(pNv);
+ RM_API *pRmApi = rmapiGetInterface(RMAPI_GPU_LOCK_INTERNAL);
+ NV_STATUS status;
+ NV0080_CTRL_GPU_GET_VIRTUALIZATION_MODE_PARAMS virtModeParams = { 0 };
+ if (!pGpu->getProperty(pGpu, PDB_PROP_GPU_UNIX_DYNAMIC_POWER_SUPPORTED))
+ {
+ NV_PRINTF(LEVEL_NOTICE, "RTD3 is not supported for this arch\n");
+ return NV_FALSE;
+ }
+
+ *bGC6Support = pGpu->getProperty(pGpu, PDB_PROP_GPU_RTD3_GC6_SUPPORTED);
+ *bGCOFFSupport = pGpu->getProperty(pGpu, PDB_PROP_GPU_RTD3_GCOFF_SUPPORTED) ||
+ pGpu->getProperty(pGpu, PDB_PROP_GPU_LEGACY_GCOFF_SUPPORTED);
+
+ if (!(*bGC6Support) &&
+ !(*bGCOFFSupport) &&
+ !(pGpu->getProperty(pGpu, PDB_PROP_GPU_RTD3_RG_SUPPORTED)))
+ {
+ NV_PRINTF(LEVEL_NOTICE,
+ "Disabling RTD3. [GC6 support=%d GCOFF support=%d RG support=%d]\n",
+ *bGC6Support,
+ *bGCOFFSupport,
+ pGpu->getProperty(pGpu, PDB_PROP_GPU_RTD3_RG_SUPPORTED));
+ return NV_FALSE;
+ }
+
+ status = pRmApi->Control(pRmApi, pNv->rmapi.hClient, pNv->rmapi.hDevice,
+ NV0080_CTRL_CMD_GPU_GET_VIRTUALIZATION_MODE,
+ &virtModeParams, sizeof(virtModeParams));
+
+ if (status != NV_OK)
+ {
+ NV_PRINTF(LEVEL_ERROR,
+ "Failed to get Virtualization mode, status=0x%x\n",
+ status);
+ return NV_FALSE;
+ }
+
+ if ((virtModeParams.virtualizationMode != NV0080_CTRL_GPU_VIRTUALIZATION_MODE_NONE) &&
+ (virtModeParams.virtualizationMode != NV0080_CTRL_GPU_VIRTUALIZATION_MODE_NMOS))
+ {
+ NV_PRINTF(LEVEL_NOTICE, "RTD3 is not supported on VM\n");
+ return NV_FALSE;
+ }
+
+ if (!nvp->pr3_acpi_method_present &&
+ !(pGpu->getProperty(pGpu, PDB_PROP_GPU_RTD3_RG_SUPPORTED)))
+ {
+ NV_PRINTF(LEVEL_NOTICE, "RTD3 ACPI support is not available.\n");
+ return NV_FALSE;
+ }
+
+ return NV_TRUE;
+}
+
+/*!
+ * @brief Allocate resources needed to track deferred power management, and
+ * schedule the initial periodic callbacks.
+ *
+ * @param[in] nv nv_state_t pointer.
+ */
+static void RmInitDeferredDynamicPowerManagement(
+ nv_state_t *nv,
+ NvBool bRtd3Support
+)
+{
+ NV_STATUS status;
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+
+ if (nvp->dynamic_power.mode == NV_DYNAMIC_PM_FINE)
+ {
+ OBJGPU *pGpu = NV_GET_NV_PRIV_PGPU(nv);
+
+ if (!bRtd3Support)
+ {
+ nvp->dynamic_power.mode = NV_DYNAMIC_PM_NEVER;
+ nvp->dynamic_power.b_fine_not_supported = NV_TRUE;
+ NV_PRINTF(LEVEL_NOTICE, "RTD3 is not supported.\n");
+ return;
+ }
+ AddGpuDynamicPowerSupported(gpuGetInstance(pGpu));
+ nvp->dynamic_power.b_fine_not_supported = NV_FALSE;
+ status = CreateDynamicPowerCallbacks(pGpu);
+
+ if (status == NV_OK)
+ {
+ RmScheduleCallbackForIdlePreConditionsUnderGpuLock(pGpu);
+
+ nvp->dynamic_power.deferred_idle_enabled = NV_TRUE;
+ // RM's default is GCOFF allow
+ nvp->dynamic_power.clients_gcoff_disallow_refcount = 0;
+ }
+ else
+ {
+ NV_PRINTF(LEVEL_ERROR, "Failed to register for dynamic power callbacks\n");
+ }
+ }
+}
+
+/*!
+ * @brief Check if GCOFF state can be used for Power Management.
+ *
+ * @param[in] pGpu OBJGPU pointer.
+ * @param[in] usedFbSize Used FB Allocation size.
+ * @param[in] bIsDynamicPM If true, check for dynamic PM; otherwise, check
+ * for system PM (suspend/resume).
+ *
+ * returns NV_TRUE if GCOFF state can be used, otherwise NV_FALSE.
+ *
+ */
+static NvBool RmCheckForGcOffPM(
+ OBJGPU *pGpu,
+ NvU64 usedFbSize,
+ NvBool bIsDynamicPM
+)
+{
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+ NvU64 gcoff_max_fb_size;
+
+ if (bIsDynamicPM)
+ {
+ /*
+ * GCOFF won't be enaged for Dynamic PM if X server does not allow.
+ * The dynamic_power.clients_gcoff_disallow_refcount is being accessed
+ * without acquiring dynamic power mutex since this value can be
+ * modified only when GPU is in active state. The os_ref_dynamic_power()
+ * function will be called to hold a reference to the GPU whenever
+ * RM is processing osClientGcoffDisallowRefcount() calls. This either
+ * prevents the GPU from going into a low power state or will wait for
+ * it to be resumed before proceeding.
+ */
+ if (nvp->dynamic_power.clients_gcoff_disallow_refcount != 0)
+ return NV_FALSE;
+
+ gcoff_max_fb_size = nvp->dynamic_power.gcoff_max_fb_size;
+ }
+ else
+ {
+ gcoff_max_fb_size = nvp->s0ix_gcoff_max_fb_size;
+ }
+
+ /*
+ * GCOFF will be engaged whenever the following necessary preconditions
+ * are met:
+ *
+ * 1. The GCOFF has not been disabled with regkey by setting it to zero.
+ * 2. Used FB allocation size are within limits.
+ */
+ return (gcoff_max_fb_size > 0) &&
+ (usedFbSize <= gcoff_max_fb_size);
+}
+
+//
+// Function to update fixed fbsr modes to support multiple vairants such as
+// GCOFF and cuda S3/resume.
+//
+static void
+RmUpdateFixedFbsrModes(OBJGPU *pGpu)
+{
+ MemoryManager *pMemoryManager = GPU_GET_MEMORY_MANAGER(pGpu);
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+
+ if (pGpu->getProperty(pGpu, PDB_PROP_GPU_GCOFF_STATE_ENTERING))
+ {
+ pMemoryManager->fixedFbsrModesMask = NVBIT(FBSR_TYPE_DMA);
+ }
+ else if (nv->preserve_vidmem_allocations)
+ {
+ pMemoryManager->fixedFbsrModesMask = NVBIT(FBSR_TYPE_FILE);
+ }
+}
+
+static NV_STATUS
+RmPowerManagement(
+ OBJGPU *pGpu,
+ nv_pm_action_t pmAction
+)
+{
+ // default to NV_OK. there may cases where resman is loaded, but
+ // no devices are allocated (we're still at the console). in these
+ // cases, it's fine to let the system do whatever it wants.
+ NV_STATUS rmStatus = NV_OK;
+
+ if (pGpu)
+ {
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+ NvBool bcState = gpumgrGetBcEnabledStatus(pGpu);
+ Intr *pIntr = GPU_GET_INTR(pGpu);
+ MemoryManager *pMemoryManager = GPU_GET_MEMORY_MANAGER(pGpu);
+
+ if ((pmAction == NV_PM_ACTION_HIBERNATE) || (pmAction == NV_PM_ACTION_STANDBY))
+ {
+ //
+ // pFb object store the FBSR mode through which FB state unload has happened,
+ // so os layer doesn't need to set FBSR mode on resume.
+ //
+ RmUpdateFixedFbsrModes(pGpu);
+ }
+
+ switch (pmAction)
+ {
+ case NV_PM_ACTION_HIBERNATE:
+ nvp->pm_state.InHibernate = NV_TRUE;
+ nvp->pm_state.IntrEn = intrGetIntrEn(pIntr);
+ intrSetIntrEn(pIntr, INTERRUPT_TYPE_DISABLED);
+ gpumgrSetBcEnabledStatus(pGpu, NV_FALSE);
+
+ rmStatus = gpuEnterHibernate(pGpu);
+ gpumgrSetBcEnabledStatus(pGpu, bcState);
+
+ break;
+
+ case NV_PM_ACTION_STANDBY:
+ nvp->pm_state.InHibernate = NV_FALSE;
+ nvp->pm_state.IntrEn = intrGetIntrEn(pIntr);
+ intrSetIntrEn(pIntr, INTERRUPT_TYPE_DISABLED);
+ gpumgrSetBcEnabledStatus(pGpu, NV_FALSE);
+
+ rmStatus = gpuEnterStandby(pGpu);
+ gpumgrSetBcEnabledStatus(pGpu, bcState);
+
+ break;
+
+ case NV_PM_ACTION_RESUME:
+ gpumgrSetBcEnabledStatus(pGpu, NV_FALSE);
+
+ if (nvp->pm_state.InHibernate)
+ {
+ gpuResumeFromHibernate(pGpu);
+ }
+ else
+ {
+ gpuResumeFromStandby(pGpu);
+ }
+ intrSetIntrEn(pIntr, nvp->pm_state.IntrEn);
+ gpumgrSetBcEnabledStatus(pGpu, bcState);
+ NvU32 ac_plugged = 0;
+
+ if (IsMobile(pGpu))
+ {
+ if (nv_acpi_get_powersource(&ac_plugged) == NV_OK)
+ {
+ //
+ // As we have already acquired API and GPU lock here, we are
+ // directly calling RmPowerSourceChangeEvent.
+ //
+ RmPowerSourceChangeEvent(nv, !ac_plugged);
+ }
+ RmRequestDNotifierState(nv);
+ }
+ break;
+
+ default:
+ rmStatus = NV_ERR_INVALID_ARGUMENT;
+ break;
+ }
+
+ pMemoryManager->fixedFbsrModesMask = 0;
+ }
+
+ return rmStatus;
+}
+
+/*!
+ * @brief Call core RM to perform the GCx (GC6/GCOF) entry sequence (before
+ * powering off the GPU) or exit sequence (after powering the GPU back on).
+ *
+ * The GPU lock should be held when calling this function.
+ *
+ * @param[in] pGpu OBJGPU pointer.
+ * @param[in] bEnter If true, perform entry sequence; exit sequence
+ * otherwise.
+ * @param[in] bIsDynamicPM If true, it is for dynamic PM; otherwise, it is
+ * for system PM (suspend/resume).
+ *
+ * @return NV_STATUS code indicating if the operation was successful.
+ */
+NV_STATUS RmGcxPowerManagement(
+ OBJGPU *pGpu,
+ NvBool bEnter,
+ NvBool bIsDynamicPM,
+ NvBool *bTryAgain
+)
+{
+ MemoryManager *pMemoryManager = GPU_GET_MEMORY_MANAGER(pGpu);
+ KernelMemorySystem *pKernelMemorySystem = GPU_GET_KERNEL_MEMORY_SYSTEM(pGpu);
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+ NV_STATUS status = NV_OK;
+
+ if (pGpu->acpiMethodData.jtMethodData.bSBIOSCaps &&
+ !pGpu->getProperty(pGpu, PDB_PROP_GPU_IS_MOBILE))
+ {
+ //
+ // AML override is expected only on NB platforms to support GCOFF-1.0(
+ // which is legacy GCOFF) and GC6-3.0
+ // GC6 3.0 is possible without AML override but due to changes required
+ // for GCOFF-1.0 in SBIOS & HW, AML override is needed for GC6-3.0 also.
+ //
+ NV_PRINTF(LEVEL_INFO,"AML overrides present in Desktop");
+ }
+
+ nv->d0_state_in_suspend = NV_FALSE;
+
+ if (bEnter)
+ {
+ NvU64 usedFbSize = 0;
+ NvBool bCanUseGc6 = NV_FALSE;
+ NV_STATUS fbsrStatus = NV_ERR_GENERIC;
+
+ //
+ // If the GPU supports GC6, then check if GC6 can be used for
+ // the current power management request.
+ // 1. For dynamic PM, GC6 can be used if it is supported by the GPU.
+ // 2. For system PM with s2idle, GC6 can be used if it is
+ // supported by the GPU.
+ //
+ if (pGpu->getProperty(pGpu, PDB_PROP_GPU_RTD3_GC6_SUPPORTED) &&
+ nvp->gc6_upstream_port_configured)
+ {
+ bCanUseGc6 = bIsDynamicPM ? NV_TRUE : nv_s2idle_pm_configured();
+ }
+
+ if (pGpu->getProperty(pGpu, PDB_PROP_GPU_RTD3_RG_SUPPORTED))
+ {
+ pGpu->setProperty(pGpu, PDB_PROP_GPU_RG_STATE_ENTERING, NV_TRUE);
+ status = RmPowerManagement(pGpu, NV_PM_ACTION_STANDBY);
+ pGpu->setProperty(pGpu, PDB_PROP_GPU_RG_STATE_ENTERING, NV_FALSE);
+ if (status == NV_OK)
+ {
+ pGpu->setProperty(pGpu, PDB_PROP_GPU_RG_STATE_ENTERED, NV_TRUE);
+ }
+ }
+ //
+ // If GC6 cannot be used, then no need to compare the used FB size with
+ // threshold value and select GCOFF irrespective of FB size.
+ //
+ else if ((memmgrGetUsedRamSize(pGpu, pMemoryManager, &usedFbSize) == NV_OK) &&
+ (!bCanUseGc6 || RmCheckForGcOffPM(pGpu, usedFbSize, bIsDynamicPM)) &&
+ ((fbsrStatus = fbsrReserveSysMemoryForPowerMgmt(pGpu, pMemoryManager->pFbsr[FBSR_TYPE_DMA],
+ usedFbSize)) == NV_OK))
+ {
+ pGpu->setProperty(pGpu, PDB_PROP_GPU_GCOFF_STATE_ENTERING, NV_TRUE);
+
+ //
+ // Set 'bPreserveComptagBackingStoreOnSuspend' so that comptag
+ // related handling can be done during state unload/load.
+ //
+ if (!pMemoryManager->bUseVirtualCopyOnSuspend)
+ {
+ pKernelMemorySystem->bPreserveComptagBackingStoreOnSuspend = NV_TRUE;
+ }
+
+ status = RmPowerManagement(pGpu, NV_PM_ACTION_STANDBY);
+ pGpu->setProperty(pGpu, PDB_PROP_GPU_GCOFF_STATE_ENTERING, NV_FALSE);
+
+ if (status == NV_OK)
+ {
+ pGpu->setProperty(pGpu, PDB_PROP_GPU_GCOFF_STATE_ENTERED, NV_TRUE);
+ }
+ else
+ {
+ /*
+ * Normally the NV_PM_ACTION_RESUME resume should free the
+ * the reserved memory while doing FB state load. But if the
+ * failure has happened at very early stage in FB state unload
+ * while doing NV_PM_ACTION_STANDBY, then reserved system memory
+ * might not be freed.
+ */
+ fbsrFreeReservedSysMemoryForPowerMgmt(pMemoryManager->pFbsr[FBSR_TYPE_DMA]);
+
+ if (!pMemoryManager->bUseVirtualCopyOnSuspend)
+ {
+ pKernelMemorySystem->bPreserveComptagBackingStoreOnSuspend = nv->preserve_vidmem_allocations;
+ }
+ }
+ }
+ else if (bCanUseGc6)
+ {
+ NV2080_CTRL_GC6_ENTRY_PARAMS entryParams;
+ portMemSet(&entryParams, 0, sizeof(entryParams));
+
+ entryParams.flavorId = NV2080_CTRL_GC6_FLAVOR_ID_MSHYBRID;
+ entryParams.stepMask = NVBIT(NV2080_CTRL_GC6_STEP_ID_GPU_OFF);
+ entryParams.params.bIsRTD3Transition = NV_TRUE;
+
+ //
+ // Currently if the GPU is not in the Lowest P-State, then the
+ // GC6 entry will fail in its internal sanity check. The system
+ // suspend can be triggered in any P-State, so sanity check
+ // for the lowest P-State needs to be skipped. In this case, during
+ // Perf state unload time, the forceful P-State switch will
+ // happen which will bring the GPU into lowest P-State.
+ //
+ entryParams.params.bSkipPstateSanity = !bIsDynamicPM;
+
+ status = gpuGc6Entry(pGpu, &entryParams);
+
+ //
+ // The GC6 state requires SW involvement before each transition
+ // from D0 to D3cold. In case of system suspend with pass-through
+ // mode, the VM suspend should happen before host suspend. During
+ // VM suspend, the NVIDIA driver running in the VM side will be
+ // involved in D3cold transition, but in the host side, it will
+ // go through D3cold->D0->D3cold transition and will make the
+ // second D3cold transition without NVIDIA driver. To handle this
+ // use-case, during VM suspend, use the D0 state and the host linux
+ // kernel will put the device into D3cold state.
+ //
+ if ((status == NV_OK) && ((nv->flags & NV_FLAG_PASSTHRU) != 0))
+ {
+ nv->d0_state_in_suspend = NV_TRUE;
+ }
+ }
+ //
+ // The else condition below will hit in the following cases:
+ // Case 1. During system suspend transition: For systems that support s2idle but are configured
+ // for deep sleep, this "else" condition will be hit when the system memory
+ // is not sufficient. In this case, we should unset bTryAgain to abort the current suspend entry.
+ // Case 2. During runtime suspend transition: For systems that do not support GC6 but support
+ // GCOFF, this "else" condition will be hit when system memory is not sufficent, In this case, we
+ // should set bTryagain so that the kernel can reschedule the callback later.
+ //
+ else
+ {
+ if (bIsDynamicPM)
+ {
+ if (fbsrStatus == NV_ERR_NO_MEMORY)
+ {
+ *bTryAgain = NV_TRUE;
+ }
+ status = fbsrStatus;
+ }
+ else
+ {
+ status = NV_ERR_NOT_SUPPORTED;
+ NV_PRINTF(LEVEL_ERROR,
+ "System suspend failed with current system suspend configuration. "
+ "Please change the system suspend configuration to s2idle in /sys/power/mem_sleep.\n");
+ }
+ }
+ }
+ else
+ {
+ if (pGpu->getProperty(pGpu, PDB_PROP_GPU_GCOFF_STATE_ENTERED))
+ {
+ status = RmPowerManagement(pGpu, NV_PM_ACTION_RESUME);
+ pGpu->setProperty(pGpu, PDB_PROP_GPU_GCOFF_STATE_ENTERED, NV_FALSE);
+ if (!pMemoryManager->bUseVirtualCopyOnSuspend)
+ {
+ pKernelMemorySystem->bPreserveComptagBackingStoreOnSuspend = nv->preserve_vidmem_allocations;
+ }
+ }
+ else if (pGpu->getProperty(pGpu, PDB_PROP_GPU_RG_STATE_ENTERED))
+ {
+ status = RmPowerManagement(pGpu, NV_PM_ACTION_RESUME);
+ if (status == NV_OK)
+ {
+ pGpu->setProperty(pGpu, PDB_PROP_GPU_RG_STATE_ENTERED, NV_FALSE);
+ }
+ }
+ else
+ {
+ NV2080_CTRL_GC6_EXIT_PARAMS exitParams;
+ portMemSet(&exitParams, 0, sizeof(exitParams));
+
+ exitParams.flavorId = NV2080_CTRL_GC6_FLAVOR_ID_MSHYBRID;
+ exitParams.params.bIsRTD3Transition = NV_TRUE;
+
+ status = gpuGc6Exit(pGpu, &exitParams);
+ }
+ }
+
+ return status;
+}
+
+NV_STATUS NV_API_CALL rm_power_management(
+ nvidia_stack_t *sp,
+ nv_state_t *pNv,
+ nv_pm_action_t pmAction
+)
+{
+ THREAD_STATE_NODE threadState;
+ NV_STATUS rmStatus = NV_OK;
+ void *fp;
+ NvBool bTryAgain = NV_FALSE;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_DEVICE_INIT);
+
+ NV_ASSERT_OK(os_flush_work_queue(pNv->queue, pmAction != NV_PM_ACTION_RESUME));
+ //
+ // For GPU driving console, disable console access here, to ensure no console
+ // writes through BAR1 can interfere with physical RM's setup of BAR1
+ //
+ if (pNv->client_managed_console && !pNv->sysmem_mapped_console)
+ {
+ os_disable_console_access();
+ }
+
+ // LOCK: acquire API lock
+ if ((rmStatus = rmapiLockAcquire(API_LOCK_FLAGS_NONE, RM_LOCK_MODULES_DYN_POWER)) == NV_OK)
+ {
+ OBJGPU *pGpu = NV_GET_NV_PRIV_PGPU(pNv);
+
+ if (pGpu != NULL)
+ {
+ if ((rmStatus = os_ref_dynamic_power(pNv, NV_DYNAMIC_PM_FINE)) == NV_OK)
+ {
+ // LOCK: acquire GPUs lock
+ if ((rmStatus = rmGpuLocksAcquire(GPUS_LOCK_FLAGS_NONE, RM_LOCK_MODULES_DYN_POWER)) == NV_OK)
+ {
+ if (pGpu->getProperty(pGpu, PDB_PROP_GPU_TEGRA_SOC_NVDISPLAY))
+ {
+ rmStatus = RmPowerManagementTegra(pGpu, pmAction);
+
+ //
+ // RmPowerManagementTegra() is most likely to fail due to
+ // gpuStateUnload() failures deep in the RM's GPU power
+ // management paths. However, those paths make no
+ // attempt to unwind in case of errors. Rather, they
+ // soldier on and simply report an error at the very end.
+ // GPU software state meanwhile will indicate the GPU
+ // has been suspended.
+ //
+ // Sadly, in case of an error during suspend/hibernate,
+ // the only path forward here is to attempt to resume the
+ // GPU, accepting that the odds of success will vary.
+ //
+ if (rmStatus != NV_OK && pmAction != NV_PM_ACTION_RESUME)
+ {
+ RmPowerManagementTegra(pGpu, NV_PM_ACTION_RESUME);
+ }
+ }
+ else
+ {
+ nv_priv_t *nvp = NV_GET_NV_PRIV(pNv);
+
+ //
+ // Before going to S3 or S4, remove idle holdoff which was
+ // applied during gc6 exit.
+ //
+ if ((pmAction != NV_PM_ACTION_RESUME) &&
+ (nvp->dynamic_power.b_idle_holdoff == NV_TRUE))
+ {
+ nv_indicate_idle(pNv);
+ RmCancelCallbackToRemoveIdleHoldoff(pGpu);
+ nvp->dynamic_power.b_idle_holdoff = NV_FALSE;
+ }
+
+ //
+ // Use GCx (GCOFF/GC6) power management if S0ix-based PM is
+ // enabled and the request is for system suspend/resume.
+ // Otherwise, use the existing mechanism.
+ //
+ if (nvp->s0ix_pm_enabled &&
+ (pmAction == NV_PM_ACTION_STANDBY ||
+ (pmAction == NV_PM_ACTION_RESUME &&
+ !nvp->pm_state.InHibernate)))
+ {
+ rmStatus = RmGcxPowerManagement(pGpu,
+ pmAction == NV_PM_ACTION_STANDBY,
+ NV_FALSE, &bTryAgain);
+
+ }
+ else
+ {
+ rmStatus = RmPowerManagement(pGpu, pmAction);
+ }
+ }
+
+ // UNLOCK: release GPUs lock
+ rmGpuLocksRelease(GPUS_LOCK_FLAGS_NONE, NULL);
+ }
+ os_unref_dynamic_power(pNv, NV_DYNAMIC_PM_FINE);
+ }
+ }
+ // UNLOCK: release API lock
+ rmapiLockRelease();
+ }
+
+ if (pNv->client_managed_console && !pNv->sysmem_mapped_console)
+ {
+ os_enable_console_access();
+ }
+
+ NV_ASSERT_OK(os_flush_work_queue(pNv->queue, pmAction != NV_PM_ACTION_RESUME));
+
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return rmStatus;
+}
+
+/*!
+ * @brief Wrapper around RmGcxPowerManagement() and removes the Idle holdoff
+ * during exit sequence.
+ *
+ * The GPU lock should be held when calling this function.
+ *
+ * @param[in] pGpu OBJGPU pointer.
+ * @param[in] bEnter If true, perform entry sequence; exit sequence
+ * otherwise.
+ *
+ * @return NV_STATUS code indicating if the operation was successful.
+ */
+static NV_STATUS RmTransitionDynamicPower(
+ OBJGPU *pGpu,
+ NvBool bEnter,
+ NvBool *bTryAgain
+)
+{
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ NV_STATUS status;
+
+ status = RmGcxPowerManagement(pGpu, bEnter, NV_TRUE, bTryAgain);
+
+ if (!bEnter && status == NV_OK)
+ {
+ nv_idle_holdoff(nv);
+ RmScheduleCallbackToRemoveIdleHoldoff(pGpu);
+ }
+
+ return status;
+}
+
+/*!
+ * @brief Wrapper around RmTransitionDynamicPower() which sets up the RM
+ * runtime (thread state and altstack), and takes the GPU lock for the duration
+ * of the operation.
+ *
+ * @param[in] sp nvidia_stack_t pointer.
+ * @param[in] nv nv_state_t pointer.
+ * @param[in] bEnter If true, perform entry sequence; exit sequence
+ * otherwise.
+ *
+ * @return NV_STATUS code indicating if the operation was successful.
+ */
+NV_STATUS NV_API_CALL rm_transition_dynamic_power(
+ nvidia_stack_t *sp,
+ nv_state_t *nv,
+ NvBool bEnter,
+ NvBool *bTryAgain
+)
+{
+ OBJGPU *pGpu = NV_GET_NV_PRIV_PGPU(nv);
+ NV_STATUS status = NV_OK;
+ THREAD_STATE_NODE threadState;
+ void *fp;
+
+ if (NV_IS_SOC_DISPLAY_DEVICE(nv))
+ {
+ return NV_OK;
+ }
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ if (!bEnter &&
+ !threadState.bValid &&
+ (threadState.threadId == 0) &&
+ pGpu->getProperty(pGpu, PDB_PROP_GPU_RTD3_RG_SUPPORTED))
+ {
+ /*
+ * If the thread node is already present in the database,
+ * reset the thread timeout before the resume operation starts
+ * for IGPU.
+ */
+ threadStateResetTimeout(pGpu);
+ }
+
+ if (nv->client_managed_console && !nv->sysmem_mapped_console)
+ {
+ os_disable_console_access();
+ }
+
+ // LOCK: acquire GPUs lock
+ status = rmGpuLocksAcquire(GPUS_LOCK_FLAGS_NONE, RM_LOCK_MODULES_DYN_POWER);
+ if (status == NV_OK)
+ {
+ rmapiEnterRtd3PmPath();
+
+ status = RmTransitionDynamicPower(pGpu, bEnter, bTryAgain);
+
+ rmapiLeaveRtd3PmPath();
+
+ // UNLOCK: release GPUs lock
+ rmGpuLocksRelease(GPUS_LOCK_FLAGS_NONE, NULL);
+ }
+
+ if (nv->client_managed_console && !nv->sysmem_mapped_console)
+ {
+ os_enable_console_access();
+ }
+
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return status;
+}
+
+/*!
+ * @brief: Notify client about hot-plugged/unplugged displays.
+ * Called after GPU exits GC6 because of display hot-plug/unplug.
+ *
+ * @param[in] nv nv_state_t pointer.
+ */
+static void RmNotifyClientAboutHotplug(
+ nv_state_t *nv
+)
+{
+ NV_STATUS status;
+ GPU_MASK gpuMask;
+ OBJGPU *pGpu = NV_GET_NV_PRIV_PGPU(nv);
+
+ Nv2080HotplugNotification hotplugNotificationParams;
+
+ portMemSet(&hotplugNotificationParams, 0, sizeof(hotplugNotificationParams));
+
+ // LOCK: acquire per device lock
+ status = rmGpuGroupLockAcquire(pGpu->gpuInstance, GPU_LOCK_GRP_SUBDEVICE,
+ GPUS_LOCK_FLAGS_NONE, RM_LOCK_MODULES_HOTPLUG,
+ &gpuMask);
+ if (status == NV_OK)
+ {
+ gpuNotifySubDeviceEvent(pGpu, NV2080_NOTIFIERS_HOTPLUG,
+ &hotplugNotificationParams,
+ sizeof(hotplugNotificationParams), 0, 0);
+ // UNLOCK: release per device lock
+ rmGpuGroupLockRelease(gpuMask, GPUS_LOCK_FLAGS_NONE);
+ }
+}
+
+/*!
+ * @brief If GPU is in GC6, exit GC6 state and
+ * notify client about display hot-plug/unplug.
+ *
+ * @param[in] sp nvidia_stack_t pointer.
+ * @param[in] nv nv_state_t pointer.
+ */
+void RmHandleDisplayChange(
+ nvidia_stack_t *sp,
+ nv_state_t *nv
+)
+{
+ OBJGPU *pGpu = NV_GET_NV_PRIV_PGPU(nv);
+
+ if (pGpu &&
+ (IS_GPU_GC6_STATE_ENTERED(pGpu) ||
+ pGpu->getProperty(pGpu, PDB_PROP_GPU_GCOFF_STATE_ENTERED)))
+ {
+ if (rm_ref_dynamic_power(sp, nv, NV_DYNAMIC_PM_FINE) == NV_OK)
+ {
+ RmNotifyClientAboutHotplug(nv);
+ rm_unref_dynamic_power(sp, nv, NV_DYNAMIC_PM_FINE);
+ }
+ else
+ NV_PRINTF(LEVEL_ERROR,
+ "Failed to increment dynamic power refcount\n");
+ }
+}
+
+/*!
+ * @brief RmGetDynamicBoostSupport() gets the notebook DB
+ * support. DB support is static information for vast majority
+ * of notebooks and hence we fetch it only once (during the first
+ * call to this function). This way, the GPU remains in RTD3 state
+ * when procfs read is done.
+ *
+ * @param[in] nv nv_state_t pointer.
+ */
+static const char* RmGetDynamicBoostSupport(
+ nv_state_t *pNv
+)
+{
+ nv_priv_t *pNvp = NV_GET_NV_PRIV(pNv);
+ const char* DbStatus = "?";
+
+ if (pNvp->db_supported == -1)
+ {
+ pNvp->db_supported = os_get_dynamic_boost_support(pNv);
+ }
+
+ if (pNvp->db_supported == 0)
+ {
+ DbStatus = "Not Supported";
+ }
+ else if (pNvp->db_supported == 1)
+ {
+ DbStatus = "Supported";
+ }
+ return DbStatus;
+}
+
+/*!
+ * @brief: Function to query Dynamic Power Management
+ *
+ * @param[in] nvp nv_priv_t pointer.
+ *
+ * @return String indicating Dynamic Power Management status.
+ */
+static const char* RmGetDynamicPowerManagementStatus(
+ nv_priv_t *nvp
+)
+{
+ /*
+ * If the platform/driver does not support Dynamic Power Management,
+ * we set mode as NV_DYNAMIC_PM_NEVER. Hence, after RmInit if the
+ * mode is still NV_DYNAMIC_PM_FINE, we are sure that it is
+ * supported and enabled. Also see NOTE.
+ */
+ if (nvp->dynamic_power.mode == NV_DYNAMIC_PM_FINE)
+ {
+ return "Enabled (fine-grained)";
+ }
+ else if (nvp->dynamic_power.mode == NV_DYNAMIC_PM_COARSE)
+ {
+ return "Enabled (coarse-grained)";
+ }
+ else if (nvp->dynamic_power.mode == NV_DYNAMIC_PM_NEVER)
+ {
+
+ if (nvp->dynamic_power.dynamic_power_regkey ==
+ NV_REG_DYNAMIC_POWER_MANAGEMENT_NEVER)
+ return "Disabled";
+ else if (nvp->dynamic_power.dynamic_power_regkey ==
+ NV_REG_DYNAMIC_POWER_MANAGEMENT_DEFAULT)
+ return "Disabled by default";
+ }
+
+ return "Not supported";
+}
+
+static void RmHandleIdleSustained(
+ NvU32 gpuInstance,
+ void *pArgs
+)
+{
+ OBJGPU *pGpu = gpumgrGetGpu(gpuInstance);
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+
+ nv_revoke_gpu_mappings(NV_GET_NV_STATE(pGpu));
+ RmScheduleCallbackToIndicateIdle(pGpu);
+ nvp->dynamic_power.b_idle_sustained_workitem_queued = NV_FALSE;
+}
+
+/*
+ * Queue a workitem for revoking GPU mappings, and scheduling a callback to indicate idle.
+ */
+static void RmQueueIdleSustainedWorkitem(
+ OBJGPU *pGpu
+)
+{
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+ NV_STATUS status = NV_OK;
+
+ if (!nvp->dynamic_power.b_idle_sustained_workitem_queued)
+ {
+ status = osQueueWorkItem(pGpu,
+ RmHandleIdleSustained,
+ NULL,
+ (OsQueueWorkItemFlags){.bLockGpuGroupSubdevice = NV_TRUE});
+ if (status != NV_OK)
+ {
+ NV_PRINTF(LEVEL_WARNING,
+ "Failed to queue RmHandleIdleSustained() workitem.\n");
+ RmScheduleCallbackForIdlePreConditionsUnderGpuLock(pGpu);
+ return;
+ }
+ nvp->dynamic_power.b_idle_sustained_workitem_queued = NV_TRUE;
+ }
+}
+
+/*
+ * Allocate resources needed for S0ix-based system power management.
+ */
+static void
+RmInitS0ixPowerManagement(
+ nv_state_t *nv,
+ NvBool bRtd3Support,
+ NvBool bGC6Support
+)
+{
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+ NvU32 data;
+
+ // S0ix-based S2Idle, on desktops, is not supported yet. Return early for desktop SKUs
+ if (!nvp->b_mobile_config_enabled)
+ {
+ return;
+ }
+
+ /*
+ * The GPU S0ix-based system power management will be enabled
+ * only if all the following necessary requirements are met:
+ *
+ * 1. The GPU has RTD3 support.
+ * 2. The platform has support for s0ix.
+ * 3. Feature regkey EnableS0ixPowerManagement is enabled.
+ */
+ if (bRtd3Support && bGC6Support &&
+ nv_platform_supports_s0ix() &&
+ (osReadRegistryDword(NULL, NV_REG_ENABLE_S0IX_POWER_MANAGEMENT,
+ &data) == NV_OK) && (data == 1))
+ {
+ nvp->s0ix_pm_enabled = NV_TRUE;
+
+ /*
+ * Read the OS registry for Maximum FB size for S0ix-based PM
+ * which will be expressed in Megabytes (1048576 bytes) and
+ * convert it into bytes.
+ */
+ if ((osReadRegistryDword(NULL,
+ NV_REG_S0IX_POWER_MANAGEMENT_VIDEO_MEMORY_THRESHOLD,
+ &data) == NV_OK))
+ {
+ nvp->s0ix_gcoff_max_fb_size = (NvU64)data * 1024 * 1024;
+ }
+ }
+}
+
+/*!
+ * @brief: Helper function to abstract the execution and return value verification
+ * of PEX DSM methods, necessary for GC6 to work in Desktops.
+ *
+ * This function is capable to invoke three _DSM methods, as listed below:
+ * 0x0: _DSM for "Query supported functions"
+ * (for more details, refer to section 9.1.1 of the ACPI 6.3 Specification).
+ * 0xA: _DSM for "Requesting D3cold Aux Power Limit"
+ * (for more details, refer to section 4.6.10 of PCI Firmware Specification v3.3)
+ * 0xB: _DSM for "Adding PERST# Assertion Delay"
+ * (for more details, refer to section 4.6.11 of PCI Firmware Specification v3.3)
+ *
+ * @param[in] nv nv_state_t pointer.
+ * @param[in] dsmSubFunc subfunction to invoke.
+ * @param[in] data input data for dsmSubFunc.
+ *
+ * @return TRUE if dsmSubFunc executed successfully and return value is as expected;
+ * FALSE otherwise.
+ */
+static NvBool RmAcpiD3ColdDsm
+(
+ nv_state_t *nv,
+ NvU32 dsmSubFunc,
+ NvU32 data
+)
+{
+ NvU32 inData = data;
+
+ /*
+ * Third argument (i.e. acpiDsmRev) is sent as 4 because PEX_FUNC_AUXPOWERLIMIT and
+ * PEX_FUNC_PEXRST_DELAY sub-functions were introduced in PCI Firmware Specification 3.2
+ * and they are supported only for _DSM revision 4 onwards. But, RM still use _DSM
+ * revision 2 (see drivers/common/inc/pex.h). Hence, the need to hardcode 4 here.
+ */
+ if (nv_acpi_d3cold_dsm_for_upstream_port(nv, (NvU8 *)&PEX_DSM_GUID, 4, dsmSubFunc, &data) != NV_OK)
+ {
+ NV_PRINTF(LEVEL_NOTICE, "%s: PEX _DSM subfunction: 0x%X failed.\n", __FUNCTION__, dsmSubFunc);
+ return NV_FALSE;
+ }
+
+ switch (dsmSubFunc)
+ {
+ case NV_ACPI_ALL_FUNC_SUPPORT:
+ return ((data & NVBIT(PEX_FUNC_PEXRST_DELAY)) &&
+ (data & NVBIT(PEX_FUNC_AUXPOWERLIMIT)));
+
+ case PEX_FUNC_PEXRST_DELAY:
+ return (inData == data);
+
+ case PEX_FUNC_AUXPOWERLIMIT:
+ return ((data == NV_AUX_POWER_REQUEST_STATUS_GRANTED_WITH_12V_POWER) ||
+ (data == NV_AUX_POWER_REQUEST_STATUS_GRANTED_WITHOUT_12V_POWER));
+
+ default:
+ return NV_FALSE;
+ }
+
+ return NV_FALSE;
+}
+
+static NvBool RmConfigureUpstreamPortForRTD3(
+ nv_state_t *nv,
+ NvBool bConfigureForGC6
+)
+{
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+ OBJGPU *pGpu = NV_GET_NV_PRIV_PGPU(nv);
+
+ if (nvp->b_mobile_config_enabled)
+ return NV_TRUE;
+
+ if (!RmAcpiD3ColdDsm(nv, NV_ACPI_ALL_FUNC_SUPPORT, 0))
+ {
+ return NV_FALSE;
+ }
+
+ if (!RmAcpiD3ColdDsm(nv, PEX_FUNC_PEXRST_DELAY,
+ bConfigureForGC6 ? pGpu->gc6State.GC6PerstDelay : DEFAULT_GCOFF_PEXRST_DELAY))
+ {
+ return NV_FALSE;
+ }
+
+ if (!RmAcpiD3ColdDsm(nv, PEX_FUNC_AUXPOWERLIMIT,
+ bConfigureForGC6 ? pGpu->gc6State.GC6TotalBoardPower : 0))
+ {
+ if (bConfigureForGC6)
+ RmAcpiD3ColdDsm(nv, PEX_FUNC_PEXRST_DELAY, DEFAULT_GCOFF_PEXRST_DELAY);
+
+ return NV_FALSE;
+ }
+
+ NV_PRINTF(LEVEL_NOTICE,
+ "Aux Power and Pex delay settings %s successfully.\n",
+ bConfigureForGC6? "applied": "cleared");
+
+ return NV_TRUE;
+}
+
+void RmInitPowerManagement(
+ nv_state_t *nv
+)
+{
+ // LOCK: acquire GPUs lock
+ if (rmGpuLocksAcquire(GPUS_LOCK_FLAGS_NONE, RM_LOCK_MODULES_INIT) == NV_OK)
+ {
+ NvBool bGC6Support = NV_FALSE;
+ NvBool bGCOFFSupport = NV_FALSE;
+ NvBool bRtd3Support = RmCheckRtd3GcxSupport(nv, &bGC6Support, &bGCOFFSupport);
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+ OBJGPU *pGpu = NV_GET_NV_PRIV_PGPU(nv);
+
+ RmInitDeferredDynamicPowerManagement(nv, bRtd3Support);
+ RmInitS0ixPowerManagement(nv, bRtd3Support, bGC6Support);
+
+ if (bRtd3Support && bGC6Support &&
+ (nvp->s0ix_pm_enabled || (nvp->dynamic_power.mode == NV_DYNAMIC_PM_FINE)))
+ {
+ nvp->gc6_upstream_port_configured = RmConfigureUpstreamPortForRTD3(nv, NV_TRUE);
+ }
+
+ nv->is_pm_unsupported = pGpu->getProperty(pGpu, PDB_PROP_GPU_POWER_MANAGEMENT_UNSUPPORTED);
+
+ // UNLOCK: release GPUs lock
+ rmGpuLocksRelease(GPUS_LOCK_FLAGS_NONE, NULL);
+ }
+}
+
+void RmDestroyPowerManagement(
+ nv_state_t *nv
+)
+{
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+
+ if (nvp->gc6_upstream_port_configured)
+ {
+ RmConfigureUpstreamPortForRTD3(nv, NV_FALSE);
+ }
+
+ RmDestroyDeferredDynamicPowerManagement(nv);
+}
+
+void NV_API_CALL rm_get_power_info(
+ nvidia_stack_t *sp,
+ nv_state_t *pNv,
+ nv_power_info_t *powerInfo
+)
+{
+ THREAD_STATE_NODE threadState;
+ void *fp;
+ GPU_MASK gpuMask;
+ const char *pVidmemPowerStatus = "?";
+ const char *pGc6Supported = "?";
+ const char *pGcoffSupported = "?";
+ const char *pDynamicPowerStatus = "?";
+ const char *pS0ixStatus = "?";
+ const char *pDbStatus = "?";
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ // LOCK: acquire API lock
+ if ((rmapiLockAcquire(API_LOCK_FLAGS_NONE, RM_LOCK_MODULES_DYN_POWER)) == NV_OK)
+ {
+ OBJGPU *pGpu = NV_GET_NV_PRIV_PGPU(pNv);
+
+ // LOCK: acquire per device lock
+ if ((pGpu != NULL) &&
+ ((rmGpuGroupLockAcquire(pGpu->gpuInstance, GPU_LOCK_GRP_SUBDEVICE,
+ GPUS_LOCK_FLAGS_NONE, RM_LOCK_MODULES_DYN_POWER,
+ &gpuMask)) == NV_OK))
+ {
+ nv_priv_t *pNvp = NV_GET_NV_PRIV(pNv);
+
+ pVidmemPowerStatus = pGpu->getProperty(pGpu, PDB_PROP_GPU_GCOFF_STATE_ENTERED) ?
+ "Off" : "Active";
+ pDynamicPowerStatus = RmGetDynamicPowerManagementStatus(pNvp);
+ pGc6Supported = RmGetGpuGcxSupport(pGpu, NV_TRUE);
+ pGcoffSupported = RmGetGpuGcxSupport(pGpu, NV_FALSE);
+ pS0ixStatus = pNvp->s0ix_pm_enabled ? "Enabled" : "Disabled";
+ pDbStatus = RmGetDynamicBoostSupport(pNv);
+ // UNLOCK: release per device lock
+ rmGpuGroupLockRelease(gpuMask, GPUS_LOCK_FLAGS_NONE);
+ }
+
+ // UNLOCK: release API lock
+ rmapiLockRelease();
+ }
+
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ powerInfo->vidmem_power_status = pVidmemPowerStatus;
+ powerInfo->dynamic_power_status = pDynamicPowerStatus;
+ powerInfo->gc6_support = pGc6Supported;
+ powerInfo->gcoff_support = pGcoffSupported;
+ powerInfo->s0ix_status = pS0ixStatus;
+ powerInfo->db_support = pDbStatus;
+}
+
diff --git a/userspace/sdks/nv570/nvalloc/unix/src/escape.c b/userspace/sdks/nv570/nvalloc/unix/src/escape.c
new file mode 100644
index 0000000..fae7b8d
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/src/escape.c
@@ -0,0 +1,1017 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 1999-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+
+
+//***************************** Module Header **********************************
+//
+// This code is linked into the resource manager proper. It receives the
+// ioctl from the resource manager's customer, unbundles the args and
+// calls the correct resman routines.
+//
+//******************************************************************************
+
+#include <core/prelude.h>
+#include <core/locks.h>
+#include <nv.h>
+#include <nv_escape.h>
+#include <osapi.h>
+#include <rmapi/exports.h>
+#include <nv-unix-nvos-params-wrappers.h>
+
+#include <nvos.h>
+#include <class/cl0000.h> // NV01_ROOT
+#include <class/cl0001.h> // NV01_ROOT_NON_PRIV
+#include <class/cl0005.h> // NV01_EVENT
+#include <class/cl003e.h> // NV01_MEMORY_SYSTEM
+#include <class/cl0071.h> // NV01_MEMORY_SYSTEM_OS_DESCRIPTOR
+
+#include "rmapi/client_resource.h"
+#include "nvlog/nvlog.h"
+#include <nv-ioctl-lockless-diag.h>
+
+#include <ctrl/ctrl00fd.h>
+
+#include <ctrl/ctrl00e0.h>
+
+#define NV_CTL_DEVICE_ONLY(nv) \
+{ \
+ if (((nv)->flags & NV_FLAG_CONTROL) == 0) \
+ { \
+ rmStatus = NV_ERR_INVALID_ARGUMENT; \
+ goto done; \
+ } \
+}
+
+#define NV_ACTUAL_DEVICE_ONLY(nv) \
+{ \
+ if (((nv)->flags & NV_FLAG_CONTROL) != 0) \
+ { \
+ rmStatus = NV_ERR_INVALID_ARGUMENT; \
+ goto done; \
+ } \
+}
+
+static NV_STATUS RmGetDeviceFd(NVOS54_PARAMETERS *pApi, NvS32 *pFd,
+ NvBool *pSkipDeviceRef)
+{
+ RMAPI_PARAM_COPY paramCopy;
+ void *pKernelParams;
+ NvU32 paramSize;
+ NV_STATUS status;
+
+ *pFd = -1;
+ *pSkipDeviceRef = NV_TRUE;
+
+ switch(pApi->cmd)
+ {
+ case NV00FD_CTRL_CMD_ATTACH_GPU:
+ paramSize = sizeof(NV00FD_CTRL_ATTACH_GPU_PARAMS);
+ break;
+ case NV00E0_CTRL_CMD_EXPORT_MEM:
+ paramSize = sizeof(NV00E0_CTRL_EXPORT_MEM_PARAMS);
+ break;
+ default:
+ return NV_OK;
+ }
+
+ RMAPI_PARAM_COPY_INIT(paramCopy, pKernelParams, pApi->params, paramSize, 1);
+
+ status = rmapiParamsAcquire(&paramCopy, NV_TRUE);
+ if (status != NV_OK)
+ return status;
+
+ switch(pApi->cmd)
+ {
+ case NV00FD_CTRL_CMD_ATTACH_GPU:
+ {
+ NV00FD_CTRL_ATTACH_GPU_PARAMS *pAttachGpuParams = pKernelParams;
+
+ *pSkipDeviceRef = NV_FALSE;
+ *pFd = (NvS32)pAttachGpuParams->devDescriptor;
+ }
+ break;
+ case NV00E0_CTRL_CMD_EXPORT_MEM:
+ {
+ NV00E0_CTRL_EXPORT_MEM_PARAMS *pExportMemParams = pKernelParams;
+
+ // If hParent is client, no need to reference device.
+ *pSkipDeviceRef = (pExportMemParams->hParent == pApi->hClient);
+ *pFd = (NvS32)pExportMemParams->devDescriptor;
+ }
+ break;
+ default:
+ NV_ASSERT(0);
+ break;
+ }
+
+ NV_ASSERT(rmapiParamsRelease(&paramCopy) == NV_OK);
+
+ return status;
+}
+
+// Only return errors through pApi->status
+static void RmCreateOsDescriptor(NVOS32_PARAMETERS *pApi, API_SECURITY_INFO secInfo)
+{
+ NV_STATUS rmStatus;
+ NvBool writable;
+ NvU32 flags = 0;
+ NvU64 allocSize, pageCount, *pPteArray = NULL;
+ void *pDescriptor, *pPageArray = NULL;
+ NVOS32_PARAMETERS allocApi = *pApi;
+ NVOS32_PARAMETERS *pAllocApi = &allocApi;
+
+ pDescriptor = NvP64_VALUE(pApi->data.AllocOsDesc.descriptor);
+ if (((NvUPtr)pDescriptor & ~os_page_mask) != 0)
+ {
+ rmStatus = NV_ERR_NOT_SUPPORTED;
+ goto done;
+ }
+
+ // Check to prevent an NvU64 overflow
+ if ((pApi->data.AllocOsDesc.limit + 1) == 0)
+ {
+ rmStatus = NV_ERR_INVALID_LIMIT;
+ goto done;
+ }
+
+ allocSize = (pApi->data.AllocOsDesc.limit + 1);
+ pageCount = (1 + ((allocSize - 1) / os_page_size));
+
+ writable = FLD_TEST_DRF(OS32, _ATTR2, _PROTECTION_USER, _READ_WRITE, pApi->data.AllocOsDesc.attr2);
+
+ flags = FLD_SET_DRF_NUM(_LOCK_USER_PAGES, _FLAGS, _WRITE, writable, flags);
+ rmStatus = os_lock_user_pages(pDescriptor, pageCount, &pPageArray, flags);
+ if (rmStatus == NV_OK)
+ {
+ pAllocApi->data.AllocOsDesc.descriptor = (NvP64)(NvUPtr)pPageArray;
+ pAllocApi->data.AllocOsDesc.descriptorType = NVOS32_DESCRIPTOR_TYPE_OS_PAGE_ARRAY;
+ }
+ else if (rmStatus == NV_ERR_INVALID_ADDRESS)
+ {
+ rmStatus = os_lookup_user_io_memory(pDescriptor, pageCount, &pPteArray);
+ if (rmStatus == NV_OK)
+ {
+ pAllocApi->data.AllocOsDesc.descriptor = (NvP64)(NvUPtr)pPteArray;
+ pAllocApi->data.AllocOsDesc.descriptorType = NVOS32_DESCRIPTOR_TYPE_OS_IO_MEMORY;
+ }
+ }
+ if (rmStatus != NV_OK)
+ goto done;
+
+ Nv04VidHeapControlWithSecInfo(pAllocApi, secInfo);
+
+ pApi->status = pAllocApi->status;
+ pApi->data.AllocOsDesc.hMemory = pAllocApi->data.AllocOsDesc.hMemory;
+
+ if ((pAllocApi->status != NV_OK) &&
+ (pAllocApi->data.AllocOsDesc.descriptor != NvP64_NULL))
+ {
+ switch (pAllocApi->data.AllocOsDesc.descriptorType)
+ {
+ default:
+ break;
+ case NVOS32_DESCRIPTOR_TYPE_OS_PAGE_ARRAY:
+ os_unlock_user_pages(pageCount, pPageArray, flags);
+ break;
+ }
+ }
+
+done:
+ if (rmStatus != NV_OK)
+ pApi->status = rmStatus;
+}
+
+// Only return errors through pApi->status
+static void RmAllocOsDescriptor(NVOS02_PARAMETERS *pApi, API_SECURITY_INFO secInfo)
+{
+ NV_STATUS rmStatus = NV_OK;
+ NvU32 flags, attr, attr2;
+ NVOS32_PARAMETERS *pVidHeapParams;
+
+ if (!FLD_TEST_DRF(OS02, _FLAGS, _LOCATION, _PCI, pApi->flags) ||
+ !FLD_TEST_DRF(OS02, _FLAGS, _MAPPING, _NO_MAP, pApi->flags))
+ {
+ rmStatus = NV_ERR_INVALID_FLAGS;
+ goto done;
+ }
+
+ attr = DRF_DEF(OS32, _ATTR, _LOCATION, _PCI);
+
+ if (FLD_TEST_DRF(OS02, _FLAGS, _COHERENCY, _CACHED, pApi->flags) ||
+ FLD_TEST_DRF(OS02, _FLAGS, _COHERENCY, _WRITE_BACK, pApi->flags))
+ {
+ attr = FLD_SET_DRF(OS32, _ATTR, _COHERENCY, _WRITE_BACK, attr);
+ }
+ else if (FLD_TEST_DRF(OS02, _FLAGS, _COHERENCY, _UNCACHED, pApi->flags))
+ attr = FLD_SET_DRF(OS32, _ATTR, _COHERENCY, _UNCACHED, attr);
+ else {
+ rmStatus = NV_ERR_INVALID_FLAGS;
+ goto done;
+ }
+
+ if (FLD_TEST_DRF(OS02, _FLAGS, _PHYSICALITY, _CONTIGUOUS, pApi->flags))
+ attr = FLD_SET_DRF(OS32, _ATTR, _PHYSICALITY, _CONTIGUOUS, attr);
+ else
+ attr = FLD_SET_DRF(OS32, _ATTR, _PHYSICALITY, _NONCONTIGUOUS, attr);
+
+ if (FLD_TEST_DRF(OS02, _FLAGS, _GPU_CACHEABLE, _YES, pApi->flags))
+ attr2 = DRF_DEF(OS32, _ATTR2, _GPU_CACHEABLE, _YES);
+ else
+ attr2 = DRF_DEF(OS32, _ATTR2, _GPU_CACHEABLE, _NO);
+
+ if (FLD_TEST_DRF(OS02, _FLAGS, _MEMORY_PROTECTION, _UNPROTECTED, pApi->flags))
+ attr2 = FLD_SET_DRF(OS32, _ATTR2, _MEMORY_PROTECTION, _UNPROTECTED, attr2);
+
+ pVidHeapParams = portMemAllocNonPaged(sizeof(NVOS32_PARAMETERS));
+ if (pVidHeapParams == NULL)
+ {
+ rmStatus = NV_ERR_NO_MEMORY;
+ goto done;
+ }
+ portMemSet(pVidHeapParams, 0, sizeof(NVOS32_PARAMETERS));
+
+ pVidHeapParams->hRoot = pApi->hRoot;
+ pVidHeapParams->hObjectParent = pApi->hObjectParent;
+ pVidHeapParams->function = NVOS32_FUNCTION_ALLOC_OS_DESCRIPTOR;
+
+ flags = (NVOS32_ALLOC_FLAGS_MEMORY_HANDLE_PROVIDED |
+ NVOS32_ALLOC_FLAGS_MAP_NOT_REQUIRED);
+
+ if (DRF_VAL(OS02, _FLAGS, _ALLOC_USER_READ_ONLY, pApi->flags))
+ attr2 = FLD_SET_DRF(OS32, _ATTR2, _PROTECTION_USER, _READ_ONLY, attr2);
+
+ // Currently CPU-RO memory implies GPU-RO as well
+ if (DRF_VAL(OS02, _FLAGS, _ALLOC_DEVICE_READ_ONLY, pApi->flags) ||
+ DRF_VAL(OS02, _FLAGS, _ALLOC_USER_READ_ONLY, pApi->flags))
+ attr2 = FLD_SET_DRF(OS32, _ATTR2, _PROTECTION_DEVICE, _READ_ONLY, attr2);
+
+ pVidHeapParams->data.AllocOsDesc.hMemory = pApi->hObjectNew;
+ pVidHeapParams->data.AllocOsDesc.flags = flags;
+ pVidHeapParams->data.AllocOsDesc.attr = attr;
+ pVidHeapParams->data.AllocOsDesc.attr2 = attr2;
+ pVidHeapParams->data.AllocOsDesc.descriptor = pApi->pMemory;
+ pVidHeapParams->data.AllocOsDesc.limit = pApi->limit;
+ pVidHeapParams->data.AllocOsDesc.descriptorType = NVOS32_DESCRIPTOR_TYPE_VIRTUAL_ADDRESS;
+
+ RmCreateOsDescriptor(pVidHeapParams, secInfo);
+
+ pApi->status = pVidHeapParams->status;
+
+ portMemFree(pVidHeapParams);
+
+done:
+ if (rmStatus != NV_OK)
+ pApi->status = rmStatus;
+}
+
+ct_assert(NV_OFFSETOF(NVOS21_PARAMETERS, hRoot) == NV_OFFSETOF(NVOS64_PARAMETERS, hRoot));
+ct_assert(NV_OFFSETOF(NVOS21_PARAMETERS, hObjectParent) == NV_OFFSETOF(NVOS64_PARAMETERS, hObjectParent));
+ct_assert(NV_OFFSETOF(NVOS21_PARAMETERS, hObjectNew) == NV_OFFSETOF(NVOS64_PARAMETERS, hObjectNew));
+ct_assert(NV_OFFSETOF(NVOS21_PARAMETERS, hClass) == NV_OFFSETOF(NVOS64_PARAMETERS, hClass));
+ct_assert(NV_OFFSETOF(NVOS21_PARAMETERS, pAllocParms) == NV_OFFSETOF(NVOS64_PARAMETERS, pAllocParms));
+
+
+NV_STATUS RmValidateIoctl(NvU32 cmd, NvU32 size)
+{
+ int i = 0;
+ const unsigned int arg_cmd = (cmd & 0xFF);
+ static const struct {
+ unsigned int cmdKey;
+ unsigned int paramSize;
+ } RmIoctlsTable[] = {
+
+ #define _RM_ESC_IOCTL_ENTRY(_cmd, _type) \
+ { .cmdKey = ((_cmd) & 0xFF), .paramSize = sizeof(_type) }
+
+ _RM_ESC_IOCTL_ENTRY(NV_ESC_STATUS_CODE, nv_ioctl_status_code_t),
+ _RM_ESC_IOCTL_ENTRY(NV_ESC_RM_ALLOC_MEMORY, nv_ioctl_nvos02_parameters_with_fd),
+ _RM_ESC_IOCTL_ENTRY(NV_ESC_RM_ALLOC_OBJECT, NVOS05_PARAMETERS),
+ _RM_ESC_IOCTL_ENTRY(NV_ESC_RM_FREE, NVOS00_PARAMETERS),
+ _RM_ESC_IOCTL_ENTRY(NV_ESC_RM_CONTROL, NVOS54_PARAMETERS),
+ _RM_ESC_IOCTL_ENTRY(NV_ESC_RM_DUP_OBJECT, NVOS55_PARAMETERS),
+ _RM_ESC_IOCTL_ENTRY(NV_ESC_RM_SHARE, NVOS57_PARAMETERS),
+ _RM_ESC_IOCTL_ENTRY(NV_ESC_RM_I2C_ACCESS, NVOS_I2C_ACCESS_PARAMS),
+ _RM_ESC_IOCTL_ENTRY(NV_ESC_RM_IDLE_CHANNELS, NVOS30_PARAMETERS),
+ _RM_ESC_IOCTL_ENTRY(NV_ESC_RM_VID_HEAP_CONTROL, NVOS32_PARAMETERS),
+ _RM_ESC_IOCTL_ENTRY(NV_ESC_RM_ACCESS_REGISTRY, NVOS38_PARAMETERS),
+ _RM_ESC_IOCTL_ENTRY(NV_ESC_RM_MAP_MEMORY, nv_ioctl_nvos33_parameters_with_fd),
+ _RM_ESC_IOCTL_ENTRY(NV_ESC_RM_UNMAP_MEMORY, NVOS34_PARAMETERS),
+ _RM_ESC_IOCTL_ENTRY(NV_ESC_RM_ALLOC_CONTEXT_DMA2, NVOS39_PARAMETERS),
+ _RM_ESC_IOCTL_ENTRY(NV_ESC_RM_MAP_MEMORY_DMA, NVOS46_PARAMETERS),
+ _RM_ESC_IOCTL_ENTRY(NV_ESC_RM_UNMAP_MEMORY_DMA, NVOS47_PARAMETERS),
+ _RM_ESC_IOCTL_ENTRY(NV_ESC_RM_BIND_CONTEXT_DMA, NVOS49_PARAMETERS),
+ _RM_ESC_IOCTL_ENTRY(NV_ESC_RM_UPDATE_DEVICE_MAPPING_INFO, NVOS56_PARAMETERS),
+ _RM_ESC_IOCTL_ENTRY(NV_ESC_RM_LOCKLESS_DIAGNOSTIC, NV_LOCKLESS_DIAGNOSTIC_PARAMS),
+ _RM_ESC_IOCTL_ENTRY(NV_ESC_REGISTER_FD, nv_ioctl_register_fd_t),
+ };
+
+ if (arg_cmd == NV_ESC_RM_ALLOC)
+ {
+ if (size == sizeof(NVOS64_PARAMETERS) || size == sizeof(NVOS21_PARAMETERS))
+ {
+ return NV_OK;
+ }
+ else
+ {
+ nv_printf(NV_DBG_ERRORS, "NVRM: invalid %d structure size!\n", arg_cmd);
+
+ return NV_ERR_INVALID_ARGUMENT;
+ }
+ }
+
+ for (i = 0; i < NV_ARRAY_ELEMENTS(RmIoctlsTable); ++i)
+ {
+ if (arg_cmd == RmIoctlsTable[i].cmdKey)
+ {
+ if (size != RmIoctlsTable[i].paramSize)
+ {
+ nv_printf(NV_DBG_ERRORS, "NVRM: invalid %d structure size, expected %d, got %d!\n",
+ RmIoctlsTable[i].cmdKey, RmIoctlsTable[i].paramSize, size);
+ // If IOCTL is found and size is mismatched, return NV_ERR_INVALID_ARGUMENT
+ return NV_ERR_INVALID_ARGUMENT;
+ }
+ // If IOCTL is found and size is valid, return NV_OK
+ return NV_OK;
+ }
+ }
+ // If IOCTL is not found, return NV_ERR_INVALID_COMMAND
+ return NV_ERR_INVALID_COMMAND;
+}
+
+NV_STATUS RmIoctl(
+ nv_state_t *nv,
+ nv_file_private_t *nvfp,
+ NvU32 cmd,
+ void *data,
+ NvU32 dataSize
+)
+{
+ // nvfp->ctl_nvfp
+ ct_assert(sizeof(PORT_ATOMIC nv_file_private_t *) == sizeof(nv_file_private_t *));
+ ct_assert(_Alignof(PORT_ATOMIC nv_file_private_t *) == _Alignof(nv_file_private_t *));
+
+ // nvfp->register_or_refcount
+ ct_assert(sizeof(PORT_ATOMIC NvU32) == sizeof(NvU32));
+ ct_assert(_Alignof(PORT_ATOMIC NvU32) == _Alignof(NvU32));
+
+ NV_STATUS rmStatus = NV_ERR_GENERIC;
+ API_SECURITY_INFO secInfo = { };
+
+ secInfo.privLevel = osIsAdministrator() ? RS_PRIV_LEVEL_USER_ROOT : RS_PRIV_LEVEL_USER;
+ secInfo.paramLocation = PARAM_LOCATION_USER;
+ secInfo.pProcessToken = NULL;
+ secInfo.gpuOsInfo = NULL;
+ secInfo.clientOSInfo = nvfp->ctl_nvfp;
+ if (secInfo.clientOSInfo == NULL)
+ secInfo.clientOSInfo = nvfp;
+
+ switch (cmd)
+ {
+ case NV_ESC_RM_ALLOC_MEMORY:
+ {
+ nv_ioctl_nvos02_parameters_with_fd *pApi;
+ NVOS02_PARAMETERS *pParms;
+
+ if (dataSize != sizeof(*pApi))
+ {
+ rmStatus = NV_ERR_INVALID_ARGUMENT;
+ goto done;
+ }
+
+ pApi = data;
+ pParms = &pApi->params;
+
+ NV_ACTUAL_DEVICE_ONLY(nv);
+
+ if (pParms->hClass == NV01_MEMORY_SYSTEM_OS_DESCRIPTOR)
+ RmAllocOsDescriptor(pParms, secInfo);
+ else
+ {
+ NvU32 flags = pParms->flags;
+
+ Nv01AllocMemoryWithSecInfo(pParms, secInfo);
+
+ //
+ // If the system memory is going to be mapped immediately,
+ // create the mmap context for it now.
+ //
+ if ((pParms->hClass == NV01_MEMORY_SYSTEM) &&
+ (!FLD_TEST_DRF(OS02, _FLAGS, _ALLOC, _NONE, flags)) &&
+ (!FLD_TEST_DRF(OS02, _FLAGS, _MAPPING, _NO_MAP, flags)) &&
+ (pParms->status == NV_OK))
+ {
+ if (rm_create_mmap_context(pParms->hRoot,
+ pParms->hObjectParent, pParms->hObjectNew,
+ pParms->pMemory, pParms->limit + 1, 0,
+ NV_MEMORY_DEFAULT,
+ pApi->fd) != NV_OK)
+ {
+ NV_PRINTF(LEVEL_WARNING,
+ "could not create mmap context for %p\n",
+ NvP64_VALUE(pParms->pMemory));
+ rmStatus = NV_ERR_INVALID_ARGUMENT;
+ goto done;
+ }
+ }
+ }
+
+ break;
+ }
+
+ case NV_ESC_RM_ALLOC_OBJECT:
+ {
+ NVOS05_PARAMETERS *pApi = data;
+
+ if (dataSize != sizeof(*pApi))
+ {
+ rmStatus = NV_ERR_INVALID_ARGUMENT;
+ goto done;
+ }
+
+ NV_CTL_DEVICE_ONLY(nv);
+
+ Nv01AllocObjectWithSecInfo(pApi, secInfo);
+ break;
+ }
+
+ case NV_ESC_RM_ALLOC:
+ {
+ NVOS21_PARAMETERS *pApi = data;
+ NVOS64_PARAMETERS *pApiAccess = data;
+ NvBool bAccessApi = (dataSize == sizeof(NVOS64_PARAMETERS));
+
+ if ((dataSize != sizeof(*pApi)) &&
+ (dataSize != sizeof(*pApiAccess)))
+ {
+ rmStatus = NV_ERR_INVALID_ARGUMENT;
+ goto done;
+ }
+
+ switch (pApi->hClass)
+ {
+ case NV01_ROOT:
+ case NV01_ROOT_CLIENT:
+ case NV01_ROOT_NON_PRIV:
+ {
+ NV_CTL_DEVICE_ONLY(nv);
+
+ // Force userspace client allocations to be the _CLIENT class.
+ pApi->hClass = NV01_ROOT_CLIENT;
+ break;
+ }
+ case NV01_EVENT:
+ case NV01_EVENT_OS_EVENT:
+ case NV01_EVENT_KERNEL_CALLBACK:
+ case NV01_EVENT_KERNEL_CALLBACK_EX:
+ {
+ break;
+ }
+ default:
+ {
+ NV_CTL_DEVICE_ONLY(nv);
+ break;
+ }
+ }
+
+ if (!bAccessApi)
+ {
+ Nv04AllocWithSecInfo(pApi, secInfo);
+ }
+ else
+ {
+ Nv04AllocWithAccessSecInfo(pApiAccess, secInfo);
+ }
+
+ break;
+ }
+
+ case NV_ESC_RM_FREE:
+ {
+ NVOS00_PARAMETERS *pApi = data;
+
+ if (dataSize != sizeof(*pApi))
+ {
+ rmStatus = NV_ERR_INVALID_ARGUMENT;
+ goto done;
+ }
+
+ NV_CTL_DEVICE_ONLY(nv);
+
+ Nv01FreeWithSecInfo(pApi, secInfo);
+
+ if (pApi->status == NV_OK &&
+ pApi->hObjectOld == pApi->hRoot)
+ {
+ rm_client_free_os_events(pApi->hRoot);
+ }
+
+ break;
+ }
+
+ case NV_ESC_RM_VID_HEAP_CONTROL:
+ {
+ NVOS32_PARAMETERS *pApi = data;
+
+ if (dataSize != sizeof(*pApi))
+ {
+ rmStatus = NV_ERR_INVALID_ARGUMENT;
+ goto done;
+ }
+
+ NV_CTL_DEVICE_ONLY(nv);
+
+ if (pApi->function == NVOS32_FUNCTION_ALLOC_OS_DESCRIPTOR)
+ RmCreateOsDescriptor(pApi, secInfo);
+ else
+ Nv04VidHeapControlWithSecInfo(pApi, secInfo);
+
+ break;
+ }
+
+ case NV_ESC_RM_I2C_ACCESS:
+ {
+ NVOS_I2C_ACCESS_PARAMS *pApi = data;
+
+ if (dataSize != sizeof(*pApi))
+ {
+ rmStatus = NV_ERR_INVALID_ARGUMENT;
+ goto done;
+ }
+
+ NV_ACTUAL_DEVICE_ONLY(nv);
+
+ Nv04I2CAccessWithSecInfo(pApi, secInfo);
+ break;
+ }
+
+ case NV_ESC_RM_IDLE_CHANNELS:
+ {
+ NVOS30_PARAMETERS *pApi = data;
+
+ if (dataSize != sizeof(*pApi))
+ {
+ rmStatus = NV_ERR_INVALID_ARGUMENT;
+ goto done;
+ }
+
+ NV_CTL_DEVICE_ONLY(nv);
+
+ Nv04IdleChannelsWithSecInfo(pApi, secInfo);
+ break;
+ }
+
+ case NV_ESC_RM_MAP_MEMORY:
+ {
+ nv_ioctl_nvos33_parameters_with_fd *pApi;
+ NVOS33_PARAMETERS *pParms;
+
+ if (dataSize != sizeof(*pApi))
+ {
+ rmStatus = NV_ERR_INVALID_ARGUMENT;
+ goto done;
+ }
+
+ pApi = data;
+ pParms = &pApi->params;
+
+ NV_CTL_DEVICE_ONLY(nv);
+
+ // Don't allow userspace to override the caching type
+ pParms->flags = FLD_SET_DRF(OS33, _FLAGS, _CACHING_TYPE, _DEFAULT, pParms->flags);
+ Nv04MapMemoryWithSecInfo(pParms, secInfo);
+
+ if (pParms->status == NV_OK)
+ {
+ pParms->status = rm_create_mmap_context(pParms->hClient,
+ pParms->hDevice, pParms->hMemory,
+ pParms->pLinearAddress, pParms->length,
+ pParms->offset,
+ DRF_VAL(OS33, _FLAGS, _CACHING_TYPE, pParms->flags),
+ pApi->fd);
+ if (pParms->status != NV_OK)
+ {
+ NVOS34_PARAMETERS params;
+ portMemSet(&params, 0, sizeof(params));
+ params.hClient = pParms->hClient;
+ params.hDevice = pParms->hDevice;
+ params.hMemory = pParms->hMemory;
+ params.pLinearAddress = pParms->pLinearAddress;
+ params.flags = pParms->flags;
+ Nv04UnmapMemoryWithSecInfo(&params, secInfo);
+ }
+ }
+ break;
+ }
+
+ case NV_ESC_RM_UNMAP_MEMORY:
+ {
+ NVOS34_PARAMETERS *pApi = data;
+
+ if (dataSize != sizeof(*pApi))
+ {
+ rmStatus = NV_ERR_INVALID_ARGUMENT;
+ goto done;
+ }
+
+ NV_CTL_DEVICE_ONLY(nv);
+
+ Nv04UnmapMemoryWithSecInfo(pApi, secInfo);
+ break;
+ }
+
+ case NV_ESC_RM_ACCESS_REGISTRY:
+ {
+ NVOS38_PARAMETERS *pApi = data;
+
+ if (dataSize != sizeof(*pApi))
+ {
+ rmStatus = NV_ERR_INVALID_ARGUMENT;
+ goto done;
+ }
+
+ NV_CTL_DEVICE_ONLY(nv);
+
+ pApi->status = rm_access_registry(pApi->hClient,
+ pApi->hObject,
+ pApi->AccessType,
+ pApi->pDevNode,
+ pApi->DevNodeLength,
+ pApi->pParmStr,
+ pApi->ParmStrLength,
+ pApi->pBinaryData,
+ &pApi->BinaryDataLength,
+ &pApi->Data,
+ &pApi->Entry);
+ break;
+ }
+
+ case NV_ESC_RM_ALLOC_CONTEXT_DMA2:
+ {
+ NVOS39_PARAMETERS *pApi = data;
+
+ if (dataSize != sizeof(*pApi))
+ {
+ rmStatus = NV_ERR_INVALID_ARGUMENT;
+ goto done;
+ }
+
+ NV_CTL_DEVICE_ONLY(nv);
+
+ Nv04AllocContextDmaWithSecInfo(pApi, secInfo);
+ break;
+ }
+
+ case NV_ESC_RM_BIND_CONTEXT_DMA:
+ {
+ NVOS49_PARAMETERS *pApi = data;
+
+ if (dataSize != sizeof(*pApi))
+ {
+ rmStatus = NV_ERR_INVALID_ARGUMENT;
+ goto done;
+ }
+
+ NV_CTL_DEVICE_ONLY(nv);
+
+ Nv04BindContextDmaWithSecInfo(pApi, secInfo);
+ break;
+ }
+
+ case NV_ESC_RM_MAP_MEMORY_DMA:
+ {
+ NVOS46_PARAMETERS *pApi = data;
+
+ if (dataSize != sizeof(*pApi))
+ {
+ rmStatus = NV_ERR_INVALID_ARGUMENT;
+ goto done;
+ }
+
+ NV_CTL_DEVICE_ONLY(nv);
+
+ Nv04MapMemoryDmaWithSecInfo(pApi, secInfo);
+ break;
+ }
+
+ case NV_ESC_RM_UNMAP_MEMORY_DMA:
+ {
+ NVOS47_PARAMETERS *pApi = data;
+
+ if (dataSize != sizeof(*pApi))
+ {
+ rmStatus = NV_ERR_INVALID_ARGUMENT;
+ goto done;
+ }
+
+ NV_CTL_DEVICE_ONLY(nv);
+
+ Nv04UnmapMemoryDmaWithSecInfo(pApi, secInfo);
+ break;
+ }
+
+ case NV_ESC_RM_DUP_OBJECT:
+ {
+ NVOS55_PARAMETERS *pApi = data;
+
+ if (dataSize != sizeof(*pApi))
+ {
+ rmStatus = NV_ERR_INVALID_ARGUMENT;
+ goto done;
+ }
+
+ NV_CTL_DEVICE_ONLY(nv);
+
+ Nv04DupObjectWithSecInfo(pApi, secInfo);
+ break;
+ }
+
+ case NV_ESC_RM_SHARE:
+ {
+ NVOS57_PARAMETERS *pApi = data;
+
+ if (dataSize != sizeof(*pApi))
+ {
+ rmStatus = NV_ERR_INVALID_ARGUMENT;
+ goto done;
+ }
+
+ NV_CTL_DEVICE_ONLY(nv);
+
+ Nv04ShareWithSecInfo(pApi, secInfo);
+ break;
+ }
+
+ case NV_ESC_STATUS_CODE:
+ {
+ nv_state_t *pNv;
+ nv_ioctl_status_code_t *pApi = data;
+
+ if (dataSize != sizeof(*pApi))
+ {
+ rmStatus = NV_ERR_INVALID_ARGUMENT;
+ goto done;
+ }
+
+ NV_CTL_DEVICE_ONLY(nv);
+
+ pNv = nv_get_adapter_state(pApi->domain, pApi->bus, pApi->slot);
+ if (pNv == NULL)
+ {
+ rmStatus = NV_ERR_INVALID_ARGUMENT;
+ goto done;
+ }
+
+ rmStatus = rm_get_adapter_status(pNv, &pApi->status);
+
+ if (rmStatus != NV_OK)
+ goto done;
+
+ break;
+ }
+
+ case NV_ESC_RM_CONTROL:
+ {
+ NVOS54_PARAMETERS *pApi = data;
+ void *priv = NULL;
+ nv_file_private_t *dev_nvfp = NULL;
+ NvS32 fd;
+ NvBool bSkipDeviceRef;
+
+ if (dataSize != sizeof(*pApi))
+ {
+ rmStatus = NV_ERR_INVALID_ARGUMENT;
+ goto done;
+ }
+
+ NV_CTL_DEVICE_ONLY(nv);
+
+ rmStatus = RmGetDeviceFd(pApi, &fd, &bSkipDeviceRef);
+ if (rmStatus != NV_OK)
+ {
+ goto done;
+ }
+
+ if (!bSkipDeviceRef)
+ {
+ dev_nvfp = nv_get_file_private(fd, NV_FALSE, &priv);
+ if (dev_nvfp == NULL)
+ {
+ rmStatus = NV_ERR_INVALID_DEVICE;
+ goto done;
+ }
+
+ // Check to avoid cyclic dependency with NV_ESC_REGISTER_FD
+ if (!portAtomicCompareAndSwapU32(&dev_nvfp->register_or_refcount,
+ NVFP_TYPE_REFCOUNTED,
+ NVFP_TYPE_NONE))
+ {
+ // Is this already refcounted...
+ if (dev_nvfp->register_or_refcount != NVFP_TYPE_REFCOUNTED)
+ {
+ nv_put_file_private(priv);
+ rmStatus = NV_ERR_IN_USE;
+ goto done;
+ }
+ }
+
+ secInfo.gpuOsInfo = priv;
+ }
+
+ Nv04ControlWithSecInfo(pApi, secInfo);
+
+ if ((pApi->status != NV_OK) && (priv != NULL))
+ {
+ //
+ // No need to reset `register_or_refcount` as it might be set
+ // for previous successful calls. We let it clear with FD close.
+ //
+ nv_put_file_private(priv);
+
+ secInfo.gpuOsInfo = NULL;
+ }
+
+ break;
+ }
+
+ case NV_ESC_RM_UPDATE_DEVICE_MAPPING_INFO:
+ {
+ NVOS56_PARAMETERS *pApi = data;
+ void *pOldCpuAddress;
+ void *pNewCpuAddress;
+
+ if (dataSize != sizeof(*pApi))
+ {
+ rmStatus = NV_ERR_INVALID_ARGUMENT;
+ goto done;
+ }
+
+ NV_CTL_DEVICE_ONLY(nv);
+
+ pOldCpuAddress = NvP64_VALUE(pApi->pOldCpuAddress);
+ pNewCpuAddress = NvP64_VALUE(pApi->pNewCpuAddress);
+
+ pApi->status = rm_update_device_mapping_info(pApi->hClient,
+ pApi->hDevice,
+ pApi->hMemory,
+ pOldCpuAddress,
+ pNewCpuAddress);
+ break;
+ }
+
+ case NV_ESC_RM_LOCKLESS_DIAGNOSTIC:
+ {
+ NV_LOCKLESS_DIAGNOSTIC_PARAMS *pParams = data;
+
+ if (dataSize != sizeof(*pParams))
+ {
+ rmStatus = NV_ERR_INVALID_ARGUMENT;
+ goto done;
+ }
+
+ NV_CTL_DEVICE_ONLY(nv);
+
+ if (!osIsAdministrator())
+ {
+ rmStatus = NV_ERR_INSUFFICIENT_PERMISSIONS;
+ goto done;
+ }
+
+ switch (pParams->cmd)
+ {
+ // Do not use NVOC _DISPATCH here as it dereferences NULL RmClientResource*
+ case NV0000_CTRL_CMD_NVD_GET_NVLOG_INFO:
+ rmStatus = cliresCtrlCmdNvdGetNvlogInfo_IMPL(NULL, &pParams->params.getNvlogInfo);
+ break;
+ case NV0000_CTRL_CMD_NVD_GET_NVLOG_BUFFER_INFO:
+ rmStatus = cliresCtrlCmdNvdGetNvlogBufferInfo_IMPL(NULL, &pParams->params.getNvlogBufferInfo);
+ break;
+ case NV0000_CTRL_CMD_NVD_GET_NVLOG:
+ rmStatus = cliresCtrlCmdNvdGetNvlog_IMPL(NULL, &pParams->params.getNvlog);
+ break;
+ default:
+ rmStatus = NV_ERR_NOT_SUPPORTED;
+ break;
+ }
+
+ pParams->status = rmStatus;
+ goto done;
+ }
+
+ case NV_ESC_REGISTER_FD:
+ {
+ nv_ioctl_register_fd_t *params = data;
+ void *priv = NULL;
+ nv_file_private_t *ctl_nvfp;
+
+ if (dataSize != sizeof(*params))
+ {
+ rmStatus = NV_ERR_INVALID_ARGUMENT;
+ goto done;
+ }
+
+ // LOCK: acquire API lock
+ rmStatus = rmapiLockAcquire(API_LOCK_FLAGS_NONE, RM_LOCK_MODULES_OSAPI);
+ if (rmStatus != NV_OK)
+ goto done;
+
+ // If there is already a ctl fd registered on this nvfp, fail.
+ if (nvfp->ctl_nvfp != NULL)
+ {
+ // UNLOCK: release API lock
+ rmapiLockRelease();
+ rmStatus = NV_ERR_INVALID_STATE;
+ goto done;
+ }
+
+ //
+ // Note that this call is valid for both "actual" devices and ctrl
+ // devices. In particular, NV_ESC_ALLOC_OS_EVENT can be used with
+ // both types of devices.
+ // But, the ctl_fd passed in should always correspond to a control FD.
+ //
+ ctl_nvfp = nv_get_file_private(params->ctl_fd,
+ NV_TRUE, /* require ctl fd */
+ &priv);
+ if (ctl_nvfp == NULL)
+ {
+ // UNLOCK: release API lock
+ rmapiLockRelease();
+ rmStatus = NV_ERR_INVALID_ARGUMENT;
+ goto done;
+ }
+
+ // Disallow self-referential links, and disallow links to FDs that
+ // themselves have a link.
+ if ((ctl_nvfp == nvfp) || (ctl_nvfp->ctl_nvfp != NULL))
+ {
+ nv_put_file_private(priv);
+ // UNLOCK: release API lock
+ rmapiLockRelease();
+ rmStatus = NV_ERR_INVALID_ARGUMENT;
+ goto done;
+ }
+
+ // Check to avoid cyclic dependency with device refcounting
+ if (!portAtomicCompareAndSwapU32(&nvfp->register_or_refcount,
+ NVFP_TYPE_REGISTERED,
+ NVFP_TYPE_NONE))
+ {
+ nv_put_file_private(priv);
+ // UNLOCK: release API lock
+ rmapiLockRelease();
+ rmStatus = NV_ERR_IN_USE;
+ goto done;
+ }
+
+ //
+ // nvfp->ctl_nvfp is read outside the lock, so set it atomically.
+ // Note that once set, this can never be removed until the fd
+ // associated with nvfp is closed. We hold on to 'priv' until the
+ // fd is closed, too, to ensure that the fd associated with
+ // ctl_nvfp remains valid.
+ //
+ portAtomicSetSize(&nvfp->ctl_nvfp, ctl_nvfp);
+ nvfp->ctl_nvfp_priv = priv;
+
+ // UNLOCK: release API lock
+ rmapiLockRelease();
+
+ // NOTE: nv_put_file_private(priv) is not called here. It MUST be
+ // called during cleanup of this nvfp.
+ rmStatus = NV_OK;
+ break;
+ }
+
+ default:
+ {
+ NV_PRINTF(LEVEL_ERROR, "unknown NVRM ioctl command: 0x%x\n", cmd);
+ goto done;
+ }
+ }
+
+ rmStatus = NV_OK;
+done:
+
+ return rmStatus;
+}
diff --git a/userspace/sdks/nv570/nvalloc/unix/src/exports-stubs.c b/userspace/sdks/nv570/nvalloc/unix/src/exports-stubs.c
new file mode 100644
index 0000000..ff40300
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/src/exports-stubs.c
@@ -0,0 +1,30 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2020-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <nv.h>
+#include "os/os.h"
+#include <rmconfig.h>
+#include <gpu/subdevice/subdevice.h>
+#include <ctrl/ctrl0080/ctrl0080unix.h>
+#include <ctrl/ctrl2080/ctrl2080unix.h>
+
diff --git a/userspace/sdks/nv570/nvalloc/unix/src/gcc_helper.c b/userspace/sdks/nv570/nvalloc/unix/src/gcc_helper.c
new file mode 100644
index 0000000..3c1037c
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/src/gcc_helper.c
@@ -0,0 +1,35 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 1999-2021 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <nvtypes.h>
+#include <os-interface.h>
+
+void* memset(void* s, int c, NvUPtr n)
+{
+ return os_mem_set(s, (NvU8)c, (NvU32)n);
+}
+
+void* memcpy(void* dest, const void* src, NvUPtr n)
+{
+ return os_mem_copy(dest, src, (NvU32)n);
+}
diff --git a/userspace/sdks/nv570/nvalloc/unix/src/os-hypervisor.c b/userspace/sdks/nv570/nvalloc/unix/src/os-hypervisor.c
new file mode 100644
index 0000000..26c468f
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/src/os-hypervisor.c
@@ -0,0 +1,994 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2014-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/*!
+ *
+ * @file os-hypervisor.c
+ * @brief OS specific Hypervisor interfaces for RM
+ *
+ */
+
+#include "os/os.h"
+#include "nv.h"
+#include "nv-priv.h"
+#include <nvrm_registry.h>
+#include <virtualization/hypervisor/hypervisor.h>
+#include "core/thread_state.h"
+#include "core/locks.h"
+#include "virtualization/kernel_vgpu_mgr.h"
+#include "kernel/gpu/mig_mgr/kernel_mig_manager.h"
+#include "kernel/gpu/fifo/kernel_fifo.h"
+#include "osapi.h"
+#include "virtualization/kernel_hostvgpudeviceapi.h"
+#include "gpu/timer/objtmr.h"
+#include "gpu/bif/kernel_bif.h"
+#include "gpu/bus/kern_bus.h"
+#include <nv_ref.h> // NV_PMC_BOOT_1_VGPU
+#include "nvdevid.h"
+#include "ctrl/ctrl0000/ctrl0000vgpu.h"
+
+#include "g_vgpu_chip_flags.h" // vGPU device names
+
+#define NV_VFIO_PCI_BAR0_REGION_INDEX 0
+#define NV_VFIO_PCI_BAR1_REGION_INDEX 1
+#define NV_VFIO_PCI_BAR2_REGION_INDEX 2
+#define NV_VFIO_PCI_BAR3_REGION_INDEX 3
+
+static NV_STATUS nv_parse_config_params(const char *, const char *, const char, NvU32 *);
+
+
+void hypervisorSetHypervVgpuSupported_IMPL(OBJHYPERVISOR *pHypervisor)
+{
+ pHypervisor->bIsHypervVgpuSupported = NV_TRUE;
+}
+
+NvBool hypervisorIsVgxHyper_IMPL(void)
+{
+ return os_is_vgx_hyper();
+}
+
+NV_STATUS hypervisorInjectInterrupt_IMPL
+(
+ OBJHYPERVISOR *pHypervisor,
+ VGPU_NS_INTR *pVgpuNsIntr
+)
+{
+ NV_STATUS status = NV_ERR_NOT_SUPPORTED;
+
+ if (osIsVgpuVfioPresent() == NV_OK)
+ return NV_ERR_NOT_SUPPORTED;
+ else
+ {
+ if (pVgpuNsIntr->guestMSIAddr && pVgpuNsIntr->guestMSIData)
+ {
+ status = os_inject_vgx_msi((NvU16)pVgpuNsIntr->guestDomainId,
+ pVgpuNsIntr->guestMSIAddr,
+ pVgpuNsIntr->guestMSIData);
+ }
+ }
+
+ return status;
+}
+
+HYPERVISOR_TYPE NV_API_CALL nv_get_hypervisor_type(void)
+{
+ OBJSYS *pSys = SYS_GET_INSTANCE();
+ OBJHYPERVISOR *pHypervisor = SYS_GET_HYPERVISOR(pSys);
+ return hypervisorGetHypervisorType(pHypervisor);
+}
+
+#define MAX_STR_LEN 256
+NV_STATUS NV_API_CALL nv_vgpu_get_type_info(
+ nvidia_stack_t *sp,
+ nv_state_t *pNv,
+ NvU32 vgpuTypeId,
+ char *buffer,
+ int type_info,
+ NvU8 devfn
+)
+{
+ THREAD_STATE_NODE threadState;
+ OBJSYS *pSys = SYS_GET_INSTANCE();
+ KernelVgpuMgr *pKernelVgpuMgr = SYS_GET_KERNEL_VGPUMGR(pSys);
+ NV_STATUS rmStatus = NV_OK;
+ VGPU_TYPE *vgpuTypeInfo;
+ NvU32 pgpuIndex, i, avail_instances = 0;
+ OBJGPU *pGpu = NULL;
+ void *fp;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ // LOCK: acquire API lock
+ if ((rmStatus = rmapiLockAcquire(API_LOCK_FLAGS_NONE, RM_LOCK_MODULES_HYPERVISOR)) == NV_OK)
+ {
+ if ((rmStatus = kvgpumgrGetPgpuIndex(pKernelVgpuMgr, pNv->gpu_id, &pgpuIndex)) ==
+ NV_OK)
+ {
+ for (i = 0; i < MAX_VGPU_TYPES_PER_PGPU; i++)
+ {
+ vgpuTypeInfo = pKernelVgpuMgr->pgpuInfo[pgpuIndex].vgpuTypes[i];
+ if (vgpuTypeInfo == NULL)
+ break;
+
+ if (vgpuTypeInfo->vgpuTypeId != vgpuTypeId)
+ continue;
+
+ switch (type_info)
+ {
+ case VGPU_TYPE_INSTANCES:
+ pGpu = NV_GET_NV_PRIV_PGPU(pNv);
+ if (pGpu == NULL)
+ {
+ NV_PRINTF(LEVEL_ERROR, "%s GPU handle is not valid \n",
+ __FUNCTION__);
+ rmStatus = NV_ERR_INVALID_STATE;
+ goto exit;
+ }
+
+ rmStatus = kvgpumgrGetAvailableInstances(&avail_instances, pGpu,
+ vgpuTypeInfo,
+ pgpuIndex, devfn);
+ if (rmStatus != NV_OK)
+ goto exit;
+
+ os_snprintf(buffer, MAX_STR_LEN, "%d\n", avail_instances);
+ break;
+ default:
+ rmStatus = NV_ERR_INVALID_ARGUMENT;
+ }
+ break;
+ }
+ }
+
+exit:
+ // UNLOCK: release API lock
+ rmapiLockRelease();
+ }
+
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL nv_vgpu_get_type_ids(
+ nvidia_stack_t *sp,
+ nv_state_t *pNv,
+ NvU32 *numVgpuTypes,
+ NvU32 *vgpuTypeIds,
+ NvBool isVirtfn,
+ NvU8 devfn,
+ NvBool getCreatableTypes
+)
+{
+ THREAD_STATE_NODE threadState;
+ OBJSYS *pSys = SYS_GET_INSTANCE();
+ OBJGPU *pGpu = NULL;
+ KernelVgpuMgr *pKernelVgpuMgr = SYS_GET_KERNEL_VGPUMGR(pSys);
+ NV_STATUS rmStatus = NV_OK;
+ NvU32 pgpuIndex, i, avail_instances = 0;
+ NvU32 numSupportedVgpuTypes = 0;
+ VGPU_TYPE *vgpuTypeInfo;
+ void *fp;
+
+ if (!vgpuTypeIds || !numVgpuTypes)
+ return NV_ERR_INVALID_ARGUMENT;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ // LOCK: acquire API lock
+ if ((rmStatus = rmapiLockAcquire(API_LOCK_FLAGS_NONE, RM_LOCK_MODULES_HYPERVISOR)) == NV_OK)
+ {
+ if ((rmStatus = kvgpumgrGetPgpuIndex(pKernelVgpuMgr, pNv->gpu_id, &pgpuIndex)) ==
+ NV_OK)
+ {
+ if (pKernelVgpuMgr->pgpuInfo[pgpuIndex].sriovEnabled && !isVirtfn)
+ {
+ *numVgpuTypes = 0;
+ }
+ else
+ {
+ numSupportedVgpuTypes = pKernelVgpuMgr->pgpuInfo[pgpuIndex].numVgpuTypes;
+ *numVgpuTypes = 0;
+
+ for (i = 0; i < numSupportedVgpuTypes; i++)
+ {
+ vgpuTypeInfo = pKernelVgpuMgr->pgpuInfo[pgpuIndex].vgpuTypes[i];
+
+ if (!getCreatableTypes)
+ {
+ // Return all available types
+ vgpuTypeIds[*numVgpuTypes] = vgpuTypeInfo->vgpuTypeId;
+ (*numVgpuTypes)++;
+ continue;
+ }
+
+ pGpu = NV_GET_NV_PRIV_PGPU(pNv);
+ if (pGpu == NULL)
+ {
+ NV_PRINTF(LEVEL_ERROR, "%s GPU handle is not valid \n",
+ __FUNCTION__);
+ goto exit;
+ }
+
+ rmStatus = kvgpumgrGetAvailableInstances(&avail_instances, pGpu,
+ vgpuTypeInfo, pgpuIndex,
+ devfn);
+ if (rmStatus != NV_OK)
+ {
+ NV_PRINTF(LEVEL_ERROR, "Failed to get available instances for vGPU ID: %d, status: 0x%x\n",
+ vgpuTypeInfo->vgpuTypeId, rmStatus);
+ continue;
+ }
+
+ if (avail_instances == 0)
+ continue;
+
+ vgpuTypeIds[*numVgpuTypes] = vgpuTypeInfo->vgpuTypeId;
+ (*numVgpuTypes)++;
+ }
+ }
+ }
+
+exit:
+ // UNLOCK: release API lock
+ rmapiLockRelease();
+ }
+
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL nv_vgpu_delete(
+ nvidia_stack_t *sp,
+ const NvU8 *pVgpuDevName,
+ NvU16 vgpuId
+)
+{
+ THREAD_STATE_NODE threadState;
+ void *fp = NULL;
+ NvU32 rmStatus = NV_OK;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ // LOCK: acquire API lock
+ if ((rmStatus = rmapiLockAcquire(API_LOCK_FLAGS_NONE, RM_LOCK_MODULES_HYPERVISOR)) == NV_OK)
+ {
+ rmStatus = kvgpumgrDeleteRequestVgpu(pVgpuDevName, vgpuId);
+ // UNLOCK: release API lock
+ rmapiLockRelease();
+ }
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL nv_vgpu_process_vf_info(
+ nvidia_stack_t *sp,
+ nv_state_t *pNv,
+ NvU8 cmd,
+ NvU32 domain,
+ NvU8 bus,
+ NvU8 slot,
+ NvU8 function,
+ NvBool isMdevAttached,
+ void *vf_pci_info
+)
+{
+ THREAD_STATE_NODE threadState;
+ NV_STATUS rmStatus = NV_OK;
+ void *fp = NULL;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ // LOCK: acquire API lock
+ if ((rmStatus = rmapiLockAcquire(API_LOCK_FLAGS_NONE, RM_LOCK_MODULES_HYPERVISOR)) == NV_OK)
+ {
+ rmStatus = kvgpumgrProcessVfInfo(pNv->gpu_id, cmd, domain, bus, slot, function, isMdevAttached, (vgpu_vf_pci_info *) vf_pci_info);
+
+ // UNLOCK: release API lock
+ rmapiLockRelease();
+ }
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL nv_vgpu_create_request(
+ nvidia_stack_t *sp,
+ nv_state_t *pNv,
+ const NvU8 *pVgpuDevName,
+ NvU32 vgpuTypeId,
+ NvU16 *vgpuId,
+ NvU32 *gpu_instance_id,
+ NvU32 *placement_id,
+ NvU32 gpuPciBdf
+)
+{
+ THREAD_STATE_NODE threadState;
+ void *fp = NULL;
+ NV_STATUS rmStatus = NV_OK;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ // LOCK: acquire API lock
+ if ((rmStatus = rmapiLockAcquire(API_LOCK_FLAGS_NONE, RM_LOCK_MODULES_HYPERVISOR)) == NV_OK)
+ {
+ rmStatus = kvgpumgrCreateRequestVgpu(pNv->gpu_id, pVgpuDevName,
+ vgpuTypeId, vgpuId, gpu_instance_id, placement_id, gpuPciBdf);
+
+ // UNLOCK: release API lock
+ rmapiLockRelease();
+ }
+
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return rmStatus;
+}
+
+static NV_STATUS is_bar_64bit(
+ OBJGPU *pGpu,
+ NvU32 regionIndex,
+ NvBool *isBar64bit
+)
+{
+ NV_STATUS rmStatus = NV_OK;
+
+ if (pGpu == NULL)
+ {
+ NV_PRINTF(LEVEL_ERROR, "%s GPU handle is not valid \n", __FUNCTION__);
+ rmStatus = NV_ERR_INVALID_STATE;
+ goto exit;
+ }
+
+ switch (regionIndex)
+ {
+ case NV_VFIO_PCI_BAR0_REGION_INDEX:
+ *isBar64bit = pGpu->sriovState.b64bitVFBar0;
+ break;
+
+ case NV_VFIO_PCI_BAR1_REGION_INDEX:
+ *isBar64bit = pGpu->sriovState.b64bitVFBar1;
+ break;
+
+ case NV_VFIO_PCI_BAR2_REGION_INDEX:
+ *isBar64bit = pGpu->sriovState.b64bitVFBar2;
+ break;
+
+ default:
+ NV_PRINTF(LEVEL_ERROR, "BAR%d region doesn't exist!\n", regionIndex);
+ rmStatus = NV_ERR_INVALID_ARGUMENT;
+ goto exit;
+ break;
+ }
+
+ NV_PRINTF(LEVEL_INFO, "BAR%d region is_64bit: %d\n", regionIndex, *isBar64bit);;
+
+exit:
+ return rmStatus;
+}
+
+static NV_STATUS
+_nv_vgpu_get_bar_size(OBJGPU *pGpu, KERNEL_HOST_VGPU_DEVICE *pKernelHostVgpuDevice,
+ NvU32 regionIndex, NvU64 *size, NvU8 *configParams)
+{
+ OBJSYS *pSys = SYS_GET_INSTANCE();
+ KernelVgpuMgr *pKernelVgpuMgr = SYS_GET_KERNEL_VGPUMGR(pSys);
+ NV_STATUS status;
+ KernelBus *pKernelBus;
+ NvU32 value = 0;
+
+ pKernelBus = GPU_GET_KERNEL_BUS(pGpu);
+ *size = kbusGetPciBarSize(pKernelBus, regionIndex);
+
+ if (regionIndex == NV_VFIO_PCI_BAR1_REGION_INDEX)
+ {
+ VGPU_TYPE *vgpuTypeInfo;
+ NvU32 pgpuIndex = 0;
+ NvBool bOverrideBar1Size = NV_FALSE;
+
+ // Read BAR1 length from vgpuTypeInfo
+ NV_ASSERT_OK_OR_RETURN(kvgpumgrGetVgpuTypeInfo(pKernelHostVgpuDevice->vgpuType,
+ &vgpuTypeInfo));
+
+ *size = vgpuTypeInfo->bar1Length << 20;
+ NV_ASSERT_OK_OR_RETURN(kvgpumgrGetPgpuIndex(pKernelVgpuMgr, pGpu->gpuId, &pgpuIndex));
+
+ /*
+ * check for 'override_bar1_size' param in vgpuExtraParams list first,
+ * if param is missing there then check it in vgpu_params list
+ */
+ status = nv_parse_config_params((const char*)vgpuTypeInfo->vgpuExtraParams,
+ "override_bar1_size", ';', &value);
+ if (status == NV_OK && value)
+ {
+ bOverrideBar1Size = NV_TRUE;
+ }
+ else if (status == NV_ERR_OBJECT_NOT_FOUND)
+ {
+ status = nv_parse_config_params((const char *)configParams,
+ "override_bar1_size", ',', &value);
+ if (status == NV_OK && value)
+ bOverrideBar1Size = NV_TRUE;
+ }
+
+ if (gpuIsVfResizableBAR1Supported(pGpu))
+ {
+ if ((*size > pGpu->sriovState.vfBarSize[1]) ||
+ (!portStringCompare("Compute", (const char *)vgpuTypeInfo->vgpuClass, 7)))
+ {
+ *size = pGpu->sriovState.vfBarSize[1];
+ }
+ }
+
+ if (bOverrideBar1Size)
+ {
+ NvU64 bar1SizeInBytes, guestBar1;
+ NvU64 gpuBar1LowerLimit = 256 * 1024 * 1024; // bar1 lower limit for override_bar1_length parameter
+ bar1SizeInBytes = kbusGetPciBarSize(pKernelBus, NV_VFIO_PCI_BAR1_REGION_INDEX);
+
+ if (pKernelVgpuMgr->pgpuInfo[pgpuIndex].sriovEnabled)
+ {
+ *size = pGpu->sriovState.vfBarSize[1];
+ }
+ else if (bar1SizeInBytes > gpuBar1LowerLimit)
+ {
+ guestBar1 = bar1SizeInBytes / vgpuTypeInfo->maxInstance;
+ *size = nvPrevPow2_U64(guestBar1);
+ }
+ }
+ }
+ else if (regionIndex == NV_VFIO_PCI_BAR2_REGION_INDEX ||
+ regionIndex == NV_VFIO_PCI_BAR3_REGION_INDEX)
+ {
+ status = nv_parse_config_params((const char *)configParams,
+ "address64", ',', &value);
+
+ if ((status != NV_OK) || ((status == NV_OK) && (value != 0)))
+ {
+ if (regionIndex == NV_VFIO_PCI_BAR2_REGION_INDEX)
+ *size = 0;
+ else if (regionIndex == NV_VFIO_PCI_BAR3_REGION_INDEX)
+ *size = kbusGetPciBarSize(pKernelBus, NV_VFIO_PCI_BAR2_REGION_INDEX);
+ }
+ }
+
+ return NV_OK;
+}
+
+NV_STATUS NV_API_CALL nv_vgpu_get_bar_info
+(
+ nvidia_stack_t *sp,
+ nv_state_t *pNv,
+ const NvU8 *pVgpuDevName,
+ NvU64 *barSizes,
+ NvU64 *sparseOffsets,
+ NvU64 *sparseSizes,
+ NvU32 *sparseCount,
+ NvBool *isBar064bit,
+ NvU8 *configParams
+)
+{
+ THREAD_STATE_NODE threadState;
+ NV_STATUS rmStatus = NV_OK;
+ OBJGPU *pGpu = NULL;
+ void *fp = NULL;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ // LOCK: acquire API lock
+ NV_CHECK_OK_OR_GOTO(rmStatus, LEVEL_SILENT,
+ rmapiLockAcquire(API_LOCK_FLAGS_NONE, RM_LOCK_MODULES_HYPERVISOR), exit);
+
+ pGpu = NV_GET_NV_PRIV_PGPU(pNv);
+ if (pGpu == NULL)
+ {
+ NV_PRINTF(LEVEL_ERROR, "%s GPU handle is not valid \n", __FUNCTION__);
+ rmStatus = NV_ERR_INVALID_STATE;
+ goto release_lock;
+ }
+
+ NV_CHECK_OK_OR_GOTO(rmStatus, LEVEL_SILENT,
+ nv_vgpu_rm_get_bar_info(pGpu, pVgpuDevName, barSizes,
+ sparseOffsets, sparseSizes,
+ sparseCount, isBar064bit,
+ configParams),
+ release_lock);
+release_lock:
+ // UNLOCK: release API lock
+ rmapiLockRelease();
+
+exit:
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL nv_vgpu_update_sysfs_info
+(
+ nvidia_stack_t *sp,
+ nv_state_t *pNv,
+ const NvU8 *pVgpuDevName,
+ NvU32 mode,
+ NvU32 *sysfs_val
+)
+{
+ THREAD_STATE_NODE threadState;
+ void *fp = NULL;
+ OBJSYS *pSys = SYS_GET_INSTANCE();
+ KernelVgpuMgr *pKernelVgpuMgr = SYS_GET_KERNEL_VGPUMGR(pSys);
+ REQUEST_VGPU_INFO_NODE *pRequestVgpu = NULL;
+ NV_STATUS rmStatus = NV_OK;
+ VGPU_SYSFS_OP updateMode = (VGPU_SYSFS_OP)mode;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ // LOCK: acquire API lock
+ NV_CHECK_OK_OR_GOTO(rmStatus, LEVEL_SILENT,
+ rmapiLockAcquire(API_LOCK_FLAGS_NONE, RM_LOCK_MODULES_HYPERVISOR), exit);
+
+ // Check the corresponding REQUEST_VGPU_INFO_NODE
+ for (pRequestVgpu = listHead(&pKernelVgpuMgr->listRequestVgpuHead);
+ pRequestVgpu != NULL;
+ pRequestVgpu = listNext(&pKernelVgpuMgr->listRequestVgpuHead, pRequestVgpu))
+ {
+ if (portMemCmp(pRequestVgpu->vgpuDevName, pVgpuDevName, VM_UUID_SIZE) == 0)
+ break;
+ }
+
+ if (pRequestVgpu == NULL)
+ {
+ rmStatus = NV_ERR_OBJECT_NOT_FOUND;
+ goto release_lock;
+ }
+
+ if (updateMode == SET_GPU_INSTANCE_ID)
+ rmStatus = kvgpumgrSetGpuInstanceId(pRequestVgpu, *sysfs_val);
+ else if (updateMode == SET_PLACEMENT_ID)
+ rmStatus = kvgpumgrSetPlacementId(pRequestVgpu, *sysfs_val);
+ else if (updateMode == GET_PLACEMENT_ID)
+ *sysfs_val = pRequestVgpu->placementId;
+
+release_lock:
+ // UNLOCK: release API lock
+ rmapiLockRelease();
+
+exit:
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL nv_vgpu_get_hbm_info(
+ nvidia_stack_t *sp,
+ nv_state_t *pNv,
+ const NvU8 *pVgpuDevName,
+ NvU64 *hbmAddr,
+ NvU64 *size
+)
+{
+ NV_STATUS rmStatus = NV_OK;
+ THREAD_STATE_NODE threadState;
+ OBJGPU *pGpu = NULL;
+ KERNEL_HOST_VGPU_DEVICE *pKernelHostVgpuDevice;
+ void *fp = NULL;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ if ((size == NULL) || (hbmAddr == NULL))
+ {
+ rmStatus = NV_ERR_INVALID_ARGUMENT;
+ goto exit;
+ }
+
+ // LOCK: acquire API lock
+ NV_CHECK_OK_OR_GOTO(rmStatus, LEVEL_SILENT, rmapiLockAcquire(API_LOCK_FLAGS_NONE, RM_LOCK_MODULES_HYPERVISOR), exit);
+
+ pGpu = NV_GET_NV_PRIV_PGPU(pNv);
+ if (pGpu == NULL)
+ {
+ NV_PRINTF(LEVEL_ERROR, "%s GPU handle is not valid \n", __FUNCTION__);
+ rmStatus = NV_ERR_INVALID_STATE;
+ goto release_lock;
+ }
+
+ NV_CHECK_OK_OR_GOTO(rmStatus, LEVEL_SILENT,
+ kvgpumgrGetHostVgpuDeviceFromVgpuDevName(pNv->gpu_id,
+ pVgpuDevName,
+ &pKernelHostVgpuDevice), release_lock);
+ if (pKernelHostVgpuDevice->numValidHbmRegions > 1)
+ {
+ NV_PRINTF(LEVEL_NOTICE, "non contiguous HBM region is not supported\n");
+ NV_ASSERT(0);
+ }
+
+ if (pKernelHostVgpuDevice->hbmRegionList != NULL)
+ {
+ *hbmAddr = pKernelHostVgpuDevice->hbmRegionList[0].hbmBaseAddr;
+ *size = pKernelHostVgpuDevice->hbmRegionList[0].size;
+ }
+ else
+ {
+ *hbmAddr = 0;
+ *size = 0;
+ }
+
+release_lock:
+ // UNLOCK: release API lock
+ rmapiLockRelease();
+exit:
+
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+static NV_STATUS nv_parse_config_params(
+ const char *config_params,
+ const char *key,
+ const char delim,
+ NvU32 *config_value
+)
+{
+ char *ptr, *configParams = rm_remove_spaces(config_params);
+ char *token, *value, *name;
+ NvU32 data;
+ NV_STATUS rmStatus = NV_ERR_OBJECT_NOT_FOUND;
+
+ ptr = configParams;
+ while ((token = rm_string_token(&ptr, delim)) != NULL)
+ {
+ if (!(name = rm_string_token(&token, '=')) || !os_string_length(name))
+ continue;
+
+ if (!(value = rm_string_token(&token, '=')) || !os_string_length(value))
+ continue;
+
+ data = os_strtoul(value, NULL, 0);
+
+ if (os_string_compare(name, key) == 0)
+ {
+ rmStatus = NV_OK;
+ *config_value = data;
+ }
+ }
+
+ // Free the memory allocated by rm_remove_spaces()
+ os_free_mem(configParams);
+
+ return rmStatus;
+}
+
+static NV_STATUS _nv_vgpu_get_sparse_mmap(
+ OBJGPU *pGpu,
+ KERNEL_HOST_VGPU_DEVICE *pKernelHostVgpuDevice,
+ NvU64 *offsets,
+ NvU64 *sizes,
+ NvU32 *numAreas,
+ NvU8 *configParams
+)
+{
+ NV_STATUS rmStatus = NV_OK, status;
+ OBJTMR *pTmr = GPU_GET_TIMER(pGpu);;
+ KernelFifo *pKernelFifo = GPU_GET_KERNEL_FIFO(pGpu);;
+ KernelBif *pKernelBif = GPU_GET_KERNEL_BIF(pGpu);
+ NvU32 value = 0;
+
+ *numAreas = 0;
+ if (pKernelHostVgpuDevice->gfid != 0)
+ {
+ rmStatus = kbifGetVFSparseMmapRegions_HAL(pGpu, pKernelBif, pKernelHostVgpuDevice,
+ os_page_size, numAreas, NULL, NULL);
+ if (rmStatus == NV_OK)
+ {
+ if (*numAreas > NVA081_MAX_SPARSE_REGION_COUNT)
+ {
+ NV_PRINTF(LEVEL_ERROR, "Not enough space for sparse mmap region info\n");
+ return NV_ERR_INSUFFICIENT_RESOURCES;
+ }
+
+
+ rmStatus = kbifGetVFSparseMmapRegions_HAL(pGpu, pKernelBif, pKernelHostVgpuDevice, os_page_size,
+ numAreas, offsets, sizes);
+ if (rmStatus != NV_OK)
+ return rmStatus;
+ }
+ }
+ else
+ {
+ status = nv_parse_config_params((const char *)configParams,
+ "direct_gpu_timer_access", ',', &value);
+ if ((status == NV_OK) && (value != 0))
+ {
+ NvU64 offset = 0;
+ NvU32 size = 0;
+
+ rmStatus = tmrGetTimerBar0MapInfo_HAL(pGpu, pTmr, &offset, &size);
+
+ if (rmStatus == NV_OK)
+ {
+ offsets[*numAreas] = offset;
+ sizes[*numAreas] = size;
+ (*numAreas)++;
+ }
+ }
+
+ value = 0;
+ {
+ NvU64 offset = 0;
+ NvU32 size = 0;
+
+ status = kfifoGetUsermodeMapInfo_HAL(pGpu, pKernelFifo, &offset, &size);
+
+ if (status == NV_OK)
+ {
+ offsets[*numAreas] = offset;
+ sizes[*numAreas] = size;
+ (*numAreas)++;
+ }
+ }
+ }
+
+ return rmStatus;
+}
+
+NV_STATUS nv_vgpu_rm_get_bar_info
+(
+ OBJGPU *pGpu,
+ const NvU8 *pVgpuDevName,
+ NvU64 *barSizes,
+ NvU64 *sparseOffsets,
+ NvU64 *sparseSizes,
+ NvU32 *sparseCount,
+ NvBool *isBar064bit,
+ NvU8 *configParams
+)
+{
+ KERNEL_HOST_VGPU_DEVICE *pKernelHostVgpuDevice;
+ NV_STATUS rmStatus;
+ NvU32 i = 0;
+
+ NV_CHECK_OK_OR_GOTO(rmStatus, LEVEL_SILENT,
+ is_bar_64bit(pGpu, NV_VFIO_PCI_BAR0_REGION_INDEX, isBar064bit),
+ exit);
+
+ NV_CHECK_OK_OR_GOTO(rmStatus, LEVEL_SILENT,
+ kvgpumgrGetHostVgpuDeviceFromVgpuDevName(pGpu->gpuId,
+ pVgpuDevName,
+ &pKernelHostVgpuDevice),
+ exit);
+
+ for (i = 0; i < NVA081_MAX_BAR_REGION_COUNT; i++)
+ {
+ /*
+ * For SRIOV, only VF BAR1 is queried via RM, others BARs are directly
+ * queried via VF config space in vgpu-vfio
+ */
+ if (gpuIsSriovEnabled(pGpu) && (i != NV_VFIO_PCI_BAR1_REGION_INDEX))
+ {
+ barSizes[i] = 0;
+ continue;
+ }
+
+ rmStatus = _nv_vgpu_get_bar_size(pGpu, pKernelHostVgpuDevice, i,
+ &barSizes[i], configParams);
+ if (rmStatus != NV_OK)
+ {
+ NV_PRINTF(LEVEL_ERROR, "Failed to query BAR size for index %u 0x%x\n",
+ i, rmStatus);
+ goto exit;
+ }
+ }
+
+ NV_CHECK_OK_OR_GOTO(rmStatus, LEVEL_SILENT,
+ _nv_vgpu_get_sparse_mmap(pGpu, pKernelHostVgpuDevice,
+ sparseOffsets, sparseSizes,
+ sparseCount, configParams),
+ exit);
+
+exit:
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL nv_gpu_unbind_event
+(
+ nvidia_stack_t *sp,
+ NvU32 gpuId,
+ NvBool *isEventNotified
+)
+{
+ THREAD_STATE_NODE threadState;
+ NV_STATUS rmStatus = NV_OK;
+ void *fp = NULL;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ // LOCK: acquire API lock
+ if ((rmStatus = rmapiLockAcquire(API_LOCK_FLAGS_NONE, RM_LOCK_MODULES_HYPERVISOR)) == NV_OK)
+ {
+ NV0000_CTRL_SYSTEM_EVENT_DATA_VGPU_UNBIND eventData = { 0 };
+
+ // Send gpu_id so that nvidia-vgpu-mgr daemon knows which GPU is being unbound
+ eventData.gpuId = gpuId;
+ CliAddSystemEvent(NV0000_NOTIFIERS_VGPU_UNBIND_EVENT, &eventData, isEventNotified);
+
+ // UNLOCK: release API lock
+ rmapiLockRelease();
+ }
+
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL nv_gpu_bind_event(
+ nvidia_stack_t *sp,
+ NvU32 gpuId,
+ NvBool *isEventNotified
+)
+{
+ THREAD_STATE_NODE threadState;
+ NV_STATUS rmStatus = NV_OK;
+ void *fp = NULL;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ // LOCK: acquire API lock
+ if ((rmStatus = rmapiLockAcquire(API_LOCK_FLAGS_NONE, RM_LOCK_MODULES_HYPERVISOR)) == NV_OK)
+ {
+ NV0000_CTRL_SYSTEM_EVENT_DATA_VGPU_BIND eventData = { 0 };
+
+ eventData.gpuId = gpuId;
+ CliAddSystemEvent(NV0000_NOTIFIERS_VGPU_BIND_EVENT, &eventData, isEventNotified);
+
+ // UNLOCK: release API lock
+ rmapiLockRelease();
+ }
+
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return rmStatus;
+}
+
+NV_STATUS osIsVgpuVfioPresent(void)
+{
+ vgpu_vfio_info vgpu_info;
+
+ return os_call_vgpu_vfio((void *) &vgpu_info, CMD_VGPU_VFIO_PRESENT);
+}
+
+NV_STATUS osIsVfioPciCorePresent(void)
+{
+ vgpu_vfio_info vgpu_info;
+
+ return os_call_vgpu_vfio((void *) &vgpu_info, CMD_VFIO_PCI_CORE_PRESENT);
+}
+
+void osWakeRemoveVgpu(NvU32 gpuId, NvU32 returnStatus)
+{
+ vgpu_vfio_info vgpu_info;
+
+ vgpu_info.return_status = returnStatus;
+ vgpu_info.domain = GPU_32_BIT_ID_DECODE_DOMAIN(gpuId);
+ vgpu_info.bus = GPU_32_BIT_ID_DECODE_BUS(gpuId);
+ vgpu_info.device = GPU_32_BIT_ID_DECODE_DEVICE(gpuId);
+
+ os_call_vgpu_vfio((void *)&vgpu_info, CMD_VFIO_WAKE_REMOVE_GPU);
+}
+
+NvBool osIsGridSupported(OBJGPU *pGpu)
+{
+ return (os_is_grid_supported() || os_get_grid_csp_support() || hypervisorIsVgxHyper());
+}
+
+NvU32 osGetGridCspSupport(void)
+{
+ return os_get_grid_csp_support();
+}
+
+void initVGXSpecificRegistry(OBJGPU *pGpu)
+{
+ NvU32 data32;
+ osWriteRegistryDword(pGpu, NV_REG_STR_RM_POWER_FEATURES, 0x55455555);
+ osWriteRegistryDword(pGpu, NV_REG_STR_RM_INFOROM_DISABLE_BBX,
+ NV_REG_STR_RM_INFOROM_DISABLE_BBX_YES);
+ if ((osReadRegistryDword(pGpu, NV_REG_STR_RM_DUMP_NVLOG, &data32) != NV_OK))
+ {
+ osWriteRegistryDword(pGpu, NV_REG_STR_RM_DUMP_NVLOG,
+ NV_REG_STR_RM_DUMP_NVLOG_ENABLE);
+ }
+ osWriteRegistryDword(pGpu, NV_REG_STR_RM_RC_WATCHDOG,
+ NV_REG_STR_RM_RC_WATCHDOG_DISABLE);
+ osWriteRegistryDword(pGpu, NV_REG_STR_CL_FORCE_P2P,
+ DRF_DEF(_REG_STR, _CL_FORCE_P2P, _READ, _DISABLE) |
+ DRF_DEF(_REG_STR, _CL_FORCE_P2P, _WRITE, _DISABLE));
+}
+
+
+NV_STATUS rm_is_vgpu_supported_device(
+ OS_GPU_INFO *pOsGpuInfo,
+ NvU32 pmc_boot_1,
+ NvU32 pmc_boot_42
+)
+{
+ OBJSYS *pSys = SYS_GET_INSTANCE();
+ OBJHYPERVISOR *pHypervisor = SYS_GET_HYPERVISOR(pSys);
+ NvBool is_sriov_enabled = FLD_TEST_DRF(_PMC, _BOOT_1, _VGPU, _VF, pmc_boot_1);
+ NvU32 i;
+
+ // if not running in vGPU mode (guest VM) return NV_OK
+ if (!(pHypervisor && pHypervisor->bIsHVMGuest &&
+ (FLD_TEST_DRF(_PMC, _BOOT_1, _VGPU, _PV, pmc_boot_1) ||
+ is_sriov_enabled)))
+ {
+ return NV_OK;
+ }
+
+ if (!is_sriov_enabled)
+ {
+ return NV_OK;
+ }
+
+ if (os_is_grid_supported() && !gpumgrIsVgxRmFirmwareCapableChip(pmc_boot_42))
+ {
+ return NV_ERR_NOT_SUPPORTED;
+ }
+
+ if (os_is_grid_supported())
+ {
+ for (i = 0; i < NV_ARRAY_ELEMENTS(sVgpuUsmTypes); i++)
+ {
+ if (pOsGpuInfo->pci_info.device_id == sVgpuUsmTypes[i].ulDevID &&
+ pOsGpuInfo->subsystem_id == sVgpuUsmTypes[i].ulSubID)
+ {
+ return NV_OK;
+ }
+ }
+ }
+
+ return NV_ERR_NOT_SUPPORTED;
+}
+
+NV_STATUS osIsVgpuDeviceVmPresent(void)
+{
+ return os_device_vm_present();
+}
diff --git a/userspace/sdks/nv570/nvalloc/unix/src/os.c b/userspace/sdks/nv570/nvalloc/unix/src/os.c
new file mode 100644
index 0000000..b441a66
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/src/os.c
@@ -0,0 +1,6359 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 1999-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <nv.h> // NV device driver interface
+#include <nv-priv.h>
+#include <nv-caps.h>
+#include <os/os.h>
+#include <nvos.h>
+#include <osapi.h>
+#include <ctrl/ctrl0000/ctrl0000gpu.h>
+#include <ctrl/ctrl0000/ctrl0000unix.h>
+#include <class/cl90cd.h> // NV_EVENT_BUFFER_BIND
+#include <nvdevid.h>
+
+#include <nverror.h>
+#include <gpu/device/device.h>
+
+#include "gpu/gpu.h"
+#include <gpu_mgr/gpu_mgr.h>
+#include <platform/chipset/chipset.h>
+
+#include "nverror.h"
+#include "kernel/gpu/bif/kernel_bif.h"
+
+#include "gpu/mig_mgr/kernel_mig_manager.h"
+
+#include "gpu/mem_sys/kern_mem_sys.h"
+
+#include "mem_mgr/io_vaspace.h"
+#include <diagnostics/journal.h>
+#include "kernel/diagnostics/xid_context.h"
+#include "gpu/mem_mgr/mem_desc.h"
+#include "gpu/mem_mgr/mem_mgr.h"
+#include "core/thread_state.h"
+#include <nvacpitypes.h>
+#include <platform/acpi_common.h>
+#include <core/locks.h>
+#include <ctrl/ctrl2080/ctrl2080gpu.h>
+#include "virtualization/hypervisor/hypervisor.h"
+#include "rmobjexportimport.h"
+#include <nvi2c.h>
+#include "rmapi/rs_utils.h"
+#include "rmapi/client_resource.h"
+#include "os/dce_rm_client_ipc.h"
+#include "mem_mgr/mem.h"
+#include "gpu/mem_mgr/virt_mem_allocator_common.h"
+#include "nvrm_registry.h"
+
+#include "vgpu/vgpu_util.h"
+
+#include "platform/chipset/chipset.h"
+
+#include <acpidsmguids.h>
+#include <pex.h>
+#include "gps.h"
+#include "jt.h"
+
+
+
+
+extern const char *ppOsBugCheckBugcodeStr[];
+
+
+ct_assert(NV_RM_PAGE_SIZE == RM_PAGE_SIZE);
+ct_assert(NV_RM_PAGE_MASK == RM_PAGE_MASK);
+ct_assert(NV_RM_PAGE_SHIFT == RM_PAGE_SHIFT);
+
+typedef struct
+{
+ NvU32 euid;
+ NvU32 pid;
+} TOKEN_USER, *PTOKEN_USER;
+
+struct OS_RM_CAPS
+{
+ NvU32 count;
+
+ // This should be the last element
+ nv_cap_t **caps;
+};
+
+NvBool osIsRaisedIRQL(void)
+{
+ return (!os_semaphore_may_sleep());
+}
+
+NvBool osIsISR(void)
+{
+ return os_is_isr();
+}
+
+NV_STATUS osGetDriverBlock
+(
+ OS_GPU_INFO *pOsGpuInfo,
+ OS_DRIVER_BLOCK *pBlock
+)
+{
+ return NV_ERR_NOT_SUPPORTED;
+}
+
+NvU64 osGetMonotonicTimeNs(void)
+{
+ return os_get_monotonic_time_ns();
+}
+
+NV_STATUS osGetPerformanceCounter(NvU64 *pTimeInNs)
+{
+ *pTimeInNs = os_get_monotonic_time_ns_hr();
+ return NV_OK;
+}
+
+NV_STATUS osGetSystemTime(
+ NvU32 *pSeconds,
+ NvU32 *pMicroSeconds
+)
+{
+ return os_get_system_time(pSeconds, pMicroSeconds);
+}
+
+/*!
+ * @brief Get timestamp for logging.
+ *
+ * Everything that logs a time stamp should use this routine for consistency.
+ *
+ * The returned value is OS dependent. We want the time stamp to use
+ * KeQueryPerformanceCounter on Windows so it matches the DirectX timestamps.
+ * Linux uses microseconds since 1970 (osGetSystemTime), since matching DirectX
+ * is not a priority.
+ *
+ * osGetTimestampFreq returns the frequency required to decode the time stamps.
+ *
+ * @returns system dependent timestamp.
+ */
+NvU64 osGetTimestamp(void)
+{
+ NvU32 sec = 0;
+ NvU32 usec = 0;
+ osGetSystemTime(&sec, &usec);
+ return (NvU64)sec * 1000000 + usec;
+}
+
+/*!
+ * @brief Get timestamp frequency.
+ *
+ * Timestamps are OS dependent. This call returns the frequency
+ * required to decode them.
+ *
+ * @returns Timestamp frequency. For example, 1000000 for MHz.
+ */
+NvU64 osGetTimestampFreq(void)
+{
+ return 1000000;
+}
+
+NV_STATUS osDelay(NvU32 milliseconds)
+{
+ return os_delay(milliseconds);
+}
+
+NV_STATUS osDelayUs(NvU32 microseconds)
+{
+ return os_delay_us(microseconds);
+}
+
+NV_STATUS osDelayNs(NvU32 nanoseconds)
+{
+ NvU32 microseconds = NV_MAX(1, (nanoseconds / 1000));
+ return os_delay_us(microseconds);
+}
+
+NvU32 osGetCpuFrequency(void)
+{
+ /* convert os_get_cpu_frequency()'s return value from Hz to MHz */
+ return ((NvU32)(os_get_cpu_frequency() / 1000000ULL));
+}
+
+void* osPciInitHandle(
+ NvU32 Domain,
+ NvU8 Bus,
+ NvU8 Slot,
+ NvU8 Function,
+ NvU16 *pVendor,
+ NvU16 *pDevice
+)
+{
+ //
+ // Check if the BDF is for a GPU that's already been attached, for which
+ // we should already have a handle cached. This won't catch devices that
+ // have been probed but not yet attached, but that shouldn't be a common
+ // occurrence.
+ //
+ // More importantly, having this check here means we don't need to check
+ // a global list of devices in the kernel interface layer, which could
+ // have the implication of taking another lock, causing hairy lock
+ // ordering issues.
+ //
+ if (Function == 0)
+ {
+ OBJGPU *pGpu = gpumgrGetGpuFromBusInfo(Domain, Bus, Slot);
+ if (pGpu != NULL)
+ {
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ if (pVendor) *pVendor = nv->pci_info.vendor_id;
+ if (pDevice) *pDevice = nv->pci_info.device_id;
+ return nv->handle;
+ }
+ }
+
+ return os_pci_init_handle(Domain, Bus, Slot, Function, pVendor, pDevice);
+}
+
+NvU8 osPciReadByte(
+ void *pHandle,
+ NvU32 Offset
+)
+{
+ NvU8 val;
+ os_pci_read_byte(pHandle, Offset, &val);
+ return val;
+}
+
+NvU16 osPciReadWord(
+ void *pHandle,
+ NvU32 Offset
+)
+{
+ NvU16 val;
+ os_pci_read_word(pHandle, Offset, &val);
+ return val;
+}
+
+NvU32 osPciReadDword(
+ void *pHandle,
+ NvU32 Offset
+)
+{
+ NvU32 val;
+ os_pci_read_dword(pHandle, Offset, &val);
+ return val;
+}
+
+void osPciWriteByte(
+ void *pHandle,
+ NvU32 Offset,
+ NvU8 Value
+)
+{
+ os_pci_write_byte(pHandle, Offset, Value);
+}
+
+void osPciWriteWord(
+ void *pHandle,
+ NvU32 Offset,
+ NvU16 Value
+)
+{
+ os_pci_write_word(pHandle, Offset, Value);
+}
+
+void osPciWriteDword(
+ void *pHandle,
+ NvU32 Offset,
+ NvU32 Value
+)
+{
+ os_pci_write_dword(pHandle, Offset, Value);
+}
+
+void* osMapKernelSpace(
+ RmPhysAddr Start,
+ NvU64 Size,
+ NvU32 Mode,
+ NvU32 Protect
+)
+{
+ NvU64 offset;
+ NvU8 *ptr;
+
+ if (0 == Size)
+ {
+ NV_ASSERT(Size != 0);
+ return NULL;
+ }
+
+ offset = (Start & ~os_page_mask);
+ Start &= os_page_mask;
+
+ if (!portSafeAddU64(Size, offset, &Size) ||
+ !portSafeAddU64(Size, ~os_page_mask, &Size))
+ {
+ return NULL;
+ }
+ Size &= os_page_mask;
+
+ ptr = os_map_kernel_space(Start, Size, Mode);
+ if (ptr != NULL)
+ return (ptr + offset);
+
+ return NULL;
+}
+
+void osUnmapKernelSpace(
+ void *pAddress,
+ NvU64 Size
+)
+{
+ NvU64 offset;
+ NvUPtr ptr = (NvUPtr)pAddress;
+
+ if (0 == Size)
+ {
+ NV_ASSERT(Size != 0);
+ return;
+ }
+
+ offset = (ptr & ~os_page_mask);
+ ptr &= os_page_mask;
+ Size = ((Size + offset + ~os_page_mask) & os_page_mask);
+ os_unmap_kernel_space((void *)ptr, Size);
+}
+
+static NV_STATUS setNumaPrivData
+(
+ KernelMemorySystem *pKernelMemorySystem,
+ nv_state_t *nv,
+ MEMORY_DESCRIPTOR *pMemDesc
+)
+{
+ NV_STATUS rmStatus = NV_OK;
+ void *pAllocPrivate = NULL;
+ NvU64 *addrArray = NULL;
+ NvU64 numPages = pMemDesc->PageCount;
+ NvU64 numOsPages = numPages;
+ RmPhysAddr *pteArray = memdescGetPteArray(pMemDesc, AT_CPU);
+ NvU64 i;
+
+ //
+ // Since this function will also deal with the memory allocated from PMA,
+ // we have to perform page size inflate/deflate here.
+ //
+ if (IS_DISCONTIG_AND_DYNGRAN_ENABLED(pMemDesc))
+ {
+ NvU64 size = pMemDesc->ActualSize;
+ numOsPages = size / NV_MIN(os_page_size, pMemDesc->pageArrayGranularity);
+ }
+
+ addrArray = portMemAllocNonPaged(numOsPages * sizeof(NvU64));
+ if (addrArray == NULL)
+ {
+ return NV_ERR_NO_MEMORY;
+ }
+
+ if (!IS_DISCONTIG_AND_DYNGRAN_ENABLED(pMemDesc) && NV_RM_PAGE_SIZE < os_page_size)
+ {
+ numOsPages = NV_RM_PAGES_TO_OS_PAGES(numPages);
+ }
+
+ if (!memdescGetContiguity(pMemDesc, AT_CPU))
+ {
+ NvU64 copyByteSize = 0;
+ if (IS_DISCONTIG_AND_DYNGRAN_ENABLED(pMemDesc))
+ {
+ // pMemDesc->pageArraySize is calculated by 4KB, it should NOT smaller than `numOSPages`.
+ NV_ASSERT_OR_ELSE(pMemDesc->pageArraySize >= numOsPages, rmStatus = NV_ERR_INVALID_STATE; goto errors);
+ copyByteSize = numOsPages * sizeof(NvU64);
+ }
+ else
+ {
+ copyByteSize = numPages * sizeof(NvU64);
+ }
+
+ portMemCopy((void*)addrArray,
+ copyByteSize,
+ (void*)pteArray,
+ copyByteSize);
+
+ if (IS_DISCONTIG_AND_DYNGRAN_ENABLED(pMemDesc))
+ {
+ NvU64 size = pMemDesc->ActualSize;
+ //
+ // Because of PMA case, we need to convert page array
+ // from RM native granularity to OS granularity.
+ //
+ convertPageArrayBetweenOsAndRm(
+ addrArray,
+ size / pMemDesc->pageArrayGranularity,
+ pMemDesc->pageArrayGranularity,
+ size / os_page_size,
+ os_page_size,
+ &numOsPages
+ );
+ }
+ else if (NV_RM_PAGE_SIZE < os_page_size)
+ {
+ RmDeflateRmToOsPageArray(addrArray, numPages);
+ }
+
+ for (i = 0; i < numOsPages; i++)
+ {
+ // Update GPA to system physical address
+ addrArray[i] += pKernelMemorySystem->coherentCpuFbBase;
+ }
+ }
+ else
+ {
+ //
+ // Original PTE array in contiguous memdesc only holds start address.
+ // We need to fill the OS page array with adjacent page addresses to
+ // map contiguously.
+ //
+ NvU64 offset = pteArray[0] + pKernelMemorySystem->coherentCpuFbBase;
+
+ for (i = 0; i < numOsPages; i++, offset += os_page_size)
+ {
+ addrArray[i] = offset;
+ }
+ }
+
+ rmStatus = nv_register_phys_pages(nv, addrArray, numOsPages, NV_MEMORY_CACHED, &pAllocPrivate);
+ if (rmStatus != NV_OK)
+ {
+ goto errors;
+ }
+
+ memdescSetMemData(pMemDesc, pAllocPrivate, NULL);
+
+errors:
+ portMemFree(addrArray);
+
+ return rmStatus;
+}
+
+NV_STATUS osGetNumMemoryPages
+(
+ MEMORY_DESCRIPTOR *pMemDesc,
+ NvU32 *pNumPages
+)
+{
+ void *pAllocPrivate = NULL;
+
+ pAllocPrivate = memdescGetMemData(pMemDesc);
+ if (pAllocPrivate == NULL)
+ {
+ NV_PRINTF(LEVEL_ERROR, "pAllocPrivate is NULL!\n");
+ return NV_ERR_INVALID_STATE;
+ }
+
+ return nv_get_num_phys_pages(pAllocPrivate, pNumPages);
+}
+
+NV_STATUS osGetMemoryPages
+(
+ MEMORY_DESCRIPTOR *pMemDesc,
+ void *pPages,
+ NvU32 *pNumPages
+)
+{
+ void *pAllocPrivate = NULL;
+
+ pAllocPrivate = memdescGetMemData(pMemDesc);
+ if (pAllocPrivate == NULL)
+ {
+ NV_PRINTF(LEVEL_ERROR, "pAllocPrivate is NULL!\n");
+ return NV_ERR_INVALID_STATE;
+ }
+
+ return nv_get_phys_pages(pAllocPrivate, pPages, pNumPages);
+}
+
+NV_STATUS osMapSystemMemory
+(
+ MEMORY_DESCRIPTOR *pMemDesc,
+ NvU64 Offset,
+ NvU64 Length,
+ NvBool Kernel,
+ NvU32 Protect,
+ NvP64 *ppAddress,
+ NvP64 *ppPrivate
+)
+{
+ OBJGPU *pGpu = pMemDesc->pGpu;
+
+ NvU64 rootOffset = 0;
+ pMemDesc = memdescGetRootMemDesc(pMemDesc, &rootOffset);
+ Offset += rootOffset;
+
+ RmPhysAddr userAddress;
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ NV_STATUS rmStatus = NV_OK;
+ void *pAllocPrivate = NULL;
+ void *pAddress;
+ void *pPrivate = NULL;
+ NvU64 pageIndex;
+ NvU32 pageOffset = (Offset & ~os_page_mask);
+
+ if (pGpu != NULL &&
+ pGpu->getProperty(pGpu, PDB_PROP_GPU_COHERENT_CPU_MAPPING) &&
+ memdescGetAddressSpace(pMemDesc) == ADDR_FBMEM)
+ {
+ KernelMemorySystem *pKernelMemorySystem = GPU_GET_KERNEL_MEMORY_SYSTEM(pGpu);
+
+ rmStatus = setNumaPrivData(pKernelMemorySystem, nv, pMemDesc);
+ if (rmStatus != NV_OK)
+ return rmStatus;
+
+ pageOffset = memdescGetPhysAddr(pMemDesc, FORCE_VMMU_TRANSLATION(pMemDesc, AT_GPU), Offset) & ~os_page_mask;
+ }
+
+ *ppAddress = NvP64_NULL;
+ *ppPrivate = NvP64_NULL;
+
+ if ((Offset + Length) < Length)
+ return NV_ERR_INVALID_ARGUMENT;
+ if ((Offset + Length) > pMemDesc->Size)
+ return NV_ERR_INVALID_ARGUMENT;
+
+ pageIndex = (Offset >> os_page_shift);
+
+ pAllocPrivate = memdescGetMemData(pMemDesc);
+ if (!pAllocPrivate)
+ {
+ NV_PRINTF(LEVEL_ERROR, "pAllocPrivate is NULL!\n");
+ return NV_ERR_INVALID_STATE;
+ }
+
+ if (Kernel)
+ {
+ pAddress = nv_alloc_kernel_mapping(nv, pAllocPrivate,
+ pageIndex, pageOffset, Length, &pPrivate);
+ if (pAddress == NULL)
+ {
+ NV_PRINTF(LEVEL_ERROR,
+ "failed to create system memory kernel mapping!\n");
+ rmStatus = NV_ERR_GENERIC;
+ }
+ else
+ {
+ *ppAddress = NV_PTR_TO_NvP64(pAddress);
+ *ppPrivate = NV_PTR_TO_NvP64(pPrivate);
+ }
+ }
+ else
+ {
+ rmStatus = nv_alloc_user_mapping(nv, pAllocPrivate,
+ pageIndex, pageOffset, Length, Protect, &userAddress,
+ &pPrivate);
+ if (rmStatus != NV_OK)
+ {
+ NV_PRINTF(LEVEL_ERROR,
+ "failed to create system memory user mapping!\n");
+ }
+ else
+ {
+ *ppAddress = (NvP64)(userAddress);
+ *ppPrivate = NV_PTR_TO_NvP64(pPrivate);
+ }
+ }
+
+ return rmStatus;
+}
+
+void osUnmapSystemMemory
+(
+ MEMORY_DESCRIPTOR *pMemDesc,
+ NvBool Kernel,
+ NvP64 pAddress,
+ NvP64 pPrivate
+)
+{
+ void *pAllocPrivate;
+ OBJGPU *pGpu = pMemDesc->pGpu;
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+
+ pMemDesc = memdescGetRootMemDesc(pMemDesc, NULL);
+ pAllocPrivate = memdescGetMemData(pMemDesc);
+
+ if (Kernel)
+ {
+ nv_free_kernel_mapping(nv, pAllocPrivate, NvP64_VALUE(pAddress),
+ NvP64_VALUE(pPrivate));
+ }
+ else
+ {
+ nv_free_user_mapping(nv, pAllocPrivate, (NvU64)pAddress,
+ NvP64_VALUE(pPrivate));
+ }
+
+ if (pGpu != NULL &&
+ pGpu->getProperty(pGpu, PDB_PROP_GPU_COHERENT_CPU_MAPPING) &&
+ memdescGetAddressSpace(pMemDesc) == ADDR_FBMEM &&
+ pAllocPrivate != NULL)
+ {
+ nv_unregister_phys_pages(nv, pAllocPrivate);
+ memdescSetMemData(pMemDesc, NULL, NULL);
+ }
+}
+
+void osIoWriteByte(
+ NvU32 Address,
+ NvU8 Value
+)
+{
+ os_io_write_byte(Address, Value);
+}
+
+NvU16 osIoReadWord(
+ NvU32 Address
+)
+{
+ return os_io_read_word(Address);
+}
+
+void osIoWriteWord(
+ NvU32 Address,
+ NvU16 Value
+)
+{
+ os_io_write_word(Address, Value);
+}
+
+NvU8 osIoReadByte(
+ NvU32 Address
+)
+{
+ return os_io_read_byte(Address);
+}
+
+NvBool osIsAdministrator(void)
+{
+ return os_is_administrator();
+}
+
+NvBool osCheckAccess(RsAccessRight accessRight)
+{
+ return os_check_access(accessRight);
+}
+
+NvU32 osGetCurrentProcess(void)
+{
+ return os_get_current_process();
+}
+
+void osGetCurrentProcessName(char *ProcName, NvU32 Length)
+{
+ return os_get_current_process_name(ProcName, Length);
+}
+
+NV_STATUS osGetCurrentThread(OS_THREAD_HANDLE *pThreadId)
+{
+ NV_STATUS rmStatus;
+ NvU64 threadId = 0;
+
+ if (pThreadId == NULL)
+ {
+ return NV_ERR_INVALID_ARGUMENT;
+ }
+
+ rmStatus = os_get_current_thread(&threadId);
+ if (rmStatus == NV_OK)
+ {
+ *pThreadId = threadId;
+ }
+ else
+ {
+ *pThreadId = 0;
+ }
+
+ return rmStatus;
+}
+
+void* osGetPidInfo(void)
+{
+ return os_get_pid_info();
+}
+
+void osPutPidInfo(void *pOsPidInfo)
+{
+ os_put_pid_info(pOsPidInfo);
+}
+
+NV_STATUS osFindNsPid(void *pOsPidInfo, NvU32 *pNsPid)
+{
+ return os_find_ns_pid(pOsPidInfo, pNsPid);
+}
+
+NvBool osIsInitNs(void)
+{
+ return os_is_init_ns();
+}
+
+NV_STATUS osAttachToProcess(void** ppProcessInfo, NvU32 ProcessId)
+{
+ //
+ // This function is used by RmUnmapMemory() to attach to the
+ // process for which a given device memory mapping was
+ // created, in order to be able to unmap it. On Linux/UNIX
+ // platforms, we can't "attach" to a random process, but
+ // since we don't create/destroy user mappings in the RM, we
+ // don't need to, either.
+ //
+ // Report success to the caller to keep RmUnmapMemory() from
+ // failing, and memory from being leaked as a result.
+ //
+ *ppProcessInfo = NULL;
+ return NV_OK;
+}
+
+void osDetachFromProcess(void* pProcessInfo)
+{
+ // stub
+ return;
+}
+
+NV_STATUS osAcquireRmSema(void *pSema)
+{
+ return NV_OK;
+}
+
+NV_STATUS osCondAcquireRmSema(void *pSema)
+{
+ return NV_OK;
+}
+
+NvU32 osReleaseRmSema(void *pSema, OBJGPU *pDpcGpu)
+{
+ return NV_SEMA_RELEASE_SUCCEED;
+}
+
+void osSpinLoop(void)
+{
+
+}
+
+NvU64 osGetMaxUserVa(void)
+{
+ return os_get_max_user_va();
+}
+
+NV_STATUS osSchedule(void)
+{
+ return os_schedule();
+}
+
+NV_STATUS osQueueWorkItem(
+ OBJGPU *pGpu,
+ OSWorkItemFunction pFunction,
+ void *pParams,
+ OsQueueWorkItemFlags flags
+)
+{
+ nv_work_item_t *pWi;
+ nv_state_t *nv;
+ NV_STATUS status;
+
+ pWi = portMemAllocNonPaged(sizeof(nv_work_item_t));
+
+ if (NULL == pWi)
+ {
+ return NV_ERR_NO_MEMORY;
+ }
+
+ pWi->flags = (OsQueueWorkItemFlags){0};
+ pWi->flags.bDontFreeParams = flags.bDontFreeParams;
+ pWi->flags.bLockSema = flags.bLockSema;
+ pWi->flags.apiLock = flags.apiLock;
+ pWi->flags.bLockGpus = flags.bLockGpus;
+ pWi->flags.bLockGpuGroupDevice = flags.bLockGpuGroupDevice;
+ pWi->flags.bLockGpuGroupSubdevice = flags.bLockGpuGroupSubdevice;
+ pWi->flags.bFullGpuSanity = flags.bFullGpuSanity;
+ pWi->flags.bDropOnUnloadQueueFlush = flags.bDropOnUnloadQueueFlush;
+ pWi->flags.bSetExpandedGpuVisibility = flags.bSetExpandedGpuVisibility;
+
+ pWi->flags.bRequiresGpu = NV_TRUE;
+ pWi->gpuInstance = gpuGetInstance(pGpu);
+
+ pWi->func.pGpuFunction = pFunction;
+ pWi->pData = pParams;
+ nv = NV_GET_NV_STATE(pGpu);
+
+ status = os_queue_work_item(nv ? nv->queue : NULL, pWi);
+
+ if (NV_OK != status)
+ {
+ portMemFree((void *)pWi);
+ }
+
+ return status;
+}
+
+NV_STATUS osQueueSystemWorkItem(
+ OSSystemWorkItemFunction pFunction,
+ void *pParams
+)
+{
+ nv_work_item_t *pWi;
+ NV_STATUS status;
+
+ pWi = portMemAllocNonPaged(sizeof(nv_work_item_t));
+
+ if (NULL == pWi)
+ {
+ return NV_ERR_NO_MEMORY;
+ }
+
+ pWi->flags = (OsQueueWorkItemFlags){0};
+ pWi->func.pSystemFunction = pFunction;
+ pWi->pData = pParams;
+
+ status = os_queue_work_item(NULL, pWi);
+
+ if (NV_OK != status)
+ {
+ portMemFree((void *)pWi);
+ }
+
+ return status;
+}
+
+NV_STATUS osQueueSystemWorkItemWithFlags(
+ OSSystemWorkItemFunction pFunction,
+ void *pParams,
+ OsQueueWorkItemFlags flags
+)
+{
+ nv_work_item_t *pWi;
+ NV_STATUS status;
+
+ pWi = portMemAllocNonPaged(sizeof(nv_work_item_t));
+
+ if (NULL == pWi)
+ {
+ return NV_ERR_NO_MEMORY;
+ }
+
+ pWi->flags = (OsQueueWorkItemFlags){0};
+ pWi->flags.bDontFreeParams = flags.bDontFreeParams;
+ pWi->flags.bLockSema = flags.bLockSema;
+ pWi->flags.apiLock = flags.apiLock;
+ pWi->flags.bLockGpus = flags.bLockGpus;
+ pWi->flags.bLockGpuGroupDevice = flags.bLockGpuGroupDevice;
+ pWi->flags.bLockGpuGroupSubdevice = flags.bLockGpuGroupSubdevice;
+ pWi->flags.bFullGpuSanity = flags.bFullGpuSanity;
+ pWi->flags.bDropOnUnloadQueueFlush = flags.bDropOnUnloadQueueFlush;
+ pWi->func.pSystemFunction = pFunction;
+ pWi->pData = pParams;
+
+ status = os_queue_work_item(NULL, pWi);
+
+ if (NV_OK != status)
+ {
+ portMemFree((void *)pWi);
+ }
+
+ return status;
+}
+
+void osQueueMMUFaultHandler(OBJGPU *pGpu)
+{
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+
+ nv_schedule_uvm_isr(nv);
+}
+
+NvBool osGpuSupportsAts(OBJGPU *pGpu)
+{
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+
+ // Checks ATS support from both OS side and RM side.
+ return nv->ats_support &&
+ pGpu->getProperty(pGpu, PDB_PROP_GPU_ATS_SUPPORTED);
+}
+
+NV_STATUS osQueueDrainP2PHandler(NvU8 *pUuid)
+{
+ return nv_schedule_uvm_drain_p2p(pUuid);
+}
+
+void osQueueResumeP2PHandler(NvU8 *pUuid)
+{
+ nv_schedule_uvm_resume_p2p(pUuid);
+}
+
+static inline nv_dma_device_t* osGetDmaDeviceForMemDesc(
+ OS_GPU_INFO *pOsGpuInfo,
+ MEMORY_DESCRIPTOR *pMemDesc
+)
+{
+ return (pOsGpuInfo->niso_dma_dev != NULL) &&
+ memdescGetFlag(pMemDesc, MEMDESC_FLAGS_MEMORY_TYPE_DISPLAY_NISO) ?
+ pOsGpuInfo->niso_dma_dev : pOsGpuInfo->dma_dev;
+}
+
+//
+// Set the DMA address size for the given GPU
+//
+// This is a global device setting and care would need to be taken if it was to
+// be modified outside of GPU initialization. At least on Linux other drivers,
+// like UVM, might be requesting its own DMA mappings for the same GPU after
+// the GPU has been initialized.
+//
+void osDmaSetAddressSize(
+ OS_GPU_INFO *pOsGpuInfo,
+ NvU32 bits
+)
+{
+ nv_set_dma_address_size(pOsGpuInfo, bits);
+}
+
+static NV_STATUS osGetPagesInfo(
+ MEMORY_DESCRIPTOR *pMemDesc,
+ NvU64 *pageSize,
+ NvU64 *osPageCount,
+ NvU64 *rmPageCount
+)
+{
+ NvU64 osPageSize = osGetPageSize();
+ NvU64 maxPageSize = NV_MAX(osPageSize, RM_PAGE_SIZE);
+ NvU64 alignedSize = NV_ALIGN_UP(pMemDesc->Size, maxPageSize);
+
+ *osPageCount = alignedSize >> BIT_IDX_32(osPageSize);
+ *rmPageCount = alignedSize >> RM_PAGE_SHIFT;
+ *pageSize = memdescGetAdjustedPageSize(pMemDesc);
+
+ // In the non-contig case need to protect against page array overflows.
+ if (!memdescGetContiguity(pMemDesc, AT_CPU))
+ NV_ASSERT_OR_RETURN(*rmPageCount <= pMemDesc->pageArraySize, NV_ERR_INVALID_ARGUMENT);
+
+ if (*osPageCount > NV_U32_MAX || *rmPageCount > NV_U32_MAX)
+ return NV_ERR_INVALID_LIMIT;
+
+ return NV_OK;
+}
+
+NV_STATUS osAllocPagesInternal(
+ MEMORY_DESCRIPTOR *pMemDesc
+)
+{
+ OBJSYS *pSys = SYS_GET_INSTANCE();
+ OBJGPU *pGpu = pMemDesc->pGpu;
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ void *pMemData = NULL;
+ NV_STATUS status;
+ NvS32 nodeId = memdescGetNumaNode(pMemDesc);
+ NV_ADDRESS_SPACE addrSpace = memdescGetAddressSpace(pMemDesc);
+ NvU64 pageSize;
+ NvU64 osPageCount;
+ NvU64 rmPageCount;
+ NvU32 cpuCacheAttrib = memdescGetCpuCacheAttrib(pMemDesc);
+
+ memdescSetMemData(pMemDesc, NULL, NULL);
+
+#if (defined(NVCPU_AARCH64) && RMCFG_MODULE_CL)
+ {
+ OBJCL *pCl = SYS_GET_CL(pSys);
+
+ if ((pCl != NULL) &&
+ pCl->getProperty(pCl, PDB_PROP_CL_IS_CHIPSET_IO_COHERENT) &&
+ !memdescGetFlag(pMemDesc, MEMDESC_FLAGS_NON_IO_COHERENT))
+ {
+ cpuCacheAttrib = NV_MEMORY_CACHED;
+ }
+ }
+#endif
+
+ //
+ // For carveout, the memory is already reserved so we don't have
+ // to allocate memory.
+ //
+ if (memdescIsCarveoutMemory(pMemDesc) ||
+ memdescGetFlag(pMemDesc, MEMDESC_FLAGS_GUEST_ALLOCATED))
+ {
+ // We only support carveout with contiguous memory.
+ if (memdescIsCarveoutMemory(pMemDesc) &&
+ !memdescGetContiguity(pMemDesc, AT_CPU))
+ {
+ status = NV_ERR_NOT_SUPPORTED;
+ goto done;
+ }
+
+ status = osGetPagesInfo(pMemDesc, &pageSize, &osPageCount, &rmPageCount);
+ if (status != NV_OK)
+ goto done;
+
+ if (!IS_DISCONTIG_AND_DYNGRAN_ENABLED(pMemDesc) &&
+ NV_RM_PAGE_SIZE < os_page_size &&
+ !memdescGetContiguity(pMemDesc, AT_CPU))
+ {
+ RmDeflateRmToOsPageArray(memdescGetPteArray(pMemDesc, AT_CPU),
+ rmPageCount);
+ }
+
+ status = nv_alias_pages(
+ NV_GET_NV_STATE(pGpu),
+ osPageCount,
+ pageSize,
+ memdescGetContiguity(pMemDesc, AT_CPU),
+ cpuCacheAttrib,
+ memdescGetGuestId(pMemDesc),
+ memdescGetPteArray(pMemDesc, AT_CPU),
+ memdescIsCarveoutMemory(pMemDesc),
+ &pMemData);
+ }
+ else
+ {
+ NvBool unencrypted = 0;
+
+ if (nv && (memdescGetFlag(pMemDesc, MEMDESC_FLAGS_ALLOC_32BIT_ADDRESSABLE)))
+ nv->force_dma32_alloc = NV_TRUE;
+
+ //
+ // If AMD SEV is enabled but APM(Ampere protected) or CC(Confidential
+ // Compute) mode is not enabled on the GPU, all RM and client
+ // allocations must be an unprotected sysmem. If APM is enabled and RM
+ // is allocating sysmem for its internal use, then it has to be
+ // unprotected as protected sysmem is not accessible to GPU.
+ //
+ unencrypted = memdescGetFlag(pMemDesc, MEMDESC_FLAGS_ALLOC_IN_UNPROTECTED_MEMORY);
+
+ //
+ // OBJGPU/nv may be NULL if constructing NV01_MEMORY_DEVICELESS. Assume that
+ // NV01_MEMORY_DEVICELESS won't be used for display.
+ //
+ if (pGpu != NULL &&
+ pGpu->getProperty(pGpu, PDB_PROP_GPU_TEGRA_SOC_NVDISPLAY) &&
+ addrSpace == ADDR_SYSMEM)
+ {
+ if (!memdescGetFlag(pMemDesc, MEMDESC_FLAGS_MEMORY_TYPE_DISPLAY_NISO) &&
+ !NV_SOC_IS_ISO_IOMMU_PRESENT(nv))
+ {
+ NV_PRINTF(LEVEL_INFO, "Forcing physically contiguous flags for ISO\n");
+ memdescSetContiguity(pMemDesc, AT_CPU, NV_TRUE);
+ }
+
+ if (memdescGetFlag(pMemDesc, MEMDESC_FLAGS_MEMORY_TYPE_DISPLAY_NISO) &&
+ !NV_SOC_IS_NISO_IOMMU_PRESENT(nv))
+ {
+ NV_PRINTF(LEVEL_INFO, "Forcing physically contiguous flags for NISO\n");
+ memdescSetContiguity(pMemDesc, AT_CPU, NV_TRUE);
+ }
+ }
+
+ status = osGetPagesInfo(pMemDesc, &pageSize, &osPageCount, &rmPageCount);
+ if (status != NV_OK)
+ goto done;
+
+ status = nv_alloc_pages(
+ NV_GET_NV_STATE(pGpu),
+ osPageCount, // TODO: This call needs to receive the page count param at the requested page size.
+ pageSize,
+ memdescGetContiguity(pMemDesc, AT_CPU),
+ cpuCacheAttrib,
+ pSys->getProperty(pSys,
+ PDB_PROP_SYS_INITIALIZE_SYSTEM_MEMORY_ALLOCATIONS),
+ unencrypted,
+ nodeId,
+ memdescGetPteArray(pMemDesc, AT_CPU),
+ &pMemData);
+
+ if (nv && nv->force_dma32_alloc)
+ nv->force_dma32_alloc = NV_FALSE;
+ }
+
+ if (status != NV_OK)
+ {
+ goto done;
+ }
+
+ // Guest allocated memory is already initialized
+ if (!memdescGetFlag(pMemDesc, MEMDESC_FLAGS_GUEST_ALLOCATED))
+ {
+ if (IS_DISCONTIG_AND_DYNGRAN_ENABLED(pMemDesc))
+ {
+ NV_ASSERT_OK_OR_RETURN(memdescSetAllocSizeFields(pMemDesc, osPageCount * os_page_size, os_page_size));
+ }
+ else
+ {
+ NV_ASSERT_OK_OR_RETURN(memdescSetAllocSizeFields(pMemDesc, rmPageCount * RM_PAGE_SIZE, RM_PAGE_SIZE));
+ }
+ }
+
+ //
+ // If the OS layer doesn't think in RM page size, we need to inflate the
+ // PTE array into RM pages.
+ //
+ if (IS_DISCONTIG_AND_DYNGRAN_ENABLED(pMemDesc))
+ {
+ NV_ASSERT_OR_RETURN(pMemDesc->pageArrayGranularity == os_page_size, NV_ERR_INVALID_ARGUMENT);
+ }
+ else if (NV_RM_PAGE_SIZE < os_page_size &&
+ !memdescGetContiguity(pMemDesc, AT_CPU))
+ {
+ RmInflateOsToRmPageArray(memdescGetPteArray(pMemDesc, AT_CPU),
+ pMemDesc->PageCount);
+ }
+
+ memdescSetMemData(pMemDesc, pMemData, NULL);
+
+ if ((pGpu != NULL) && IS_VIRTUAL(pGpu))
+ NV_ASSERT_OK_OR_RETURN(vgpuUpdateGuestSysmemPfnBitMap(pGpu, pMemDesc, NV_TRUE));
+done:
+ return status;
+}
+
+void osFreePagesInternal(
+ MEMORY_DESCRIPTOR *pMemDesc
+)
+{
+ OBJGPU *pGpu = pMemDesc->pGpu;
+ NV_STATUS rmStatus;
+ NvU64 osPageCount;
+
+ if ((pGpu != NULL) && IS_VIRTUAL(pGpu))
+ NV_ASSERT_OR_RETURN_VOID(vgpuUpdateGuestSysmemPfnBitMap(pGpu, pMemDesc, NV_FALSE) == NV_OK);
+
+ if (IS_DISCONTIG_AND_DYNGRAN_ENABLED(pMemDesc))
+ {
+ NV_ASSERT(pMemDesc->pageArrayGranularity == os_page_size);
+ osPageCount = pMemDesc->PageCount;
+ }
+ else if (NV_RM_PAGE_SIZE < os_page_size &&
+ !memdescGetContiguity(pMemDesc, AT_CPU))
+ {
+ osPageCount = NV_RM_PAGES_TO_OS_PAGES(pMemDesc->PageCount);
+ RmDeflateRmToOsPageArray(memdescGetPteArray(pMemDesc, AT_CPU),
+ pMemDesc->PageCount);
+ }
+ else
+ {
+ osPageCount = NV_RM_PAGES_TO_OS_PAGES(pMemDesc->PageCount);
+ }
+
+ rmStatus = nv_free_pages(NV_GET_NV_STATE(pGpu),
+ osPageCount,
+ memdescGetContiguity(pMemDesc, AT_CPU),
+ memdescGetCpuCacheAttrib(pMemDesc),
+ memdescGetMemData(pMemDesc));
+ NV_ASSERT(rmStatus == NV_OK);
+}
+
+NV_STATUS osLockMem(
+ MEMORY_DESCRIPTOR *pMemDesc
+)
+{
+ // Not supported on this OS.
+ DBG_BREAKPOINT();
+ return NV_ERR_NOT_SUPPORTED;
+}
+
+NV_STATUS osUnlockMem(
+ MEMORY_DESCRIPTOR *pMemDesc
+)
+{
+ // Not supported on this OS.
+ DBG_BREAKPOINT();
+ return NV_ERR_NOT_SUPPORTED;
+}
+
+NV_STATUS osMapPciMemoryAreaUser
+(
+ OS_GPU_INFO *pOsGpuInfo,
+ MemoryArea memArea,
+ NvU32 protect,
+ NvU32 mode,
+ NvP64 *pVirtualAddress,
+ NvP64 *pPriv
+)
+{
+ NV_STATUS status = NV_OK;
+ NvU64 origStart;
+ NvU64 origSize;
+ NvU64 diffStart;
+
+ if (memArea.numRanges == 0)
+ {
+ *pVirtualAddress = (NvP64) NULL;
+ *pPriv = NULL;
+ return NV_OK;
+ }
+
+ // Fix alignment insofar as we can (middle blocks can't be force-aligned this way)
+ origStart = memArea.pRanges[0].start;
+ memArea.pRanges[0].start = NV_ALIGN_DOWN64(origStart, os_page_size);
+ diffStart = origStart - memArea.pRanges[0].start;
+ memArea.pRanges[0].size += diffStart;
+ origSize = memArea.pRanges[memArea.numRanges - 1llu].size;
+ memArea.pRanges[memArea.numRanges - 1llu].size = NV_ALIGN_UP64(origSize, os_page_size);
+
+ {
+ nv_usermap_access_params_t **ppNvuap, tNvuap;
+ NvU64 totalRangeSize = sizeof(MemoryRange) * memArea.numRanges;
+
+ portMemSet(&tNvuap, 0, sizeof(nv_usermap_access_params_t));
+
+ tNvuap.memArea = memArea;
+ // access_size is only for caching, we can use os_page_size for now until linux has been properly plumbed
+ tNvuap.access_start = memArea.pRanges[0].start;
+ tNvuap.access_size = os_page_size;
+
+ tNvuap.caching = mode;
+ tNvuap.contig = NV_TRUE;
+
+ ppNvuap = (nv_usermap_access_params_t **) tlsEntryAcquire(TLS_ENTRY_ID_MAPPING_CONTEXT);
+ NV_ASSERT_OR_RETURN(ppNvuap != NULL, NV_ERR_INVALID_STATE);
+
+ NV_ASSERT_OK_OR_GOTO(status,
+ os_alloc_mem((void**) ppNvuap, sizeof(nv_alloc_mapping_context_t)),
+ free_tls);
+
+ portMemCopy(*ppNvuap, sizeof(nv_usermap_access_params_t),
+ &tNvuap, sizeof(nv_usermap_access_params_t));
+
+ NV_ASSERT_OK_OR_GOTO(status,
+ os_alloc_mem((void**) &((*ppNvuap)->memArea.pRanges), totalRangeSize),
+ free_nvuap);
+
+ portMemCopy((*ppNvuap)->memArea.pRanges, totalRangeSize, memArea.pRanges, totalRangeSize);
+
+ *pVirtualAddress = (NvP64) (memArea.pRanges[0].start + diffStart);
+ goto unalign_and_return;
+
+free_nvuap:
+ os_free_mem(*ppNvuap);
+free_tls:
+ tlsEntryRelease(TLS_ENTRY_ID_MAPPING_CONTEXT);
+ }
+unalign_and_return:
+ memArea.pRanges[memArea.numRanges - 1llu].size = origSize;
+ memArea.pRanges[0].size -= diffStart;
+ memArea.pRanges[0].start = origStart;
+ return status;
+}
+
+NV_STATUS osMapPciMemoryUser(
+ OS_GPU_INFO *pOsGpuInfo,
+ RmPhysAddr busAddress,
+ NvU64 length,
+ NvU32 Protect,
+ NvP64 *pVirtualAddress,
+ NvP64 *pPriv,
+ NvU32 modeFlag
+)
+{
+ MemoryArea memArea;
+ MemoryRange memRange;
+
+ memArea.numRanges = 1;
+ memArea.pRanges = &memRange;
+
+ memRange.start = busAddress;
+ memRange.size = length;
+
+ return osMapPciMemoryAreaUser(pOsGpuInfo, memArea, Protect, modeFlag, pVirtualAddress, pPriv);
+}
+
+void osUnmapPciMemoryUser(
+ OS_GPU_INFO *pOsGpuInfo,
+ NvP64 virtualAddress,
+ NvU64 length,
+ NvP64 pPriv
+)
+{
+}
+
+NV_STATUS osMapPciMemoryKernelOld
+(
+ OBJGPU *pGpu,
+ RmPhysAddr busAddress,
+ NvU64 length,
+ NvU32 Protect,
+ void **pVirtualAddress,
+ NvU32 modeFlag
+)
+{
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ nv_kern_mapping_t *mapping;
+
+ if (pVirtualAddress == NULL)
+ return NV_ERR_GENERIC;
+
+ *pVirtualAddress = os_map_kernel_space(busAddress, length, modeFlag);
+ if (*pVirtualAddress == NULL)
+ return NV_ERR_GENERIC;
+
+ mapping = portMemAllocNonPaged(sizeof(nv_kern_mapping_t));
+ if (NULL == mapping)
+ {
+ os_unmap_kernel_space(*pVirtualAddress, length);
+ *pVirtualAddress = 0;
+ return NV_ERR_GENERIC;
+ }
+
+ mapping->addr = *pVirtualAddress;
+ mapping->size = length;
+ mapping->modeFlag = modeFlag;
+
+ mapping->next = nv->kern_mappings;
+ nv->kern_mappings = mapping;
+
+ return NV_OK;
+}
+
+NV_STATUS osMapPciMemoryKernel64
+(
+ OBJGPU *pGpu,
+ RmPhysAddr busAddress,
+ NvU64 length,
+ NvU32 Protect,
+ NvP64 *pVirtualAddress,
+ NvU32 modeFlag
+)
+{
+ void *tmppVirtualAddress = NvP64_VALUE(pVirtualAddress);
+ NV_STATUS rc;
+
+ rc = osMapPciMemoryKernelOld(pGpu,
+ busAddress,
+ length,
+ Protect,
+ &tmppVirtualAddress,
+ modeFlag);
+
+ *pVirtualAddress = NV_PTR_TO_NvP64(tmppVirtualAddress);
+
+ return rc;
+}
+
+void osUnmapPciMemoryKernelOld
+(
+ OBJGPU *pGpu,
+ void* virtualAddress
+)
+{
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ nv_kern_mapping_t *mapping, *tmp;
+
+ // this can happen, for example, during a call to RmShutdownAdapter()
+ // from a failed RmInitAdapter()
+ if (virtualAddress == NULL)
+ {
+ return;
+ }
+
+ tmp = mapping = nv->kern_mappings;
+ while (mapping)
+ {
+ if (mapping->addr == virtualAddress)
+ {
+ if (mapping == nv->kern_mappings)
+ {
+ nv->kern_mappings = mapping->next;
+ }
+ else
+ {
+ tmp->next = mapping->next;
+ }
+
+ os_unmap_kernel_space(mapping->addr, mapping->size);
+
+ portMemFree(mapping);
+ return;
+ }
+ tmp = mapping;
+ mapping = mapping->next;
+ }
+
+ DBG_BREAKPOINT();
+}
+
+void osUnmapPciMemoryKernel64
+(
+ OBJGPU *pGpu,
+ NvP64 virtualAddress
+)
+{
+ osUnmapPciMemoryKernelOld(pGpu, NvP64_VALUE(virtualAddress));
+}
+
+NV_STATUS osMapGPU(
+ OBJGPU *pGpu,
+ RS_PRIV_LEVEL privLevel,
+ NvU64 offset,
+ NvU64 length,
+ NvU32 Protect,
+ NvP64 *pAddress,
+ NvP64 *pPriv
+)
+{
+ NV_STATUS rmStatus = NV_OK;
+
+ if (privLevel >= RS_PRIV_LEVEL_KERNEL)
+ {
+ if (!portSafeAddU64((NvUPtr)pGpu->deviceMappings[0].gpuNvAddr, offset, (NvU64*)pAddress))
+ {
+ rmStatus = NV_ERR_INVALID_LIMIT;
+ }
+ }
+ else
+ {
+ RmPhysAddr busAddress;
+ if (!portSafeAddU64(pGpu->busInfo.gpuPhysAddr, offset, &busAddress))
+ {
+ rmStatus = NV_ERR_INVALID_LIMIT;
+ }
+ else
+ {
+ rmStatus = osMapPciMemoryUser(pGpu->pOsGpuInfo,
+ busAddress,
+ length,
+ Protect,
+ pAddress,
+ pPriv,
+ NV_MEMORY_UNCACHED);
+ }
+ }
+
+ return rmStatus;
+}
+
+void osUnmapGPU(
+ OS_GPU_INFO *pOsGpuInfo,
+ RS_PRIV_LEVEL privLevel,
+ NvP64 address,
+ NvU64 length,
+ NvP64 priv
+)
+{
+ if (privLevel < RS_PRIV_LEVEL_KERNEL)
+ {
+ osUnmapPciMemoryUser(pOsGpuInfo, address, length, priv);
+ }
+}
+
+static NV_STATUS referenceEventForPost(
+ nv_event_t *event,
+ NvBool bDoRefCount,
+ nv_event_t *eventSnapshot,
+ nv_file_private_t **ppNvfp
+)
+{
+ nv_state_t *nv = nv_get_ctl_state();
+
+ portSyncSpinlockAcquire(nv->event_spinlock);
+
+ if (event->active == 0)
+ {
+ portSyncSpinlockRelease(nv->event_spinlock);
+ return NV_ERR_INVALID_EVENT;
+ }
+
+ if (bDoRefCount)
+ ++event->refcount;
+
+ // Snapshot while event_spinlock still protects the event lifetime.
+ *eventSnapshot = *event;
+ *ppNvfp = eventSnapshot->nvfp;
+ portAtomicIncrementS32(&(*ppNvfp)->event_posting_refcount);
+
+ portSyncSpinlockRelease(nv->event_spinlock);
+ return NV_OK;
+}
+
+static void dereferenceEventForPost(
+ nv_event_t *event,
+ NvBool bDoRefCount,
+ nv_file_private_t *nvfp
+)
+{
+ if (bDoRefCount)
+ {
+ nv_state_t *nv = nv_get_ctl_state();
+
+ portSyncSpinlockAcquire(nv->event_spinlock);
+
+ NV_ASSERT(event->refcount > 0);
+ if (--event->refcount == 0 && !event->active)
+ portMemFree(event);
+
+ portSyncSpinlockRelease(nv->event_spinlock);
+ }
+
+ portAtomicDecrementS32(&nvfp->event_posting_refcount);
+}
+
+static void postEvent(
+ nv_event_t *event,
+ NvU32 hEvent,
+ NvU32 notifyIndex,
+ NvU32 info32,
+ NvU16 info16,
+ NvBool dataValid,
+ NvBool bDoRefCount
+)
+{
+ nv_event_t *eventToPost = event;
+
+ nv_file_private_t *nvfp = NULL;
+ nv_event_t eventSnapshot;
+
+ if (referenceEventForPost(event, bDoRefCount, &eventSnapshot, &nvfp) != NV_OK)
+ return;
+
+ eventToPost = &eventSnapshot;
+
+ nv_post_event(eventToPost, hEvent, notifyIndex,
+ info32, info16, dataValid);
+
+ dereferenceEventForPost(bDoRefCount ? event : NULL, bDoRefCount, nvfp);
+}
+
+NvU32 osSetEvent
+(
+ OBJGPU *pGpu,
+ NvP64 eventID
+)
+{
+ nv_event_t *event = NvP64_VALUE(eventID);
+ postEvent(event, 0, 0, 0, 0, NV_FALSE, NV_TRUE);
+ return 1;
+}
+
+NV_STATUS osNotifyEvent(
+ OBJGPU *pGpu,
+ PEVENTNOTIFICATION NotifyEvent,
+ NvU32 Method,
+ NvU32 Data,
+ NV_STATUS Status,
+ NvBool bDoRefCount
+)
+{
+ NV_STATUS rmStatus = NV_OK;
+
+ // notify the event
+ switch (NotifyEvent->NotifyType)
+ {
+ case NV01_EVENT_OS_EVENT:
+ {
+ nv_event_t *event = NvP64_VALUE(NotifyEvent->Data);
+ postEvent(event,
+ NotifyEvent->hEvent,
+ NotifyEvent->NotifyIndex,
+ 0, 0,
+ NotifyEvent->bEventDataRequired,
+ bDoRefCount);
+ break;
+ }
+
+ // NOTE: NV01_EVENT_KERNEL_CALLBACK is deprecated. please use NV01_EVENT_KERNEL_CALLBACK_EX.
+ case NV01_EVENT_KERNEL_CALLBACK:
+ {
+ MINIPORT_CALLBACK callBackToMiniport =
+ (MINIPORT_CALLBACK)NvP64_VALUE(NotifyEvent->Data);
+
+ // perform a direct callback to the miniport
+ if (callBackToMiniport)
+ callBackToMiniport(NV_GET_NV_STATE(pGpu));
+ break;
+ }
+
+ case NV01_EVENT_KERNEL_CALLBACK_EX:
+ {
+ NVOS10_EVENT_KERNEL_CALLBACK_EX *kc = (NVOS10_EVENT_KERNEL_CALLBACK_EX *)NvP64_VALUE(NotifyEvent->Data);
+
+ // passes two arguments (arg, params) to the kernel callback instead of one (arg).
+ if (kc && kc->func)
+ {
+ kc->func(kc->arg, NULL, NotifyEvent->hEvent, Data, Status);
+ }
+ break;
+ }
+
+
+ default:
+ {
+ rmStatus = NV_ERR_GENERIC;
+ break;
+ }
+ }
+
+ return rmStatus;
+
+} // end of osNotifyEvent()
+
+// Allow CPL Events to be callback or events
+NV_STATUS osEventNotification
+(
+ OBJGPU *pGpu,
+ PEVENTNOTIFICATION pNotifyEvent,
+ NvU32 notifyIndex,
+ void * pEventData,
+ NvU32 eventDataSize
+)
+{
+ return osEventNotificationWithInfo(pGpu, pNotifyEvent, notifyIndex, 0, 0,
+ pEventData, eventDataSize);
+}
+
+NV_STATUS osEventNotificationWithInfo
+(
+ OBJGPU *pGpu,
+ PEVENTNOTIFICATION pNotifyEvent,
+ NvU32 notifyIndex,
+ NvU32 info32,
+ NvU16 info16,
+ void * pEventData,
+ NvU32 eventDataSize
+)
+{
+ NV_STATUS rmStatus = NV_OK;
+ NvBool bMatchSubdev = NV_FALSE;
+
+ if ((notifyIndex != OS_EVENT_NOTIFICATION_INDEX_ALL) &&
+ (OS_EVENT_NOTIFICATION_INDEX_MATCH_SUBDEV & notifyIndex))
+ {
+ bMatchSubdev = NV_TRUE;
+ notifyIndex &= ~OS_EVENT_NOTIFICATION_INDEX_MATCH_SUBDEV;
+ }
+
+ // walk this object's event list and find any matches for this specific notify
+ for (; pNotifyEvent; pNotifyEvent = pNotifyEvent->Next)
+ {
+ // notifyIndex must match if request isn't for all
+ if ((notifyIndex != OS_EVENT_NOTIFICATION_INDEX_ALL) &&
+ (pNotifyEvent->NotifyIndex != notifyIndex))
+ {
+ continue;
+ }
+
+ if (bMatchSubdev && (pGpu->subdeviceInstance != pNotifyEvent->subdeviceInst))
+ continue;
+
+ switch (pNotifyEvent->NotifyType)
+ {
+ case NV_EVENT_BUFFER_BIND:
+ case NV01_EVENT_WIN32_EVENT:
+ {
+ nv_event_t *event = NvP64_VALUE(pNotifyEvent->Data);
+ postEvent(event,
+ pNotifyEvent->hEvent,
+ pNotifyEvent->NotifyIndex,
+ info32, info16,
+ pNotifyEvent->bEventDataRequired,
+ NV_TRUE);
+ break;
+ }
+
+ // NOTE: NV01_EVENT_KERNEL_CALLBACK is deprecated. please use NV01_EVENT_KERNEL_CALLBACK_EX.
+ case NV01_EVENT_KERNEL_CALLBACK:
+ {
+ MINIPORT_CALLBACK callBackToMiniport =
+ (MINIPORT_CALLBACK)NvP64_VALUE(pNotifyEvent->Data);
+
+ // perform a direct callback to the miniport
+ if (callBackToMiniport)
+ callBackToMiniport(NV_GET_NV_STATE(pGpu));
+ break;
+ }
+
+ case NV01_EVENT_KERNEL_CALLBACK_EX:
+ {
+ NVOS10_EVENT_KERNEL_CALLBACK_EX *kc = (NVOS10_EVENT_KERNEL_CALLBACK_EX *)NvP64_VALUE(pNotifyEvent->Data);
+
+ if (kc && kc->func)
+ {
+ kc->func(kc->arg, pEventData, pNotifyEvent->hEvent, 0, NV_OK);
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
+
+ return rmStatus;
+}
+
+// Allow CPL Events to be callback or events
+NV_STATUS osObjectEventNotification
+(
+ NvHandle hClient,
+ NvHandle hObject,
+ NvU32 hClass,
+ PEVENTNOTIFICATION pNotifyEvent,
+ NvU32 notifyIndex,
+ void *pEventData,
+ NvU32 eventDataSize
+)
+{
+ NV_STATUS rmStatus = NV_OK;
+
+ NV_PRINTF(LEVEL_INFO, "%s()\n", __FUNCTION__);
+ // walk this object's event list and find any matches for this specific notify
+ for (; pNotifyEvent; pNotifyEvent = pNotifyEvent->Next)
+ {
+ // notifyIndex must match if request isn't for all
+ if ((notifyIndex != OS_EVENT_NOTIFICATION_INDEX_ALL) &&
+ (pNotifyEvent->NotifyIndex != notifyIndex))
+ {
+ continue;
+ }
+
+ switch (pNotifyEvent->NotifyType)
+ {
+ case NV01_EVENT_OS_EVENT:
+ {
+ nv_event_t *event = NvP64_VALUE(pNotifyEvent->Data);
+ postEvent(event,
+ pNotifyEvent->hEvent,
+ pNotifyEvent->NotifyIndex,
+ 0, 0,
+ pNotifyEvent->bEventDataRequired,
+ NV_TRUE);
+ break;
+ }
+
+ case NV01_EVENT_KERNEL_CALLBACK_EX:
+ {
+ NVOS10_EVENT_KERNEL_CALLBACK_EX *kc = (NVOS10_EVENT_KERNEL_CALLBACK_EX *)NvP64_VALUE(pNotifyEvent->Data);
+
+ if (kc && kc->func)
+ {
+ kc->func(kc->arg, pEventData, pNotifyEvent->hEvent, 0, NV_OK);
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
+
+ return rmStatus;
+}
+
+NV_STATUS osReferenceObjectCount(void *pEvent)
+{
+ nv_state_t *nv = nv_get_ctl_state();
+ nv_event_t *event = pEvent;
+
+ portSyncSpinlockAcquire(nv->event_spinlock);
+ // If event->active is false, don't allow any more reference
+ if (event->active == 0)
+ {
+ portSyncSpinlockRelease(nv->event_spinlock);
+ return NV_ERR_INVALID_EVENT;
+ }
+ ++event->refcount;
+ portSyncSpinlockRelease(nv->event_spinlock);
+ return NV_OK;
+}
+
+NV_STATUS osDereferenceObjectCount(void *pOSEvent)
+{
+ nv_state_t *nv = nv_get_ctl_state();
+ nv_event_t *event = pOSEvent;
+
+ portSyncSpinlockAcquire(nv->event_spinlock);
+ NV_ASSERT(event->refcount > 0);
+ // If event->refcount == 0 but event->active is true, the client
+ // has not yet freed the OS event. free_os_event will free its
+ // memory when they do, or else when the client itself is freed.
+ if (--event->refcount == 0 && !event->active)
+ portMemFree(event);
+ portSyncSpinlockRelease(nv->event_spinlock);
+
+ return NV_OK;
+}
+
+NV_STATUS osUserHandleToKernelPtr(NvHandle hClient, NvP64 hEvent, NvP64 *pEvent)
+{
+ nv_state_t *nv = nv_get_ctl_state();
+ NvU32 fd = (NvU64)hEvent;
+ NV_STATUS result;
+
+ portSyncSpinlockAcquire(nv->event_spinlock);
+ nv_event_t *e = nv->event_list;
+ while (e != NULL)
+ {
+ if (e->fd == fd && e->hParent == hClient)
+ break;
+ e = e->next;
+ }
+
+ if (e != NULL)
+ {
+ ++e->refcount;
+ *pEvent = NV_PTR_TO_NvP64(e);
+ result = NV_OK;
+ }
+ else
+ result = NV_ERR_OBJECT_NOT_FOUND;
+ portSyncSpinlockRelease(nv->event_spinlock);
+
+ return result;
+}
+
+NV_STATUS osFlushCpuCache(void)
+{
+ return os_flush_cpu_cache_all();
+}
+
+void osFlushCpuWriteCombineBuffer(void)
+{
+ os_flush_cpu_write_combine_buffer();
+}
+
+
+//
+// Evict GPU memory range from the CPU caches.
+//
+// On some platforms (e.g. P9+V100), the CPU can coherently cache GPU memory
+// and RM takes advantage of that. Most everything is handled transparently,
+// but there are two exceptions that require explicitly flushing any CPU cache
+// lines of GPU memory. These are:
+//
+// 1) Flushing memory backing ACR regions before they get locked.
+//
+// Otherwise the cache could get flushed while the regions are locked causing a
+// region violation physical fault. See more details in
+// acrFlushRegionsFromGpuCoherentCpuCache_IMPL().
+//
+// 2) Flushing all of FB before GPU reset (NVLink going down)
+//
+// Leaving cache entries on the CPU causes fatal errors when the CPU tries
+// flushing them later while the link is down. See more details in
+// nvlinkStatePostUnload_IMPL().
+//
+void osFlushGpuCoherentCpuCacheRange
+(
+ OS_GPU_INFO *pOsGpuInfo,
+ NvU64 cpuVirtual,
+ NvU64 size
+)
+{
+ nv_flush_coherent_cpu_cache_range(pOsGpuInfo, cpuVirtual, size);
+}
+
+void osErrorLogV(OBJGPU *pGpu, XidContext context, const char * pFormat, va_list arglist)
+{
+ NV_STATUS rmStatus;
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+
+ if ((pFormat == NULL) || (*pFormat == '\0'))
+ {
+ return;
+ }
+
+ rmStatus = nv_log_error(nv, context.xid, pFormat, arglist);
+ NV_ASSERT(rmStatus == NV_OK);
+}
+
+void osErrorLog(OBJGPU *pGpu, NvU32 num, const char* pFormat, ...)
+{
+ va_list arglist;
+ va_start(arglist, pFormat);
+ osErrorLogV(pGpu, (XidContext){.xid = num}, pFormat, arglist);
+ va_end(arglist);
+}
+
+NvU32
+osPollHotkeyState
+(
+ OBJGPU *pGpu
+)
+{
+ return 0;
+}
+
+void osDevWriteReg008(
+ OBJGPU *pGpu,
+ DEVICE_MAPPING *pMapping,
+ NvU32 thisAddress,
+ NvV8 thisValue
+)
+{
+ if (thisAddress >= pMapping->gpuNvLength)
+ {
+ NV_ASSERT(thisAddress < pMapping->gpuNvLength);
+ return;
+ }
+
+ NV_PRIV_REG_WR08(pMapping->gpuNvAddr, thisAddress, thisValue);
+}
+
+void osDevWriteReg016(
+ OBJGPU *pGpu,
+ DEVICE_MAPPING *pMapping,
+ NvU32 thisAddress,
+ NvV16 thisValue
+)
+{
+ if (thisAddress >= pMapping->gpuNvLength)
+ {
+ NV_ASSERT(thisAddress < pMapping->gpuNvLength);
+ return;
+ }
+
+ NV_PRIV_REG_WR16(pMapping->gpuNvAddr, thisAddress, thisValue);
+}
+
+void osDevWriteReg032(
+ OBJGPU *pGpu,
+ DEVICE_MAPPING *pMapping,
+ NvU32 thisAddress,
+ NvV32 thisValue
+)
+{
+ NvBool vgpuHandled = NV_FALSE;
+
+ vgpuDevWriteReg032(pGpu, thisAddress, thisValue, &vgpuHandled);
+ if (vgpuHandled)
+ {
+ return;
+ }
+
+ if (thisAddress >= pMapping->gpuNvLength)
+ {
+ NV_ASSERT(thisAddress < pMapping->gpuNvLength);
+ return;
+ }
+
+ NV_PRIV_REG_WR32(pMapping->gpuNvAddr, thisAddress, thisValue);
+}
+
+NvU8 osDevReadReg008(
+ OBJGPU *pGpu,
+ DEVICE_MAPPING *pMapping,
+ NvU32 thisAddress
+)
+{
+ NvU8 retval = 0;
+
+ if (thisAddress >= pMapping->gpuNvLength)
+ {
+ NV_ASSERT(thisAddress < pMapping->gpuNvLength);
+ }
+ else
+ retval = NV_PRIV_REG_RD08(pMapping->gpuNvAddr, thisAddress);
+
+ return retval;
+}
+
+NvU16 osDevReadReg016(
+ OBJGPU *pGpu,
+ DEVICE_MAPPING *pMapping,
+ NvU32 thisAddress
+)
+{
+ NvU16 retval = 0;
+
+ if (thisAddress >= pMapping->gpuNvLength)
+ {
+ NV_ASSERT(thisAddress < pMapping->gpuNvLength);
+ }
+ else
+ retval = NV_PRIV_REG_RD16(pMapping->gpuNvAddr, thisAddress);
+
+ return retval;
+}
+
+NvU32 osDevReadReg032(
+ OBJGPU *pGpu,
+ DEVICE_MAPPING *pMapping,
+ NvU32 thisAddress
+)
+{
+ NvU32 retval = 0;
+ NvBool vgpuHandled = NV_FALSE;
+
+ retval = vgpuDevReadReg032(pGpu, thisAddress, &vgpuHandled);
+ if (vgpuHandled)
+ {
+ return retval;
+ }
+
+ if (thisAddress >= pMapping->gpuNvLength)
+ {
+ NV_ASSERT(thisAddress < pMapping->gpuNvLength);
+ }
+ else
+ retval = NV_PRIV_REG_RD32(pMapping->gpuNvAddr, thisAddress);
+
+ return retval;
+}
+
+NV_STATUS osReadRegistryDwordBase(
+ OBJGPU *pGpu,
+ const char *regParmStr,
+ NvU32 *Data
+)
+{
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ return RmReadRegistryDword(nv, regParmStr, Data);
+}
+
+NV_STATUS osWriteRegistryDword(
+ OBJGPU *pGpu,
+ const char *regParmStr,
+ NvU32 Data
+)
+{
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ return RmWriteRegistryDword(nv, regParmStr, Data);
+}
+
+NV_STATUS osReadRegistryBinary(
+ OBJGPU *pGpu,
+ const char *regParmStr,
+ NvU8 *Data,
+ NvU32 *cbLen
+)
+{
+#if defined(DEBUG) || defined(DEVELOP)
+ NV_ASSERT_OK_OR_RETURN(osValidateRegistryKeyPrefix(regParmStr));
+#endif
+
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ return RmReadRegistryBinary(nv, regParmStr, Data, cbLen);
+}
+
+NV_STATUS osWriteRegistryBinary(
+ OBJGPU *pGpu,
+ const char *regParmStr,
+ NvU8 *Data,
+ NvU32 cbLen
+)
+{
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ return RmWriteRegistryBinary(nv, regParmStr, Data, cbLen);
+}
+
+NV_STATUS osWriteRegistryVolatile(
+ OBJGPU *pGpu,
+ const char *regParmStr,
+ NvU8 *Data,
+ NvU32 cbLen
+)
+{
+ return NV_ERR_NOT_SUPPORTED;
+}
+
+NV_STATUS osReadRegistryVolatile
+(
+ OBJGPU *pGpu,
+ const char *regParmStr,
+ NvU8 *Data,
+ NvU32 cbLen
+)
+{
+ return NV_ERR_NOT_SUPPORTED;
+}
+
+NV_STATUS osReadRegistryVolatileSize
+(
+ OBJGPU *pGpu,
+ const char *regParmStr,
+ NvU32 *pSize
+)
+{
+ return NV_ERR_NOT_SUPPORTED;
+}
+
+NV_STATUS osReadRegistryStringBase(
+ OBJGPU *pGpu,
+ const char *regParmStr,
+ NvU8 *buffer,
+ NvU32 *pBufferLength
+)
+{
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ return RmReadRegistryString(nv, regParmStr, buffer, pBufferLength);
+}
+
+NV_STATUS osPackageRegistry(
+ OBJGPU *pGpu,
+ PACKED_REGISTRY_TABLE *pRegTable,
+ NvU32 *pSize
+)
+{
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ return RmPackageRegistry(nv, pRegTable, pSize);
+}
+
+NvU32 osGetCpuCount(void)
+{
+ return os_get_cpu_count(); // Total number of logical CPUs.
+}
+
+NvU32 osGetCurrentProcessorNumber(void)
+{
+ return os_get_cpu_number();
+}
+
+ClientGroupID osClientGroupID(NvU64 process, void *pidInfo)
+{
+ return os_cgroup_for_pid(process, pidInfo);
+}
+
+NvCgroupImpl osCgroupImplementation(void)
+{
+ switch (os_cgroup_implementation())
+ {
+ case OS_CGROUP_IMPL_DMEM: return CGROUP_IMPL_OS;
+ case OS_CGROUP_IMPL_MISC: return CGROUP_IMPL_FALLBACK;
+ default: return CGROUP_IMPL_NONE;
+ }
+}
+
+void *osCgroupRegisterRegion(OBJGPU *pGpu, NvU64 size)
+{
+ char name[32];
+ nvDbgSnprintf(name, sizeof name, "nvidia/%04x:%02x:%02x/vidmem",
+ gpuGetDomain(pGpu),
+ gpuGetBus(pGpu),
+ gpuGetDevice(pGpu));
+ return os_dmem_cgroup_register_region(size, name);
+}
+
+void osCgroupUnregisterRegion(void *region)
+{
+ os_dmem_cgroup_unregister_region(region);
+}
+
+NV_STATUS osMemacctTryCharge(void *pRegion, NvLength size, void **ppPool)
+{
+ return os_dmem_cgroup_try_charge(pRegion, size, ppPool, NULL);
+}
+
+void osMemacctReleaseCharge(void *pool, NvLength size)
+{
+ os_dmem_cgroup_uncharge(pool, size);
+}
+
+void *osCgroupGetFromFd(NvS32 fd)
+{
+ return os_cgroup_get_from_fd(fd);
+}
+
+void osCgroupPut(void *cgroup)
+{
+ os_cgroup_put(cgroup);
+}
+
+void osGetTimeoutParams(OBJGPU *pGpu, NvU32 *pTimeoutUs, NvU32 *pScale, NvU32 *pFlags)
+{
+ NvU32 gpuMode = gpuGetMode(pGpu);
+
+ NV_ASSERT((NV_GPU_MODE_GRAPHICS_MODE == gpuMode) ||
+ (NV_GPU_MODE_COMPUTE_MODE == gpuMode));
+
+ if (hypervisorIsVgxHyper())
+ {
+ //
+ // 1.8 seconds is chosen because it is 90% of the overall hard limit of 2.0
+ // seconds, imposed by WDDM driver rules.
+ // Currently primary use case of VGX is Windows, so setting 1.8 as default
+ //
+ *pTimeoutUs = 1.8 * 1000000;
+ }
+ else
+ {
+ switch (gpuMode)
+ {
+ default:
+ case NV_GPU_MODE_GRAPHICS_MODE:
+ *pTimeoutUs = 4 * 1000000;
+ break;
+
+ case NV_GPU_MODE_COMPUTE_MODE:
+ *pTimeoutUs = 30 * 1000000;
+ break;
+ }
+ }
+
+ *pFlags = GPU_TIMEOUT_FLAGS_OSTIMER;
+
+ *pScale = 1;
+ if (IS_EMULATION(pGpu) || IS_SIMULATION(pGpu))
+ {
+ *pScale = 60; // 1s -> 1m
+ }
+
+ return;
+}
+
+void osFlushLog(void)
+{
+ // Not implemented
+}
+
+static NvU32 _osGetTegraPlatform(void)
+{
+ NV_STATUS status;
+ NvU32 mode;
+
+ status = os_get_tegra_platform(&mode);
+ if (status != NV_ERR_NOT_SUPPORTED)
+ {
+ return mode;
+ }
+
+ return NV_OS_TEGRA_PLATFORM_SILICON;
+}
+
+NvU32 osGetSimulationMode(void)
+{
+ NvU32 mode;
+
+ switch (_osGetTegraPlatform())
+ {
+ case NV_OS_TEGRA_PLATFORM_SIM:
+ mode = NV_SIM_MODE_CMODEL;
+ break;
+ case NV_OS_TEGRA_PLATFORM_FPGA:
+ mode = NV_SIM_MODE_TEGRA_FPGA;
+ break;
+ case NV_OS_TEGRA_PLATFORM_SILICON:
+ default:
+ mode = NV_SIM_MODE_HARDWARE;
+ break;
+ }
+
+ return mode;
+}
+
+NV_STATUS
+cliresCtrlCmdOsUnixFlushUserCache_IMPL
+(
+ RmClientResource *pRmCliRes,
+ NV0000_CTRL_OS_UNIX_FLUSH_USER_CACHE_PARAMS *pAddressSpaceParams
+)
+{
+ Memory *pMemory;
+ MEMORY_DESCRIPTOR *pMemDesc;
+ NvU64 start, end;
+ NvBool bInvalidateOnly;
+
+ NV_CHECK_OK_OR_RETURN(LEVEL_SILENT,
+ memGetByHandle(RES_GET_CLIENT(pRmCliRes),
+ pAddressSpaceParams->hObject,
+ &pMemory));
+
+ pMemDesc = pMemory->pMemDesc;
+
+ if (memdescGetAddressSpace(pMemDesc) != ADDR_SYSMEM)
+ {
+ NV_PRINTF(LEVEL_ERROR, "%s: wrong address space %d\n",
+ __FUNCTION__, memdescGetAddressSpace(pMemDesc));
+ return NV_ERR_INVALID_COMMAND;
+ }
+
+ if (memdescGetCpuCacheAttrib(pMemDesc) != NV_MEMORY_CACHED)
+ {
+ NV_PRINTF(LEVEL_ERROR, "%s: wrong caching type %d\n",
+ __FUNCTION__, memdescGetCpuCacheAttrib(pMemDesc));
+ return NV_ERR_INVALID_COMMAND;
+ }
+
+ start = pAddressSpaceParams->offset;
+ end = start + pAddressSpaceParams->length;
+
+ switch(pAddressSpaceParams->cacheOps)
+ {
+ case NV0000_CTRL_OS_UNIX_FLAGS_USER_CACHE_FLUSH_INVALIDATE:
+ case NV0000_CTRL_OS_UNIX_FLAGS_USER_CACHE_FLUSH:
+ bInvalidateOnly = NV_FALSE;
+ break;
+
+ case NV0000_CTRL_OS_UNIX_FLAGS_USER_CACHE_INVALIDATE:
+ bInvalidateOnly = NV_TRUE;
+ break;
+
+ default:
+ NV_PRINTF(LEVEL_ERROR, "%s: cacheOps not specified\n", __FUNCTION__);
+ return NV_ERR_INVALID_COMMAND;
+ }
+
+ if ((end - start) > pMemory->Length)
+ {
+ NV_PRINTF(LEVEL_ERROR,
+ "%s: end address 0x%llx exceeded buffer length: 0x%llx\n",
+ __FUNCTION__, end, pMemory->Length);
+ return NV_ERR_INVALID_LIMIT;
+ }
+
+ if (bInvalidateOnly)
+ {
+ //
+ // XXX: this seems fishy - I'm not sure if invalidating by the kernel
+ // VA only as nv_dma_cache_invalidate() does here is sufficient for
+ // this control call.
+ // pAddressSpaceParams->internalOnly is expected to be the RM client
+ // VA for this control call; if we wanted to invalidate the user VA we
+ // could do so using that.
+ //
+ // For I/O coherent platforms this won't actually do anything.
+ // On non-I/O-coherent platforms, there's no need to do a second
+ // invalidation after the full flush.
+ //
+ nv_state_t *nv = NV_GET_NV_STATE(pMemDesc->pGpu);
+ if (nv->iovaspace_id != NV_IOVA_DOMAIN_NONE)
+ {
+ PIOVAMAPPING pIovaMapping = memdescGetIommuMap(pMemDesc, nv->iovaspace_id);
+ //
+ // This should only be called for devices that map memory descriptors
+ // through the nv-dma library, where the memory descriptor data
+ // contains all the kernel-specific context we need for the
+ // invalidation.
+ //
+ // (These checks match those in osIovaUnmap() leading up to
+ // nv_dma_unmap_alloc()).
+ //
+ if (pIovaMapping == NULL ||
+ pIovaMapping->pOsData == NULL ||
+ memdescGetFlag(pIovaMapping->pPhysMemDesc, MEMDESC_FLAGS_GUEST_ALLOCATED) ||
+ memdescGetFlag(pIovaMapping->pPhysMemDesc, MEMDESC_FLAGS_PEER_IO_MEM))
+ {
+ return NV_ERR_INVALID_ARGUMENT;
+ }
+
+ nv_dma_cache_invalidate(nv->dma_dev, pIovaMapping->pOsData);
+ }
+ else
+ {
+ return NV_ERR_INVALID_ARGUMENT;
+ }
+ }
+ else
+ {
+ return os_flush_user_cache();
+ }
+
+ return NV_OK;
+}
+
+static NV_STATUS
+_initializeExportObjectFd
+(
+ nv_file_private_t *nvfp,
+ NvHandle hClient,
+ NvHandle hDevice,
+ NvU16 maxObjects,
+ NvU8 *metadata
+)
+{
+ NV_STATUS status;
+ RsResourceRef *pResourceRef;
+ Device *pDevice;
+ NvU32 deviceInstance = NV_MAX_DEVICES;
+ NvU32 gpuInstanceId = NV_U32_MAX;
+
+ if (nvfp->handles != NULL)
+ {
+ return NV_ERR_STATE_IN_USE;
+ }
+
+ if (hDevice != 0)
+ {
+ OBJGPU *pGpu;
+ MIG_INSTANCE_REF ref;
+
+ status = serverutilGetResourceRef(hClient, hDevice, &pResourceRef);
+ if (status != NV_OK)
+ {
+ return status;
+ }
+
+ pDevice = dynamicCast(pResourceRef->pResource, Device);
+ if (pDevice == NULL)
+ {
+ return NV_ERR_INVALID_PARAMETER;
+ }
+
+ deviceInstance = pDevice->deviceInst;
+ pGpu = GPU_RES_GET_GPU(pDevice);
+
+ if (IS_MIG_IN_USE(pGpu))
+ {
+ KernelMIGManager *pKernelMIGManager = GPU_GET_KERNEL_MIG_MANAGER(pGpu);
+ status = kmigmgrGetInstanceRefFromDevice(pGpu, pKernelMIGManager,
+ pDevice, &ref);
+ if (status == NV_OK)
+ {
+ gpuInstanceId = ref.pKernelMIGGpuInstance->swizzId;
+ }
+ }
+ }
+
+ NV_ASSERT_OK_OR_RETURN(os_alloc_mem((void **)&nvfp->handles,
+ sizeof(nvfp->handles[0]) * maxObjects));
+
+ os_mem_set(nvfp->handles, 0,
+ sizeof(nvfp->handles[0]) * maxObjects);
+
+ nvfp->maxHandles = maxObjects;
+ nvfp->deviceInstance = deviceInstance;
+ nvfp->gpuInstanceId = gpuInstanceId;
+
+ if (metadata != NULL)
+ {
+ os_mem_copy(nvfp->metadata, metadata, sizeof(nvfp->metadata));
+ }
+
+ return NV_OK;
+}
+
+NV_STATUS
+cliresCtrlCmdOsUnixExportObjectToFd_IMPL
+(
+ RmClientResource *pRmCliRes,
+ NV0000_CTRL_OS_UNIX_EXPORT_OBJECT_TO_FD_PARAMS *pParams
+)
+{
+ NvHandle hClient = RES_GET_CLIENT_HANDLE(pRmCliRes);
+ RmObjExportHandle hExportHandle = 0;
+ nv_file_private_t *nvfp = NULL;
+ void *priv = NULL;
+ NV_STATUS status = NV_OK;
+
+ /*
+ * This flag is intended to be implemented entirely in the rmapi library in
+ * userspace, we should never encounter it here.
+ */
+ if (FLD_TEST_DRF(0000_CTRL, _OS_UNIX_EXPORT_OBJECT_TO_FD_FLAGS,
+ _EMPTY_FD, _TRUE, pParams->flags))
+ {
+ return NV_ERR_INVALID_PARAMETER;
+ }
+
+ if (pParams->object.type != NV0000_CTRL_OS_UNIX_EXPORT_OBJECT_TYPE_RM ||
+ pParams->fd == -1)
+ {
+ return NV_ERR_INVALID_PARAMETER;
+ }
+
+ status = RmExportObject(hClient,
+ pParams->object.data.rmObject.hObject,
+ &hExportHandle, NULL);
+ if (status != NV_OK)
+ {
+ goto done;
+ }
+ NV_ASSERT(hExportHandle != 0);
+
+ nvfp = nv_get_file_private(pParams->fd, NV_TRUE, &priv);
+ if (nvfp == NULL)
+ {
+ NV_ASSERT(priv == NULL);
+ status = NV_ERR_INVALID_PARAMETER;
+ goto done;
+ }
+
+ status = _initializeExportObjectFd(nvfp, hClient,
+ pParams->object.data.rmObject.hDevice,
+ 1, NULL);
+ if (status != NV_OK)
+ {
+ goto done;
+ }
+
+ nvfp->handles[0] = hExportHandle;
+
+done:
+
+ if (status != NV_OK && hExportHandle != 0)
+ {
+ RmFreeObjExportHandle(hExportHandle);
+ }
+
+ if (priv != NULL)
+ {
+ nv_put_file_private(priv);
+ }
+
+ return status;
+}
+
+// This control call has been deprecated. It will be deleted soon.
+NV_STATUS
+cliresCtrlCmdOsUnixCreateExportObjectFd_IMPL
+(
+ RmClientResource *pRmCliRes,
+ NV0000_CTRL_OS_UNIX_CREATE_EXPORT_OBJECT_FD_PARAMS *pParams
+)
+{
+ NV_STATUS status;
+ NvHandle hClient = RES_GET_CLIENT_HANDLE(pRmCliRes);
+ nv_file_private_t *nvfp = NULL;
+ void *priv = NULL;
+
+ ct_assert(sizeof(nvfp->metadata) == sizeof(pParams->metadata));
+
+ if (pParams->maxObjects == 0)
+ {
+ return NV_ERR_INVALID_PARAMETER;
+ }
+
+ nvfp = nv_get_file_private(pParams->fd, NV_TRUE, &priv);
+ if (nvfp == NULL)
+ {
+ NV_ASSERT(priv == NULL);
+ status = NV_ERR_INVALID_PARAMETER;
+ goto done;
+ }
+
+ status = _initializeExportObjectFd(nvfp, hClient, pParams->hDevice,
+ pParams->maxObjects, pParams->metadata);
+
+done:
+ if (priv != NULL)
+ {
+ nv_put_file_private(priv);
+ }
+
+ return status;
+}
+
+NV_STATUS
+cliresCtrlCmdOsUnixExportObjectsToFd_IMPL
+(
+ RmClientResource *pRmCliRes,
+ NV0000_CTRL_OS_UNIX_EXPORT_OBJECTS_TO_FD_PARAMS *pParams
+)
+{
+ NvHandle hClient = RES_GET_CLIENT_HANDLE(pRmCliRes);
+ RmObjExportHandle *pExportHandle;
+ nv_file_private_t *nvfp = NULL;
+ void *priv = NULL;
+ NV_STATUS status = NV_OK;
+ NvU32 i;
+ NvU32 deviceInstance;
+ NvU32 result;
+ NvHandle *exportHandles = NULL;
+ NvBool bFdSetup = NV_FALSE;
+
+ nvfp = nv_get_file_private(pParams->fd, NV_TRUE, &priv);
+ if (nvfp == NULL)
+ {
+ NV_ASSERT(priv == NULL);
+ status = NV_ERR_INVALID_PARAMETER;
+ goto done;
+ }
+
+ ct_assert(sizeof(nvfp->metadata) == sizeof(pParams->metadata));
+
+ /* Setup export FD if not done */
+ if (nvfp->handles == NULL)
+ {
+ if (pParams->maxObjects == 0)
+ {
+ status = NV_ERR_INVALID_PARAMETER;
+ goto done;
+ }
+
+ status = _initializeExportObjectFd(nvfp, hClient, pParams->hDevice,
+ pParams->maxObjects,
+ pParams->metadata);
+ if (status != NV_OK)
+ {
+ goto done;
+ }
+
+ bFdSetup = NV_TRUE;
+ }
+
+ if ((nvfp->handles == NULL) ||
+ (pParams->numObjects >
+ NV0000_CTRL_OS_UNIX_EXPORT_OBJECTS_TO_FD_MAX_OBJECTS))
+ {
+ status = NV_ERR_INVALID_PARAMETER;
+ goto done;
+ }
+
+ if (!portSafeAddU32(pParams->numObjects, pParams->index, &result) ||
+ (result > nvfp->maxHandles))
+ {
+ status = NV_ERR_OUT_OF_RANGE;
+ goto done;
+ }
+
+ status = os_alloc_mem((void **)&exportHandles,
+ sizeof(exportHandles[0]) *
+ pParams->numObjects);
+ if (status != NV_OK)
+ {
+ goto done;
+ }
+
+ for (i = 0; i < pParams->numObjects; i++)
+ {
+ exportHandles[i] = 0;
+
+ if (pParams->objects[i] == 0)
+ {
+ continue;
+ }
+
+ status = RmExportObject(hClient,
+ pParams->objects[i],
+ &exportHandles[i],
+ &deviceInstance);
+ if (status != NV_OK)
+ {
+ goto done;
+ }
+
+ NV_ASSERT(exportHandles[i] != 0);
+
+ if (deviceInstance != nvfp->deviceInstance)
+ {
+ status = NV_ERR_INVALID_PARAMETER;
+ goto done;
+ }
+ }
+
+ for (i = 0; i < pParams->numObjects; i++)
+ {
+ pExportHandle = &nvfp->handles[i + pParams->index];
+
+ // If the handle already exists in this position, free it
+ if (*pExportHandle != 0)
+ {
+ RmFreeObjExportHandle(*pExportHandle);
+ *pExportHandle = 0;
+ }
+
+ *pExportHandle = exportHandles[i];
+ }
+
+done:
+
+ if ((status != NV_OK) && (exportHandles != NULL))
+ {
+ for (i = 0; i < pParams->numObjects; i++)
+ {
+ if (exportHandles[i] != 0)
+ {
+ RmFreeObjExportHandle(exportHandles[i]);
+ }
+ }
+ }
+
+ if (exportHandles != NULL)
+ {
+ os_free_mem(exportHandles);
+ }
+
+ if ((status != NV_OK) && bFdSetup)
+ {
+ os_free_mem(nvfp->handles);
+ nvfp->handles = NULL;
+ nvfp->maxHandles = 0;
+ }
+
+ if (priv != NULL)
+ {
+ nv_put_file_private(priv);
+ }
+
+ return status;
+}
+
+NV_STATUS
+cliresCtrlCmdOsUnixImportObjectFromFd_IMPL
+(
+ RmClientResource *pRmCliRes,
+ NV0000_CTRL_OS_UNIX_IMPORT_OBJECT_FROM_FD_PARAMS *pParams
+)
+{
+ NvHandle hClient = RES_GET_CLIENT_HANDLE(pRmCliRes);
+ nv_file_private_t *nvfp = NULL;
+ void *priv = NULL;
+ NV_STATUS status = NV_OK;
+
+ if (pParams->object.type != NV0000_CTRL_OS_UNIX_EXPORT_OBJECT_TYPE_RM ||
+ pParams->fd == -1)
+ {
+ return NV_ERR_INVALID_PARAMETER;
+ }
+
+ nvfp = nv_get_file_private(pParams->fd, NV_TRUE, &priv);
+ if (nvfp == NULL)
+ {
+ NV_ASSERT(priv == NULL);
+ status = NV_ERR_INVALID_PARAMETER;
+ goto done;
+ }
+
+ if ((nvfp->handles == NULL) || (nvfp->handles[0] == 0) ||
+ (nvfp->maxHandles < 1))
+ {
+ status = NV_ERR_INVALID_PARAMETER;
+ goto done;
+ }
+
+ status = RmImportObject(hClient,
+ pParams->object.data.rmObject.hParent,
+ &pParams->object.data.rmObject.hObject,
+ nvfp->handles[0], NULL);
+
+done:
+ if (priv != NULL)
+ {
+ nv_put_file_private(priv);
+ }
+
+ return status;
+}
+
+NV_STATUS
+cliresCtrlCmdOsUnixImportObjectsFromFd_IMPL
+(
+ RmClientResource *pRmCliRes,
+ NV0000_CTRL_OS_UNIX_IMPORT_OBJECTS_FROM_FD_PARAMS *pParams
+)
+{
+ NvHandle hClient = RES_GET_CLIENT_HANDLE(pRmCliRes);
+ nv_file_private_t *nvfp = NULL;
+ void *priv = NULL;
+ NV_STATUS status = NV_OK;
+ NvU32 i = 0;
+ RmObjExportHandle hImportHandle;
+ NvU32 result;
+ RM_API *pRmApi;
+
+ nvfp = nv_get_file_private(pParams->fd, NV_TRUE, &priv);
+ if (nvfp == NULL)
+ {
+ NV_ASSERT(priv == NULL);
+ status = NV_ERR_INVALID_PARAMETER;
+ goto done;
+ }
+
+ if ((nvfp->handles == NULL) ||
+ (pParams->numObjects >
+ NV0000_CTRL_OS_UNIX_IMPORT_OBJECTS_TO_FD_MAX_OBJECTS))
+ {
+ status = NV_ERR_INVALID_PARAMETER;
+ goto done;
+ }
+
+ if (!portSafeAddU32(pParams->numObjects, pParams->index, &result) ||
+ (result > nvfp->maxHandles))
+ {
+ status = NV_ERR_OUT_OF_RANGE;
+ goto done;
+ }
+
+ for (i = 0; i < pParams->numObjects; i++)
+ {
+ hImportHandle = nvfp->handles[i + pParams->index];
+
+ /* Nothing to import, just continue */
+ if (hImportHandle == 0)
+ {
+ pParams->objectTypes[i] = \
+ NV0000_CTRL_CMD_OS_UNIX_IMPORT_OBJECT_TYPE_NONE;
+ continue;
+ }
+
+ status = RmImportObject(hClient,
+ pParams->hParent,
+ &pParams->objects[i],
+ hImportHandle,
+ &pParams->objectTypes[i]);
+ if (status != NV_OK)
+ {
+ NV_PRINTF(LEVEL_ERROR, "%s: Unable to import handle (%x, %x, %x)\n",
+ __FUNCTION__, pParams->hParent, pParams->objects[i], hImportHandle);
+ goto done;
+ }
+ }
+
+done:
+
+ if (status != NV_OK)
+ {
+ pRmApi = rmapiGetInterface(RMAPI_API_LOCK_INTERNAL);
+ while (i > 0)
+ {
+ i--;
+
+ if (pParams->objects[i] != 0)
+ {
+ pRmApi->Free(pRmApi, hClient, pParams->objects[i]);
+ }
+ }
+ }
+
+ if (priv != NULL)
+ {
+ nv_put_file_private(priv);
+ }
+
+ return status;
+}
+
+NV_STATUS
+cliresCtrlCmdOsUnixGetExportObjectInfo_IMPL
+(
+ RmClientResource *pRmCliRes,
+ NV0000_CTRL_OS_UNIX_GET_EXPORT_OBJECT_INFO_PARAMS *pParams
+)
+{
+ nv_file_private_t *nvfp = NULL;
+ void *priv = NULL;
+ NV_STATUS status = NV_OK;
+
+ if (pParams->fd < 0)
+ {
+ return NV_ERR_INVALID_PARAMETER;
+ }
+
+ nvfp = nv_get_file_private(pParams->fd, NV_TRUE, &priv);
+ if (nvfp == NULL)
+ {
+ NV_ASSERT(priv == NULL);
+ status = NV_ERR_INVALID_PARAMETER;
+ goto done;
+ }
+
+ if (nvfp->handles == NULL)
+ {
+ status = NV_ERR_INVALID_PARAMETER;
+ goto done;
+ }
+
+ pParams->maxObjects = nvfp->maxHandles;
+ pParams->deviceInstance = nvfp->deviceInstance;
+ pParams->gpuInstanceId = nvfp->gpuInstanceId;
+
+ os_mem_copy(pParams->metadata, nvfp->metadata, sizeof(nvfp->metadata));
+
+done:
+ if (priv != NULL)
+ {
+ nv_put_file_private(priv);
+ }
+
+ return status;
+}
+
+NV_STATUS
+cliresCtrlCmdOsUnixMemacctSetLimits_IMPL
+(
+ RmClientResource *pRmCliRes,
+ NV0000_CTRL_OS_UNIX_MEMACCT_SET_LIMITS_PARAMS *pParams
+)
+{
+ void *cgroup = osCgroupGetFromFd(pParams->cgroupFd);
+ if (cgroup == NULL)
+ {
+ return NV_ERR_INVALID_ARGUMENT;
+ }
+
+ NV_STATUS status = memacctSetLimits((ClientGroupID)cgroup, pParams->gpuId, pParams->softLimit, pParams->hardLimit);
+ osCgroupPut(cgroup);
+ return status;
+}
+
+NV_STATUS
+cliresCtrlCmdOsUnixMemacctGetLimits_IMPL
+(
+ RmClientResource *pRmCliRes,
+ NV0000_CTRL_OS_UNIX_MEMACCT_GET_LIMITS_PARAMS *pParams
+)
+{
+ NvU32 gpuMask = 0;
+ NvU32 gpuIdx = 0;
+ OBJGPU *pGpu = NULL;
+ NV_STATUS status = NV_OK;
+
+ pParams->count = 0;
+ NV_ASSERT_OK_OR_RETURN(gpumgrGetGpuAttachInfo(NULL, &gpuMask));
+
+ void *cgroup = osCgroupGetFromFd(pParams->cgroupFd);
+ if (cgroup == NULL)
+ {
+ return NV_ERR_INVALID_ARGUMENT;
+ }
+
+ NvU32 i = 0;
+ while ((i < NV0000_CTRL_GPU_MAX_ATTACHED_GPUS) &&
+ ((pGpu = gpumgrGetNextGpu(gpuMask, &gpuIdx)) != NULL))
+ {
+ NV_CHECK_OK_OR_GOTO(status, LEVEL_ERROR,
+ memacctGetLimits((ClientGroupID)cgroup, pGpu->gpuId,
+ &pParams->limits[i].soft,
+ &pParams->limits[i].hard,
+ &pParams->limits[i].current),
+ out);
+ pParams->limits[i].gpuId = pGpu->gpuId;
+ i++;
+ }
+ pParams->count = i;
+out:
+ osCgroupPut(cgroup);
+ return status;
+}
+
+/*!
+ * osAcpiDsm
+ *
+ * @brief Handles os specific _DSM method function calls.
+ *
+ * Input parameters:
+ * @param[in] pGpu : OBJGPU pointer
+ * @param[in] acpiDsmFunction : ACPI DSM function
+ * @param[in] acpiDsmSubFunction : ACPI DSM subfunction
+ * @param[in/out] pInOut : in/out buffer, caller should make sure the buffer is large enough.
+ * @param[in] pSize : when input, size of data that the caller wants to read, in bytes.
+ * when output, size of valid data in pInOuta in bytes.
+ */
+NV_STATUS osCallACPI_DSM
+(
+ OBJGPU *pGpu,
+ ACPI_DSM_FUNCTION acpiDsmFunction,
+ NvU32 acpiDsmSubFunction,
+ NvU32 *pInOut,
+ NvU16 *pSize
+)
+{
+ NV_STATUS status;
+ NvU8 *pAcpiDsmGuid = NULL;
+ NvU32 acpiDsmRev;
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+ NvU16 acpiDsmInArgSize = 4;
+ NvBool acpiNvpcfDsmFunction = NV_FALSE;
+
+ // do any handling/remapping of guid needed.
+ status = checkDsmCall(pGpu,
+ (ACPI_DSM_FUNCTION *) &acpiDsmFunction,
+ &acpiDsmSubFunction,
+ pInOut,
+ pSize);
+
+ // return if subfunction is not supported or we're returning cache data
+ if (status != NV_WARN_MORE_PROCESSING_REQUIRED)
+ {
+ return status;
+ }
+
+ switch ((NvU32) acpiDsmFunction)
+ {
+ case ACPI_DSM_FUNCTION_NBSI:
+ pAcpiDsmGuid = (NvU8 *) &NBSI_DSM_GUID;
+ acpiDsmRev = NBSI_REVISION_ID;
+ break;
+ case ACPI_DSM_FUNCTION_NVHG:
+ pAcpiDsmGuid = (NvU8 *) &NVHG_DSM_GUID;
+ acpiDsmRev = NVHG_REVISION_ID;
+ break;
+ case ACPI_DSM_FUNCTION_MXM:
+ pAcpiDsmGuid = (NvU8 *) &DSM_MXM_GUID;
+ acpiDsmRev = ACPI_MXM_REVISION_ID;
+ break;
+ case ACPI_DSM_FUNCTION_NBCI:
+ pAcpiDsmGuid = (NvU8 *) &NBCI_DSM_GUID;
+ acpiDsmRev = NBCI_REVISION_ID;
+ break;
+ case ACPI_DSM_FUNCTION_NVOP:
+ pAcpiDsmGuid = (NvU8 *) &NVOP_DSM_GUID;
+ acpiDsmRev = NVOP_REVISION_ID;
+ break;
+ case ACPI_DSM_FUNCTION_PCFG:
+ pAcpiDsmGuid = (NvU8 *) &PCFG_DSM_GUID;
+ acpiDsmRev = PCFG_REVISION_ID;
+ break;
+ case ACPI_DSM_FUNCTION_GPS_2X:
+ pAcpiDsmGuid = (NvU8 *) &GPS_DSM_GUID;
+ acpiDsmRev = GPS_2X_REVISION_ID;
+ acpiDsmInArgSize = (*pSize);
+ break;
+ case ACPI_DSM_FUNCTION_GPS:
+ if (IsTU10X(pGpu))
+ {
+ pAcpiDsmGuid = (NvU8 *) &GPS_DSM_GUID;
+ acpiDsmRev = GPS_REVISION_ID;
+ acpiDsmInArgSize = (*pSize);
+ }
+ else
+ {
+ return NV_ERR_NOT_SUPPORTED;
+ }
+ break;
+ case ACPI_DSM_FUNCTION_PEX:
+ pAcpiDsmGuid = (NvU8 *) &PEX_DSM_GUID;
+ acpiDsmRev = PEX_REVISION_ID;
+ if (acpiDsmSubFunction == PEX_FUNC_SETLTRLATENCY)
+ {
+ acpiDsmInArgSize = (3 + *pSize);
+ }
+ break;
+ case (ACPI_DSM_FUNCTION_JT):
+ pAcpiDsmGuid = (NvU8 *) &JT_DSM_GUID;
+ acpiDsmRev = JT_REVISION_ID;
+ break;
+ case ACPI_DSM_FUNCTION_NVPCF:
+ {
+ pAcpiDsmGuid = (NvU8 *)&NVPCF_ACPI_DSM_GUID;
+ acpiDsmRev = NVPCF_ACPI_DSM_REVISION_ID;
+ acpiDsmInArgSize = (*pSize);
+ acpiNvpcfDsmFunction = NV_TRUE;
+ break;
+ }
+ case ACPI_DSM_FUNCTION_NVPCF_2X:
+ pAcpiDsmGuid = (NvU8 *)&NVPCF_ACPI_DSM_GUID;
+ acpiDsmRev = NVPCF_2X_ACPI_DSM_REVISION_ID;
+ acpiDsmInArgSize = (*pSize);
+ acpiNvpcfDsmFunction = NV_TRUE;
+ break;
+
+ default:
+ return NV_ERR_NOT_SUPPORTED;
+ break;
+ }
+
+ status = nv_acpi_dsm_method(nv,
+ pAcpiDsmGuid,
+ acpiDsmRev,
+ acpiNvpcfDsmFunction,
+ acpiDsmSubFunction,
+ pInOut,
+ acpiDsmInArgSize,
+ NULL,
+ pInOut,
+ pSize);
+
+ if (status == NV_OK)
+ {
+ if (acpiDsmSubFunction == NV_ACPI_ALL_FUNC_SUPPORT)
+ {
+ // if handling get supported functions list... cache it for later calls
+ cacheDsmSupportedFunction(pGpu, acpiDsmFunction, acpiDsmSubFunction, pInOut, *pSize);
+ }
+ }
+ else if (nvp->b_mobile_config_enabled)
+ {
+ NV_PRINTF(LEVEL_ERROR,
+ "osCallACPI_DSM: Error during 0x%x DSM subfunction 0x%x! status=0x%x\n",
+ acpiDsmFunction, acpiDsmSubFunction, status);
+ }
+
+ return status;
+}
+
+NV_STATUS osCallACPI_DOD
+(
+ OBJGPU *pGpu,
+ NvU32 *pOut,
+ NvU32 *pSize
+)
+{
+ NV_STATUS rmStatus;
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+
+ if ((pOut == NULL) || (pSize == NULL))
+ {
+ return NV_ERR_INVALID_POINTER;
+ }
+
+ rmStatus = nv_acpi_dod_method(nv, pOut, pSize);
+
+ return rmStatus;
+}
+
+//
+// osAcpiDdc
+//
+// Handles os specific _DDC method function calls. _DDC is to get EDID from SBIOS.
+//
+NV_STATUS osCallACPI_DDC
+(
+ OBJGPU *pGpu,
+ NvU32 ulAcpiId,
+ NvU8 *pOutData,
+ NvU32 *pOutSize,
+ NvBool bReadMultiBlock
+)
+{
+ NV_STATUS rmStatus;
+
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+
+ if ((pOutData == NULL) || (pOutSize == NULL))
+ {
+ return NV_ERR_INVALID_POINTER;
+ }
+
+ portMemSet(pOutData, 0, *pOutSize);
+
+ rmStatus = nv_acpi_ddc_method(nv, pOutData, pOutSize, bReadMultiBlock);
+
+ return rmStatus;
+}
+
+// osCallACPI_NVHG_ROM
+// Making ACPI Call into SBIOS with ROM method to get display device's ROM data.
+//
+NV_STATUS osCallACPI_NVHG_ROM
+(
+ OBJGPU *pGpu,
+ NvU32 *pInData,
+ NvU32 *pOutData
+)
+{
+ NV_STATUS rmStatus;
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+
+ if ((pOutData == NULL) || (pInData == NULL))
+ {
+ return NV_ERR_INVALID_POINTER;
+ }
+
+ if (pInData[1] > ROM_METHOD_MAX_RETURN_BUFFER_SIZE)
+ {
+ return NV_ERR_INVALID_ARGUMENT;
+ }
+
+ rmStatus = nv_acpi_rom_method(nv, pInData, pOutData);
+
+ return rmStatus;
+}
+
+void osInitSystemStaticConfig(SYS_STATIC_CONFIG *pConfig)
+{
+ pConfig->bIsNotebook = rm_is_system_notebook();
+ pConfig->bOsCCEnabled = os_cc_enabled;
+ pConfig->bOsCCSevSnpEnabled = os_cc_sev_snp_enabled;
+ pConfig->bOsCCSmeEnabled = os_cc_sme_enabled;
+ pConfig->bOsCCSnpVtomEnabled = os_cc_snp_vtom_enabled;
+ pConfig->bOsCCTdxEnabled = os_cc_tdx_enabled;
+}
+
+NvU32 osApiLockAcquireConfigureFlags(NvU32 flags)
+{
+ return flags;
+}
+
+NV_STATUS osGpuLocksQueueRelease(OBJGPU *pGpu, NvU32 dpcGpuLocksRelease)
+{
+ return NV_SEMA_RELEASE_FAILED;
+}
+
+void osSyncWithRmDestroy(void)
+{
+}
+
+void osSyncWithGpuDestroy(NvBool bEntry)
+{
+}
+
+void osModifyGpuSwStatePersistence
+(
+ OS_GPU_INFO *pOsGpuInfo,
+ NvBool bEnable
+)
+{
+ if (!osIsLegacyPersistenceModeSupported(pOsGpuInfo))
+ return;
+
+ if (bEnable)
+ {
+ pOsGpuInfo->flags |= NV_FLAG_PERSISTENT_SW_STATE;
+ }
+ else
+ {
+ pOsGpuInfo->flags &= ~NV_FLAG_PERSISTENT_SW_STATE;
+ }
+}
+
+//
+//osCallACPI_MXDS
+//
+//Handles OS specific MXDS function call.
+//
+NV_STATUS osCallACPI_MXDS
+(
+ OBJGPU *pGpu,
+ NvU32 acpiId,
+ NvU32 *pInOut
+)
+{
+ NV_STATUS rmStatus;
+
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+
+ if (pInOut == NULL)
+ {
+ return NV_ERR_INVALID_POINTER;
+ }
+
+ rmStatus = nv_acpi_mux_method(nv, pInOut, acpiId, "MXDS");
+
+ return rmStatus;
+}
+
+//
+//osCallACPI_MXDM
+//
+//Handles OS specific MXDM function call.
+//
+NV_STATUS osCallACPI_MXDM
+(
+ OBJGPU *pGpu,
+ NvU32 acpiId,
+ NvU32 *pInOut
+)
+{
+ NV_STATUS rmStatus;
+
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+
+ if (pInOut == NULL)
+ {
+ return NV_ERR_INVALID_POINTER;
+ }
+
+ rmStatus = nv_acpi_mux_method(nv, pInOut, acpiId, "MXDM");
+
+ return rmStatus;
+}
+
+#include "lib/protobuf/prb.h"
+#include "lib/protobuf/prb_util.h"
+#include "g_nvdebug_pb.h"
+
+NV_STATUS osGetVersionDump(void * pVoid)
+{
+ PRB_ENCODER * pPrbEnc = (PRB_ENCODER *)pVoid;
+ NV_STATUS rmStatus;
+ os_version_info * pOsVersionInfo = NULL;
+ const char NV_UNKNOWN_BUILD_VERSION[] = "Unknown build version";
+ const char NV_UNKNOWN_BUILD_DATE[] = "Unknown build date";
+
+ NV_ASSERT_OK_OR_RETURN(os_alloc_mem((void**)&pOsVersionInfo,
+ sizeof(os_version_info)));
+ portMemSet(pOsVersionInfo, 0, sizeof(os_version_info));
+
+ prbEncAddUInt32(pPrbEnc,
+ NVDEBUG_SYSTEMINFO_OSINFO_FAMILY,
+ NVDEBUG_OS_UNIX);
+
+ rmStatus = os_get_version_info(pOsVersionInfo);
+ if (rmStatus != NV_OK)
+ {
+ goto cleanup;
+ }
+
+ prbEncAddUInt32(pPrbEnc,
+ NVDEBUG_SYSTEMINFO_OSINFO_OSMAJORVERSION,
+ pOsVersionInfo->os_major_version);
+
+ prbEncAddUInt32(pPrbEnc,
+ NVDEBUG_SYSTEMINFO_OSINFO_OSMINORVERSION,
+ pOsVersionInfo->os_minor_version);
+
+ prbEncAddUInt32(pPrbEnc,
+ NVDEBUG_SYSTEMINFO_OSINFO_OSBLDNUM,
+ pOsVersionInfo->os_build_number);
+
+ if (NULL == pOsVersionInfo->os_build_version_str)
+ {
+ pOsVersionInfo->os_build_version_str = NV_UNKNOWN_BUILD_VERSION;
+ }
+
+ prbEncAddString(pPrbEnc,
+ NVDEBUG_SYSTEMINFO_OSINFO_BUILDVERSION,
+ pOsVersionInfo->os_build_version_str);
+
+ if (NULL == pOsVersionInfo->os_build_date_plus_str)
+ {
+ pOsVersionInfo->os_build_date_plus_str = NV_UNKNOWN_BUILD_DATE;
+ }
+
+ prbEncAddString(pPrbEnc,
+ NVDEBUG_SYSTEMINFO_OSINFO_BUILDDATEPLUS,
+ pOsVersionInfo->os_build_date_plus_str);
+
+cleanup:
+ os_free_mem(pOsVersionInfo);
+ return rmStatus;
+}
+
+NV_STATUS osTegraiGpuPerfBoost(OBJGPU *pGpu, NvBool enable, NvU32 duration)
+{
+ return os_tegra_igpu_perf_boost(pGpu->pOsGpuInfo, enable, duration);
+}
+
+NV_STATUS osGetVersion(NvU32 *majorVer, NvU32 *minorVer, NvU32 *buildNum, NvU16 *unusedPatchVersion, NvU16 *unusedProductType)
+{
+ os_version_info osVersionInfo;
+ NV_STATUS rmStatus;
+
+ portMemSet(&osVersionInfo, 0, sizeof(osVersionInfo));
+
+ rmStatus = os_get_version_info(&osVersionInfo);
+ if (rmStatus == NV_OK)
+ {
+ if (majorVer)
+ *majorVer = osVersionInfo.os_major_version;
+ if (minorVer)
+ *minorVer = osVersionInfo.os_minor_version;
+ if (buildNum)
+ *buildNum = osVersionInfo.os_build_number;
+ }
+
+ return rmStatus;
+}
+
+NV_STATUS osGetIsOpenRM(NvBool *bOpenRm)
+{
+ return os_get_is_openrm(bOpenRm);
+}
+
+NvBool osIsBifResetSupported(OS_GPU_INFO *pOsGpuInfo)
+{
+ return os_is_bif_reset_supported((void *)pOsGpuInfo);
+}
+
+NV_STATUS
+osGetCarveoutInfo
+(
+ NvU64 *pAddr,
+ NvU64 *pSize
+)
+{
+ return NV_ERR_NOT_SUPPORTED;
+}
+
+NV_STATUS
+osGetVPRInfo
+(
+ NvU64 *pAddr,
+ NvU64 *pSize
+)
+{
+ return NV_ERR_NOT_SUPPORTED;
+}
+
+NV_STATUS
+osAllocInVPR
+(
+ MEMORY_DESCRIPTOR *pMemDesc
+)
+{
+ return NV_ERR_NOT_SUPPORTED;
+}
+
+NV_STATUS
+osGetGenCarveout
+(
+ NvU64 *pAddr,
+ NvU64 *pSize,
+ NvU32 id,
+ NvU64 align
+)
+{
+ return NV_ERR_NOT_SUPPORTED;
+}
+
+NV_STATUS
+osI2CClosePorts
+(
+ OS_GPU_INFO *pOsGpuInfo,
+ NvU32 numPorts
+)
+{
+ nv_i2c_unregister_clients(pOsGpuInfo);
+ return NV_OK;
+}
+
+static NvU32
+i2cSwPortMapping(
+ nv_state_t *nv,
+ NvU32 physicalI2CPort
+)
+{
+ NvU32 linuxI2CSwPort = NV_U32_MAX;
+
+ /**
+ * For T23X, Linux Tegra I2C controller driver uses logical port(controller) number
+ * where logical port number of I2C1(Gen1) controller is 0, logical port number for
+ * I2C2(Gen2) controller is 1 and so on. But RM passes I2C physical port(controller)
+ * number i.e RM passes "1" for I2C1(Gen1), 2 for I2C2(Gen2), etc. So convert
+ * physical port number to logical port number(linuxI2CSwPort).
+ *
+ * For other chips, the above mentioned logic does not apply and we do not need
+ * conversion as the physical controller number was updated to 0 and RM passes the
+ * same.
+ */
+ if ((nv->disp_sw_soc_chip_id == NV_CHIP_ID_T234)
+ || (nv->disp_sw_soc_chip_id == NV_CHIP_ID_T239)
+ )
+ {
+ linuxI2CSwPort = physicalI2CPort - 1;
+ }
+ else
+ {
+ linuxI2CSwPort = physicalI2CPort;
+ }
+
+ return linuxI2CSwPort;
+}
+
+NV_STATUS
+osI2CTransfer
+(
+ OBJGPU *pGpu,
+ NvU32 Port,
+ NvU8 Address,
+ nv_i2c_msg_t *nv_i2c_msgs,
+ NvU32 count
+)
+{
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ if (NV_IS_SOC_DISPLAY_DEVICE(nv))
+ {
+ Port = i2cSwPortMapping(nv, Port);
+ return nv_i2c_transfer(nv, Port, Address,
+ nv_i2c_msgs, count);
+ }
+ else
+ {
+ return NV_ERR_NOT_SUPPORTED;
+ }
+}
+
+NV_STATUS
+osTegraI2CGetBusState
+(
+ OS_GPU_INFO *pOsGpuInfo,
+ NvU32 port,
+ NvS32 *scl,
+ NvS32 *sda
+)
+{
+ if (NV_IS_SOC_DISPLAY_DEVICE(pOsGpuInfo))
+ {
+ port = i2cSwPortMapping(pOsGpuInfo, port);
+ return nv_i2c_bus_status(pOsGpuInfo, port, scl, sda);
+ }
+ else
+ {
+ return NV_ERR_NOT_SUPPORTED;
+ }
+}
+
+NV_STATUS
+osReadI2CBufferDirect
+(
+ OBJGPU *pGpu,
+ NvU32 Port,
+ NvU8 Address,
+ void *pOutputBuffer,
+ NvU32 OutputSize,
+ void *pInputBuffer,
+ NvU32 InputSize
+)
+{
+ return NV_ERR_NOT_SUPPORTED;
+}
+
+NV_STATUS
+osWriteI2CBufferDirect
+(
+ OBJGPU *pGpu,
+ NvU32 Port,
+ NvU8 Address,
+ void *pOutputBuffer0,
+ NvU32 OutputSize0,
+ void *pOutputBuffer1,
+ NvU32 OutputSize1
+)
+{
+ return NV_ERR_NOT_SUPPORTED;
+}
+
+NV_STATUS
+osGC6PowerControl
+(
+ OBJGPU *pGpu,
+ NvU32 cmd,
+ NvU32 *pOut
+)
+{
+ NV_STATUS status;
+ NvU32 inOut = cmd;
+ NvU16 rtnSize = sizeof(inOut);
+
+ if (FLD_TEST_DRF(_JT_FUNC, _POWERCONTROL, _GPU_POWER_CONTROL, _GSS, inOut))
+ {
+ if (!pOut)
+ {
+ return NV_ERR_INVALID_ARGUMENT;
+ }
+ }
+
+ status = osCallACPI_DSM(pGpu,
+ ACPI_DSM_FUNCTION_JT,
+ JT_FUNC_POWERCONTROL,
+ &inOut,
+ &rtnSize);
+
+ if ((status != NV_OK) || !pOut)
+ {
+ return status;
+ }
+
+ *pOut = inOut;
+
+ return NV_OK;
+}
+
+NvBool osTestPcieExtendedConfigAccess(void *handle, NvU32 offset)
+{
+ OBJGPU *pGpu;
+ KernelBif *pKernelBif;
+ NvU32 nvXveId = 0;
+ NvU32 nvXveVccapHdr = 0;
+ NvU32 pciStart = 0;
+ NvU32 pcieStart = 0;
+
+ static NvBool retryAllowed = NV_TRUE;
+ static NvBool configAccess = NV_FALSE;
+
+ //
+ // Return early for offset within PCI space
+ // and does not requires extended config space access
+ //
+ if (offset < 0x100)
+ {
+ return NV_TRUE;
+ }
+
+ if (!retryAllowed)
+ {
+ return configAccess;
+ }
+
+ pGpu = gpumgrGetSomeGpu();
+ if (pGpu == NULL)
+ {
+ return configAccess;
+ }
+
+ retryAllowed = NV_FALSE;
+
+ pKernelBif = GPU_GET_KERNEL_BIF(pGpu);
+ if (pKernelBif == NULL || gpuGetBusIntfType_HAL(pGpu) !=
+ NV2080_CTRL_BUS_INFO_TYPE_PCI_EXPRESS)
+ {
+ return configAccess;
+ }
+
+ // Now verify PCI and PCIe config start registers.
+ kbifGetPcieConfigAccessTestRegisters_HAL(pGpu, pKernelBif, &pciStart, &pcieStart);
+ os_pci_read_dword(handle, pciStart, &nvXveId);
+ os_pci_read_dword(handle, pcieStart, &nvXveVccapHdr);
+
+ if (NV_OK == kbifVerifyPcieConfigAccessTestRegisters_HAL(pGpu,
+ pKernelBif,
+ nvXveId,
+ nvXveVccapHdr))
+ {
+ configAccess = NV_TRUE;
+ }
+
+ return configAccess;
+}
+
+static NvBool skipIovaMappingForTegra
+(
+ PIOVAMAPPING pIovaMapping,
+ nv_state_t *nv
+)
+{
+ //
+ // TODO: When ISO SMMU is not present, dma mapping of imported ISO memory
+ // causes crash during __clean_dcache_area_poc. dma mapping of ISO
+ // memory allocated by RM (via __get_free_pages) still works.
+ // Skip dma mapping of imported ISO memory to unblock Tegra Display in
+ // AV+L. Bug 200765629
+ //
+
+ NV_ASSERT(nv != NULL);
+
+ if (NV_IS_SOC_DISPLAY_DEVICE(nv) &&
+ !NV_SOC_IS_ISO_IOMMU_PRESENT(nv) &&
+ !memdescGetFlag(pIovaMapping->pPhysMemDesc, MEMDESC_FLAGS_MEMORY_TYPE_DISPLAY_NISO) &&
+ memdescGetFlag(pIovaMapping->pPhysMemDesc, MEMDESC_FLAGS_EXT_PAGE_ARRAY_MEM))
+ {
+ NV_PRINTF(LEVEL_INFO, "%s: Skip memdescMapIommu mapping\n", __FUNCTION__);
+ return NV_TRUE;
+ }
+
+ return NV_FALSE;
+}
+
+static NvBool osMemDescRequiresReadOnlyDeviceDmaMap
+(
+ MEMORY_DESCRIPTOR *pMemDesc
+)
+{
+ //
+ // MEMDESC_FLAGS_USER_READ_ONLY is also used by RM-owned buffers that the
+ // kernel writes and user/GSP reads. Restrict RO DMA direction to external
+ // OS descriptor mappings.
+ //
+ return memdescGetFlag(pMemDesc, MEMDESC_FLAGS_EXT_PAGE_ARRAY_MEM) &&
+ !memdescGetFlag(pMemDesc, MEMDESC_FLAGS_KERNEL_MODE) &&
+ (memdescGetFlag(pMemDesc, MEMDESC_FLAGS_USER_READ_ONLY) ||
+ memdescGetFlag(pMemDesc, MEMDESC_FLAGS_DEVICE_READ_ONLY));
+}
+
+/*!
+ * @brief Map memory into an IOVA space according to the given mapping info.
+ *
+ * @param[in] pIovaMapping IOVA mapping info
+ *
+ * @return NV_ERR_NOT_SUPPORTED
+ */
+NV_STATUS
+osIovaMap
+(
+ PIOVAMAPPING pIovaMapping
+)
+{
+ OBJGPU *pGpu;
+ nv_state_t *nv, *peer;
+ NV_STATUS status;
+ RmPhysAddr base;
+ NvBool bIsBar0;
+ PMEMORY_DESCRIPTOR pRootMemDesc;
+ NvBool bIsFbOffset = NV_FALSE;
+ NvBool bIsIndirectPeerMapping = NV_FALSE;
+ NvBool bIsContig;
+ NV_ADDRESS_SPACE addressSpace;
+ NvU32 osPageCount;
+
+ if (pIovaMapping == NULL)
+ {
+ return NV_ERR_INVALID_ARGUMENT;
+ }
+
+ pGpu = gpumgrGetGpuFromId(pIovaMapping->iovaspaceId);
+ if (pGpu == NULL)
+ {
+ return NV_ERR_INVALID_ARGUMENT;
+ }
+
+ pRootMemDesc = memdescGetRootMemDesc(pIovaMapping->pPhysMemDesc, NULL);
+ addressSpace = memdescGetAddressSpace(pIovaMapping->pPhysMemDesc);
+ if (gpumgrCheckIndirectPeer(pGpu, pRootMemDesc->pGpu) &&
+ (addressSpace == ADDR_FBMEM))
+ {
+ bIsIndirectPeerMapping = NV_TRUE;
+ }
+
+ if ((addressSpace != ADDR_SYSMEM) && !bIsIndirectPeerMapping)
+ {
+ NV_PRINTF(LEVEL_INFO,
+ "%s passed memory descriptor in an unsupported address space (%s)\n",
+ __FUNCTION__,
+ memdescGetApertureString(memdescGetAddressSpace(pIovaMapping->pPhysMemDesc)));
+ return NV_ERR_NOT_SUPPORTED;
+ }
+
+ //
+ // For guest-allocated memory, we don't actually want to do any remapping,
+ // since the physical address is already the DMA address to be used by the
+ // GPU.
+ //
+ // For carveout memory, we setup identity mapping, so physical
+ // address is same as the DMA address.
+ //
+ //
+ if (memdescIsCarveoutMemory(pIovaMapping->pPhysMemDesc) ||
+ memdescGetFlag(pIovaMapping->pPhysMemDesc, MEMDESC_FLAGS_GUEST_ALLOCATED))
+ {
+ return NV_OK;
+ }
+
+ nv = NV_GET_NV_STATE(pGpu);
+ if (IS_DISCONTIG_AND_DYNGRAN_ENABLED(pIovaMapping->pPhysMemDesc))
+ {
+ osPageCount = pIovaMapping->pPhysMemDesc->PageCount;
+ NV_ASSERT_OR_RETURN(os_page_size == pIovaMapping->pPhysMemDesc->pageArrayGranularity, NV_ERR_INVALID_PARAMETER);
+ }
+ else
+ {
+ osPageCount = NV_RM_PAGES_TO_OS_PAGES(pIovaMapping->pPhysMemDesc->PageCount);
+ }
+
+ //
+ // Intercept peer IO type memory. These are contiguous allocations, so no
+ // need to adjust pages.
+ //
+ if (memdescGetFlag(pIovaMapping->pPhysMemDesc, MEMDESC_FLAGS_PEER_IO_MEM))
+ {
+ NV_ASSERT(memdescGetContiguity(pIovaMapping->pPhysMemDesc, AT_CPU));
+
+ status = nv_dma_map_mmio(nv->dma_dev,
+ osPageCount,
+ &pIovaMapping->iovaArray[0]);
+
+ if (status != NV_OK)
+ {
+ NV_PRINTF(LEVEL_ERROR,
+ "%s: failed to map peer IO mem (status = 0x%x)\n",
+ __FUNCTION__, status);
+ }
+
+ return status;
+ }
+
+ //
+ // We need to check against the "root" GPU, e.g., the GPU that owns this
+ // allocation. If we're trying to map one of its BARs for a peer, we need
+ // to handle it differently because it wouldn't have gone through our system
+ // memory page allocation paths, obviously, and wouldn't have alloc private
+ // data associated with it.
+ //
+ peer = NV_GET_NV_STATE(pRootMemDesc->pGpu);
+ bIsContig = memdescGetContiguity(pIovaMapping->pPhysMemDesc, AT_CPU);
+ if (IS_DISCONTIG_AND_DYNGRAN_ENABLED(pIovaMapping->pPhysMemDesc))
+ {
+ NV_ASSERT_OR_RETURN(pIovaMapping->pPhysMemDesc->pageArrayGranularity == os_page_size, NV_ERR_INVALID_ARGUMENT);
+ }
+ else if (NV_RM_PAGE_SIZE < os_page_size && !bIsContig)
+ {
+ RmDeflateRmToOsPageArray(&pIovaMapping->iovaArray[0],
+ pIovaMapping->pPhysMemDesc->PageCount);
+ }
+
+ base = memdescGetPhysAddr(pIovaMapping->pPhysMemDesc, AT_CPU, 0);
+ bIsBar0 = IS_REG_OFFSET(peer, base, pIovaMapping->pPhysMemDesc->Size);
+
+ bIsFbOffset = IS_FB_OFFSET(peer, base, pIovaMapping->pPhysMemDesc->Size);
+
+ void *pPriv = memdescGetMemData(pIovaMapping->pPhysMemDesc);
+
+ if (!bIsBar0 && !bIsFbOffset)
+ {
+ if (pPriv == NULL)
+ {
+ return NV_ERR_INVALID_STATE;
+ }
+ }
+ else if(bIsIndirectPeerMapping)
+ {
+ NV_ASSERT(!bIsBar0 && bIsFbOffset);
+ //
+ // TODO: Align onlined GPU memory allocation paths with system memory allocation
+ // That way pMemDesc->pMemData is setup correctly when we try to create mapping
+ // to onlined memory of indirect peer. After that we can also get rid of some
+ // extra code in nv_dma_map_alloc. See bug 190324 for details
+ //
+
+ status = memdescGetNvLinkGpa(pRootMemDesc->pGpu, (bIsContig ? 1 : osPageCount),
+ &pIovaMapping->iovaArray[0]);
+ if (status != NV_OK)
+ {
+ NV_PRINTF(LEVEL_ERROR, "%s Failed to get SPA\n", __FUNCTION__);
+ return status;
+ }
+ }
+
+ if (skipIovaMappingForTegra(pIovaMapping, nv))
+ {
+ return NV_OK;
+ }
+
+ if (!bIsBar0 && (!bIsFbOffset || bIsIndirectPeerMapping))
+ {
+ NvBool bReadOnlyDeviceMap =
+ osMemDescRequiresReadOnlyDeviceDmaMap(pIovaMapping->pPhysMemDesc);
+
+ status = nv_dma_map_alloc(
+ osGetDmaDeviceForMemDesc(nv, pIovaMapping->pPhysMemDesc),
+ osPageCount,
+ &pIovaMapping->iovaArray[0],
+ bIsContig, bReadOnlyDeviceMap, &pPriv);
+ if (status != NV_OK)
+ {
+ NV_PRINTF(LEVEL_ERROR,
+ "%s: failed to map allocation (status = 0x%x)\n",
+ __FUNCTION__, status);
+ return status;
+ }
+
+ pIovaMapping->pOsData = pPriv;
+ }
+ else if (peer != nv)
+ {
+ status = nv_dma_map_peer(nv->dma_dev, peer->dma_dev, bIsBar0 ? 0 : 1,
+ osPageCount, &pIovaMapping->iovaArray[0]);
+ if (status != NV_OK)
+ {
+ NV_PRINTF(LEVEL_INFO,
+ "%s: failed to map peer (base = 0x%llx, status = 0x%x)\n",
+ __FUNCTION__, base, status);
+ return status;
+ }
+
+ //
+ // pOsData must be NULL to distinguish a peer DMA mapping from a
+ // system memory mapping in osIovaUnmap(), so make sure to set it
+ // accordingly here.
+ //
+ pIovaMapping->pOsData = NULL;
+ }
+ else
+ {
+ NV_PRINTF(LEVEL_INFO, "cannot map a GPU's BAR to itself\n");
+ return NV_ERR_NOT_SUPPORTED;
+ }
+
+ //
+ // If the OS layer doesn't think in RM page size, we need to inflate the
+ // PTE array into RM pages.
+ //
+ if (IS_DISCONTIG_AND_DYNGRAN_ENABLED(pIovaMapping->pPhysMemDesc))
+ {
+ NV_ASSERT_OR_RETURN(pIovaMapping->pPhysMemDesc->pageArrayGranularity == os_page_size, NV_ERR_INVALID_ARGUMENT);
+ }
+ else if (NV_RM_PAGE_SIZE < os_page_size && !bIsContig)
+ {
+ RmInflateOsToRmPageArray(&pIovaMapping->iovaArray[0],
+ pIovaMapping->pPhysMemDesc->PageCount);
+ }
+
+ return NV_OK;
+}
+
+/*!
+ * @brief Unmap memory from an IOVA space according to the given mapping info.
+ *
+ * This mapping info must have been previously mapped by osIovaMap().
+ *
+ * @param[in] pIovaMapping IOVA mapping info
+ *
+ */
+void
+osIovaUnmap
+(
+ PIOVAMAPPING pIovaMapping
+)
+{
+ OBJGPU *pGpu;
+ nv_state_t *nv;
+ void *pPriv;
+ NV_STATUS status;
+ NvU64 osPageCount;
+
+ if (pIovaMapping == NULL)
+ {
+ return;
+ }
+
+ pGpu = gpumgrGetGpuFromId(pIovaMapping->iovaspaceId);
+ if (pGpu == NULL)
+ {
+ return;
+ }
+
+ //
+ // For guest-allocated or carveout memory, we never actually remapped the
+ // memory, so we shouldn't try to unmap it here.
+ //
+ if (memdescIsCarveoutMemory(pIovaMapping->pPhysMemDesc) ||
+ memdescGetFlag(pIovaMapping->pPhysMemDesc, MEMDESC_FLAGS_GUEST_ALLOCATED))
+ {
+ return;
+ }
+
+ nv = NV_GET_NV_STATE(pGpu);
+
+ if (skipIovaMappingForTegra(pIovaMapping, nv))
+ {
+ return;
+ }
+ if (IS_DISCONTIG_AND_DYNGRAN_ENABLED(pIovaMapping->pPhysMemDesc))
+ {
+ osPageCount = pIovaMapping->pPhysMemDesc->PageCount;
+ NV_ASSERT(os_page_size == pIovaMapping->pPhysMemDesc->pageArrayGranularity);
+ }
+ else
+ {
+ osPageCount = NV_RM_PAGES_TO_OS_PAGES(pIovaMapping->pPhysMemDesc->PageCount);
+ }
+
+ if (memdescGetFlag(pIovaMapping->pPhysMemDesc, MEMDESC_FLAGS_PEER_IO_MEM))
+ {
+ nv_dma_unmap_mmio(nv->dma_dev,
+ osPageCount,
+ pIovaMapping->iovaArray[0]);
+
+ return;
+ }
+
+ //
+ // TODO: Formalize the interface with the OS layers so we can use a common
+ // definition of OS_IOVA_MAPPING_DATA.
+ //
+ pPriv = (void *)pIovaMapping->pOsData;
+
+ if (IS_DISCONTIG_AND_DYNGRAN_ENABLED(pIovaMapping->pPhysMemDesc))
+ {
+ NV_ASSERT(pIovaMapping->pPhysMemDesc->pageArrayGranularity == os_page_size);
+ }
+ else if (NV_RM_PAGE_SIZE < os_page_size &&
+ !memdescGetContiguity(pIovaMapping->pPhysMemDesc, AT_CPU))
+ {
+ RmDeflateRmToOsPageArray(&pIovaMapping->iovaArray[0],
+ pIovaMapping->pPhysMemDesc->PageCount);
+ }
+
+ if (pPriv != NULL)
+ {
+ status = nv_dma_unmap_alloc(nv->dma_dev,
+ osPageCount,
+ &pIovaMapping->iovaArray[0], &pPriv);
+ if (status != NV_OK)
+ {
+ NV_PRINTF(LEVEL_ERROR,
+ "%s: failed to unmap allocation (status = 0x%x)\n",
+ __FUNCTION__, status);
+ }
+ }
+ else
+ {
+ nv_dma_unmap_peer(nv->dma_dev,
+ osPageCount,
+ pIovaMapping->iovaArray[0]);
+ }
+
+ //
+ // If the OS layer doesn't think in RM page size, we need to fluff out the
+ // PTE array into RM pages.
+ //
+ if (IS_DISCONTIG_AND_DYNGRAN_ENABLED(pIovaMapping->pPhysMemDesc))
+ {
+ NV_ASSERT(pIovaMapping->pPhysMemDesc->pageArrayGranularity == os_page_size);
+ }
+ else if (NV_RM_PAGE_SIZE < os_page_size &&
+ !memdescGetContiguity(pIovaMapping->pPhysMemDesc, AT_CPU))
+ {
+ RmInflateOsToRmPageArray(&pIovaMapping->iovaArray[0],
+ pIovaMapping->pPhysMemDesc->PageCount);
+ }
+
+ pIovaMapping->pOsData = NULL;
+}
+
+/*!
+ * @brief Set the GPU Rail Voltage in Tegra SoC. Currently not supported
+ *
+ * @param[in] pGpu GPU object pointer
+ * @param[in] reqVoltageuV Rail Voltage requested in uV
+ * @param[out] pSetVoltageuV Rail Voltage set in uV
+ *
+ * @return NV_ERR_NOT_SUPPORTED
+ */
+NV_STATUS
+osSetGpuRailVoltage
+(
+ OBJGPU *pGpu,
+ NvU32 reqVoltageuV,
+ NvU32 *pSetVoltageuV
+)
+{
+ return NV_ERR_NOT_SUPPORTED;
+}
+
+/*!
+ * @brief Get the GPU Rail Voltage in Tegra SoC. Currently not supported
+ *
+ * @param[in] pGpu GPU object pointer
+ * @param[out] voltageuV Rail Voltage in uV
+ *
+ * @return NV_ERR_NOT_SUPPORTED
+ */
+NV_STATUS
+osGetGpuRailVoltage
+(
+ OBJGPU *pGpu,
+ NvU32 *pVoltageuV
+)
+{
+ return NV_ERR_NOT_SUPPORTED;
+}
+
+/*!
+ * @brief Bring down system in a controlled manner on known error conditions.
+ *
+ * @bugCode[in] Error code / reason.
+ */
+void osBugCheck(NvU32 bugCode)
+{
+ if (bugCode > OS_BUG_CHECK_BUGCODE_LAST)
+ {
+ bugCode = OS_BUG_CHECK_BUGCODE_UNKNOWN;
+ }
+
+ os_bug_check(bugCode, ppOsBugCheckBugcodeStr[bugCode]);
+}
+
+/*!
+ * @brief Perform an action at assertion failure.
+ */
+void osAssertFailed(void)
+{
+ os_dump_stack();
+}
+
+/*!
+ * @brief Get the GPU Chip Info - Speedo and IDDQ values
+ *
+ *
+ * @param[in] pGpu GPU object pointer
+ * @param[out] pGpuSpeedoHv Pointer to GPU Speedo value at high voltage corner.
+ * @param[out] pGpuSpeedoLv Pointer to GPU Speedo value at low voltage corner.
+ * @param[out] pGpuIddq Pointer to GPU Iddq Value
+ * @param[out] pChipSkuId SKU ID for the chip
+ *
+ * @return NV_ERR_NOT_SUPPORTED
+ */
+NV_STATUS
+osGetChipInfo
+(
+ OBJGPU *pGpu,
+ NvU32 *pGpuSpeedoHv,
+ NvU32 *pGpuSpeedoLv,
+ NvU32 *pGpuIddq,
+ NvU32 *pChipSkuId
+)
+{
+ return NV_ERR_NOT_SUPPORTED;
+}
+
+/*
+ * @brief Get the GPU Rail Voltage Info (i.e. Min, Max and StepSize) in Tegra SoC.
+ *
+ * @param[in] pGpu GPU object pointer
+ * @param[out] pMinVoltageuV Minimum Voltage supported on the Rail in Micro Volts
+ * @param[out] pMaxVoltageuV Maximum Voltage supported on the Rail in Micro Volts
+ * @param[out] pStepVoltageuV Voltage Step-size supported on the Rail in Micro Volts
+ *
+ * @return NV_ERR_NOT_SUPPORTED
+ */
+NV_STATUS
+osGetGpuRailVoltageInfo
+(
+ OBJGPU *pGpu,
+ NvU32 *pMinVoltageuV,
+ NvU32 *pMaxVoltageuV,
+ NvU32 *pStepVoltageuV
+)
+{
+ return NV_ERR_NOT_SUPPORTED;
+}
+
+/*!
+ * @brief Get the current opaque security token.
+ *
+ * For Linux the security token is the effective UID of a process and process ID
+ *
+ * Note: This function allocates memory for the token. The onus is on the calling
+ * function to free the memory associated with the token once its done with it.
+ *
+ * @return pointer to the security token.
+ */
+PSECURITY_TOKEN
+osGetSecurityToken(void)
+{
+ NV_STATUS rmStatus;
+ TOKEN_USER *pTokenUser;
+
+ pTokenUser = portMemAllocNonPaged(sizeof(TOKEN_USER));
+ if (pTokenUser == NULL)
+ {
+ return NULL;
+ }
+ rmStatus = os_get_euid(&pTokenUser->euid);
+ if (rmStatus != NV_OK)
+ {
+ portMemFree(pTokenUser);
+ return NULL;
+ }
+
+ pTokenUser->pid = os_get_current_process();
+
+ return (PSECURITY_TOKEN)pTokenUser;
+}
+
+PUID_TOKEN
+osGetCurrentUidToken(void)
+{
+ NV_STATUS rmStatus;
+ NvU32 *pUidToken;
+
+ pUidToken = portMemAllocNonPaged(sizeof(NvU32));
+ if (pUidToken == NULL)
+ {
+ return NULL;
+ }
+
+ rmStatus = os_get_euid(pUidToken);
+ if (rmStatus != NV_OK)
+ {
+ portMemFree(pUidToken);
+ return NULL;
+ }
+
+ return (PUID_TOKEN)pUidToken;
+}
+
+/*!
+ * @brief Interface function to validate the token for the current client
+ *
+ * This function takes two tokens as parameters, validates them and checks
+ * if either the PID or EUID from client database matches the current PID or EUID.
+ *
+ * @param[in] pClientSecurityToken security token cached in the client db
+ * @param[in] pCurrentSecurityToken security token of the current client
+ * @return NV_OK if the validation is successful
+ * NV_ERR_INVALID_CLIENT if the tokens do not match
+ * NV_ERR_INVALID_POINTER if the tokens are invalid
+ */
+NV_STATUS
+osValidateClientTokens
+(
+ PSECURITY_TOKEN pClientSecurityToken,
+ PSECURITY_TOKEN pCurrentSecurityToken
+)
+{
+ PTOKEN_USER pClientTokenUser = (PTOKEN_USER)pClientSecurityToken;
+ PTOKEN_USER pCurrentTokenUser = (PTOKEN_USER)pCurrentSecurityToken;
+
+ if (pClientTokenUser == NULL || pCurrentTokenUser == NULL)
+ return NV_ERR_INVALID_POINTER;
+
+ if ((pClientTokenUser->euid != pCurrentTokenUser->euid) &&
+ (pClientTokenUser->pid != pCurrentTokenUser->pid))
+ {
+ NV_PRINTF(LEVEL_INFO,
+ "NVRM: %s: Current security token doesn't match the one in the client database. "
+ "Current EUID: %d, PID: %d; Client DB EUID: %d, PID: %d\n",
+ __FUNCTION__, pCurrentTokenUser->euid, pCurrentTokenUser->pid,
+ pClientTokenUser->euid, pClientTokenUser->pid);
+ return NV_ERR_INVALID_CLIENT;
+ }
+
+ return NV_OK;
+}
+
+/*!
+ * @brief Interface function to compare the tokens for two client
+ *
+ * This function takes two tokens as parameters, validates them and checks
+ * if the EUIDs of each token match.
+ *
+ * @param[in] pToken1 Token to compare
+ * @param[in] pToken2 Token to compare
+ * @return NV_TRUE if the tokens match
+ * NV_FALSE if the tokens do not match
+ */
+NvBool
+osUidTokensEqual
+(
+ PUID_TOKEN pUidToken1,
+ PUID_TOKEN pUidToken2
+)
+{
+ NvU32 * pTokenUser1 = (NvU32*)pUidToken1;
+ NvU32 * pTokenUser2 = (NvU32*)pUidToken2;
+
+ NV_ASSERT_OR_RETURN((pTokenUser1 != NULL), NV_FALSE);
+ NV_ASSERT_OR_RETURN((pTokenUser2 != NULL), NV_FALSE);
+
+ if (*pTokenUser1 != *pTokenUser2)
+ {
+ return NV_FALSE;
+ }
+
+ return NV_TRUE;
+}
+
+NvBool
+osRemoveGpuSupported
+(
+ void
+)
+{
+ return os_pci_remove_supported();
+}
+
+/*
+ * @brief Get the address ranges assigned to local or peer GPUs on a system that
+ * supports hardware address translation services (ATS) over NVLink/C2C.
+ *
+ * @note
+ * - All address values are in the System Physical Address (SPA) space
+ * - Targets can either be "Local" (bIsPeer=False) or for a specified "Peer"
+ * (bIsPeer=True, peerIndex=#) GPU
+ * - Target address and mask values have a specified bit width, and represent
+ * the higher order bits above the target address granularity
+ *
+ * @param[in] pGpu GPU object pointer
+ * @param[out] pAddrSysPhys Pointer to hold SPA
+ * @param[out] pAddrWidth Address range width value pointer
+ * @param[out] pMask Mask value pointer
+ * @param[out] pMaskWidth Mask width value pointer
+ * @param[in] bIsPeer NV_TRUE if this is a peer, local GPU otherwise
+ * @param[in] peerIndex Peer index
+ *
+ * @return NV_OK or NV_ERR_NOT_SUPPORTED
+ *
+ * A return value of NV_ERR_NOT_SUPPORTED for the local GPU would
+ * indicate that the system does not support ATS over NVLink/C2C
+ */
+NV_STATUS
+osGetAtsTargetAddressRange
+(
+ OBJGPU *pGpu,
+ NvU64 *pAddrSysPhys,
+ NvU32 *pAddrWidth,
+ NvU32 *pMask,
+ NvU32 *pMaskWidth,
+ NvBool bIsPeer,
+ NvU32 peerIndex
+)
+{
+#if RMCFG_MODULE_KERNEL_BIF && RMCFG_MODULE_KERNEL_NVLINK && defined(NVCPU_AARCH64)
+ KernelNvlink *pKernelNvlink = GPU_GET_KERNEL_NVLINK(pGpu);
+ KernelBif *pKernelBif = GPU_GET_KERNEL_BIF(pGpu);
+ nv_state_t *nv;
+ const int addrMaskWidth = 0x10;
+
+ if (!pKernelNvlink && !pKernelBif->getProperty(pKernelBif, PDB_PROP_KBIF_IS_C2C_LINK_UP))
+ return NV_ERR_INVALID_ARGUMENT;
+
+ nv = NV_GET_NV_STATE(pGpu);
+
+ //
+ // TODO : Bug 1848958 restricts peer device tree parsing. Return early if
+ // peer values are requested. This should be fixed by passing correct pGpu
+ // pointer of the peer GPU retrieved using peerIds.
+ //
+ if (bIsPeer)
+ {
+ const int addrWidth = 0x10;
+
+ *pAddrSysPhys = 0;
+ *pAddrWidth = addrWidth;
+ *pMask = 0;
+ *pMaskWidth = addrMaskWidth;
+ return NV_OK;
+ }
+ else
+ {
+ NV_STATUS status = nv_get_device_memory_config(nv, pAddrSysPhys, NULL, NULL, NULL,
+ pAddrWidth, NULL);
+ if (status == NV_OK)
+ {
+ *pMask = NVBIT(*pAddrWidth) - 1U;
+ *pMaskWidth = addrMaskWidth;
+ }
+ return status;
+ }
+
+ return NV_OK;
+#endif
+ return NV_ERR_NOT_SUPPORTED;
+}
+
+/*
+ * @brief Get the physical address in CPU address map and NUMA node id
+ * of the GPU memory.
+ *
+ * @note
+ * - The physical address is System Physical Address (SPA) in baremetal/host
+ * and Intermediate Physical Address(IPA) or Guest Physical Address(GPA)
+ * inside a VM.
+ *
+ * @param[in] pGpu GPU object pointer
+ * @param[out] pAddrPhys Pointer to hold the physical address of FB in
+ * CPU address map
+ * @param[out] pSizePhys Pointer to hold the size of FB mapped to CPU
+ * @param[out] pNodeId NUMA nodeID of respective GPU memory
+ *
+ * @return NV_OK or NV_ERR_NOT_SUPPORTED
+ *
+ */
+NV_STATUS
+osGetFbNumaInfo
+(
+ OBJGPU *pGpu,
+ NvU64 *pAddrPhys,
+ NvU64 *pSizePhys,
+ NvU64 *pAddrRsvdPhys,
+ NvS32 *pNodeId
+)
+{
+#if RMCFG_MODULE_KERNEL_BIF && RMCFG_MODULE_KERNEL_NVLINK && defined(NVCPU_AARCH64)
+ KernelNvlink *pKernelNvlink = GPU_GET_KERNEL_NVLINK(pGpu);
+ KernelBif *pKernelBif = GPU_GET_KERNEL_BIF(pGpu);
+ nv_state_t *nv;
+
+ *pNodeId = NV0000_CTRL_NO_NUMA_NODE;
+
+ if (!pKernelNvlink && !pKernelBif->getProperty(pKernelBif, PDB_PROP_KBIF_IS_C2C_LINK_UP))
+ return NV_ERR_INVALID_ARGUMENT;
+
+ nv = NV_GET_NV_STATE(pGpu);
+
+ NV_STATUS status = nv_get_device_memory_config(nv, NULL, pAddrPhys, pSizePhys,
+ pAddrRsvdPhys, NULL, pNodeId);
+
+ return status;
+#endif
+ return NV_ERR_NOT_SUPPORTED;
+}
+
+
+/*
+ * @brief Verif only function to get the chiplib overrides for link connection
+ * state for all C2C links.
+ *
+ * If chiplib overrides exist, each link can either be enabled (1) or disabled (0)
+ *
+ * @param[in] pGpu GPU object pointer
+ * @param[in] maxLinks Size of pLinkConnection array
+ * @param[out] pLinkConnection array of pLinkConnection values to be populated by MODS
+ *
+ * @return NV_OK or NV_ERR_NOT_SUPPORTED (no overrides available)
+ */
+NV_STATUS
+osGetForcedC2CConnection
+(
+ OBJGPU *pGpu,
+ NvU32 maxLinks,
+ NvU32 *pLinkConnection
+)
+{
+ int i, ret;
+ NV_STATUS status;
+ char path[64];
+
+ NV_ASSERT_OR_RETURN((pLinkConnection != NULL), NV_ERR_INVALID_POINTER);
+ NV_ASSERT_OR_RETURN((maxLinks > 0), NV_ERR_NOT_SUPPORTED);
+ NV_ASSERT_OR_RETURN((pGpu != NULL), NV_ERR_INVALID_ARGUMENT);
+
+ for (i = 0; i < maxLinks; i++)
+ {
+ ret = os_snprintf(path, sizeof(path), "CPU_MODEL|CM_ATS_ADDRESS|C2C%u", i);
+ NV_ASSERT((ret > 0) && (ret < (sizeof(path) - 1)));
+
+ status = gpuSimEscapeRead(pGpu, path, 0, 4, &pLinkConnection[i]);
+ if (status == NV_OK)
+ {
+ NV_PRINTF(LEVEL_INFO, "%s: %s=0x%X\n", __FUNCTION__,
+ path, pLinkConnection[i]);
+ }
+ else
+ {
+ NV_PRINTF(LEVEL_INFO, "%s: gpuSimEscapeRead for '%s' failed (%u)\n",
+ __FUNCTION__, path, status);
+ return NV_ERR_NOT_SUPPORTED;
+ }
+ }
+ return NV_OK;
+}
+
+static NV_STATUS
+osGetSmbiosTableInfo
+(
+ const NvU8 *pMappedAddr,
+ NvU64 *pBaseAddr,
+ NvU64 *pLength,
+ NvU64 *pNumSubTypes,
+ NvU32 *pVersion
+)
+{
+ *pBaseAddr = 0;
+ *pLength = 0;
+ *pNumSubTypes = 0;
+ *pVersion = 0;
+
+ if (portMemCmp(pMappedAddr, "_SM3_", 5) == 0)
+ {
+ *pVersion = (pMappedAddr[7] << 8) | pMappedAddr[8];
+ portMemCopy(pLength, 4, pMappedAddr + 12, 4);
+ portMemCopy(pBaseAddr, 8, pMappedAddr + 16, 8);
+
+ *pNumSubTypes = *pLength / 4;
+
+ return NV_OK;
+ }
+
+ if (portMemCmp(pMappedAddr, "_SM_", 4) == 0)
+ {
+ *pVersion = (pMappedAddr[6] << 8) | pMappedAddr[7];
+
+ pMappedAddr += 16;
+
+ if (portMemCmp(pMappedAddr, "_DMI_", 5) == 0)
+ {
+ portMemCopy(pLength, 2, pMappedAddr + 6, 2);
+ portMemCopy(pBaseAddr, 4, pMappedAddr + 8, 4);
+ portMemCopy(pNumSubTypes, 2, pMappedAddr + 12, 2);
+
+ if (!*pVersion)
+ *pVersion = (pMappedAddr[14] & 0xF0) << 4 |
+ (pMappedAddr[14] & 0x0F);
+
+ return NV_OK;
+ }
+ }
+
+ return NV_ERR_INVALID_ADDRESS;
+}
+
+
+/*
+ * @brief Function to export SMBIOS table. Also, maps table in kernel-space.
+ *
+ * @param[out] ppBaseVAddr Base virtual address of SMBIOS table.
+ * @param[out] pLength Size of SMBIOS table.
+ * @param[out] pNumSubTypes Count of structures (types) embedded in
+ * the SMBIOS table.
+ * @param[out] pVersion SMBIOS version
+ *
+ * @return NV_OK, NV_ERR_INSUFFICIENT_RESOURCES or NV_ERR_INVALID_ADDRESS
+ * or errors from OS layer
+ */
+NV_STATUS
+osGetSmbiosTable
+(
+ void **ppBaseVAddr,
+ NvU64 *pLength,
+ NvU64 *pNumSubTypes,
+ NvU32 *pVersion
+)
+{
+ NV_STATUS status = NV_OK;
+ NvU64 physSmbiosAddr = ~0ull;
+ void *pMappedAddr = NULL;
+ NvU64 basePAddr = 0;
+
+ if (!NVCPU_IS_X86_64 && !NVCPU_IS_AARCH64)
+ {
+ return NV_ERR_NOT_SUPPORTED;
+ }
+
+ status = os_get_smbios_header(&physSmbiosAddr);
+ if (status != NV_OK)
+ {
+ NV_PRINTF(LEVEL_INFO, "%s: Failed query SMBIOS table with error: %x \n",
+ __FUNCTION__, status);
+ return status;
+ }
+
+ NV_ASSERT(physSmbiosAddr != ~0ull);
+
+ pMappedAddr = osMapKernelSpace(physSmbiosAddr,
+ os_page_size,
+ NV_MEMORY_CACHED,
+ NV_PROTECT_READ_WRITE);
+ if (!pMappedAddr)
+ {
+ return NV_ERR_INSUFFICIENT_RESOURCES;
+ }
+
+ status = osGetSmbiosTableInfo(pMappedAddr,
+ &basePAddr,
+ pLength,
+ pNumSubTypes,
+ pVersion);
+
+ osUnmapKernelSpace(pMappedAddr, os_page_size);
+
+ if (status != NV_OK)
+ {
+ return status;
+ }
+
+ *ppBaseVAddr = osMapKernelSpace(basePAddr,
+ *pLength,
+ NV_MEMORY_CACHED,
+ NV_PROTECT_READ_WRITE);
+ if (!*ppBaseVAddr)
+ {
+ return NV_ERR_INSUFFICIENT_RESOURCES;
+ }
+
+ return NV_OK;
+}
+
+/*
+ * @brief Function to free SMBIOS table mappings
+ *
+ * @param[in] pBaseVAddr Base virtual address of SMBIOS table.
+ * @param[in] length Size of SMBIOS table.
+ *
+ */
+void
+osPutSmbiosTable
+(
+ void *pBaseVAddr,
+ NvU64 length
+)
+{
+ osUnmapKernelSpace(pBaseVAddr, length);
+}
+
+NV_STATUS
+osGetAcpiRsdpFromUefi
+(
+ NvU32 *pRsdpAddr
+)
+{
+ return os_get_acpi_rsdp_from_uefi(pRsdpAddr);
+}
+
+/*
+ * @brief Returns NV_TRUE if NvSwitch device is present in the system.
+ */
+NvBool
+osIsNvswitchPresent
+(
+ void
+)
+{
+ return os_is_nvswitch_present();
+}
+
+/*
+ * @brief Function to add crashlog buffer entry.
+ *
+ * @param[in] pBuffer virt_addr of nvlog buffer
+ * @param[in] length size of nvlog buffer
+ */
+void
+osAddRecordForCrashLog
+(
+ void *pBuffer,
+ NvU32 length
+)
+{
+ os_add_record_for_crashLog(pBuffer, length);
+}
+
+/*
+ * @brief Function to delete crashlog buffer entry.
+ *
+ * @param[in] pBuffer virt_addr of nvlog buffer
+ */
+void
+osDeleteRecordForCrashLog
+(
+ void *pBuffer
+)
+{
+ os_delete_record_for_crashLog(pBuffer);
+}
+
+/*
+ * @brief Queries the sysfs interface to get memblock size
+ * @param[out] memblock_size Pointer to the memblock_size
+ */
+NV_STATUS
+osNumaMemblockSize
+(
+ NvU64 *memblock_size
+)
+{
+ return os_numa_memblock_size(memblock_size);
+}
+
+NvBool
+osNumaOnliningEnabled
+(
+ OS_GPU_INFO *pOsGpuInfo
+)
+{
+ NvS32 numaNodeId = NV0000_CTRL_NO_NUMA_NODE;
+
+ //
+ // Note that this numaNodeId value fetched from Linux layer might not be
+ // accurate since it is possible to overwrite it with regkey on some configs
+ //
+ if (nv_get_device_memory_config(pOsGpuInfo, NULL, NULL, NULL, NULL, NULL,
+ &numaNodeId) != NV_OK)
+ {
+ return NV_FALSE;
+ }
+
+ return (numaNodeId != NV0000_CTRL_NO_NUMA_NODE);
+}
+
+/*
+ * @brief Function to call NUMA allocation entry.
+ *
+ * @param[in] nid NUMA node id
+ * @param[in] size Allocation size
+ * @param[in] flag Allocation flags
+ * @param[out] pAddress Ptr to the allocated physical address
+ */
+NV_STATUS
+osAllocPagesNode
+(
+ NvS32 nid,
+ NvLength size,
+ NvU32 flag,
+ NvU64 *pAddress
+)
+{
+ NV_STATUS status = NV_OK;
+ NvU32 localFlag = NV_ALLOC_PAGES_NODE_NONE;
+
+ if (pAddress == NULL || nid < 0 || size > NV_U32_MAX)
+ {
+ return NV_ERR_INVALID_ARGUMENT;
+ }
+
+ // Translate the flags
+ if (flag & OS_ALLOC_PAGES_NODE_SKIP_RECLAIM)
+ {
+ localFlag |= NV_ALLOC_PAGES_NODE_SKIP_RECLAIM;
+ }
+
+ status = os_alloc_pages_node(nid, (NvU32)size, localFlag, pAddress);
+ return status;
+}
+
+void
+osAllocAcquirePage
+(
+ NvU64 pAddress,
+ NvU32 pageCount
+)
+{
+ NvU32 i;
+
+ for (i = 0; i < pageCount; i++)
+ {
+ os_get_page(pAddress + (i << os_page_shift));
+ }
+}
+
+void
+osAllocReleasePage
+(
+ NvU64 pAddress,
+ NvU32 pageCount
+)
+{
+ NvU32 i;
+
+ for (i = 0; i < pageCount; i++)
+ {
+ os_put_page(pAddress + (i << os_page_shift));
+ }
+}
+
+/*
+ * @brief Function to return refcount on a page
+ * @param[in] address The physical address of the page
+ */
+NvU32
+osGetPageRefcount
+(
+ NvU64 pAddress
+)
+{
+ return os_get_page_refcount(pAddress);
+}
+
+/*
+ * @brief Function to return the number of tail pages if the address is
+ * referring to a compound page; For non-compound pages, 1 is returned.
+ * @param[in] address The physical address of the page
+ */
+NvU32
+osCountTailPages
+(
+ NvU64 pAddress
+)
+{
+ return os_count_tail_pages(pAddress);
+}
+
+NvU64
+osGetPageSize(void)
+{
+ return os_page_size;
+}
+
+NvU64
+osGetSupportedSysmemPageSizeMask(void)
+{
+ //
+ // We assume that the kernel can support all power-of-two pagesizes
+ // between os_page_size and os_max_page_size (inclusive). Return a
+ // bitmask containing all of those.
+ //
+ return (((os_max_page_size << 1) - 1) & (~(os_page_size - 1)));
+}
+
+NvU8
+osGetPageShift(void)
+{
+ return os_page_shift;
+}
+
+
+
+/*
+ * @brief Opens a new temporary file for reading and writing
+ *
+ * @param[in] ppFile void double pointer
+ *
+ * @returns NV_STATUS, NV_OK if success,
+ NV_ERR_GENERIC, if error
+ NV_ERR_NOT_SUPPORTED, for unsupported platforms
+ */
+NV_STATUS
+osOpenTemporaryFile
+(
+ void **ppFile
+)
+{
+ return os_open_temporary_file(ppFile);
+}
+
+/*
+ * @brief Closes the specified temporary file
+ *
+ * @param[in] pFile Pointer to file
+ *
+ * @returns void
+ */
+void
+osCloseFile
+(
+ void *pFile
+)
+{
+ os_close_file(pFile);
+}
+
+/*
+ * @brief Writes the buffer to the specified file at the given offset
+ *
+ * @param[in] pFile Pointer to file (void)
+ * @param[in] pBuffer Pointer to buffer from which to copy
+ * @param[in] size Size of the copy
+ * @parma[in] offset offset in the file
+ *
+ * @returns NV_STATUS, NV_OK if success,
+ NV_ERR_GENERIC, if error
+ NV_ERR_NOT_SUPPORTED, for unsupported platforms
+ */
+NV_STATUS
+osWriteToFile
+(
+ void *pFile,
+ NvU8 *pBuffer,
+ NvU64 size,
+ NvU64 offset
+)
+{
+ return os_write_file(pFile, pBuffer, size, offset);
+}
+
+/*
+ * @brief Reads from the specified file at the given offset
+ *
+ * @param[in] pFile Pointer to file (void *)
+ * @param[in] pBuffer Pointer to buffer to which the data is copied
+ * @param[in] size Size of the copy
+ * @parma[in] offset offset in the file
+ *
+ * @returns NV_STATUS, NV_OK if success,
+ NV_ERR_GENERIC, if error
+ NV_ERR_NOT_SUPPORTED, for unsupported platforms
+ */
+NV_STATUS
+osReadFromFile
+(
+ void *pFile,
+ NvU8 *pBuffer,
+ NvU64 size,
+ NvU64 offset
+)
+{
+ return os_read_file(pFile, pBuffer, size, offset);
+}
+
+/*
+ * @brief Unregisters caps from the capability framework.
+ * The function assumes that the caps are allocated and stored in the
+ * hierarchical order. If they aren't, OS (Linux kernel) would warn and
+ * leak the caps.
+ *
+ * @param[in] pOsRmCaps caps of interest
+ */
+void
+osRmCapUnregister
+(
+ OS_RM_CAPS **ppOsRmCaps
+)
+{
+ OS_RM_CAPS *pOsRmCaps = *ppOsRmCaps;
+ NvS32 i;
+
+ if (pOsRmCaps == NULL)
+ {
+ return;
+ }
+
+ for (i = pOsRmCaps->count - 1; i >= 0; i--)
+ {
+ if (pOsRmCaps->caps[i] != NULL)
+ {
+ os_nv_cap_destroy_entry(pOsRmCaps->caps[i]);
+ }
+ }
+
+ os_free_mem(pOsRmCaps->caps);
+ os_free_mem(pOsRmCaps);
+
+ *ppOsRmCaps = NULL;
+}
+
+static NV_STATUS
+_allocOsRmCaps
+(
+ OS_RM_CAPS **ppOsRmCaps,
+ NvU32 count
+)
+{
+ NV_STATUS status;
+ OS_RM_CAPS *pOsRmCaps;
+
+ *ppOsRmCaps = NULL;
+
+ status = os_alloc_mem((void**)&pOsRmCaps, sizeof(OS_RM_CAPS));
+ if (status != NV_OK)
+ return status;
+
+ pOsRmCaps->count = count;
+
+ status = os_alloc_mem((void**)&pOsRmCaps->caps, sizeof(pOsRmCaps->caps[0]) * count);
+ if (status != NV_OK)
+ {
+ os_free_mem(pOsRmCaps);
+ return status;
+ }
+
+ os_mem_set(pOsRmCaps->caps, 0, sizeof(pOsRmCaps->caps[0]) * count);
+
+ *ppOsRmCaps = pOsRmCaps;
+ return NV_OK;
+}
+
+#define OS_RM_CAP_GPU_DIR 0
+#define OS_RM_CAP_GPU_MIG_DIR 1
+#define OS_RM_CAP_GPU_COUNT 2
+
+/*
+ * @brief Registers OBJGPU with the capability framework.
+ *
+ * @param[in] pOsGpuInfo OS specific GPU information pointer
+ * @param[out] ppOsRmCaps GPU OS specific capabilities pointer
+ */
+NV_STATUS
+osRmCapRegisterGpu
+(
+ OS_GPU_INFO *pOsGpuInfo,
+ OS_RM_CAPS **ppOsRmCaps
+)
+{
+ NvU32 minor = nv_get_dev_minor(pOsGpuInfo);
+ char name[16];
+ NV_STATUS status;
+ OS_RM_CAPS *pOsRmCaps;
+ nv_cap_t *parent;
+ nv_cap_t *cap;
+
+ // Return success on the unsupported platforms.
+ if (nvidia_caps_root == NULL)
+ {
+ return NV_OK;
+ }
+
+ if (*ppOsRmCaps != NULL)
+ {
+ return NV_ERR_INVALID_ARGUMENT;
+ }
+
+ status = _allocOsRmCaps(&pOsRmCaps, OS_RM_CAP_GPU_COUNT);
+ if (status != NV_OK)
+ return status;
+
+ *ppOsRmCaps = pOsRmCaps;
+
+ os_snprintf(name, sizeof(name), "gpu%u", minor);
+ name[sizeof(name) - 1] = '\0';
+ parent = nvidia_caps_root;
+
+ cap = os_nv_cap_create_dir_entry(parent, name, (OS_RUGO | OS_XUGO));
+ if (cap == NULL)
+ {
+ NV_PRINTF(LEVEL_ERROR, "Failed to setup gpu%u directory\n", minor);
+ status = NV_ERR_OPERATING_SYSTEM;
+ goto failed;
+ }
+
+ pOsRmCaps->caps[OS_RM_CAP_GPU_DIR] = cap;
+ parent = cap;
+
+ // TODO: Bug 2679591: Add MIG directory only if SMC is enabled.
+ // For now, always add "mig" directory.
+ cap = os_nv_cap_create_dir_entry(parent, "mig", (OS_RUGO | OS_XUGO));
+ if (cap == NULL)
+ {
+ NV_PRINTF(LEVEL_ERROR, "Failed to setup mig directory\n");
+ status = NV_ERR_OPERATING_SYSTEM;
+ goto failed;
+ }
+
+ pOsRmCaps->caps[OS_RM_CAP_GPU_MIG_DIR] = cap;
+
+ return NV_OK;
+
+failed:
+ osRmCapUnregister(ppOsRmCaps);
+
+ return status;
+}
+
+#define OS_RM_CAP_SMC_PART_DIR 0
+#define OS_RM_CAP_SMC_PART_ACCESS_FILE 1
+#define OS_RM_CAP_SMC_PART_COUNT 2
+
+/*
+ * @brief Registers SMC partition (a.k.a. GPU instance) with the capability
+ * framework
+ *
+ * @param[in] pGpuOsRmCaps GPU OS specific capabilities pointer
+ * @param[out] ppPartitionOsRmCaps OS specific capabilities pointer for SMC partition
+ * @param[in] swizzId SMC partition swizz ID
+ */
+NV_STATUS
+osRmCapRegisterSmcPartition
+(
+ OS_RM_CAPS *pGpuOsRmCaps,
+ OS_RM_CAPS **ppPartitionOsRmCaps,
+ NvU32 swizzId
+)
+{
+ char name[16];
+ NV_STATUS status;
+ nv_cap_t *parent;
+ nv_cap_t *cap;
+ OS_RM_CAPS *pOsRmCaps;
+
+ // Return success as there is nothing to do.
+ if (pGpuOsRmCaps == NULL)
+ {
+ return NV_OK;
+ }
+
+ if (*ppPartitionOsRmCaps != NULL || swizzId >= NV_U32_MAX)
+ {
+ return NV_ERR_INVALID_ARGUMENT;
+ }
+
+ parent = pGpuOsRmCaps->caps[OS_RM_CAP_GPU_MIG_DIR];
+ if (parent == NULL)
+ {
+ return NV_ERR_INVALID_STATE;
+ }
+
+ status = _allocOsRmCaps(&pOsRmCaps, OS_RM_CAP_SMC_PART_COUNT);
+ if (status != NV_OK)
+ return status;
+
+ *ppPartitionOsRmCaps = pOsRmCaps;
+
+ os_snprintf(name, sizeof(name), "gi%u", swizzId);
+ name[sizeof(name) - 1] = '\0';
+
+ cap = os_nv_cap_create_dir_entry(parent, name, OS_RUGO | OS_XUGO);
+ if (cap == NULL)
+ {
+ NV_PRINTF(LEVEL_ERROR, "Failed to setup gi%u directory\n",
+ swizzId);
+ status = NV_ERR_OPERATING_SYSTEM;
+ goto failed;
+ }
+
+ pOsRmCaps->caps[OS_RM_CAP_SMC_PART_DIR] = cap;
+ parent = cap;
+
+ cap = os_nv_cap_create_file_entry(parent, "access", OS_RUGO);
+ if (cap == NULL)
+ {
+ NV_PRINTF(LEVEL_ERROR, "Failed to setup access file for ID:%u\n",
+ swizzId);
+ status = NV_ERR_OPERATING_SYSTEM;
+ goto failed;
+ }
+
+ pOsRmCaps->caps[OS_RM_CAP_SMC_PART_ACCESS_FILE] = cap;
+
+ return NV_OK;
+
+failed:
+ osRmCapUnregister(ppPartitionOsRmCaps);
+
+ return status;
+}
+
+#define OS_RM_CAP_SMC_EXEC_PART_DIR 0
+#define OS_RM_CAP_SMC_EXEC_PART_ACCESS_FILE 1
+#define OS_RM_CAP_SMC_EXEC_PART_COUNT 2
+
+/*
+ * @brief Registers SMC execution partition (a.k.a. compute instance) with the
+ * capability framework
+ *
+ * @param[in] pPartitionOsRmCaps OS specific capabilities pointer for SMC partition
+ * @param[out] ppExecPartitionOsRmCaps OS specific capabilities pointer for SMC execution partition
+ * @param[in] execPartitionId SMC execution partition ID
+ */
+NV_STATUS
+osRmCapRegisterSmcExecutionPartition
+(
+ OS_RM_CAPS *pPartitionOsRmCaps,
+ OS_RM_CAPS **ppExecPartitionOsRmCaps,
+ NvU32 execPartitionId
+)
+{
+ char name[16];
+ NV_STATUS status;
+ nv_cap_t *parent;
+ nv_cap_t *cap;
+ OS_RM_CAPS *pOsRmCaps;
+
+ // Return success as there is nothing to do.
+ if (pPartitionOsRmCaps == NULL)
+ {
+ return NV_OK;
+ }
+
+ if ((*ppExecPartitionOsRmCaps != NULL) || (execPartitionId >= NV_U32_MAX))
+ {
+ return NV_ERR_INVALID_ARGUMENT;
+ }
+
+ parent = pPartitionOsRmCaps->caps[OS_RM_CAP_SMC_PART_DIR];
+ if (parent == NULL)
+ {
+ return NV_ERR_INVALID_STATE;
+ }
+
+ status = _allocOsRmCaps(&pOsRmCaps, OS_RM_CAP_SMC_EXEC_PART_COUNT);
+ if (status != NV_OK)
+ {
+ return status;
+ }
+
+ *ppExecPartitionOsRmCaps = pOsRmCaps;
+
+ os_snprintf(name, sizeof(name), "ci%u", execPartitionId);
+ name[sizeof(name) - 1] = '\0';
+
+ cap = os_nv_cap_create_dir_entry(parent, name, OS_RUGO | OS_XUGO);
+ if (cap == NULL)
+ {
+ NV_PRINTF(LEVEL_ERROR, "Failed to setup ci%u directory\n",
+ execPartitionId);
+ status = NV_ERR_OPERATING_SYSTEM;
+ goto failed;
+ }
+
+ pOsRmCaps->caps[OS_RM_CAP_SMC_EXEC_PART_DIR] = cap;
+ parent = cap;
+
+ cap = os_nv_cap_create_file_entry(parent, "access", OS_RUGO);
+ if (cap == NULL)
+ {
+ NV_PRINTF(LEVEL_ERROR, "Failed to setup access file for ID:%u\n",
+ execPartitionId);
+ status = NV_ERR_OPERATING_SYSTEM;
+ goto failed;
+ }
+
+ pOsRmCaps->caps[OS_RM_CAP_SMC_EXEC_PART_ACCESS_FILE] = cap;
+
+ return NV_OK;
+
+failed:
+ osRmCapUnregister(ppExecPartitionOsRmCaps);
+
+ return status;
+}
+
+/*
+ * @brief Release the acquired capability
+ *
+ * @param[in] dupedCapDescriptor descriptor to be released
+ */
+void
+osRmCapRelease
+(
+ NvU64 dupedCapDescriptor
+)
+{
+ if (dupedCapDescriptor == NV_U64_MAX)
+ {
+ return;
+ }
+
+ os_nv_cap_close_fd((int)dupedCapDescriptor);
+}
+
+#define OS_RM_CAP_SYS_MIG_DIR 0
+#define OS_RM_CAP_SYS_SMC_CONFIG_FILE 1
+#define OS_RM_CAP_SYS_SMC_MONITOR_FILE 2
+#define OS_RM_CAP_SYS_FABRIC_IMEX_MGMT_FILE 3
+#define OS_RM_CAP_SYS_PROFILER_DEVICE_FILE 4
+#define OS_RM_CAP_SYS_PROFILER_CONTEXT_FILE 5
+#define OS_RM_CAP_SYS_TRACE_DEVICE_FILE 6
+#define OS_RM_CAP_SYS_COUNT 7
+
+NV_STATUS
+osRmCapRegisterSys
+(
+ OS_RM_CAPS **ppOsRmCaps
+)
+{
+ nv_cap_t **ppCaps;
+ nv_cap_t *parent;
+ nv_cap_t *cap;
+ NV_STATUS status;
+ OS_RM_CAPS *pOsRmCaps;
+
+ if (nvidia_caps_root == NULL)
+ return NV_ERR_NOT_SUPPORTED;
+
+ status = _allocOsRmCaps(&pOsRmCaps, OS_RM_CAP_SYS_COUNT);
+ if (status != NV_OK)
+ return status;
+
+ *ppOsRmCaps = pOsRmCaps;
+
+ ppCaps = pOsRmCaps->caps;
+
+ parent = os_nv_cap_create_dir_entry(nvidia_caps_root, "mig", OS_RUGO | OS_XUGO);
+ if (parent == NULL)
+ {
+ NV_PRINTF(LEVEL_ERROR, "Failed to create mig directory\n");
+ status = NV_ERR_OPERATING_SYSTEM;
+ goto failed;
+ }
+ ppCaps[OS_RM_CAP_SYS_MIG_DIR] = parent;
+
+ cap = os_nv_cap_create_file_entry(parent, "config", OS_RUSR);
+ if (cap == NULL)
+ {
+ NV_PRINTF(LEVEL_ERROR, "Failed to create mig config file\n");
+ status = NV_ERR_OPERATING_SYSTEM;
+ goto failed;
+ }
+ ppCaps[OS_RM_CAP_SYS_SMC_CONFIG_FILE] = cap;
+
+ cap = os_nv_cap_create_file_entry(parent, "monitor", OS_RUGO);
+ if (cap == NULL)
+ {
+ NV_PRINTF(LEVEL_ERROR, "Failed to create mig monitor file\n");
+ status = NV_ERR_OPERATING_SYSTEM;
+ goto failed;
+ }
+ ppCaps[OS_RM_CAP_SYS_SMC_MONITOR_FILE] = cap;
+
+ cap = os_nv_cap_create_file_entry(nvidia_caps_root, "fabric-imex-mgmt", OS_RUSR);
+ if (cap == NULL)
+ {
+ NV_PRINTF(LEVEL_ERROR, "Failed to create imex file\n");
+ status = NV_ERR_OPERATING_SYSTEM;
+ goto failed;
+ }
+ ppCaps[OS_RM_CAP_SYS_FABRIC_IMEX_MGMT_FILE] = cap;
+
+ cap = os_nv_cap_create_file_entry(nvidia_caps_root, "profiler-device", OS_RUSR);
+ if (cap == NULL)
+ {
+ NV_PRINTF(LEVEL_ERROR, "Failed to create profiler-device file\n");
+ status = NV_ERR_OPERATING_SYSTEM;
+ goto failed;
+ }
+ ppCaps[OS_RM_CAP_SYS_PROFILER_DEVICE_FILE] = cap;
+
+ cap = os_nv_cap_create_file_entry(nvidia_caps_root, "profiler-context", OS_RUSR);
+ if (cap == NULL)
+ {
+ NV_PRINTF(LEVEL_ERROR, "Failed to create profiler-context file\n");
+ status = NV_ERR_OPERATING_SYSTEM;
+ goto failed;
+ }
+ ppCaps[OS_RM_CAP_SYS_PROFILER_CONTEXT_FILE] = cap;
+
+ cap = os_nv_cap_create_file_entry(nvidia_caps_root, "trace-device", OS_RUSR);
+ if (cap == NULL)
+ {
+ NV_PRINTF(LEVEL_ERROR, "Failed to create trace-device file\n");
+ status = NV_ERR_OPERATING_SYSTEM;
+ goto failed;
+ }
+ ppCaps[OS_RM_CAP_SYS_TRACE_DEVICE_FILE] = cap;
+
+ return NV_OK;
+
+failed:
+ osRmCapUnregister(ppOsRmCaps);
+ return status;
+}
+
+/*
+ * @brief Acquire the requested capability
+ *
+ * @param[in] pOsRmCaps opaque pointer to the caps.
+ * @param[in] rmCap the capability to be acquired.
+ * @param[in] capDescriptor descriptor to be used for validation
+ * @param[out] dupedCapDescriptor returns duplicated descriptor if validation
+ * is successful
+ *
+ * Note: On Linux, duplicating fd is helpful to let administrators know about
+ * the capability users. See https://linux.die.net/man/8/lsof usage.
+ */
+NV_STATUS
+osRmCapAcquire
+(
+ OS_RM_CAPS *pOsRmCaps,
+ NvU32 rmCap,
+ NvU64 capDescriptor,
+ NvU64 *dupedCapDescriptor
+)
+{
+ nv_cap_t *cap;
+ int fd = (int)capDescriptor;
+ int duped_fd;
+ NvU32 index;
+ NV_STATUS status;
+
+ *dupedCapDescriptor = NV_U64_MAX;
+
+ switch (rmCap)
+ {
+ case NV_RM_CAP_SMC_PARTITION_ACCESS:
+ {
+ index = OS_RM_CAP_SMC_PART_ACCESS_FILE;
+ break;
+ }
+ case NV_RM_CAP_EXT_FABRIC_MGMT:
+ {
+ status = nv_acquire_fabric_mgmt_cap(fd, &duped_fd);
+ if (status != NV_OK)
+ {
+ return status;
+ }
+
+ goto done;
+ }
+ case NV_RM_CAP_SMC_EXEC_PARTITION_ACCESS:
+ {
+ index = OS_RM_CAP_SMC_EXEC_PART_ACCESS_FILE;
+ break;
+ }
+ case NV_RM_CAP_SYS_SMC_CONFIG:
+ {
+ index = OS_RM_CAP_SYS_SMC_CONFIG_FILE;
+ break;
+ }
+ case NV_RM_CAP_SYS_SMC_MONITOR:
+ {
+ index = OS_RM_CAP_SYS_SMC_MONITOR_FILE;
+ break;
+ }
+ case NV_RM_CAP_SYS_FABRIC_IMEX_MGMT:
+ {
+ index = OS_RM_CAP_SYS_FABRIC_IMEX_MGMT_FILE;
+ break;
+ }
+ case NV_RM_CAP_SYS_PROFILER_DEVICE:
+ {
+ index = OS_RM_CAP_SYS_PROFILER_DEVICE_FILE;
+ break;
+ }
+ case NV_RM_CAP_SYS_PROFILER_CONTEXT:
+ {
+ index = OS_RM_CAP_SYS_PROFILER_CONTEXT_FILE;
+ break;
+ }
+ case NV_RM_CAP_SYS_TRACE_DEVICE:
+ {
+ index = OS_RM_CAP_SYS_TRACE_DEVICE_FILE;
+ break;
+ }
+ default:
+ {
+ return NV_ERR_INVALID_ARGUMENT;
+ }
+ }
+
+ if (pOsRmCaps == NULL)
+ {
+ return NV_ERR_NOT_SUPPORTED;
+ }
+
+ if (index >= pOsRmCaps->count)
+ {
+ return NV_ERR_INVALID_ARGUMENT;
+ }
+
+ cap = pOsRmCaps->caps[index];
+
+ duped_fd = os_nv_cap_validate_and_dup_fd(cap, fd);
+ if (duped_fd < 0)
+ {
+ return NV_ERR_INSUFFICIENT_PERMISSIONS;
+ }
+
+done:
+ *dupedCapDescriptor = duped_fd;
+
+ return NV_OK;
+}
+
+/*
+ * @brief Initializes capability descriptor
+ *
+ * @param[out] pCapDescriptor descriptor to be used
+ *
+ */
+void
+osRmCapInitDescriptor
+(
+ NvU64 *pCapDescriptor
+)
+{
+ *pCapDescriptor = NV_U64_MAX;
+}
+
+/*
+ * @brief Checks if IMEX channel support is present.
+ */
+NvBool
+osImexChannelIsSupported(void)
+{
+ return os_imex_channel_is_supported;
+}
+
+/*
+ * @brief Returns IMEX channel count.
+ */
+NvS32
+osImexChannelCount
+(
+ void
+)
+{
+ return os_imex_channel_count();
+}
+
+/*
+ * @brief Returns IMEX channel number.
+ *
+ * @param[in] descriptor OS specific descriptor to query channel number.
+ *
+ */
+NvS32
+osImexChannelGet(NvU64 descriptor)
+{
+ return os_imex_channel_get(descriptor);
+}
+
+/*
+ * @brief Generates random bytes which can be used as a universally unique
+ * identifier.
+ *
+ * This function may sleep (interruptible).
+ *
+ * @param[out] pBytes Array of random bytes
+ * @param[in] numBytes Size of the array
+ */
+NV_STATUS
+osGetRandomBytes
+(
+ NvU8 *pBytes,
+ NvU16 numBytes
+)
+{
+ return os_get_random_bytes(pBytes, numBytes);
+}
+
+/*
+ * @brief Get current process flags..
+ */
+NvU32
+osGetCurrentProcessFlags
+(
+ void
+)
+{
+ return os_get_current_process_flags();
+}
+
+/*
+ * @brief Allocate wait queue
+ *
+ * @param[out] ppWq Wait queue
+ */
+NV_STATUS
+osAllocWaitQueue
+(
+ OS_WAIT_QUEUE **ppWq
+)
+{
+ return os_alloc_wait_queue(ppWq);
+}
+
+/*
+ * @brief Free wait queue
+ *
+ * @param[in] pWq Wait queue
+ */
+void
+osFreeWaitQueue
+(
+ OS_WAIT_QUEUE *pWq
+)
+{
+ os_free_wait_queue(pWq);
+}
+
+/*
+ * @brief Put thread to uninterruptible sleep
+ *
+ * @param[in] pWq Wait queue
+ */
+void
+osWaitUninterruptible
+(
+ OS_WAIT_QUEUE *pWq
+)
+{
+ os_wait_uninterruptible(pWq);
+}
+
+/*
+ * @brief Put thread to interruptible sleep
+ *
+ * @param[in] pWq Wait queue
+ */
+void
+osWaitInterruptible
+(
+ OS_WAIT_QUEUE *pWq
+)
+{
+ os_wait_interruptible(pWq);
+}
+
+/*
+ * @brief Wake up thread from uninterruptible sleep
+ *
+ * @param[in] pWq Wait queue
+ */
+void
+osWakeUp
+(
+ OS_WAIT_QUEUE *pWq
+)
+{
+ os_wake_up(pWq);
+}
+
+NV_STATUS
+osReadPFPciConfigInVF
+(
+ NvU32 addr,
+ NvU32 *data
+)
+{
+ return NV_ERR_NOT_SUPPORTED;
+}
+
+/*!
+ * @brief Callback function to notify RM when unix layer receives an event
+ *
+ * This function is basically a wrapper to call the Core RM layer and is
+ * being called from DCE KMD when an event is received from DCE RM.
+ *
+ * @param[in] handle handle allocated for corresponding IPC type with DCE
+ * @param[in] interfaceType RM IPC interface type
+ * @param[in] length length of the message passed from DCE
+ * @param[in] data any specific data if present
+ * @param[in] usrCtx any specific user context if present
+ *
+ * @returns void
+ */
+static void
+osTegraDceClientIpcCallback
+(
+ NvU32 handle,
+ NvU32 interfaceType,
+ NvU32 length,
+ void *data,
+ void *usrCtx
+)
+{
+ THREAD_STATE_NODE threadState;
+ NvU32 rmInterfaceType = nv_tegra_get_rm_interface_type(interfaceType);
+
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ if (rmLocksAcquireAll(RM_LOCK_MODULES_KERNEL_RM_EVENTS) == NV_OK)
+ {
+ dceclientHandleAsyncRpcCallback(handle, rmInterfaceType, length, data, usrCtx);
+
+ rmLocksReleaseAll();
+ }
+
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+}
+
+/*!
+ * @brief Performs IPC Client registration with DCE
+ *
+ * This function is basically a wrapper to call the unix/linux layer.
+ *
+ * @param[in] interfaceType RM IPC interface type
+ * @param[in] usrCtx any specific user context if present
+ * @param[out] clientId unique ID registered with DCE for IPC
+ *
+ * @returns NV_OK if successful,
+ * NV_ERR_NOT_SUPPORTED if the functionality is not available, or
+ * other errors as may be returned by subfunctions.
+ */
+NV_STATUS
+osTegraDceRegisterIpcClient
+(
+ NvU32 interfaceType,
+ void *usrCtx,
+ NvU32 *clientId
+)
+{
+ if (interfaceType == DCE_CLIENT_RM_IPC_TYPE_SYNC)
+ return nv_tegra_dce_register_ipc_client(interfaceType, usrCtx, NULL, clientId);
+ else if (interfaceType == DCE_CLIENT_RM_IPC_TYPE_EVENT)
+ return nv_tegra_dce_register_ipc_client(interfaceType, usrCtx, osTegraDceClientIpcCallback, clientId);
+ else
+ return NV_ERR_INVALID_ARGUMENT;
+}
+
+/*!
+ * @brief Performs IPC Client destroy with DCE
+ *
+ * This function is basically a wrapper to call the unix/linux layer.
+ *
+ * @param[in] clientId unique ID registered with DCE for IPC
+ *
+ * @returns NV_OK if successful,
+ * NV_ERR_NOT_SUPPORTED if the functionality is not available, or
+ * other errors as may be returned by subfunctions.
+ */
+NV_STATUS
+osTegraDceUnregisterIpcClient
+(
+ NvU32 clientId
+)
+{
+ return nv_tegra_dce_unregister_ipc_client(clientId);
+}
+
+/*!
+ * @brief Performs IPC Send/Receive to/from DCE
+ *
+ * This function is basically a wrapper to call the unix/linux layer.
+ *
+ * @param[in] clientId unique ID registered with DCE KMD for corresponding IPC type
+ * @param[in] msg structure to hold dce ipc message info
+ * @param[in] msgLength length of the message
+ *
+ * @returns NV_OK if successful,
+ * NV_ERR_NOT_SUPPORTED if the functionality is not available, or
+ * other errors as may be returned by subfunctions.
+ */
+NV_STATUS
+osTegraDceClientIpcSendRecv
+(
+ NvU32 clientId,
+ void *msg,
+ NvU32 msgLength
+)
+{
+ return nv_tegra_dce_client_ipc_send_recv(clientId, msg, msgLength);
+}
+
+/*!
+ * @brief Sends an MRQ (message-request) to BPMP
+ *
+ * The request, response, and ret parameters of this function correspond to the
+ * components of the tegra_bpmp_message struct, which BPMP uses to receive
+ * MRQs.
+ *
+ * @param[in] pGpu OBJGPU pointer
+ * @param[in] mrq MRQ_xxx ID specifying what is requested
+ * @param[in] pRequestData Pointer to request input data
+ * @param[in] requestDataSize Size of structure pointed to by pRequestData
+ * @param[out] pResponseData Pointer to response output data
+ * @param[in] responseDataSize Size of structure pointed to by pResponseData
+ * @param[out] ret MRQ return code (from "ret" element of
+ * tegra_bpmp_message struct)
+ * @param[out] apiRet Return code from tegra_bpmp_transfer call
+ *
+ * @returns NV_OK if successful,
+ * NV_ERR_NOT_SUPPORTED if the functionality is not available,
+ * NV_ERR_INVALID_POINTER if the tegra_bpmp struct pointer could not
+ * be obtained from nv, or
+ * NV_ERR_GENERIC if the tegra_bpmp_transfer call failed (see apiRet
+ * for Linux error code).
+ */
+NV_STATUS
+osTegraSocBpmpSendMrq
+(
+ OBJGPU *pGpu,
+ NvU32 mrq,
+ const void *pRequestData,
+ NvU32 requestDataSize,
+ void *pResponseData,
+ NvU32 responseDataSize,
+ NvS32 *pRet,
+ NvS32 *pApiRet
+)
+{
+ if (pGpu->getProperty(pGpu, PDB_PROP_GPU_IS_SOC_SDM))
+ {
+ return NV_ERR_NOT_SUPPORTED;
+ }
+ else if (pGpu->getProperty(pGpu, PDB_PROP_GPU_TEGRA_SOC_NVDISPLAY))
+ {
+ return nv_bpmp_send_mrq(pGpu->pOsGpuInfo,
+ mrq,
+ pRequestData,
+ requestDataSize,
+ pResponseData,
+ responseDataSize,
+ pRet,
+ pApiRet);
+ }
+ else
+ {
+ return NV_ERR_NOT_SUPPORTED;
+ }
+}
+
+/*!
+ * @brief Returns IMP-relevant data collected from other modules
+ *
+ * This function is basically a wrapper to call the unix/linux layer.
+ *
+ * @param[out] pTegraImpImportData Structure to receive the data
+ *
+ * @returns NV_OK if successful,
+ * NV_ERR_BUFFER_TOO_SMALL if the array in TEGRA_IMP_IMPORT_DATA is
+ * too small,
+ * NV_ERR_NOT_SUPPORTED if the functionality is not available, or
+ * other errors as may be returned by subfunctions.
+ */
+NV_STATUS
+osTegraSocGetImpImportData
+(
+ OBJGPU *pGpu,
+ TEGRA_IMP_IMPORT_DATA *pTegraImpImportData
+)
+{
+ if (pGpu->getProperty(pGpu, PDB_PROP_GPU_TEGRA_SOC_NVDISPLAY))
+ {
+ return nv_imp_get_import_data(pTegraImpImportData);
+ }
+ else
+ {
+ return NV_ERR_NOT_SUPPORTED;
+ }
+}
+
+/*!
+ * @brief Returns IMP-relevant data collected from UEFI
+ *
+ * This function is basically a wrapper to call the unix/linux layer.
+ *
+ * @param[in] pOsGpuInfo Per GPU Linux state
+ * @param[out] pIsoBwKbps ISO BW set by UEFI
+ * @param[out] pFloorBwKbps DRAM Floor BW set by UEFI
+ *
+ * @returns NV_OK if successful,
+ * NV_ERR_NOT_SUPPORTED if the functionality is not available, or
+ * other errors as may be returned by subfunctions.
+ */
+NV_STATUS
+osTegraSocGetImpUefiData
+(
+ OS_GPU_INFO *pOsGpuInfo,
+ NvU32 *pIsoBwKbps,
+ NvU32 *pFloorBwKbps
+)
+{
+ return nv_imp_get_uefi_data(pOsGpuInfo, pIsoBwKbps, pFloorBwKbps);
+}
+
+/*!
+ * @brief Tells BPMP whether or not RFL is valid
+ *
+ * Display HW generates an ok_to_switch signal which asserts when mempool
+ * occupancy is high enough to be able to turn off memory long enough to
+ * execute a dramclk frequency switch without underflowing display output.
+ * ok_to_switch drives the RFL ("request for latency") signal in the memory
+ * unit, and the switch sequencer waits for this signal to go active before
+ * starting a dramclk switch. However, if the signal is not valid (e.g., if
+ * display HW or SW has not been initialized yet), the switch sequencer ignores
+ * the signal. This API tells BPMP whether or not the signal is valid.
+ *
+ * @param[in] pOsGpuInfo Per GPU Linux state
+ * @param[in] bEnable True if RFL will be valid; false if invalid
+ *
+ * @returns NV_OK if successful,
+ * NV_ERR_NOT_SUPPORTED if the functionality is not available, or
+ * NV_ERR_GENERIC if some other kind of error occurred.
+ */
+NV_STATUS
+osTegraSocEnableDisableRfl
+(
+ OS_GPU_INFO *pOsGpuInfo,
+ NvBool bEnable
+)
+{
+ if (NV_IS_SOC_DISPLAY_DEVICE(pOsGpuInfo))
+ {
+ return nv_imp_enable_disable_rfl(pOsGpuInfo, bEnable);
+ }
+ else
+ {
+ return NV_ERR_NOT_SUPPORTED;
+ }
+}
+
+/*!
+ * @brief Returns max rates for display clocks passed by UEFI
+ *
+ * @param[in] pOsGpuInfo Per GPU Linux state
+ * @param[out] pMaxDispClkRateDisppll disp clock maxrate with disppll as parent
+ * @param[out] pMaxDispClkRateSppllClkouta disp clock maxrate with sppllclkouta as parent
+ * @param[out] pMaxHubClkRateSppllClkoutb hub clock maxrate with sppllclkoutb as parent
+ *
+ * @returns NV_OK if successful,
+ * NV_ERR_NOT_SUPPORTED if the functionality is not available
+ */
+NV_STATUS
+osTegraSocGetDispClockRates
+(
+ OS_GPU_INFO *pOsGpuInfo,
+ NvU32 *pMaxDispClkRateDisppll,
+ NvU32 *pMaxDispClkRateSppllClkouta,
+ NvU32 *pMaxHubClkRateSppllClkoutb
+)
+{
+ nv_state_t *nv = pOsGpuInfo;
+
+ if (NV_IS_SOC_DISPLAY_DEVICE(nv))
+ {
+ *pMaxDispClkRateDisppll = nv->clocks.max_dispclk_rate_using_disppllkhz;
+ *pMaxDispClkRateSppllClkouta = nv->clocks.max_dispclk_rate_using_sppll0clkoutakhz;
+ *pMaxHubClkRateSppllClkoutb = nv->clocks.max_hubclk_rate_using_sppll0clkoutbkhz;
+
+ return NV_OK;
+ }
+ else
+ {
+ return NV_ERR_NOT_SUPPORTED;
+ }
+}
+
+/*!
+ * @brief Allocates a specified amount of ISO memory bandwidth for display
+ *
+ * floorBandwidthKBPS is the minimum required (i.e., floor) dramclk frequency
+ * multiplied by the width of the pipe over which the display data will travel.
+ * (It is understood that the bandwidth calculated by multiplying the clock
+ * frequency by the pipe width will not be realistically achievable, due to
+ * overhead in the memory subsystem. The infrastructure will not actually use
+ * the bandwidth value, except to reverse the calculation to get the required
+ * dramclk frequency.)
+ *
+ * This function is basically a wrapper to call the unix/linux layer.
+ *
+ * @param[in] pOsGpuInfo OS specific GPU information pointer
+ * @param[in] averageBandwidthKBPS Amount of ISO memory bandwidth requested
+ * @param[in] floorBandwidhtKBPS Min required dramclk freq * pipe width
+ *
+ * @returns NV_OK if successful,
+ * NV_ERR_INSUFFICIENT_RESOURCES if one of the bandwidth values is too
+ * high, and bandwidth cannot be allocated,
+ * NV_ERR_NOT_SUPPORTED if the functionality is not available, or
+ * NV_ERR_GENERIC if some other kind of error occurred.
+ */
+NV_STATUS
+osTegraAllocateDisplayBandwidth
+(
+ OS_GPU_INFO *pOsGpuInfo,
+ NvU32 averageBandwidthKBPS,
+ NvU32 floorBandwidthKBPS
+)
+{
+ if (NV_IS_SOC_DISPLAY_DEVICE(pOsGpuInfo))
+ {
+ return nv_imp_icc_set_bw(pOsGpuInfo,
+ averageBandwidthKBPS,
+ floorBandwidthKBPS);
+ }
+ else
+ {
+ return NV_ERR_NOT_SUPPORTED;
+ }
+}
+
+/*!
+ * @brief Creates or sets up platform specific nano second resolution timer
+ *
+ * @param[in] pOsGpuInfo OS specific GPU information pointer
+ * @param[in] pTmrEvent Pointer to timer event information
+ * @param[in/out] pTimer pointer to hold high resolution timer object
+ */
+NV_STATUS
+osCreateNanoTimer
+(
+ OS_GPU_INFO *pOsGpuInfo,
+ void *pTmrEvent,
+ void **pTimer
+)
+{
+ nv_create_nano_timer(pOsGpuInfo, pTmrEvent, (nv_nano_timer_t **)pTimer);
+ return NV_OK;
+}
+
+/*!
+ * @brief Starts platform specific nano second resolution timer
+ *
+ * @param[in] pOsGpuInfo OS specific GPU information pointer
+ * @param[in] pTimer pointer to high resolution timer object
+ * @param[in] timeNs Relative time in nano seconds
+ */
+NV_STATUS
+osStartNanoTimer
+(
+ OS_GPU_INFO *pOsGpuInfo,
+ void *pTimer,
+ NvU64 timeNs
+)
+{
+ nv_start_nano_timer(pOsGpuInfo, (nv_nano_timer_t *)pTimer, timeNs);
+ return NV_OK;
+}
+
+/*!
+ * @brief Cancels platform specific nano second resolution timer
+ *
+ * @param[in] pOsGpuInfo OS specific GPU information pointer
+ * @param[in] pTimer pointer to timer object
+ */
+NV_STATUS
+osCancelNanoTimer
+(
+ OS_GPU_INFO *pOsGpuInfo,
+ void *pTimer
+)
+{
+ nv_cancel_nano_timer(pOsGpuInfo, (nv_nano_timer_t *)pTimer);
+ return NV_OK;
+}
+
+/*!
+ * @brief Destroys & cancels platform specific nano second resolution timer
+ *
+ *
+ * @param[in] pGpu Device of interest
+ * @param[in] pTimer pointer to timer object
+ */
+NV_STATUS
+osDestroyNanoTimer
+(
+ OS_GPU_INFO *pOsGpuInfo,
+ void *pTimer
+)
+{
+ nv_destroy_nano_timer(pOsGpuInfo, (nv_nano_timer_t *)pTimer);
+ return NV_OK;
+}
+
+
+NvBool osIsNonPreemptableDebuggerSessionActive(OBJGPU *pGpu)
+{
+ NvU32 data = 0;
+ if ((osReadRegistryDword(pGpu, NV_REG_STR_RM_NON_PREEMTABLE_DEBUGGER_SESSION_ACTIVE, &data) == NV_OK) && (data == NV_REG_STR_RM_NON_PREEMTABLE_DEBUGGER_SESSION_ACTIVE_ENABLE))
+ {
+ return NV_TRUE;
+ }
+
+ return NV_FALSE;
+}
+
+/*!
+ * @brief Get number of dpAux instances.
+ * It is wrapper function to call unix/linux layer.
+ *
+ * @param[in] pGpu GPU object pointer
+ * @param[out] pNumIntances Number of dpAux instances.
+ *
+ * @returns NV_STATUS, NV_OK if success,
+ * NV_ERR_GENERIC, if error
+ * NV_ERR_NOT_SUPPORTED, for unsupported platforms
+ */
+
+NV_STATUS
+osGetTegraNumDpAuxInstances
+(
+ OS_GPU_INFO *pOsGpuInfo,
+ NvU32 *pNumIntances
+)
+{
+ if (NV_IS_SOC_DISPLAY_DEVICE(pOsGpuInfo))
+ {
+ return nv_get_num_dpaux_instances(pOsGpuInfo, pNumIntances);
+ }
+ else
+ {
+ return NV_ERR_NOT_SUPPORTED;
+ }
+}
+
+/*
+ * @brief Return the priv Data of current IRQ.
+ * It is wrapper function to call unix/linux layer.
+ *
+ * @param[in] pGpu Device of interest
+ * @param[out] pPrivData privData of current IRQ
+ *
+ * @returns NV_STATUS, NV_OK if success,
+ * NV_ERR_GENERIC, if error
+ * NV_ERR_NOT_SUPPORTED, for unsupported platforms
+ */
+NV_STATUS
+osGetCurrentIrqPrivData
+(
+ OS_GPU_INFO *pOsGpuInfo,
+ NvU32 *pPrivData
+)
+{
+ if (NV_IS_SOC_DISPLAY_DEVICE(pOsGpuInfo))
+ {
+ return nv_get_current_irq_priv_data(pOsGpuInfo, pPrivData);
+ }
+ else
+ {
+ return NV_ERR_NOT_SUPPORTED;
+ }
+}
+
+/*!
+ * @brief Get the brightness level
+ * It is wrapper function to call unix/linux layer.
+ *
+ * @param[in] pGpu GPU object pointer
+ * @param[out] brightness Pointer to brightness level
+ *
+ * @returns NV_STATUS, NV_OK if success,
+ * NV_ERR_GENERIC, if error
+ * NV_ERR_NOT_SUPPORTED, for unsupported platforms
+ */
+NV_STATUS
+osGetTegraBrightnessLevel
+(
+ OS_GPU_INFO *pOsGpuInfo,
+ NvU32 *brightness
+)
+{
+ if (NV_IS_SOC_DISPLAY_DEVICE(pOsGpuInfo))
+ {
+ return nv_get_tegra_brightness_level(pOsGpuInfo, brightness);
+ }
+ else
+ {
+ return NV_ERR_NOT_SUPPORTED;
+ }
+}
+
+/*!
+ * @brief Set the brightness level
+ * It is wrapper function to call unix/linux layer.
+ *
+ * @param[in] pGpu GPU object pointer
+ * @param[out] brightness brightness level
+ *
+ * @returns NV_STATUS, NV_OK if success,
+ * NV_ERR_GENERIC, if error
+ * NV_ERR_NOT_SUPPORTED, for unsupported platforms
+ */
+NV_STATUS
+osSetTegraBrightnessLevel
+(
+ OS_GPU_INFO *pOsGpuInfo,
+ NvU32 brightness
+)
+{
+ if (NV_IS_SOC_DISPLAY_DEVICE(pOsGpuInfo))
+ {
+ return nv_set_tegra_brightness_level(pOsGpuInfo, brightness);
+ }
+ else
+ {
+ return NV_ERR_NOT_SUPPORTED;
+ }
+}
+
+/* @brief Gets syncpoint aperture information
+ *
+ * @param[in] OS_GPU_INFO OS specific GPU information pointer
+ * @param[in] syncpointId
+ * @param[out] *physAddr
+ * @param[out] *limit
+ * @param[out] *offset
+ */
+NV_STATUS
+osGetSyncpointAperture
+(
+ OS_GPU_INFO *pOsGpuInfo,
+ NvU32 syncpointId,
+ NvU64 *physAddr,
+ NvU64 *limit,
+ NvU32 *offset
+)
+{
+ return nv_get_syncpoint_aperture(syncpointId, physAddr, limit, offset);
+}
+
+/*!
+ * @brief Enable PCIe AtomicOp Requester Enable and return
+ * the completer side capabilities that the requester can send.
+ *
+ * @param[in] pOsGpuInfo OS_GPU_INFO OS specific GPU information pointer
+ * @param[out] pMask mask of supported atomic size, including one or more of:
+ * OS_PCIE_CAP_MASK_REQ_ATOMICS_32
+ * OS_PCIE_CAP_MASK_REQ_ATOMICS_64
+ * OS_PCIE_CAP_MASK_REQ_ATOMICS_128
+ *
+ * @returns NV_STATUS, NV_OK if success
+ * NV_ERR_NOT_SUPPORTED if platform doesn't support this
+ * feature.
+ * NV_ERR_GENERIC for any other error
+ */
+
+NV_STATUS
+osConfigurePcieReqAtomics
+(
+ OS_GPU_INFO *pOsGpuInfo,
+ NvU32 *pMask
+)
+{
+ if (pMask)
+ {
+ *pMask = 0U;
+ if (pOsGpuInfo)
+ {
+ if (os_enable_pci_req_atomics(pOsGpuInfo->handle,
+ OS_INTF_PCIE_REQ_ATOMICS_32BIT) == NV_OK)
+ *pMask |= OS_PCIE_CAP_MASK_REQ_ATOMICS_32;
+ if (os_enable_pci_req_atomics(pOsGpuInfo->handle,
+ OS_INTF_PCIE_REQ_ATOMICS_64BIT) == NV_OK)
+ *pMask |= OS_PCIE_CAP_MASK_REQ_ATOMICS_64;
+ if (os_enable_pci_req_atomics(pOsGpuInfo->handle,
+ OS_INTF_PCIE_REQ_ATOMICS_128BIT) == NV_OK)
+ *pMask |= OS_PCIE_CAP_MASK_REQ_ATOMICS_128;
+
+ if (*pMask != 0)
+ return NV_OK;
+ }
+ }
+ return NV_ERR_NOT_SUPPORTED;
+}
+
+/*!
+ * @brief Check GPU is accessible or not
+ *
+ * @param[in] pGpu GPU object pointer
+ *
+ * @returns NVBool, Returns TRUE if the GPU is accessible,
+ * FALSE, if error
+ */
+NvBool
+osIsGpuAccessible
+(
+ OBJGPU *pGpu
+)
+{
+ return nv_is_gpu_accessible(NV_GET_NV_STATE(pGpu));
+}
+
+/*!
+ * @brief Check whether GPU has received a shutdown notification from the OS
+ */
+NvBool
+osIsGpuShutdown
+(
+ OBJGPU *pGpu
+)
+{
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ return nv ? nv->is_shutdown : NV_TRUE;
+}
+
+/*!
+ * @brief Check GPU OS info matches
+ *
+ * @param[in] pGpu GPU object pointer
+ *
+ * @returns NVBool, Returns TRUE if matched.
+ */
+NvBool
+osMatchGpuOsInfo
+(
+ OBJGPU *pGpu,
+ void *pOsInfo
+)
+{
+ return nv_match_gpu_os_info(NV_GET_NV_STATE(pGpu), pOsInfo);
+}
+
+/*!
+ * @brief Release GPU OS info.
+ *
+ * @param[in] pOsInfo GPU OS info pointer
+ *
+ * @returns void
+ */
+void
+osReleaseGpuOsInfo
+(
+ void *pOsInfo
+)
+{
+ nv_put_file_private(pOsInfo);
+}
+
+/*!
+ * @brief Get free, total memory of a NUMA node by NUMA node ID from kernel.
+ *
+ * @param[in] numaId NUMA node ID.
+ * @param[out] free_memory_bytes free memory in bytes.
+ * @param[out] total_memory_bytes total memory in bytes.
+ *
+ */
+void
+osGetNumaMemoryUsage
+(
+ NvS32 numaId,
+ NvU64 *free_memory_bytes,
+ NvU64 *total_memory_bytes
+)
+{
+ NV_STATUS status = os_get_numa_node_memory_usage(numaId,
+ free_memory_bytes,
+ total_memory_bytes);
+ NV_ASSERT(status == NV_OK);
+}
+
+/*!
+ * @brief Add GPU memory as a NUMA node.
+ *
+ * @param[in/out] pOsGpuInfo OS specific GPU information pointer
+ * @param[in] offset start offset of the partition within FB
+ * @param[in] size size of the partition
+ * @param[out] pNumaNodeId OS NUMA node id for the added memory.
+ *
+ * @returns NV_OK if all is okay. Otherwise an error-specific value.
+ *
+ */
+NV_STATUS
+osNumaAddGpuMemory
+(
+ OS_GPU_INFO *pOsGpuInfo,
+ NvU64 offset,
+ NvU64 size,
+ NvU32 *pNumaNodeId
+)
+{
+ nv_state_t *nv = pOsGpuInfo;
+
+ return os_numa_add_gpu_memory(nv->handle, offset, size, pNumaNodeId);
+}
+
+/*!
+ * @brief Remove a particular SMC partition's GPU memory from OS kernel.
+ *
+ * Remove GPU memory from the OS kernel that is earlier added as a NUMA node
+ * to the kernel in platforms where GPU is coherently connected to the CPU.
+ *
+ * @param[in/out] pOsGpuInfo OS_GPU_INFO OS specific GPU information pointer
+ * @param[in] offset start offset of the partition within FB
+ * @param[in] size size of the partition
+ * @param[in] numaNodeId OS NUMA node id of the memory to be removed.
+ *
+ */
+void
+osNumaRemoveGpuMemory
+(
+ OS_GPU_INFO *pOsGpuInfo,
+ NvU64 offset,
+ NvU64 size,
+ NvU32 numaNodeId
+)
+{
+ nv_state_t *nv = pOsGpuInfo;
+
+ NV_STATUS status = os_numa_remove_gpu_memory(nv->handle, offset, size, numaNodeId);
+ NV_ASSERT(status == NV_OK);
+
+ return;
+}
+
+NvBool
+osDmabufIsSupported(void)
+{
+ return os_dma_buf_enabled;
+}
+
+NV_STATUS
+osGetEgmInfo
+(
+ OBJGPU *pGpu,
+ NvU64 *pPhysAddr,
+ NvU64 *pSize,
+ NvS32 *pNodeId
+)
+{
+ return nv_get_egm_info(NV_GET_NV_STATE(pGpu), pPhysAddr, pSize, pNodeId);
+}
+
+/*!
+ * @brief Offline (i.e., blacklist) the page containing a given address from OS kernel.
+ *
+ * @param[in] address Address (SPA) of the page to be offlined
+ *
+ */
+NV_STATUS
+osOfflinePageAtAddress
+(
+ NvU64 address
+)
+{
+ return os_offline_page_at_address(address);
+}
+
+void osAllocatedRmClient(void *pOsInfo)
+{
+ nv_file_private_t* nvfp = (nv_file_private_t*)pOsInfo;
+
+ if (nvfp != NULL)
+ nvfp->bCleanupRmapi = NV_TRUE;
+}
+
+/*!
+ * @brief Update variable to indicate console managed by drm driver.
+ *
+ * @param[in] OBJGPU GPU object pointer
+ *
+ * @returns void
+ */
+void
+osDisableConsoleManagement
+(
+ OBJGPU *pGpu
+)
+{
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+
+ nv->client_managed_console = NV_TRUE;
+}
+
+/*
+ * @brief Return NV_TRUE if GPU is configured as CXL device.
+ *
+ * @param[in] pGpu GPU object pointer
+ */
+NvBool
+osGpuIsCxlDevice
+(
+ OBJGPU *pGpu
+)
+{
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+
+ return nv->is_cxl_dev;
+}
+
+/*
+ * @brief Disabel CXL cache and perform writeback and invalidate for CXL device.
+ *
+ * @param[in] pGpu GPU object pointer
+ * @param[in] bEnableCache Enable/Disable flag
+ */
+void
+osCxlSetCaching
+(
+ OBJGPU *pGpu,
+ NvBool bEnableCache
+)
+{
+
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+
+ nv_pci_cxl_set_caching(nv, bEnableCache);
+}
diff --git a/userspace/sdks/nv570/nvalloc/unix/src/osapi.c b/userspace/sdks/nv570/nvalloc/unix/src/osapi.c
new file mode 100644
index 0000000..a3d614d
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/src/osapi.c
@@ -0,0 +1,6284 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 1999-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+
+
+
+#include <nv_ref.h>
+#include <nv.h>
+#include <nv_escape.h>
+#include <nv-priv.h>
+#include <os/os.h>
+#include <osapi.h>
+#include <class/cl0000.h>
+#include <rmosxfac.h> // Declares RmInitRm().
+#include "gpu/gpu.h"
+#include "gps.h"
+#include <platform/chipset/chipset.h>
+
+#include <gpu/timer/objtmr.h>
+#include <gpu/subdevice/subdevice.h>
+#include <mem_mgr/mem.h>
+#include "kernel/gpu/mem_mgr/mem_mgr.h"
+
+#include <gpu/mem_sys/kern_mem_sys.h>
+
+#include <diagnostics/journal.h>
+#include <nvrm_registry.h>
+
+#include <nvUnixVersion.h>
+#include <gpu_mgr/gpu_mgr.h>
+#include <core/thread_state.h>
+#include <platform/acpi_common.h>
+#include <core/locks.h>
+#include "platform/sli/sli.h"
+
+#include <mem_mgr/p2p.h>
+
+#include "rmapi/exports.h"
+#include "rmapi/rmapi_utils.h"
+#include "rmapi/rs_utils.h"
+#include "rmapi/resource_fwd_decls.h"
+#include <nv-kernel-rmapi-ops.h>
+#include <rmobjexportimport.h>
+#include "nv-reg.h"
+#include "nv-firmware-registry.h"
+#include "core/hal_mgr.h"
+#include "gpu/device/device.h"
+
+#include "resserv/rs_server.h"
+#include "resserv/rs_client.h"
+#include "resserv/rs_resource.h"
+#include "gpu/gpu_uuid.h"
+
+#include "platform/chipset/pci_pbi.h"
+
+#include "ctrl/ctrl0000/ctrl0000system.h"
+#include "ctrl/ctrl0073/ctrl0073dp.h"
+#include "ctrl/ctrl0073/ctrl0073system.h"
+#include "ctrl/ctrl0073/ctrl0073specific.h"
+#include "ctrl/ctrl2080/ctrl2080bios.h"
+#include "ctrl/ctrl2080/ctrl2080fb.h"
+#include "ctrl/ctrl2080/ctrl2080perf.h"
+#include "ctrl/ctrl2080/ctrl2080gpu.h"
+#include "ctrl/ctrl402c.h"
+
+#include "g_nv_name_released.h" // released chip entries from nvChipAutoFlags.h
+
+#include <virtualization/hypervisor/hypervisor.h>
+
+#include "gpu/bus/kern_bus.h"
+
+//
+// If timer callback comes when PM resume is in progress, then it can't be
+// serviced. The timer needs to be rescheduled in this case. This time controls
+// the duration of rescheduling.
+//
+#define TIMER_RESCHED_TIME_DURING_PM_RESUME_NS (100 * 1000 * 1000)
+
+static void RmInflatePageArray(
+ RmPhysAddr *pteArray,
+ NvU64 pageCountFrom,
+ NvU64 pageSizeFrom,
+ NvU64 pageCountTo,
+ NvU64 pageSizeTo);
+static void RmDeflatePageArray(
+ RmPhysAddr *pteArray,
+ NvU64 pageCountFrom,
+ NvU64 pageSizeFrom,
+ NvU64 pageCountTo,
+ NvU64 pageSizeTo);
+
+static void RmInflatePageArray(
+ RmPhysAddr *pteArray,
+ NvU64 pageCountFrom,
+ NvU64 pageSizeFrom,
+ NvU64 pageCountTo,
+ NvU64 pageSizeTo)
+{
+ NV_ASSERT(pageCountFrom <= pageCountTo);
+ NV_ASSERT(pageSizeFrom >= pageSizeTo);
+ NvUPtr dstPageIdx, dstPageOffset;
+ NvU64 i;
+ // convert the idx from pageCount_to to pageCount_from.
+ NvU64 dstPageShift = NV_SRC_TO_DST_PAGE_SHIFT(pageSizeTo, pageSizeFrom);
+
+ //
+ // We can do the translation in place by moving backwards, since there
+ // will always be more RM pages than OS pages
+ //
+ for (i = pageCountTo - 1; i != NV_U64_MAX; i--)
+ {
+ dstPageIdx = i >> dstPageShift;
+ dstPageOffset = (i & ((1 << dstPageShift) - 1)) *
+ pageSizeTo;
+ pteArray[i] = pteArray[dstPageIdx] + dstPageOffset;
+ }
+}
+
+static void RmDeflatePageArray(
+ RmPhysAddr *pteArray,
+ NvU64 pageCountFrom,
+ NvU64 pageSizeFrom,
+ NvU64 pageCountTo,
+ NvU64 pageSizeTo)
+{
+ NV_ASSERT(pageCountFrom >= pageCountTo);
+ NV_ASSERT(pageSizeFrom <= pageSizeTo);
+ NvU64 i;
+
+ for (i = 0; i < pageCountTo; i++)
+ {
+ pteArray[i] = pteArray[(i << NV_SRC_TO_DST_PAGE_SHIFT(pageSizeFrom, pageSizeTo))];
+ }
+
+ // Zero out the rest of the addresses, which are now invalid
+ portMemSet(pteArray + i, 0, sizeof(*pteArray) * (pageCountFrom - i));
+}
+
+void convertPageArrayBetweenOsAndRm(
+ RmPhysAddr *pteArray,
+ NvU64 pageCountFrom,
+ NvU64 pageSizeFrom,
+ NvU64 pageCountTo,
+ NvU64 pageSizeTo,
+ NvU64 *newPageCountTo)
+{
+ if (pageSizeFrom < pageSizeTo)
+ {
+ RmDeflatePageArray(pteArray,
+ pageCountFrom,
+ pageSizeFrom,
+ pageCountTo,
+ pageSizeTo
+ );
+ if (newPageCountTo)
+ {
+ *newPageCountTo = pageCountTo;
+ }
+ }
+ else if (pageSizeFrom > pageSizeTo)
+ {
+ RmInflatePageArray(pteArray,
+ pageCountFrom,
+ pageSizeFrom,
+ pageCountTo,
+ pageSizeTo
+ );
+ }
+}
+
+//
+// Helper function which can be called before doing any RM control
+// This function:
+//
+// a. Performs threadStateInit().
+// b. Acquires API lock.
+// c. Checks if RMAPI client handle is valid (i.e. RM is initialized) and
+// returns early if RMAPI client handle is invalid.
+// d. Increments the dynamic power refcount. If GPU is in RTD3 suspended
+// state, then it will wake-up the GPU.
+// e. Returns the RMAPI interface handle.
+//
+// This function should be called only when caller doesn't have acquired API
+// lock. Caller needs to use RmUnixRmApiEpilogue() after RM control, if
+// RmUnixRmApiPrologue() is successful.
+//
+RM_API *RmUnixRmApiPrologue(nv_state_t *pNv, THREAD_STATE_NODE *pThreadNode, NvU32 module)
+{
+ threadStateInit(pThreadNode, THREAD_STATE_FLAGS_NONE);
+
+ if ((rmapiLockAcquire(API_LOCK_FLAGS_NONE, module)) == NV_OK)
+ {
+ if ((pNv->rmapi.hClient != 0) &&
+ (os_ref_dynamic_power(pNv, NV_DYNAMIC_PM_FINE) == NV_OK))
+ {
+ return rmapiGetInterface(RMAPI_API_LOCK_INTERNAL);
+ }
+
+ rmapiLockRelease();
+ }
+
+ threadStateFree(pThreadNode, THREAD_STATE_FLAGS_NONE);
+
+ return NULL;
+}
+
+//
+// Helper function which can be called after doing RM control, if
+// caller has used RmUnixRmApiPrologue() helper function. This function:
+//
+// a. Decrements the dynamic power refcount.
+// b. Release API lock.
+// c. Performs threadStateFree().
+//
+void RmUnixRmApiEpilogue(nv_state_t *pNv, THREAD_STATE_NODE *pThreadNode)
+{
+ os_unref_dynamic_power(pNv, NV_DYNAMIC_PM_FINE);
+ rmapiLockRelease();
+ threadStateFree(pThreadNode, THREAD_STATE_FLAGS_NONE);
+}
+
+NvBool RmGpuHasIOSpaceEnabled(nv_state_t * nv)
+{
+ NvU16 val;
+ NvBool has_io;
+ os_pci_read_word(nv->handle, NV_CONFIG_PCI_NV_1, &val);
+ has_io = FLD_TEST_DRF(_CONFIG, _PCI_NV_1, _IO_SPACE, _ENABLED, val);
+ return has_io;
+}
+
+// This is a stub function for unix
+void osHandleDeferredRecovery(
+ OBJGPU *pGpu
+)
+{
+
+}
+
+// This is a stub function for unix
+NvBool osIsSwPreInitOnly
+(
+ OS_GPU_INFO *pOsGpuInfo
+)
+{
+ return NV_FALSE;
+}
+
+const NvU8 * RmGetGpuUuidRaw(
+ nv_state_t *pNv
+)
+{
+ NV_STATUS rmStatus;
+ OBJGPU *pGpu = NULL;
+ NvU32 gidFlags;
+ NvBool isApiLockTaken = NV_FALSE;
+
+ if (pNv->nv_uuid_cache.valid)
+ return pNv->nv_uuid_cache.uuid;
+
+ if (!rmapiLockIsOwner())
+ {
+ rmStatus = rmapiLockAcquire(RMAPI_LOCK_FLAGS_READ, RM_LOCK_MODULES_GPU);
+ if (rmStatus != NV_OK)
+ {
+ return NULL;
+ }
+
+ isApiLockTaken = NV_TRUE;
+ }
+
+ pGpu = NV_GET_NV_PRIV_PGPU(pNv);
+
+ //
+ // PBI is not present in simulation and the loop inside
+ // pciPbiReadUuid takes up considerable amount of time in
+ // simulation environment during RM load.
+ //
+ if (pGpu && IS_SIMULATION(pGpu))
+ {
+ rmStatus = NV_ERR_NOT_SUPPORTED;
+ }
+ else
+ {
+ if (!pNv->nv_uuid_cache.pci_uuid_read_attempted)
+ {
+ rmStatus = pciPbiReadUuid(pNv->handle, pNv->nv_uuid_cache.uuid);
+ pNv->nv_uuid_cache.pci_uuid_read_attempted = NV_TRUE;
+ pNv->nv_uuid_cache.pci_uuid_status = rmStatus;
+ }
+ else
+ {
+ rmStatus = pNv->nv_uuid_cache.pci_uuid_status;
+ }
+ }
+
+ if (rmStatus == NV_OK)
+ {
+ rmStatus = gpumgrSetUuid(pNv->gpu_id, pNv->nv_uuid_cache.uuid);
+ if (rmStatus != NV_OK)
+ {
+ goto err;
+ }
+
+ pNv->nv_uuid_cache.valid = NV_TRUE;
+ goto done;
+ }
+ else if (rmStatus == NV_ERR_NOT_SUPPORTED)
+ {
+ nv_printf(NV_DBG_INFO,
+ "NVRM: PBI is not supported for GPU " NV_PCI_DEV_FMT "\n",
+ NV_PCI_DEV_FMT_ARGS(pNv));
+ }
+
+ gidFlags = DRF_DEF(2080_GPU_CMD,_GPU_GET_GID_FLAGS,_TYPE,_SHA1)
+ | DRF_DEF(2080_GPU_CMD,_GPU_GET_GID_FLAGS,_FORMAT,_BINARY);
+
+ if (!pGpu)
+ goto err;
+
+ rmStatus = gpuGetGidInfo(pGpu, NULL, NULL, gidFlags);
+ if (rmStatus != NV_OK)
+ goto err;
+
+ if (!pGpu->gpuUuid.isInitialized)
+ goto err;
+
+ // copy the uuid from the OBJGPU uuid cache
+ os_mem_copy(pNv->nv_uuid_cache.uuid, pGpu->gpuUuid.uuid, GPU_UUID_LEN);
+ pNv->nv_uuid_cache.valid = NV_TRUE;
+
+done:
+ if (isApiLockTaken)
+ {
+ rmapiLockRelease();
+ }
+
+ return pNv->nv_uuid_cache.uuid;
+
+err:
+ if (isApiLockTaken)
+ {
+ rmapiLockRelease();
+ }
+
+ return NULL;
+}
+
+static NV_STATUS RmGpuUuidRawToString(
+ const NvU8 *pGidData,
+ char *pBuf,
+ NvU32 bufLen
+)
+{
+ NvU8 *pGidString;
+ NvU32 GidStrlen;
+ NV_STATUS rmStatus;
+ NvU32 gidFlags;
+
+ gidFlags = DRF_DEF(2080_GPU_CMD, _GPU_GET_GID_FLAGS, _FORMAT, _ASCII) |
+ DRF_DEF(2080_GPU_CMD, _GPU_GET_GID_FLAGS, _TYPE, _SHA1);
+
+ rmStatus = transformGidToUserFriendlyString(pGidData, RM_SHA1_GID_SIZE,
+ &pGidString, &GidStrlen,
+ gidFlags,
+ RM_UUID_PREFIX_GPU);
+ if (rmStatus != NV_OK)
+ return rmStatus;
+
+ if (bufLen >= GidStrlen)
+ portMemCopy(pBuf, bufLen, pGidString, GidStrlen);
+ else
+ rmStatus = NV_ERR_BUFFER_TOO_SMALL;
+
+ portMemFree((void *)pGidString);
+
+ return rmStatus;
+}
+
+// This function should be called with the API and GPU locks already acquired.
+void
+RmLogGpuCrash(OBJGPU *pGpu)
+{
+ NvBool bGpuIsLost, bGpuIsConnected;
+
+ //
+ // Re-evaluate whether or not the GPU is accessible. This could be called
+ // from a recovery context where the OS has re-enabled MMIO for the device.
+ // This happens during EEH processing on IBM Power + Linux, and marking
+ // the device as connected again will allow rcdbAddRmGpuDump() to collect
+ // more GPU state.
+ //
+ bGpuIsLost = pGpu->getProperty(pGpu, PDB_PROP_GPU_IS_LOST);
+ bGpuIsConnected = pGpu->getProperty(pGpu, PDB_PROP_GPU_IS_CONNECTED);
+ if (!bGpuIsConnected || bGpuIsLost)
+ {
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+ NvU32 pmcBoot0 = NV_PRIV_REG_RD32(nv->regs->map_u, NV_PMC_BOOT_0);
+ if (pmcBoot0 == nvp->pmc_boot_0)
+ {
+ pGpu->setProperty(pGpu, PDB_PROP_GPU_IS_CONNECTED, NV_TRUE);
+ pGpu->setProperty(pGpu, PDB_PROP_GPU_IS_LOST, NV_FALSE);
+ }
+ }
+
+ {
+ //
+ // Log the engine data to the Journal object, to be pulled out later. This
+ // will return NV_WARN_MORE_PROCESSING_REQUIRED if the dump needed to be
+ // deferred to a passive IRQL. We still log the crash dump as being created
+ // in that case since it (should) be created shortly thereafter, and
+ // there's currently not a good way to print the below notification
+ // publicly from the core RM when the DPC completes.
+ //
+ NV_STATUS status = rcdbAddRmGpuDump(pGpu);
+ if (status != NV_OK && status != NV_WARN_MORE_PROCESSING_REQUIRED)
+ {
+ NV_PRINTF(LEVEL_ERROR,
+ "%s: failed to save GPU crash data\n", __FUNCTION__);
+ }
+ else
+ {
+ nv_printf(NV_DBG_ERRORS,
+ "NVRM: A GPU crash dump has been created. If possible, please run\n"
+ "NVRM: nvidia-bug-report.sh as root to collect this data before\n"
+ "NVRM: the NVIDIA kernel module is unloaded.\n");
+ if (!IS_GSP_CLIENT(pGpu) && hypervisorIsVgxHyper())
+ {
+ nv_printf(NV_DBG_ERRORS, "NVRM: Dumping nvlogs buffers\n");
+ nvlogDumpToKernelLog(NV_FALSE);
+ }
+ }
+ }
+
+ // Restore the disconnected properties, if they were reset
+ pGpu->setProperty(pGpu, PDB_PROP_GPU_IS_CONNECTED, bGpuIsConnected);
+ pGpu->setProperty(pGpu, PDB_PROP_GPU_IS_LOST, bGpuIsLost);
+
+ // Restore persistence mode to the way it was prior to the crash
+ osModifyGpuSwStatePersistence(pGpu->pOsGpuInfo,
+ pGpu->getProperty(pGpu, PDB_PROP_GPU_PERSISTENT_SW_STATE));
+}
+
+static void free_os_event_under_lock(nv_event_t *event)
+{
+ portAtomicSetS32(&event->active, 0);
+
+ // If refcount > 0, event will be freed by osDereferenceObjectCount
+ // when the last associated RM event is freed.
+ if (event->refcount == 0)
+ portMemFree(event);
+}
+
+static void free_os_events(
+ nv_file_private_t *nvfp,
+ NvHandle client
+)
+{
+ nv_state_t *nv = nv_get_ctl_state();
+ nv_event_t **pprev;
+
+ portSyncSpinlockAcquire(nv->event_spinlock);
+
+ pprev = &nv->event_list;
+ while (*pprev != NULL)
+ {
+ nv_event_t *cur = *pprev;
+ //
+ // XXX We must be called from either rm_client_free_os_events() or
+ // RmFreeUnusedClients() for this to work.
+ //
+ if ((cur->hParent == client) || (cur->nvfp == nvfp))
+ {
+ *pprev = cur->next;
+ free_os_event_under_lock(cur);
+ }
+ else
+ {
+ pprev = &cur->next;
+ }
+ }
+
+ portSyncSpinlockRelease(nv->event_spinlock);
+}
+
+static NV_STATUS get_os_event_data(
+ nv_file_private_t *nvfp,
+ NvP64 pEvent,
+ NvU32 *MoreEvents
+)
+{
+ nv_event_t nv_event;
+ NvUnixEvent *nv_unix_event;
+ NV_STATUS status;
+
+ status = os_alloc_mem((void**)&nv_unix_event, sizeof(NvUnixEvent));
+ if (status != NV_OK)
+ return status;
+
+ status = nv_get_event(nvfp, &nv_event, MoreEvents);
+ if (status != NV_OK)
+ {
+ status = NV_ERR_OPERATING_SYSTEM;
+ goto done;
+ }
+
+ os_mem_set(nv_unix_event, 0, sizeof(NvUnixEvent));
+ nv_unix_event->hObject = nv_event.hObject;
+ nv_unix_event->NotifyIndex = nv_event.index;
+ nv_unix_event->info32 = nv_event.info32;
+ nv_unix_event->info16 = nv_event.info16;
+
+ status = os_memcpy_to_user(NvP64_VALUE(pEvent), nv_unix_event, sizeof(NvUnixEvent));
+done:
+ os_free_mem(nv_unix_event);
+ return status;
+}
+
+void rm_client_free_os_events(
+ NvHandle client
+)
+{
+ free_os_events(NULL, client);
+}
+
+void RmFreeUnusedClients(
+ nv_state_t *nv,
+ nv_file_private_t *nvfp
+)
+{
+ NvU32 *pClientList;
+ NvU32 numClients, i;
+ NV_STATUS status;
+ RM_API *pRmApi = rmapiGetInterface(RMAPI_API_LOCK_INTERNAL);
+
+ //
+ // The 'nvfp' pointer uniquely identifies an open instance in kernel space
+ // and the kernel interface layer guarantees that we are not called before
+ // the associated nvfp descriptor is closed. We can thus safely free
+ // abandoned clients with matching 'nvfp' pointers.
+ //
+ status = rmapiGetClientHandlesFromOSInfo(nvfp, &pClientList, &numClients);
+ if (status != NV_OK)
+ {
+ numClients = 0;
+ }
+
+ for (i = 0; i < numClients; ++i)
+ {
+ NV_PRINTF(LEVEL_INFO, "freeing abandoned client 0x%x\n",
+ pClientList[i]);
+
+ }
+
+ if (numClients != 0)
+ {
+ pRmApi->DisableClients(pRmApi, pClientList, numClients);
+
+ portMemFree(pClientList);
+ }
+
+ // Clean up any remaining events using this nvfp.
+ free_os_events(nvfp, 0);
+}
+
+static void RmUnbindLock(
+ nv_state_t *nv
+)
+{
+ OBJGPU *pGpu = NV_GET_NV_PRIV_PGPU(nv);
+
+ if ((pGpu == NULL) || (gpuGetUserClientCount(pGpu) == 0))
+ {
+ nv->flags |= NV_FLAG_UNBIND_LOCK;
+ }
+}
+
+static NV_STATUS allocate_os_event(
+ NvHandle hParent,
+ nv_file_private_t *nvfp,
+ NvU32 fd
+)
+{
+ nv_state_t *nv = nv_get_ctl_state();
+ NvU32 status = NV_OK;
+ nv_event_t *event;
+
+ nv_event_t *new_event = portMemAllocNonPaged(sizeof(nv_event_t));
+ if (new_event == NULL)
+ {
+ status = NV_ERR_NO_MEMORY;
+ goto done;
+ }
+
+ new_event->hParent = hParent;
+ new_event->nvfp = nvfp;
+ new_event->fd = fd;
+ portAtomicSetS32(&new_event->active, 1);
+ new_event->refcount = 0;
+
+ portSyncSpinlockAcquire(nv->event_spinlock);
+ for (event = nv->event_list; event; event = event->next)
+ {
+ // Only one event may be associated with a given fd.
+ if (event->hParent == hParent && event->fd == fd)
+ {
+ status = NV_ERR_INVALID_ARGUMENT;
+ portSyncSpinlockRelease(nv->event_spinlock);
+ goto done;
+ }
+ }
+
+ new_event->next = nv->event_list;
+ nv->event_list = new_event;
+ nvfp->bCleanupRmapi = NV_TRUE;
+ portSyncSpinlockRelease(nv->event_spinlock);
+
+done:
+ if (status == NV_OK)
+ {
+ NV_PRINTF(LEVEL_INFO, "allocated OS event:\n");
+ NV_PRINTF(LEVEL_INFO, " hParent: 0x%x\n", hParent);
+ NV_PRINTF(LEVEL_INFO, " fd: %d\n", fd);
+ }
+ else
+ {
+ NV_PRINTF(LEVEL_INFO, "failed to allocate OS event: 0x%08x\n", status);
+ status = NV_ERR_INSUFFICIENT_RESOURCES;
+ portMemFree(new_event);
+ }
+
+ return status;
+}
+
+static NV_STATUS free_os_event(
+ NvHandle hParent,
+ NvU32 fd
+)
+{
+ nv_state_t *nv = nv_get_ctl_state();
+ nv_event_t *event, *tmp;
+ NV_STATUS result;
+
+ portSyncSpinlockAcquire(nv->event_spinlock);
+ tmp = event = nv->event_list;
+ while (event)
+ {
+ if ((event->fd == fd) && (event->hParent == hParent))
+ {
+ if (event == nv->event_list)
+ nv->event_list = event->next;
+ else
+ tmp->next = event->next;
+ break;
+ }
+ tmp = event;
+ event = event->next;
+ }
+
+ if (event != NULL)
+ {
+ free_os_event_under_lock(event);
+ result = NV_OK;
+ }
+ else
+ result = NV_ERR_INVALID_EVENT;
+ portSyncSpinlockRelease(nv->event_spinlock);
+
+ if (result == NV_OK)
+ {
+ NV_PRINTF(LEVEL_INFO, "freed OS event:\n");
+ NV_PRINTF(LEVEL_INFO, " hParent: 0x%x\n", hParent);
+ NV_PRINTF(LEVEL_INFO, " fd: %d\n", fd);
+ }
+ else
+ {
+ NV_PRINTF(LEVEL_ERROR, "failed to find OS event:\n");
+ NV_PRINTF(LEVEL_ERROR, " hParent: 0x%x\n", hParent);
+ NV_PRINTF(LEVEL_ERROR, " fd: %d\n", fd);
+ }
+
+ return result;
+}
+
+static void RmExecuteWorkItem(
+ void *pWorkItem
+)
+{
+ nv_work_item_t *pWi = (nv_work_item_t *)pWorkItem;
+ NvU32 gpuMask = 0;
+ OsQueueWorkItemFlags releaseLocks = {0};
+
+ if (!(pWi->flags.bRequiresGpu) &&
+ (pWi->flags.bLockGpus ||
+ pWi->flags.bLockGpuGroupDevice ||
+ pWi->flags.bLockGpuGroupSubdevice ||
+ pWi->flags.bFullGpuSanity))
+ {
+ // Requesting one of the GPU locks without providing a GPU instance
+ NV_ASSERT(0);
+ goto done;
+ }
+
+ // Get locks requested by workitem
+ if (NV_OK != workItemLocksAcquire(pWi->gpuInstance, pWi->flags,
+ &releaseLocks, &gpuMask))
+ {
+ goto done;
+ }
+
+ // Some work items may not require a valid GPU instance
+ if (pWi->flags.bRequiresGpu)
+ {
+ // Make sure that pGpu is present
+ OBJGPU *pGpu = gpumgrGetGpu(pWi->gpuInstance);
+ if (pGpu != NULL)
+ {
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+
+ NV_ASSERT_OR_GOTO(nv != NULL, done);
+
+ NvU32 prevGpuInst = gpumgrSetCurrentGpuInstance(pGpu->gpuInstance);
+
+ if (!(pWi->flags.bDropOnUnloadQueueFlush && os_is_queue_flush_ongoing(nv->queue)))
+ {
+ pWi->func.pGpuFunction(pWi->gpuInstance, pWi->pData);
+ }
+
+ gpumgrSetCurrentGpuInstance(prevGpuInst);
+ }
+ else
+ {
+ NV_PRINTF(LEVEL_ERROR, "Invalid GPU instance for workitem\n");
+ }
+ }
+ else
+ {
+ if (!(pWi->flags.bDropOnUnloadQueueFlush && os_is_queue_flush_ongoing(NULL)))
+ {
+ pWi->func.pSystemFunction(pWi->pData);
+ }
+ }
+
+done:
+ // Release any locks taken
+ workItemLocksRelease(releaseLocks, gpuMask);
+
+ if ((pWi->pData != NULL) && !(pWi->flags.bDontFreeParams))
+ {
+ portMemFree(pWi->pData);
+ }
+
+ portMemFree((void *)pWi);
+}
+
+static NV_STATUS RmAccessRegistry(
+ NvHandle hClient,
+ NvHandle hObject,
+ NvU32 AccessType,
+ NvP64 clientDevNodeAddress,
+ NvU32 DevNodeLength,
+ NvP64 clientParmStrAddress,
+ NvU32 ParmStrLength,
+ NvP64 clientBinaryDataAddress,
+ NvU32 *pBinaryDataLength,
+ NvU32 *Data,
+ NvU32 *Entry
+)
+{
+ NvU32 gpuMask = 0, gpuInstance = 0;
+ OBJGPU *pGpu;
+ NvBool isDevice = NV_FALSE;
+ NV_STATUS RmStatus = NV_ERR_OPERATING_SYSTEM;
+ CLIENT_ENTRY *pClientEntry;
+ Device *pDevice;
+ Subdevice *pSubdevice;
+
+ RMAPI_PARAM_COPY devNodeParamCopy;
+ NvU8 *tmpDevNode = NULL;
+ NvU32 copyOutDevNodeLength = 0;
+
+ RMAPI_PARAM_COPY parmStrParamCopy;
+ char *tmpParmStr = NULL;
+ NvU32 copyOutParmStrLength = 0;
+
+ RMAPI_PARAM_COPY binaryDataParamCopy;
+ NvU8 *tmpBinaryData = NULL;
+ NvU32 BinaryDataLength = 0;
+ NvU32 copyOutBinaryDataLength = 0;
+
+ if (NV_OK != serverAcquireClient(&g_resServ, hClient, LOCK_ACCESS_WRITE,
+ &pClientEntry))
+ {
+ return NV_ERR_INVALID_CLIENT;
+ }
+
+ if (hClient == hObject)
+ {
+ pGpu = NULL;
+ }
+ else
+ {
+ RsClient *pClient = pClientEntry->pClient;
+
+ RmStatus = deviceGetByHandle(pClient, hObject, &pDevice);
+ if (RmStatus != NV_OK)
+ {
+ RmStatus = subdeviceGetByHandle(pClient, hObject, &pSubdevice);
+ if (RmStatus != NV_OK)
+ goto done;
+
+ RmStatus = rmGpuGroupLockAcquire(pSubdevice->subDeviceInst,
+ GPU_LOCK_GRP_SUBDEVICE,
+ GPUS_LOCK_FLAGS_NONE,
+ RM_LOCK_MODULES_GPU,
+ &gpuMask);
+ if (RmStatus != NV_OK)
+ {
+ gpuMask = 0;
+ goto done;
+ }
+
+ GPU_RES_SET_THREAD_BC_STATE(pSubdevice);
+ pGpu = GPU_RES_GET_GPU(pSubdevice);
+ }
+ else
+ {
+ RmStatus = rmGpuGroupLockAcquire(pDevice->deviceInst,
+ GPU_LOCK_GRP_DEVICE,
+ GPUS_LOCK_FLAGS_NONE,
+ RM_LOCK_MODULES_GPU,
+ &gpuMask);
+ if (RmStatus != NV_OK)
+ {
+ gpuMask = 0;
+ goto done;
+ }
+
+ GPU_RES_SET_THREAD_BC_STATE(pDevice);
+ pGpu = GPU_RES_GET_GPU(pDevice);
+ isDevice = NV_TRUE;
+ }
+ }
+
+ if (pBinaryDataLength)
+ {
+ BinaryDataLength = *pBinaryDataLength;
+ }
+
+ // a passed-in devNode
+ if (DevNodeLength)
+ {
+ // the passed-in DevNodeLength does not account for '\0'
+ DevNodeLength++;
+
+ if (DevNodeLength > NVOS38_MAX_REGISTRY_STRING_LENGTH)
+ {
+ RmStatus = NV_ERR_INVALID_STRING_LENGTH;
+ goto done;
+ }
+
+ // get access to client's DevNode
+ RMAPI_PARAM_COPY_INIT(devNodeParamCopy, tmpDevNode, clientDevNodeAddress, DevNodeLength, 1);
+ devNodeParamCopy.flags |= RMAPI_PARAM_COPY_FLAGS_ZERO_BUFFER;
+ RmStatus = rmapiParamsAcquire(&devNodeParamCopy, NV_TRUE);
+ if (RmStatus != NV_OK)
+ {
+ RmStatus = NV_ERR_OPERATING_SYSTEM;
+ goto done;
+ }
+ }
+
+ // a passed-in parmStr
+ if (ParmStrLength)
+ {
+ // the passed-in ParmStrLength does not account for '\0'
+ ParmStrLength++;
+
+ if ((ParmStrLength == 0) || (ParmStrLength > NVOS38_MAX_REGISTRY_STRING_LENGTH))
+ {
+ RmStatus = NV_ERR_INVALID_STRING_LENGTH;
+ goto done;
+ }
+ // get access to client's parmStr
+ RMAPI_PARAM_COPY_INIT(parmStrParamCopy, tmpParmStr, clientParmStrAddress, ParmStrLength, 1);
+ RmStatus = rmapiParamsAcquire(&parmStrParamCopy, NV_TRUE);
+ if (RmStatus != NV_OK)
+ {
+ RmStatus = NV_ERR_OPERATING_SYSTEM;
+ goto done;
+ }
+ if (tmpParmStr[ParmStrLength - 1] != '\0')
+ {
+ RmStatus = NV_ERR_INVALID_ARGUMENT;
+ goto done;
+ }
+ }
+
+ if ((AccessType == NVOS38_ACCESS_TYPE_READ_BINARY) ||
+ (AccessType == NVOS38_ACCESS_TYPE_WRITE_BINARY))
+ {
+ if ((BinaryDataLength > NVOS38_MAX_REGISTRY_BINARY_LENGTH) ||
+ (BinaryDataLength == 0))
+ {
+ RmStatus = NV_ERR_INVALID_STRING_LENGTH;
+ goto done;
+ }
+
+ // get access to client's binaryData
+ RMAPI_PARAM_COPY_INIT(binaryDataParamCopy, tmpBinaryData, clientBinaryDataAddress, BinaryDataLength, 1);
+ if (AccessType == NVOS38_ACCESS_TYPE_READ_BINARY)
+ binaryDataParamCopy.flags |= RMAPI_PARAM_COPY_FLAGS_SKIP_COPYIN;
+ RmStatus = rmapiParamsAcquire(&binaryDataParamCopy, NV_TRUE);
+ if (RmStatus != NV_OK)
+ {
+ RmStatus = NV_ERR_OPERATING_SYSTEM;
+ goto done;
+ }
+ }
+
+ switch (AccessType)
+ {
+ case NVOS38_ACCESS_TYPE_READ_DWORD:
+ RmStatus = osReadRegistryDword(pGpu,
+ tmpParmStr, Data);
+ break;
+
+ case NVOS38_ACCESS_TYPE_WRITE_DWORD:
+ if (!osIsAdministrator())
+ {
+ RmStatus = NV_ERR_INSUFFICIENT_PERMISSIONS;
+ break;
+ }
+ if (isDevice)
+ {
+ while ((pGpu = gpumgrGetNextGpu(gpuMask, &gpuInstance)) != NULL)
+ {
+ RmStatus = osWriteRegistryDword(pGpu,
+ tmpParmStr, *Data);
+
+ if (RmStatus != NV_OK)
+ goto done;
+ }
+ break;
+ }
+
+ RmStatus = osWriteRegistryDword(pGpu,
+ tmpParmStr, *Data);
+ break;
+
+ case NVOS38_ACCESS_TYPE_READ_BINARY:
+ RmStatus = osReadRegistryBinary(pGpu,
+ tmpParmStr, tmpBinaryData, &BinaryDataLength);
+
+ if (RmStatus != NV_OK)
+ {
+ goto done;
+ }
+
+ if (BinaryDataLength)
+ copyOutBinaryDataLength = BinaryDataLength;
+
+ break;
+
+ case NVOS38_ACCESS_TYPE_WRITE_BINARY:
+ if (!osIsAdministrator())
+ {
+ RmStatus = NV_ERR_INSUFFICIENT_PERMISSIONS;
+ break;
+ }
+ if (isDevice)
+ {
+ while ((pGpu = gpumgrGetNextGpu(gpuMask, &gpuInstance)) != NULL)
+ {
+ RmStatus = osWriteRegistryBinary(pGpu,
+ tmpParmStr, tmpBinaryData,
+ BinaryDataLength);
+
+ if (RmStatus != NV_OK)
+ goto done;
+ }
+ break;
+ }
+
+ RmStatus = osWriteRegistryBinary(pGpu,
+ tmpParmStr, tmpBinaryData,
+ BinaryDataLength);
+ break;
+
+ default:
+ RmStatus = NV_ERR_INVALID_ACCESS_TYPE;
+ }
+
+ done:
+ if (gpuMask != 0)
+ rmGpuGroupLockRelease(gpuMask, GPUS_LOCK_FLAGS_NONE);
+
+ if (tmpDevNode != NULL)
+ {
+ // skip copyout on error
+ if ((RmStatus != NV_OK) || (copyOutDevNodeLength == 0))
+ devNodeParamCopy.flags |= RMAPI_PARAM_COPY_FLAGS_SKIP_COPYOUT;
+ devNodeParamCopy.paramsSize = copyOutDevNodeLength;
+ if (NV_OK != rmapiParamsRelease(&devNodeParamCopy))
+ if (RmStatus == NV_OK)
+ RmStatus = NV_ERR_OPERATING_SYSTEM;
+ }
+ if (tmpParmStr != NULL)
+ {
+ // skip copyout on error
+ if ((RmStatus != NV_OK) || (copyOutParmStrLength == 0))
+ parmStrParamCopy.flags |= RMAPI_PARAM_COPY_FLAGS_SKIP_COPYOUT;
+ parmStrParamCopy.paramsSize = copyOutParmStrLength;
+ if (NV_OK != rmapiParamsRelease(&parmStrParamCopy))
+ if (RmStatus == NV_OK)
+ RmStatus = NV_ERR_OPERATING_SYSTEM;
+ }
+ if (tmpBinaryData != NULL)
+ {
+ // skip copyout on error
+ if ((RmStatus != NV_OK) || (copyOutBinaryDataLength == 0))
+ binaryDataParamCopy.flags |= RMAPI_PARAM_COPY_FLAGS_SKIP_COPYOUT;
+ binaryDataParamCopy.paramsSize = copyOutBinaryDataLength;
+ if (NV_OK != rmapiParamsRelease(&binaryDataParamCopy))
+ if (RmStatus == NV_OK)
+ RmStatus = NV_ERR_OPERATING_SYSTEM;
+ *pBinaryDataLength = copyOutBinaryDataLength;
+ }
+
+ serverReleaseClient(&g_resServ, LOCK_ACCESS_WRITE, pClientEntry);
+ return RmStatus;
+}
+
+static NV_STATUS RmUpdateDeviceMappingInfo(
+ NvHandle hClient,
+ NvHandle hDevice,
+ NvHandle hMappable,
+ void *pOldCpuAddress,
+ void *pNewCpuAddress
+)
+{
+ NV_STATUS status;
+ CLIENT_ENTRY *pClientEntry;
+ RsClient *pClient;
+ RsResourceRef *pMappableRef;
+ RsCpuMapping *pCpuMapping;
+ Device *pDevice;
+ Subdevice *pSubdevice;
+ NvU32 gpuMask = 0;
+
+ status = serverAcquireClient(&g_resServ, hClient, LOCK_ACCESS_WRITE, &pClientEntry);
+ if (status != NV_OK)
+ return status;
+
+ pClient = pClientEntry->pClient;
+
+ status = deviceGetByHandle(pClient, hDevice, &pDevice);
+ if (status != NV_OK)
+ {
+ status = subdeviceGetByHandle(pClient, hDevice, &pSubdevice);
+ if (status != NV_OK)
+ goto done;
+
+ status = rmGpuGroupLockAcquire(pSubdevice->subDeviceInst,
+ GPU_LOCK_GRP_SUBDEVICE,
+ GPUS_LOCK_FLAGS_NONE,
+ RM_LOCK_MODULES_GPU,
+ &gpuMask);
+ if (status != NV_OK)
+ goto done;
+
+ GPU_RES_SET_THREAD_BC_STATE(pSubdevice);
+ }
+ else
+ {
+ status = rmGpuGroupLockAcquire(pDevice->deviceInst,
+ GPU_LOCK_GRP_DEVICE,
+ GPUS_LOCK_FLAGS_NONE,
+ RM_LOCK_MODULES_GPU,
+ &gpuMask);
+ if (status != NV_OK)
+ goto done;
+
+ GPU_RES_SET_THREAD_BC_STATE(pDevice);
+ }
+
+ status = clientGetResourceRef(pClient, hMappable, &pMappableRef);
+ if (status != NV_OK)
+ goto done;
+
+ if ((objDynamicCastById(pMappableRef->pResource, classId(Memory)) == NULL) &&
+ (objDynamicCastById(pMappableRef->pResource, classId(KernelCcuApi)) == NULL) &&
+ (objDynamicCastById(pMappableRef->pResource, classId(KernelChannel)) == NULL))
+ {
+ status = NV_ERR_INVALID_OBJECT_HANDLE;
+ goto done;
+ }
+
+ status = refFindCpuMappingWithFilter(pMappableRef,
+ NV_PTR_TO_NvP64(pOldCpuAddress),
+ serverutilMappingFilterCurrentUserProc,
+ &pCpuMapping);
+ if (status != NV_OK)
+ goto done;
+
+ pCpuMapping->pLinearAddress = NV_PTR_TO_NvP64(pNewCpuAddress);
+
+done:
+
+ if (gpuMask != 0)
+ rmGpuGroupLockRelease(gpuMask, GPUS_LOCK_FLAGS_NONE);
+
+ serverReleaseClient(&g_resServ, LOCK_ACCESS_WRITE, pClientEntry);
+ return status;
+}
+
+static void RmSanitizeLogString(
+ char *pString,
+ NvU32 stringLength
+)
+{
+ NvU32 i;
+
+ if (pString == NULL)
+ return;
+
+ for (i = 0; i < stringLength; i++)
+ {
+ NvU8 ch = (NvU8)pString[i];
+
+ if (ch == '\0')
+ return;
+
+ if ((ch < 0x20) || (ch == 0x7f))
+ {
+ pString[i] = '?';
+ }
+ }
+}
+
+static NV_STATUS RmPerformVersionCheck(
+ void *pData,
+ NvU32 dataSize
+)
+{
+ nv_ioctl_rm_api_version_t *pParams;
+ char clientCh, rmCh;
+ const char *rmStr = NV_VERSION_STRING;
+ NvBool relaxed = NV_FALSE;
+ NvU32 i;
+ NvU32 procId;
+ char procName[32];
+
+ //
+ // rmStr (i.e., NV_VERSION_STRING) must be null-terminated and fit within
+ // NV_RM_API_VERSION_STRING_LENGTH, so that:
+ //
+ // (1) If the versions don't match, we can return rmStr in
+ // pParams->versionString.
+ // (2) The below loop is guaranteed to not overrun rmStr.
+ //
+ ct_assert(sizeof(NV_VERSION_STRING) <= NV_RM_API_VERSION_STRING_LENGTH);
+
+ if (dataSize != sizeof(nv_ioctl_rm_api_version_t))
+ return NV_ERR_INVALID_ARGUMENT;
+
+ pParams = pData;
+
+ //
+ // write the reply value, so that the client knows we recognized
+ // the request
+ //
+ pParams->reply = NV_RM_API_VERSION_REPLY_RECOGNIZED;
+
+ //
+ // the client is just querying the version, not verifying against expected.
+ //
+ if (pParams->cmd == NV_RM_API_VERSION_CMD_QUERY)
+ {
+ os_string_copy(pParams->versionString, rmStr);
+ return NV_OK;
+ }
+
+ //
+ // the client requested relaxed version checking; we will only
+ // compare the strings until the first decimal point.
+ //
+ if (pParams->cmd == NV_RM_API_VERSION_CMD_RELAXED)
+ {
+ relaxed = NV_TRUE;
+ }
+
+ for (i = 0; i < NV_RM_API_VERSION_STRING_LENGTH; i++)
+ {
+ clientCh = pParams->versionString[i];
+ rmCh = rmStr[i];
+
+ //
+ // fail if the current character is not the same
+ //
+ if (clientCh != rmCh)
+ {
+ break;
+ }
+
+ //
+ // if relaxed matching was requested, succeed when we find the
+ // first decimal point
+ //
+ if ((relaxed) && (clientCh == '.'))
+ {
+ return NV_OK;
+ }
+
+ //
+ // we found the end of the strings: succeed
+ //
+ if (clientCh == '\0')
+ {
+ return NV_OK;
+ }
+ }
+
+ //
+ // the version strings did not match: print an error message and
+ // copy the RM's version string into pParams->versionString, so
+ // that the client can report the mismatch; explicitly NULL
+ // terminate the client's string, since we cannot trust it
+ //
+ pParams->versionString[NV_RM_API_VERSION_STRING_LENGTH - 1] = '\0';
+
+ procId = os_get_current_process();
+ os_get_current_process_name(procName, sizeof(procName));
+
+ RmSanitizeLogString(pParams->versionString, NV_RM_API_VERSION_STRING_LENGTH);
+ RmSanitizeLogString(procName, sizeof(procName));
+
+ nv_printf(NV_DBG_ERRORS,
+ "NVRM: API mismatch: the client '%s' (pid %u)\n"
+ "NVRM: has the version %s, but this kernel module has\n"
+ "NVRM: the version %s. Please make sure that this\n"
+ "NVRM: kernel module and all NVIDIA driver components\n"
+ "NVRM: have the same version.\n",
+ procName, procId,
+ pParams->versionString, NV_VERSION_STRING);
+
+ os_string_copy(pParams->versionString, rmStr);
+
+ return NV_ERR_GENERIC;
+}
+
+NV_STATUS RmPowerSourceChangeEvent(
+ nv_state_t *pNv,
+ NvU32 event_val
+)
+{
+ NV2080_CTRL_PERF_SET_POWERSTATE_PARAMS params = {0};
+ RM_API *pRmApi = rmapiGetInterface(RMAPI_GPU_LOCK_INTERNAL);
+
+ params.powerStateInfo.powerState = event_val ? NV2080_CTRL_PERF_POWER_SOURCE_BATTERY :
+ NV2080_CTRL_PERF_POWER_SOURCE_AC;
+
+ return pRmApi->Control(pRmApi, pNv->rmapi.hClient,
+ pNv->rmapi.hSubDevice,
+ NV2080_CTRL_CMD_PERF_SET_POWERSTATE,
+ &params, sizeof(params));
+}
+
+/*!
+ * @brief Function to request latest D-Notifier status from SBIOS.
+ *
+ * Handle certain scenarios (like a fresh boot or suspend/resume
+ * of the system) when RM is not available to receive the Dx notifiers.
+ * This function gets the latest D-Notifier status from SBIOS
+ * when RM is ready to receive and handle those events.
+ * Use GPS_FUNC_REQUESTDXSTATE subfunction to invoke current Dx state.
+ *
+ * @param[in] pNv nv_state_t pointer.
+ */
+void RmRequestDNotifierState(
+ nv_state_t *pNv
+)
+{
+ OBJGPU *pGpu = NV_GET_NV_PRIV_PGPU(pNv);
+ NvU32 supportedFuncs = 0;
+ NvU16 dsmDataSize = sizeof(supportedFuncs);
+ NV_STATUS status = NV_OK;
+
+ status = osCallACPI_DSM(pGpu, ACPI_DSM_FUNCTION_GPS_2X,
+ GPS_FUNC_REQUESTDXSTATE, &supportedFuncs,
+ &dsmDataSize);
+ if (status != NV_OK)
+ {
+ //
+ // Call for 'GPS_FUNC_REQUESTDXSTATE' subfunction may fail if the
+ // SBIOS/EC does not have the corresponding implementation.
+ //
+ NV_PRINTF(LEVEL_INFO,
+ "%s: Failed to request Dx event update, status 0x%x\n",
+ __FUNCTION__, status);
+ }
+}
+
+/*!
+ * @brief Deal with D-notifier events to apply a performance
+ * level based on the requested auxiliary power-state.
+ * Read confluence page "D-Notifiers on Linux" for more details.
+ *
+ * @param[in] pNv nv_state_t pointer.
+ * @param[in] event_type NvU32 Event type.
+ */
+static void RmHandleDNotifierEvent(
+ nv_state_t *pNv,
+ NvU32 event_type
+)
+{
+ NV2080_CTRL_PERF_SET_AUX_POWER_STATE_PARAMS params = { 0 };
+ RM_API *pRmApi;
+ THREAD_STATE_NODE threadState;
+ NV_STATUS rmStatus = NV_OK;
+
+ switch (event_type)
+ {
+ case ACPI_NOTIFY_POWER_LEVEL_D1:
+ params.powerState = NV2080_CTRL_PERF_AUX_POWER_STATE_P0;
+ break;
+ case ACPI_NOTIFY_POWER_LEVEL_D2:
+ params.powerState = NV2080_CTRL_PERF_AUX_POWER_STATE_P1;
+ break;
+ case ACPI_NOTIFY_POWER_LEVEL_D3:
+ params.powerState = NV2080_CTRL_PERF_AUX_POWER_STATE_P2;
+ break;
+ case ACPI_NOTIFY_POWER_LEVEL_D4:
+ params.powerState = NV2080_CTRL_PERF_AUX_POWER_STATE_P3;
+ break;
+ case ACPI_NOTIFY_POWER_LEVEL_D5:
+ params.powerState = NV2080_CTRL_PERF_AUX_POWER_STATE_P4;
+ break;
+ default:
+ return;
+ }
+
+ pRmApi = RmUnixRmApiPrologue(pNv, &threadState, RM_LOCK_MODULES_ACPI);
+ if (pRmApi == NULL)
+ {
+ return;
+ }
+
+ rmStatus = pRmApi->Control(pRmApi, pNv->rmapi.hClient,
+ pNv->rmapi.hSubDevice,
+ NV2080_CTRL_CMD_PERF_SET_AUX_POWER_STATE,
+ &params, sizeof(params));
+
+ RmUnixRmApiEpilogue(pNv, &threadState);
+
+ if (rmStatus != NV_OK)
+ {
+ NV_PRINTF(LEVEL_ERROR,
+ "%s: Failed to handle ACPI D-Notifier event, status=0x%x\n",
+ __FUNCTION__, rmStatus);
+ }
+}
+
+static NvU32 RmDmabufMmapGetCpuCacheType(
+ OBJGPU *pGpu,
+ MEMORY_DESCRIPTOR *pMemDesc,
+ NvU8 mappingType
+)
+{
+ if (pGpu->pGpuArch->bGpuArchIsZeroFb)
+ {
+ return memdescGetCpuCacheAttrib(pMemDesc);
+ }
+
+#if defined(NVCPU_X86_64)
+ return NV_MEMORY_WRITECOMBINED;
+#elif defined(NVCPU_AARCH64)
+ if ((pGpu->getProperty(pGpu, PDB_PROP_GPU_COHERENT_CPU_MAPPING)) &&
+ (mappingType == NV_DMABUF_EXPORT_MAPPING_TYPE_DEFAULT))
+ {
+ return NV_MEMORY_CACHED;
+ }
+ else
+ {
+ return NV_MEMORY_UNCACHED;
+ }
+#else
+ // Default to uncached for other platforms for now
+ return NV_MEMORY_UNCACHED;
+#endif
+}
+
+static NV_STATUS
+RmDmabufVerifyMemHandle(
+ OBJGPU *pGpu,
+ NvHandle hSrcClient,
+ NvHandle hMemory,
+ NvU64 offset,
+ NvU64 size,
+ void *pGpuInstanceInfo,
+ MEMORY_DESCRIPTOR **ppMemDesc
+)
+{
+ NV_STATUS status;
+ RsClient *pClient = NULL;
+ RsResourceRef *pSrcMemoryRef = NULL;
+ Memory *pSrcMemory = NULL;
+ MEMORY_DESCRIPTOR *pMemDesc = NULL;
+
+ NV_ASSERT_OK_OR_RETURN(serverGetClientUnderLock(&g_resServ, hSrcClient, &pClient));
+
+ status = clientGetResourceRef(pClient, hMemory, &pSrcMemoryRef);
+ if (status != NV_OK)
+ {
+ return status;
+ }
+
+ pSrcMemory = dynamicCast(pSrcMemoryRef->pResource, Memory);
+ if (pSrcMemory == NULL)
+ {
+ return NV_ERR_INVALID_OBJECT;
+ }
+
+ pMemDesc = pSrcMemory->pMemDesc;
+ if (pMemDesc == NULL)
+ {
+ return NV_ERR_INVALID_STATE;
+ }
+
+ //
+ // We skip the partitionable heap check when the source memory is in
+ // sysmem as there is no valid heap (pHeap will be NULL).
+ //
+ if (pGpuInstanceInfo != NULL && memdescGetAddressSpace(pMemDesc) != ADDR_SYSMEM)
+ {
+ KERNEL_MIG_GPU_INSTANCE *pKernelMIGGpuInstance;
+ pKernelMIGGpuInstance = (KERNEL_MIG_GPU_INSTANCE *) pGpuInstanceInfo;
+
+ if ((pKernelMIGGpuInstance->pMemoryPartitionHeap != pSrcMemory->pHeap))
+ {
+ return NV_ERR_INVALID_OBJECT_PARENT;
+ }
+ }
+
+ // Check if hMemory belongs to the same pGpu
+ if ((pMemDesc->pGpu != pGpu) ||
+ (pSrcMemory->pGpu != pGpu))
+ {
+ return NV_ERR_INVALID_OBJECT_PARENT;
+ }
+
+ // Offset and size must be aligned to OS page-size
+ if (!NV_IS_ALIGNED64(offset, os_page_size) ||
+ !NV_IS_ALIGNED64(size, os_page_size))
+ {
+ return NV_ERR_INVALID_ARGUMENT;
+ }
+
+ // Only supported for vidmem and sysmem(only for 0FB) handles
+ if ((memdescGetAddressSpace(pMemDesc) != ADDR_FBMEM) &&
+ (!pGpu->pGpuArch->bGpuArchIsZeroFb))
+ {
+ return NV_ERR_INVALID_ARGUMENT;
+ }
+
+ if ((size == 0) ||
+ (size > memdescGetSize(pMemDesc)) ||
+ (offset > (memdescGetSize(pMemDesc) - size)))
+ {
+ return NV_ERR_INVALID_ARGUMENT;
+ }
+
+ *ppMemDesc = pMemDesc;
+
+ return NV_OK;
+}
+
+static NV_STATUS
+RmDmabufGetClientAndDevice(
+ OBJGPU *pGpu,
+ NvHandle hClient,
+ NvHandle hMemory,
+ NvU8 mappingType,
+ NvHandle *phClient,
+ NvHandle *phDevice,
+ NvHandle *phSubdevice,
+ void **ppGpuInstanceInfo
+)
+{
+ MemoryManager *pMemoryManager = GPU_GET_MEMORY_MANAGER(pGpu);
+
+ // No dma-buf support for SLI-enabled GPU
+ if (IsSLIEnabled(pGpu))
+ {
+ return NV_ERR_NOT_SUPPORTED;
+ }
+
+ //
+ // MAPPING_TYPE_FORCE_PCIE is to be used only on coherent systems with a
+ // direct PCIe connection between the exporter and importer.
+ // MIG is not a supported use-case for dma-buf on these systems.
+ //
+ if (mappingType == NV_DMABUF_EXPORT_MAPPING_TYPE_FORCE_PCIE)
+ {
+ KernelBus *pKernelBus = GPU_GET_KERNEL_BUS(pGpu);
+
+ if (!pGpu->getProperty(pGpu, PDB_PROP_GPU_COHERENT_CPU_MAPPING) ||
+ pKernelBus->bBar1Disabled ||
+ IS_MIG_ENABLED(pGpu))
+ {
+ return NV_ERR_NOT_SUPPORTED;
+ }
+ }
+
+ if (IS_MIG_ENABLED(pGpu))
+ {
+ MIG_INSTANCE_REF ref;
+ RsClient *pClient;
+ Memory *pMemory;
+ KernelMIGManager *pKernelMIGManager = GPU_GET_KERNEL_MIG_MANAGER(pGpu);
+
+ NV_CHECK_OK_OR_RETURN(LEVEL_ERROR,
+ serverGetClientUnderLock(&g_resServ, hClient, &pClient));
+
+ NV_CHECK_OK_OR_RETURN(LEVEL_ERROR,
+ memGetByHandle(pClient, hMemory, &pMemory));
+
+ NV_CHECK_OK_OR_RETURN(LEVEL_ERROR,
+ kmigmgrGetInstanceRefFromDevice(pGpu, pKernelMIGManager,
+ pMemory->pDevice, &ref));
+
+ NV_CHECK_OK_OR_RETURN(LEVEL_ERROR,
+ kmigmgrIncRefCount(ref.pKernelMIGGpuInstance->pShare));
+
+ *phClient = ref.pKernelMIGGpuInstance->instanceHandles.hClient;
+ *phDevice = ref.pKernelMIGGpuInstance->instanceHandles.hDevice;
+ *phSubdevice = ref.pKernelMIGGpuInstance->instanceHandles.hSubdevice;
+ *ppGpuInstanceInfo = (void *) ref.pKernelMIGGpuInstance;
+
+ return NV_OK;
+ }
+
+ *phClient = pMemoryManager->hClient;
+ *phDevice = pMemoryManager->hDevice;
+ *phSubdevice = pMemoryManager->hSubdevice;
+ *ppGpuInstanceInfo = NULL;
+
+ return NV_OK;
+}
+
+static void
+RmDmabufPutClientAndDevice(
+ OBJGPU *pGpu,
+ NvHandle hClient,
+ NvHandle hDevice,
+ NvHandle hSubdevice,
+ void *pGpuInstanceInfo
+)
+{
+ KERNEL_MIG_GPU_INSTANCE *pKernelMIGGpuInstance;
+
+ if (pGpuInstanceInfo == NULL)
+ {
+ return;
+ }
+
+ pKernelMIGGpuInstance = (KERNEL_MIG_GPU_INSTANCE *) pGpuInstanceInfo;
+
+ NV_ASSERT_OK(kmigmgrDecRefCount(pKernelMIGGpuInstance->pShare));
+}
+
+static NV_STATUS RmP2PDmaMapPages(
+ nv_state_t *pNv,
+ nv_dma_device_t *peer,
+ NvU64 pageSize,
+ NvU32 pageCount,
+ NvU64 *pDmaAddresses,
+ void **ppPriv
+)
+{
+ NV_STATUS status;
+ NvU64 *pOsDmaAddresses = NULL;
+ NvU32 osPagesPerP2PPage, osPageCount, count;
+ NvBool bDmaMapped = NV_FALSE;
+ NvU32 i, j, index;
+ void *pgmap = NULL;
+ NvBool bPageMapRef = NV_FALSE;
+
+ NV_ASSERT_OR_RETURN((pageSize >= os_page_size), NV_ERR_INVALID_ARGUMENT);
+
+ if (pNv->coherent_gpu_mem_mode == NV_COHERENT_GPU_MEM_MODE_DRIVER)
+ {
+ // Take a refcount on the dev_pagemap created for GPU memory by UVM
+ pgmap = nv_dma_get_dev_pagemap(pDmaAddresses[0]);
+ if (pgmap == NULL)
+ {
+ NV_PRINTF(LEVEL_ERROR,
+ "Failed to get a reference on dev_pagemap in CDMM(driver) mode\n");
+ return NV_ERR_NOT_SUPPORTED;
+ }
+
+ bPageMapRef = NV_TRUE;
+ }
+
+ if (pageSize == os_page_size)
+ {
+ status = nv_dma_map_alloc(peer, pageCount, pDmaAddresses, NV_FALSE, NV_FALSE, ppPriv);
+
+ goto put_pgmap;
+ }
+
+ //
+ // If P2P page_size returned from nvidia_p2p_get_pages is bigger than
+ // OS page size, the page array need to be inflated to correctly do the DMA mapping.
+ // For example, if page_size = 64K and OS page size = 4K,
+ // there are 16 OS pages to this 64K P2P page.
+ //
+
+ osPagesPerP2PPage = pageSize / os_page_size;
+ osPageCount = osPagesPerP2PPage * pageCount;
+
+ status = os_alloc_mem((void **)&pOsDmaAddresses,
+ (osPageCount * sizeof(NvU64)));
+ if (status != NV_OK)
+ {
+ goto failed;
+ }
+
+ index = 0;
+ for (i = 0; i < pageCount; i++)
+ {
+ pOsDmaAddresses[index] = pDmaAddresses[i];
+ index++;
+
+ for (j = 1; j < osPagesPerP2PPage; j++)
+ {
+ pOsDmaAddresses[index] = pOsDmaAddresses[index - 1] + os_page_size;
+ index++;
+ }
+ }
+
+ status = nv_dma_map_alloc(peer, osPageCount, pOsDmaAddresses, NV_FALSE, NV_FALSE, ppPriv);
+ if (status != NV_OK)
+ {
+ goto failed;
+ }
+ bDmaMapped = NV_TRUE;
+
+ //
+ // The driver breaks down the size into submaps and dma-maps those individually.
+ // This may result in non-contiguous IOVA segments allocated to each submap.
+ // We check for OS page contiguity within the bigger pageSize since we need to
+ // return IOVA chunks at pageSize granularity.
+ //
+ count = 0;
+ for (i = 1; i < osPageCount; i++)
+ {
+ count++;
+ if (count == osPagesPerP2PPage)
+ {
+ count = 0;
+ continue;
+ }
+
+ if (pOsDmaAddresses[i] != (pOsDmaAddresses[i - 1] + os_page_size))
+ {
+ status = NV_ERR_INVALID_STATE;
+ goto failed;
+ }
+ }
+
+ //
+ // Fill pDmaAddresses at pageSize granularity
+ // from expanded pOsDmaAddresses.
+ //
+ index = 0;
+ for (i = 0; i < pageCount; i++)
+ {
+ pDmaAddresses[i] = pOsDmaAddresses[index];
+ index += osPagesPerP2PPage;
+ }
+
+ os_free_mem(pOsDmaAddresses);
+
+ if (bPageMapRef)
+ {
+ nv_dma_put_dev_pagemap(pgmap);
+ }
+
+ return NV_OK;
+
+failed:
+ if (bDmaMapped)
+ {
+ NV_ASSERT_OK(nv_dma_unmap_alloc(peer, osPageCount,
+ pOsDmaAddresses, ppPriv));
+ }
+
+ if (pOsDmaAddresses != NULL)
+ {
+ os_free_mem(pOsDmaAddresses);
+ }
+
+put_pgmap:
+ if (bPageMapRef)
+ {
+ nv_dma_put_dev_pagemap(pgmap);
+ }
+
+ return status;
+}
+
+/*
+ * ---------------------------------------------------------------------------
+ *
+ * The routines below are part of the interface between the kernel interface
+ * layer and the kernel-agnostic portions of the resource manager.
+ *
+ * ---------------------------------------------------------------------------
+ */
+
+NvBool NV_API_CALL rm_init_private_state(
+ nvidia_stack_t *sp,
+ nv_state_t *pNv
+)
+{
+ NvBool retval;
+ void *fp;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+
+ retval = RmInitPrivateState(pNv);
+
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return retval;
+}
+
+void NV_API_CALL rm_free_private_state(
+ nvidia_stack_t *sp,
+ nv_state_t *pNv
+)
+{
+ void *fp;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+
+ RmFreePrivateState(pNv);
+
+ NV_EXIT_RM_RUNTIME(sp,fp);
+}
+
+NvBool NV_API_CALL rm_init_adapter(
+ nvidia_stack_t *sp,
+ nv_state_t *pNv
+)
+{
+ THREAD_STATE_NODE threadState;
+ NvBool retval = NV_FALSE;
+ void *fp;
+ NvBool bEnabled;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_DEVICE_INIT);
+
+ //
+ // If GPU is driving any frame buffer console(vesafb, efifb etc)
+ // mark the console as client driven
+ //
+ pNv->client_managed_console = rm_get_uefi_console_status(pNv);
+
+ //
+ // For GPU driving console, disable console access here, to ensure no console
+ // writes through BAR1 can interfere with physical RM's setup of BAR1
+ //
+ if (pNv->client_managed_console && !pNv->sysmem_mapped_console)
+ {
+ os_disable_console_access();
+ }
+
+ // LOCK: acquire API lock
+ if (rmapiLockAcquire(API_LOCK_FLAGS_NONE, RM_LOCK_MODULES_INIT) == NV_OK)
+ {
+ if (!((gpumgrQueryGpuDrainState(pNv->gpu_id, &bEnabled, NULL) == NV_OK)
+ && bEnabled))
+ {
+ if (pNv->flags & NV_FLAG_PERSISTENT_SW_STATE)
+ {
+ retval = RmPartiallyInitAdapter(pNv);
+ }
+ else
+ {
+ retval = RmInitAdapter(pNv);
+ }
+ }
+
+ // UNLOCK: release API lock
+ rmapiLockRelease();
+ }
+
+ if (pNv->client_managed_console && !pNv->sysmem_mapped_console)
+ {
+ os_enable_console_access();
+ }
+
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return retval;
+}
+
+void NV_API_CALL rm_disable_adapter(
+ nvidia_stack_t *sp,
+ nv_state_t *pNv
+)
+{
+ THREAD_STATE_NODE threadState;
+ void *fp;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ NV_ASSERT_OK(os_flush_work_queue(pNv->queue, NV_TRUE));
+
+ if (pNv->client_managed_console && !pNv->sysmem_mapped_console)
+ {
+ os_disable_console_access();
+ }
+
+ // LOCK: acquire API lock
+ if (rmapiLockAcquire(API_LOCK_FLAGS_NONE, RM_LOCK_MODULES_DESTROY) == NV_OK)
+ {
+ if (pNv->flags & NV_FLAG_PERSISTENT_SW_STATE)
+ {
+ RmPartiallyDisableAdapter(pNv);
+ }
+ else
+ {
+ RmDisableAdapter(pNv);
+ }
+
+ // UNLOCK: release API lock
+ rmapiLockRelease();
+ }
+
+ if (pNv->client_managed_console && !pNv->sysmem_mapped_console)
+ {
+ os_enable_console_access();
+ }
+
+ NV_ASSERT_OK(os_flush_work_queue(pNv->queue, NV_TRUE));
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+}
+
+void NV_API_CALL rm_shutdown_adapter(
+ nvidia_stack_t *sp,
+ nv_state_t *pNv
+)
+{
+ THREAD_STATE_NODE threadState;
+ void *fp;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ if (pNv->client_managed_console && !pNv->sysmem_mapped_console)
+ {
+ os_disable_console_access();
+ }
+
+ // LOCK: acquire API lock
+ if (rmapiLockAcquire(API_LOCK_FLAGS_NONE, RM_LOCK_MODULES_DESTROY) == NV_OK)
+ {
+ RmShutdownAdapter(pNv);
+
+ // UNLOCK: release API lock
+ rmapiLockRelease();
+ }
+
+ if (pNv->client_managed_console && !pNv->sysmem_mapped_console)
+ {
+ os_enable_console_access();
+ }
+
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+}
+
+NV_STATUS NV_API_CALL rm_exclude_adapter(
+ nvidia_stack_t *sp,
+ nv_state_t *pNv
+)
+{
+ NV_STATUS rmStatus;
+ THREAD_STATE_NODE threadState;
+ void *fp;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ rmStatus = RmExcludeAdapter(pNv);
+
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_acquire_api_lock(
+ nvidia_stack_t *sp
+)
+{
+ THREAD_STATE_NODE threadState;
+ NV_STATUS rmStatus;
+ void *fp;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ // LOCK: acquire API lock
+ rmStatus = rmapiLockAcquire(API_LOCK_FLAGS_NONE, RM_LOCK_MODULES_OSAPI);
+
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_release_api_lock(
+ nvidia_stack_t *sp
+)
+{
+ THREAD_STATE_NODE threadState;
+ void *fp;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ // UNLOCK: release API lock
+ rmapiLockRelease();
+
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return NV_OK;
+}
+
+NV_STATUS NV_API_CALL rm_acquire_gpu_lock(
+ nvidia_stack_t *sp,
+ nv_state_t *nv
+)
+{
+ THREAD_STATE_NODE threadState;
+ NV_STATUS rmStatus;
+ void *fp;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ // LOCK: acquire GPU lock
+ rmStatus = rmDeviceGpuLocksAcquire(NV_GET_NV_PRIV_PGPU(nv),
+ GPUS_LOCK_FLAGS_NONE,
+ RM_LOCK_MODULES_OSAPI);
+
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_release_gpu_lock(
+ nvidia_stack_t *sp,
+ nv_state_t *nv
+)
+{
+ THREAD_STATE_NODE threadState;
+ void *fp;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ // UNLOCK: release GPU lock
+ rmDeviceGpuLocksRelease(NV_GET_NV_PRIV_PGPU(nv), GPUS_LOCK_FLAGS_NONE, NULL);
+
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return NV_OK;
+}
+
+NV_STATUS NV_API_CALL rm_acquire_all_gpus_lock(
+ nvidia_stack_t *sp
+)
+{
+ THREAD_STATE_NODE threadState;
+ NV_STATUS rmStatus;
+ void *fp;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ // LOCK: acquire all GPUs lock
+ rmStatus = rmGpuLocksAcquire(GPUS_LOCK_FLAGS_NONE, RM_LOCK_MODULES_OSAPI);
+
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_release_all_gpus_lock(
+ nvidia_stack_t *sp
+)
+{
+ THREAD_STATE_NODE threadState;
+ void *fp;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ // UNLOCK: release all GPUs lock
+ rmGpuLocksRelease(GPUS_LOCK_FLAGS_NONE, NULL);
+
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return NV_OK;
+}
+
+/*!
+ * @brief Handle ACPI_NOTIFY_GPS_STATUS_CHANGE event.
+ *
+ * This function is called for GPS when SBIOS trigger
+ * gps STATUS_CHANGE event, which calls rm control call
+ * NV0000_CTRL_CMD_SYSTEM_GPS_CONTROL to init the GPS
+ * data from SBIOS.
+ */
+static void RmHandleGPSStatusChange
+(
+ nv_state_t *pNv
+)
+{
+ NV_STATUS rmStatus;
+ RM_API *pRmApi;
+ THREAD_STATE_NODE threadState;
+ NV0000_CTRL_SYSTEM_GPS_CONTROL_PARAMS gpsControl = { 0 };
+
+ pRmApi = RmUnixRmApiPrologue(pNv, &threadState, RM_LOCK_MODULES_ACPI);
+ if (pRmApi == NULL)
+ {
+ return;
+ }
+
+ gpsControl.command = NV0000_CTRL_CMD_SYSTEM_GPS_DATA_INIT_USING_SBIOS_AND_ACK;
+ gpsControl.locale = NV0000_CTRL_CMD_SYSTEM_GPS_LOCALE_SYSTEM;
+
+ //
+ // NV0000_CTRL_CMD_SYSTEM_GPS_CONTROL is not a subdevice command.
+ // But, Inside GPS module, the first GPU, which has GPS
+ // enabled will be grabbed with GPU manager. The RMAPI_API_LOCK_INTERNAL
+ // will internally grab the GPU locks and wake-up all the GPUs. Ideally
+ // this control call should be GPU specific command, if internally
+ // it uses the GPU.
+ //
+ rmStatus = pRmApi->Control(pRmApi,
+ pNv->rmapi.hClient,
+ pNv->rmapi.hClient,
+ NV0000_CTRL_CMD_SYSTEM_GPS_CONTROL,
+ (void *)&gpsControl,
+ sizeof(NV0000_CTRL_SYSTEM_GPS_CONTROL_PARAMS));
+
+ RmUnixRmApiEpilogue(pNv, &threadState);
+
+ if (rmStatus != NV_OK)
+ {
+ NV_PRINTF(LEVEL_ERROR,
+ "%s: Failed to handle ACPI GPS status change event, status=0x%x\n",
+ __FUNCTION__, rmStatus);
+ }
+}
+
+/*!
+ * @brief Function to handle device specific ACPI events.
+ *
+ * @param[in] sp nvidia_stack_t pointer.
+ * @param[in] nv nv_state_t pointer.
+ * @param[in] event_type NvU32 Event type.
+ */
+void NV_API_CALL rm_acpi_notify(
+ nvidia_stack_t *sp,
+ nv_state_t *nv,
+ NvU32 event_type
+)
+{
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+
+ switch (event_type)
+ {
+ case ACPI_VIDEO_NOTIFY_PROBE:
+ {
+ THREAD_STATE_NODE threadState;
+
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+ RmHandleDisplayChange(sp, nv);
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ break;
+ }
+
+ case ACPI_NOTIFY_GPS_STATUS_CHANGE:
+ RmHandleGPSStatusChange(nv);
+ break;
+
+ case ACPI_NOTIFY_POWER_LEVEL_D1: /* fallthrough */
+ case ACPI_NOTIFY_POWER_LEVEL_D2: /* fallthrough */
+ case ACPI_NOTIFY_POWER_LEVEL_D3: /* fallthrough */
+ case ACPI_NOTIFY_POWER_LEVEL_D4: /* fallthrough */
+ case ACPI_NOTIFY_POWER_LEVEL_D5:
+ RmHandleDNotifierEvent(nv, event_type);
+ break;
+
+ default:
+ NV_PRINTF(LEVEL_INFO, "No support for 0x%x event\n", event_type);
+ NV_ASSERT(0);
+ break;
+ }
+
+ NV_EXIT_RM_RUNTIME(sp,fp);
+}
+
+static void nv_align_mmap_offset_length(
+ nv_usermap_access_params_t *nvuap)
+{
+ NvU64 page_size = os_page_size;
+ NvU64 end = nvuap->size + (nvuap->addr & (page_size - 1));
+
+ nvuap->memArea.numRanges = 1;
+ nvuap->memArea.pRanges[0].start = NV_ALIGN_DOWN(nvuap->addr, page_size);
+ nvuap->memArea.pRanges[0].size = NV_ALIGN_UP(end, page_size);
+ nvuap->offset = NV_ALIGN_DOWN(nvuap->offset, page_size);
+}
+
+static inline NV_STATUS RmGetArrayMinMax(
+ NvU64 *array,
+ NvU64 count,
+ NvU64 *min,
+ NvU64 *max
+)
+{
+ NvU64 i;
+
+ if (array == NULL)
+ {
+ return NV_ERR_INVALID_ARGUMENT;
+ }
+
+ *min = array[0];
+ *max = array[0];
+
+ if (count == 1)
+ return NV_OK;
+
+ for (i = 1; i < count; i++)
+ {
+ if (array[i] > *max)
+ *max = array[i];
+
+ if (array[i] < *min)
+ *min = array[i];
+ }
+
+ return NV_OK;
+}
+
+static NV_STATUS RmGetAllocPrivate(RmClient *, NvU32, NvU64, NvU64, NvU32 *, void **,
+ NvU64 *);
+
+static NV_STATUS RmValidateMmapRequest(
+ nv_state_t *pNv,
+ NvU64 offset,
+ NvU64 length,
+ NvU32 *pProtection
+)
+{
+ NV2080_CTRL_GPU_VALIDATE_MEM_MAP_REQUEST_PARAMS params = { 0 };
+ RM_API *pRmApi = rmapiGetInterface(RMAPI_GPU_LOCK_INTERNAL);
+ NV_STATUS status;
+
+ if (osIsAdministrator())
+ {
+ *pProtection = NV_PROTECT_READ_WRITE;
+ return NV_OK;
+ }
+
+ params.addressStart = offset;
+ params.addressLength = length;
+
+ status = pRmApi->Control(pRmApi, pNv->rmapi.hClient,
+ pNv->rmapi.hSubDevice,
+ NV2080_CTRL_CMD_GPU_VALIDATE_MEM_MAP_REQUEST,
+ &params, sizeof(params));
+
+ if (status == NV_OK)
+ {
+ *pProtection = params.protection;
+ }
+
+ return status;
+}
+
+static NV_STATUS RmSetUserMapAccessRange(
+ nv_usermap_access_params_t *nvuap
+)
+{
+ NV_STATUS status = NV_OK;
+
+ if (nvuap->contig)
+ {
+ nvuap->access_start = nvuap->memArea.pRanges[0].start;
+ nvuap->access_size = nvuap->memArea.pRanges[0].size;
+ }
+ else
+ {
+ NvU64 highest_address_mapped;
+ NvU64 lowest_address_mapped;
+
+ status = RmGetArrayMinMax(nvuap->page_array, nvuap->num_pages,
+ &lowest_address_mapped,
+ &highest_address_mapped);
+ if (status != NV_OK)
+ {
+ return status;
+ }
+
+ nvuap->access_start = lowest_address_mapped;
+ nvuap->access_size = (highest_address_mapped + os_page_size) - lowest_address_mapped;
+ }
+
+ return status;
+}
+
+static NV_STATUS RmGetMmapPteArray(
+ KernelMemorySystem *pKernelMemorySystem,
+ RsClient *pClient,
+ NvHandle hMemory,
+ nv_usermap_access_params_t *nvuap
+)
+{
+ NV_STATUS status = NV_OK;
+ NvU64 pages = 0;
+ Memory *pMemory = NULL;
+ PMEMORY_DESCRIPTOR pMemDesc = NULL;
+ RsResourceRef *pResourceRef;
+ NvU64 i;
+ NvU64 *pteArray;
+ NvU64 index;
+
+ if (nvuap == NULL)
+ {
+ return NV_ERR_INVALID_ARGUMENT;
+ }
+
+ //
+ // If we're mapping a memory handle, we can get the data from the
+ // descriptor (required if the allocation being mapped is discontiguous).
+ //
+ if (clientGetResourceRef(pClient, hMemory, &pResourceRef) == NV_OK)
+ {
+ pMemory = dynamicCast(pResourceRef->pResource, Memory);
+ if (pMemory != NULL)
+ {
+ pMemDesc = pMemory->pMemDesc;
+ nvuap->contig = memdescGetContiguity(pMemDesc, AT_CPU);
+ }
+ }
+
+ //
+ // In the discontiguous case, the page array needs to be large enough to hold
+ // the 4K-page-sized addresses that we will then deflate to OS page addresses.
+ // For the contiguous case, we can create the OS-page-sized addresses
+ // directly in the array.
+ //
+ if (nvuap->contig)
+ {
+ pages = nvuap->memArea.pRanges[0].size / os_page_size;
+ }
+ else
+ {
+ if (IS_DISCONTIG_AND_DYNGRAN_ENABLED(pMemDesc))
+ {
+ pages = nvuap->memArea.pRanges[0].size / NV_MIN(os_page_size, pMemDesc->pageArrayGranularity);
+ }
+ else
+ {
+ pages = nvuap->memArea.pRanges[0].size / NV_RM_PAGE_SIZE;
+ }
+ }
+
+ NV_ASSERT_OR_RETURN(pages != 0, NV_ERR_INVALID_ARGUMENT);
+
+ status = os_alloc_mem((void **)&nvuap->page_array, (pages * sizeof(NvU64)));
+ if (status != NV_OK)
+ {
+ return status;
+ }
+
+ if (!nvuap->contig)
+ {
+ pteArray = memdescGetPteArray(pMemDesc, AT_CPU);
+ if (IS_DISCONTIG_AND_DYNGRAN_ENABLED(pMemDesc))
+ {
+ index = nvuap->offset / NV_MIN(os_page_size, pMemDesc->pageArrayGranularity);
+ }
+ else
+ {
+ index = nvuap->offset / NV_RM_PAGE_SIZE;
+ }
+
+ //
+ // We're guaranteed to have a MEMORY_DESCRIPTOR in the discontiguous
+ // case. Copy over the addresses now.
+ //
+ NvU64 copyByteSize = NV_MIN(pages, pMemDesc->pageArraySize) * sizeof(NvU64);
+ portMemCopy((void *)nvuap->page_array,
+ copyByteSize, (void *)&pteArray[index],
+ copyByteSize);
+
+ if (!IS_DISCONTIG_AND_DYNGRAN_ENABLED(pMemDesc))
+ {
+ if (NV_RM_PAGE_SIZE < os_page_size)
+ {
+ RmDeflateRmToOsPageArray(nvuap->page_array, pages);
+ pages = NV_RM_PAGES_TO_OS_PAGES(pages);
+ }
+ }
+ else
+ {
+ //
+ // Because of PMA case, we need to convert page array
+ // from RM native granularity to OS granularity.
+ //
+ convertPageArrayBetweenOsAndRm(
+ nvuap->page_array,
+ nvuap->memArea.pRanges[0].size / pMemDesc->pageArrayGranularity,
+ pMemDesc->pageArrayGranularity,
+ nvuap->memArea.pRanges[0].size / os_page_size,
+ os_page_size,
+ &pages
+ );
+ }
+
+ //
+ // Convert the GPU physical addresses to system physical addresses,
+ // if applicable.
+ //
+ for (i = 0; i < pages; i++)
+ {
+ nvuap->page_array[i] += pKernelMemorySystem->coherentCpuFbBase;
+ }
+ }
+ else
+ {
+ // Offset is accounted in nvuap->memArea.pRanges[0].start.
+ for (nvuap->page_array[0] = nvuap->memArea.pRanges[0].start, i = 1;
+ i < pages; i++)
+ {
+ nvuap->page_array[i] = nvuap->page_array[i-1] + os_page_size;
+ }
+ }
+
+ nvuap->num_pages = pages;
+
+ return status;
+}
+
+/* Must be called with the API lock and the GPU locks */
+static NV_STATUS RmCreateMmapContextLocked(
+ RmClient *pRmClient,
+ NvHandle hDevice,
+ NvHandle hMemory,
+ NvP64 address,
+ NvU64 size,
+ NvU64 offset,
+ NvU32 cachingType,
+ NvU32 fd
+)
+{
+ NV_STATUS status = NV_OK;
+ void *pAllocPriv = NULL;
+ OBJGPU *pGpu = NULL;
+ RsClient *pClient = staticCast(pRmClient, RsClient);
+ KernelMemorySystem *pKernelMemorySystem = NULL;
+ NvBool bCoherentAtsCpuOffset = NV_FALSE;
+ NvBool bHostCoherentFbOffset = NV_FALSE;
+ nv_state_t *pNv = NULL;
+ NvU64 addr = (NvU64)address;
+ NvU32 prot = 0;
+ NvU64 pageIndex = 0;
+ nv_usermap_access_params_t *nvuap = NULL;
+ NvBool bClientMap = (pClient->hClient == hDevice);
+
+ if (!bClientMap)
+ {
+ if (CliSetGpuContext(pClient->hClient, hDevice, &pGpu, NULL) != NV_OK)
+ {
+ Subdevice *pSubdevice;
+
+ status = subdeviceGetByHandle(pClient, hDevice, &pSubdevice);
+ if (status != NV_OK)
+ return status;
+
+ pGpu = GPU_RES_GET_GPU(pSubdevice);
+
+ GPU_RES_SET_THREAD_BC_STATE(pSubdevice);
+ }
+ }
+ nvuap = tlsEntryGet(TLS_ENTRY_ID_MAPPING_CONTEXT);
+ if (nvuap != NULL)
+ {
+ NV_ASSERT(tlsEntryRelease(TLS_ENTRY_ID_MAPPING_CONTEXT) == 0);
+ prot = NV_PROTECT_READ_WRITE;
+ //
+ // TODO: Add this to the mapping context so we don't need to do gymnastics
+ // to figure out what the correct pNv is
+ //
+ pNv = NV_GET_NV_STATE(pGpu);
+ goto add_ctx_to_file;
+ }
+
+ NV_ASSERT_OK_OR_RETURN(os_alloc_mem((void**)&nvuap, sizeof(nv_usermap_access_params_t)));
+ portMemSet(nvuap, 0, sizeof(nv_usermap_access_params_t));
+
+ NV_ASSERT_OK_OR_GOTO(status, os_alloc_mem((void**)&(nvuap->memArea.pRanges), sizeof(MemoryRange)), free_nvuap);
+
+ nvuap->addr = addr;
+ nvuap->size = size;
+ nvuap->offset = offset;
+ nvuap->caching = cachingType;
+
+ //
+ // Assume the allocation is contiguous until RmGetMmapPteArray
+ // determines otherwise.
+ //
+ nvuap->contig = NV_TRUE;
+ nv_align_mmap_offset_length(nvuap);
+
+ if (pGpu != NULL)
+ {
+ pNv = NV_GET_NV_STATE(pGpu);
+ pKernelMemorySystem = GPU_GET_KERNEL_MEMORY_SYSTEM(pGpu);
+ bCoherentAtsCpuOffset = IS_COHERENT_CPU_ATS_OFFSET(pGpu, pKernelMemorySystem, addr, size);
+ bHostCoherentFbOffset = !bCoherentAtsCpuOffset &&
+ IS_COHERENT_FB_OFFSET(pGpu, pKernelMemorySystem, addr, size);
+ }
+ //
+ // If no device is given, or the address isn't in the given device's BARs,
+ // validate this as a system memory mapping and associate it with the
+ // control device.
+ //
+ if ((pNv == NULL) ||
+ (!IS_REG_OFFSET(pNv, addr, size) &&
+ !IS_FB_OFFSET(pNv, addr, size) &&
+ !(bCoherentAtsCpuOffset || bHostCoherentFbOffset) &&
+ !IS_IMEM_OFFSET(pNv, addr, size)))
+ {
+ pNv = nv_get_ctl_state();
+
+ //
+ // Validate the mapping request by looking up the underlying sysmem
+ // allocation.
+ //
+ status = RmGetAllocPrivate(pRmClient, hMemory, addr, size, &prot, &pAllocPriv,
+ &pageIndex);
+
+ if (status != NV_OK)
+ {
+ goto done;
+ }
+ }
+ else
+ {
+ //
+ // Validate the mapping request for ATS and get pteArray
+ //
+ if (bCoherentAtsCpuOffset)
+ {
+ status = RmGetMmapPteArray(pKernelMemorySystem, pClient, hMemory, nvuap);
+ if (status != NV_OK)
+ {
+ goto done;
+ }
+ }
+ else if (bHostCoherentFbOffset)
+ {
+ status = RmGetMmapPteArray(pKernelMemorySystem, pClient, hMemory, nvuap);
+ if (status != NV_OK)
+ {
+ goto done;
+ }
+
+ //
+ // nvuap->page_array(allocated in RmGetMmapPteArray) is not assigned
+ // to nvamc->page_array if onlining status is false(which is the case with
+ // bHostCoherentFbOffset) and so doesn't get freed if not done here.
+ // The call to RmGetMmapPteArray is for getting the contig and num
+ // pages of the allocation.
+ //
+ os_free_mem(nvuap->page_array);
+ nvuap->page_array = NULL;
+ }
+
+ NV_ASSERT_OK_OR_GOTO(status, RmSetUserMapAccessRange(nvuap), done);
+
+ // Validate the mapping request for BAR's.
+ status = RmValidateMmapRequest(pNv, nvuap->access_start,
+ nvuap->access_size, &prot);
+ if (status != NV_OK)
+ {
+ goto done;
+ }
+ }
+
+add_ctx_to_file:
+ status = nv_add_mapping_context_to_file(pNv, nvuap, prot, pAllocPriv,
+ pageIndex, fd);
+
+done:
+ os_free_mem(nvuap->memArea.pRanges);
+free_nvuap:
+ os_free_mem(nvuap);
+ return status;
+}
+
+// TODO: Bug 1802250: [uvm8] Use an alt stack in all functions in unix/src/osapi.c
+NV_STATUS rm_create_mmap_context(
+ NvHandle hClient,
+ NvHandle hDevice,
+ NvHandle hMemory,
+ NvP64 address,
+ NvU64 size,
+ NvU64 offset,
+ NvU32 cachingType,
+ NvU32 fd
+)
+{
+ NV_STATUS rmStatus = NV_OK;
+ // LOCK: acquire API lock
+ if ((rmStatus = rmapiLockAcquire(RMAPI_LOCK_FLAGS_READ, RM_LOCK_MODULES_OSAPI)) == NV_OK)
+ {
+ CLIENT_ENTRY *pClientEntry;
+ RmClient *pRmClient;
+
+ if (NV_OK != serverutilAcquireClient(hClient, LOCK_ACCESS_READ, &pClientEntry,
+ &pRmClient))
+ {
+ // UNLOCK: release API lock
+ rmapiLockRelease();
+ return NV_ERR_INVALID_CLIENT;
+ }
+
+ if (pRmClient->ProcID != osGetCurrentProcess())
+ {
+ rmStatus = NV_ERR_INVALID_CLIENT;
+ }
+ // LOCK: acquire GPUs lock
+ else if ((rmStatus = rmGpuLocksAcquire(GPUS_LOCK_FLAGS_NONE, RM_LOCK_MODULES_OSAPI)) == NV_OK)
+ {
+ rmStatus = RmCreateMmapContextLocked(pRmClient, hDevice,
+ hMemory, address, size, offset,
+ cachingType, fd);
+ // UNLOCK: release GPUs lock
+ rmGpuLocksRelease(GPUS_LOCK_FLAGS_NONE, NULL);
+ }
+
+ serverutilReleaseClient(LOCK_ACCESS_READ, pClientEntry);
+
+ // UNLOCK: release API lock
+ rmapiLockRelease();
+ }
+
+ return rmStatus;
+}
+
+static NV_STATUS RmGetAllocPrivate(
+ RmClient *pRmClient,
+ NvU32 hMemory,
+ NvU64 offset,
+ NvU64 length,
+ NvU32 *pProtection,
+ void **ppPrivate,
+ NvU64 *pPageIndex
+)
+{
+ NV_STATUS rmStatus;
+ PMEMORY_DESCRIPTOR pMemDesc;
+ NvU32 pageOffset;
+ NvU64 pageCount;
+ NvU64 endingOffset;
+ RsResourceRef *pResourceRef;
+ RmResource *pRmResource;
+ void *pMemData;
+ NvBool bPeerIoMem;
+ NvBool bReadOnlyMem;
+ *pProtection = NV_PROTECT_READ_WRITE;
+ *ppPrivate = NULL;
+
+ pageOffset = (offset & ~os_page_mask);
+ offset &= os_page_mask;
+
+ NV_ASSERT_OR_RETURN(rmapiLockIsOwner(), NV_ERR_INVALID_LOCK_STATE);
+
+ rmStatus = clientGetResourceRef(staticCast(pRmClient, RsClient),
+ hMemory, &pResourceRef);
+ if (rmStatus != NV_OK)
+ goto done;
+
+ pRmResource = dynamicCast(pResourceRef->pResource, RmResource);
+ if (!pRmResource)
+ {
+ rmStatus = NV_ERR_INVALID_OBJECT;
+ goto done;
+ }
+
+ rmStatus = rmresGetMemoryMappingDescriptor(pRmResource, &pMemDesc);
+ if (rmStatus != NV_OK)
+ goto done;
+
+ bReadOnlyMem = memdescGetFlag(pMemDesc, MEMDESC_FLAGS_USER_READ_ONLY);
+ bPeerIoMem = memdescGetFlag(pMemDesc, MEMDESC_FLAGS_PEER_IO_MEM);
+
+ if (!(pMemDesc->Allocated || bPeerIoMem ||
+ memdescIsCarveoutMemory(pMemDesc) ||
+ (memdescGetFlag(pMemDesc, MEMDESC_FLAGS_ALLOW_EXT_SYSMEM_USER_CPU_MAPPING))))
+ {
+ NV_PRINTF(LEVEL_ERROR, "Mmap is not allowed\n");
+ rmStatus = NV_ERR_OBJECT_NOT_FOUND;
+ goto done;
+ }
+
+ switch (memdescGetAddressSpace(pMemDesc))
+ {
+ case ADDR_SYSMEM:
+ break;
+ default:
+ rmStatus = NV_ERR_OBJECT_NOT_FOUND;
+ goto done;
+ }
+
+ pMemData = memdescGetMemData(pMemDesc);
+ if (pMemData == NULL)
+ {
+ rmStatus = NV_ERR_OBJECT_NOT_FOUND;
+ goto done;
+ }
+
+ rmStatus = os_match_mmap_offset(pMemData, offset, pPageIndex);
+ if (rmStatus != NV_OK)
+ goto done;
+
+ if (!portSafeAddU64(pageOffset, length, &endingOffset))
+ {
+ rmStatus = NV_ERR_INVALID_ARGUMENT;
+ goto done;
+ }
+
+ pageCount = (endingOffset / os_page_size);
+
+ if (!portSafeAddU64(*pPageIndex + ((endingOffset % os_page_size) ? 1 : 0),
+ pageCount, &pageCount))
+ {
+ rmStatus = NV_ERR_INVALID_ARGUMENT;
+ goto done;
+ }
+
+ if (IS_DISCONTIG_AND_DYNGRAN_ENABLED(pMemDesc))
+ {
+ NV_ASSERT_OR_ELSE(pageCount <= pMemDesc->PageCount, rmStatus = NV_ERR_INVALID_ARGUMENT; goto done);
+ }
+ else if (pageCount > NV_RM_PAGES_TO_OS_PAGES(pMemDesc->PageCount))
+ {
+ rmStatus = NV_ERR_INVALID_ARGUMENT;
+ goto done;
+ }
+
+ if (bReadOnlyMem)
+ *pProtection = NV_PROTECT_READABLE;
+
+ *ppPrivate = pMemData;
+
+done:
+ return rmStatus;
+}
+
+NV_STATUS rm_get_adapter_status(
+ nv_state_t *pNv,
+ NvU32 *pStatus
+)
+{
+ NV_STATUS rmStatus = NV_ERR_OPERATING_SYSTEM;
+
+ // LOCK: acquire API lock
+ if (rmapiLockAcquire(RMAPI_LOCK_FLAGS_READ, RM_LOCK_MODULES_OSAPI) == NV_OK)
+ {
+ rmStatus = RmGetAdapterStatus(pNv, pStatus);
+
+ // UNLOCK: release API lock
+ rmapiLockRelease();
+ }
+
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_get_adapter_status_external(
+ nvidia_stack_t *sp,
+ nv_state_t *pNv
+)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+
+ if (rm_get_adapter_status(pNv, &rmStatus) != NV_OK)
+ {
+ rmStatus = NV_ERR_OPERATING_SYSTEM;
+ }
+
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return rmStatus;
+}
+
+NvBool NV_API_CALL rm_init_rm(
+ nvidia_stack_t *sp
+)
+{
+ NvBool retval;
+ void *fp;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+
+ retval = RmInitRm();
+
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return retval;
+}
+
+void NV_API_CALL rm_shutdown_rm(
+ nvidia_stack_t *sp
+)
+{
+ void *fp;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+
+ RmShutdownRm();
+
+ NV_EXIT_RM_RUNTIME(sp,fp);
+}
+
+NvBool NV_API_CALL rm_init_event_locks(
+ nvidia_stack_t *sp,
+ nv_state_t *pNv
+)
+{
+ void *fp;
+ NvBool ret;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+
+ pNv->event_spinlock = portSyncSpinlockCreate(portMemAllocatorGetGlobalNonPaged());
+ ret = (pNv->event_spinlock != NULL);
+
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return ret;
+}
+
+void NV_API_CALL rm_destroy_event_locks(
+ nvidia_stack_t *sp,
+ nv_state_t *pNv
+)
+{
+ void *fp;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+
+ if (pNv && pNv->event_spinlock)
+ portSyncSpinlockDestroy(pNv->event_spinlock);
+
+ NV_EXIT_RM_RUNTIME(sp,fp);
+}
+
+NV_STATUS NV_API_CALL rm_stop_user_channels(
+ nvidia_stack_t *sp,
+ nv_state_t *pNv
+)
+{
+ NV2080_CTRL_FIFO_DISABLE_USERMODE_CHANNELS_PARAMS params = { 0 };
+ RM_API *pRmApi;
+ THREAD_STATE_NODE threadState;
+ NV_STATUS rmStatus = NV_ERR_INVALID_STATE;
+ void *fp;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+
+ pRmApi = RmUnixRmApiPrologue(pNv, &threadState, RM_LOCK_MODULES_FIFO);
+ if (pRmApi != NULL)
+ {
+ params.bDisable = NV_TRUE;
+ rmStatus = pRmApi->Control(pRmApi, pNv->rmapi.hClient,
+ pNv->rmapi.hSubDevice,
+ NV2080_CTRL_CMD_FIFO_DISABLE_USERMODE_CHANNELS,
+ &params, sizeof(params));
+
+ RmUnixRmApiEpilogue(pNv, &threadState);
+ }
+
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_restart_user_channels(
+ nvidia_stack_t *sp,
+ nv_state_t *pNv
+)
+{
+ NV2080_CTRL_FIFO_DISABLE_USERMODE_CHANNELS_PARAMS params = { 0 };
+ RM_API *pRmApi;
+ THREAD_STATE_NODE threadState;
+ NV_STATUS rmStatus = NV_ERR_INVALID_STATE;
+ void *fp;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+
+ pRmApi = RmUnixRmApiPrologue(pNv, &threadState, RM_LOCK_MODULES_FIFO);
+ if (pRmApi != NULL)
+ {
+ params.bDisable = NV_FALSE;
+ rmStatus = pRmApi->Control(pRmApi, pNv->rmapi.hClient, pNv->rmapi.hSubDevice,
+ NV2080_CTRL_CMD_FIFO_DISABLE_USERMODE_CHANNELS,
+ &params, sizeof(params));
+
+ RmUnixRmApiEpilogue(pNv, &threadState);
+ }
+
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return rmStatus;
+}
+
+//
+// Use this call to check if the chipset is io coherent
+//
+NvBool NV_API_CALL rm_is_chipset_io_coherent(
+ nvidia_stack_t *sp)
+{
+ void *fp;
+ OBJSYS *pSys;
+ OBJCL *pCl;
+ NvBool bIoCoherent = NV_FALSE;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+
+ pSys = SYS_GET_INSTANCE();
+ pCl = SYS_GET_CL(pSys);
+ if (pCl == NULL)
+ {
+ NV_PRINTF(LEVEL_ERROR,
+ "%s: no CL object found, setting io coherent by default\n",
+ __FUNCTION__);
+ goto done;
+ }
+
+ bIoCoherent = pCl->getProperty(pCl, PDB_PROP_CL_IS_CHIPSET_IO_COHERENT);
+
+done:
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return bIoCoherent;
+}
+
+NV_STATUS NV_API_CALL rm_validate_ioctls(
+ NvU32 command,
+ NvU32 dataSize
+)
+{
+ size_t arg_size = dataSize;
+ int arg_cmd = (command & 0xFF);
+ int i;
+ NV_STATUS status;
+ static const struct {
+ unsigned int cmdKey;
+ size_t paramSize;
+ } rm_ioctls_table[] = {
+ #define _RM_IOCTL_ENTRY(_cmd, _type) \
+ { .cmdKey = ((_cmd) & 0xFF), .paramSize = sizeof(_type),}
+ /*rm_ioctls */
+ _RM_IOCTL_ENTRY(NV_ESC_ALLOC_OS_EVENT, nv_ioctl_alloc_os_event_t),
+ _RM_IOCTL_ENTRY(NV_ESC_FREE_OS_EVENT, nv_ioctl_free_os_event_t),
+ _RM_IOCTL_ENTRY(NV_ESC_RM_GET_EVENT_DATA, NVOS41_PARAMETERS),
+ };
+
+ status = RmValidateIoctl(command, dataSize);
+ if (status != NV_ERR_INVALID_COMMAND)
+ {
+ return status;
+ }
+
+ for (i = 0; i < NV_ARRAY_ELEMENTS(rm_ioctls_table); ++i)
+ {
+ if (arg_cmd == rm_ioctls_table[i].cmdKey)
+ {
+ if (arg_size == rm_ioctls_table[i].paramSize)
+ {
+ return NV_OK;
+ }
+ nv_printf(NV_DBG_ERRORS, "NVRM: invalid %d structure size, expected %d, got %d!\n",
+ rm_ioctls_table[i].cmdKey, rm_ioctls_table[i].paramSize, arg_size);
+
+ return NV_ERR_INVALID_ARGUMENT;
+ }
+ }
+ // Unknown IOCTL case. Not found in any rm and RM Tables.
+ return NV_ERR_INVALID_COMMAND;
+}
+
+NV_STATUS NV_API_CALL rm_ioctl(
+ nvidia_stack_t *sp,
+ nv_state_t *pNv,
+ nv_file_private_t *nvfp,
+ NvU32 Command,
+ void *pData,
+ NvU32 dataSize
+)
+{
+ NV_STATUS rmStatus = NV_OK;
+ THREAD_STATE_NODE threadState;
+ void *fp;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+
+ //
+ // Some ioctls are handled entirely inside the OS layer and don't need to
+ // suffer the overhead of calling into RM core.
+ //
+ switch (Command)
+ {
+ case NV_ESC_ALLOC_OS_EVENT:
+ {
+ nv_ioctl_alloc_os_event_t *pApi = pData;
+
+ if (dataSize != sizeof(nv_ioctl_alloc_os_event_t))
+ {
+ rmStatus = NV_ERR_INVALID_ARGUMENT;
+ break;
+ }
+
+ pApi->Status = allocate_os_event(pApi->hClient, nvfp, pApi->fd);
+ break;
+ }
+ case NV_ESC_FREE_OS_EVENT:
+ {
+ nv_ioctl_free_os_event_t *pApi = pData;
+
+ if (dataSize != sizeof(nv_ioctl_free_os_event_t))
+ {
+ rmStatus = NV_ERR_INVALID_ARGUMENT;
+ break;
+ }
+
+ pApi->Status = free_os_event(pApi->hClient, pApi->fd);
+ break;
+ }
+ case NV_ESC_RM_GET_EVENT_DATA:
+ {
+ NVOS41_PARAMETERS *pApi = pData;
+
+ if (dataSize != sizeof(NVOS41_PARAMETERS))
+ {
+ rmStatus = NV_ERR_INVALID_ARGUMENT;
+ break;
+ }
+
+ pApi->status = get_os_event_data(nvfp,
+ pApi->pEvent,
+ &pApi->MoreEvents);
+ break;
+ }
+ default:
+ {
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+ rmStatus = RmIoctl(pNv, nvfp, Command, pData, dataSize);
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ break;
+ }
+ }
+
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return rmStatus;
+}
+
+static void _deferredClientListFreeCallback(void *unused)
+{
+ OBJSYS *pSys = SYS_GET_INSTANCE();
+ NV_STATUS status = serverFreeDisabledClients(&g_resServ, 0, pSys->clientListDeferredFreeLimit);
+ //
+ // Possible return values:
+ // NV_WARN_MORE_PROCESSING_REQUIRED - Iteration limit reached, need to call again
+ // NV_ERR_IN_USE - Already running on another thread, try again later
+ // In both cases, schedule a worker to clean up anything that remains
+ //
+ if (status != NV_OK)
+ {
+ status = osQueueSystemWorkItem(_deferredClientListFreeCallback, unused);
+ if (status != NV_OK)
+ {
+ NV_PRINTF(LEVEL_NOTICE, "Failed to schedule deferred free callback. Freeing immediately.\n");
+ serverFreeDisabledClients(&g_resServ, 0, 0);
+ }
+ }
+}
+
+void NV_API_CALL rm_cleanup_file_private(
+ nvidia_stack_t *sp,
+ nv_state_t *pNv,
+ nv_file_private_t *nvfp
+)
+{
+ THREAD_STATE_NODE threadState;
+ void *fp;
+ RM_API *pRmApi;
+ RM_API_CONTEXT rmApiContext = {0};
+ NvU32 i;
+ OBJSYS *pSys = SYS_GET_INSTANCE();
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+
+ //
+ // Skip cleaning up this fd if:
+ // - no RMAPI clients and events were ever allocated on this fd
+ // - no RMAPI object handles were exported on this fd
+ // Access nvfp->handles without locking as fd cleanup is synchronised by the kernel
+ //
+ if (!nvfp->bCleanupRmapi && nvfp->handles == NULL)
+ goto done;
+
+ pRmApi = rmapiGetInterface(RMAPI_EXTERNAL);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+ threadStateSetTimeoutOverride(&threadState, 10 * 1000);
+
+ if (rmapiPrologue(pRmApi, &rmApiContext) != NV_OK) {
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return;
+ }
+
+ // LOCK: acquire API lock. Low priority so cleanup doesn't block active threads
+ if (rmapiLockAcquire(RMAPI_LOCK_FLAGS_LOW_PRIORITY, RM_LOCK_MODULES_OSAPI) == NV_OK)
+ {
+ // Unref any object which was exported on this file.
+ if (nvfp->handles != NULL)
+ {
+ for (i = 0; i < nvfp->maxHandles; i++)
+ {
+ if (nvfp->handles[i] == 0)
+ {
+ continue;
+ }
+
+ RmFreeObjExportHandle(nvfp->handles[i]);
+ nvfp->handles[i] = 0;
+ }
+
+ os_free_mem(nvfp->handles);
+ nvfp->handles = NULL;
+ nvfp->maxHandles = 0;
+ }
+
+ // Disable any RM clients associated with this file.
+ RmFreeUnusedClients(pNv, nvfp);
+
+ // Unless configured otherwise, immediately free all disabled clients
+ if (!pSys->bUseDeferredClientListFree)
+ serverFreeDisabledClients(&g_resServ, RM_LOCK_STATES_API_LOCK_ACQUIRED, 0);
+
+ // UNLOCK: release API lock
+ rmapiLockRelease();
+ }
+
+ // Start the deferred free callback if necessary
+ if (pSys->bUseDeferredClientListFree)
+ _deferredClientListFreeCallback(NULL);
+
+ rmapiEpilogue(pRmApi, &rmApiContext);
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+
+done:
+ if (nvfp->ctl_nvfp != NULL)
+ {
+ nv_put_file_private(nvfp->ctl_nvfp_priv);
+ nvfp->ctl_nvfp = NULL;
+ nvfp->ctl_nvfp_priv = NULL;
+ }
+
+ NV_EXIT_RM_RUNTIME(sp,fp);
+}
+
+void NV_API_CALL rm_unbind_lock(
+ nvidia_stack_t *sp,
+ nv_state_t *pNv
+)
+{
+ THREAD_STATE_NODE threadState;
+ void *fp;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ // LOCK: acquire API lock
+ if (rmapiLockAcquire(API_LOCK_FLAGS_NONE, RM_LOCK_MODULES_OSAPI) == NV_OK)
+ {
+ RmUnbindLock(pNv);
+
+ // UNLOCK: release API lock
+ rmapiLockRelease();
+ }
+
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+}
+
+NV_STATUS NV_API_CALL rm_read_registry_dword(
+ nvidia_stack_t *sp,
+ nv_state_t *nv,
+ const char *regParmStr,
+ NvU32 *Data
+)
+{
+ OBJGPU *pGpu = NULL;
+ NV_STATUS RmStatus;
+ void *fp;
+ NvBool isApiLockTaken = NV_FALSE;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+
+ //
+ // We can be called from different contexts:
+ //
+ // 1) early initialization without device state.
+ // 2) from outside the RM API (without the lock held)
+ //
+ // In context 1)the API lock is not needed and
+ // in context 2), it needs to be acquired.
+ //
+ if (nv != NULL)
+ {
+ // LOCK: acquire API lock
+ if ((RmStatus = rmapiLockAcquire(RMAPI_LOCK_FLAGS_READ, RM_LOCK_MODULES_OSAPI)) != NV_OK)
+ {
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return RmStatus;
+ }
+
+ isApiLockTaken = NV_TRUE;
+ }
+
+ pGpu = NV_GET_NV_PRIV_PGPU(nv);
+
+ // Skipping the NULL check as osReadRegistryDword takes care of it.
+ RmStatus = osReadRegistryDword(pGpu, regParmStr, Data);
+
+ if (isApiLockTaken == NV_TRUE)
+ {
+ // UNLOCK: release API lock
+ rmapiLockRelease();
+ }
+
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return RmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_write_registry_dword(
+ nvidia_stack_t *sp,
+ nv_state_t *nv,
+ const char *regParmStr,
+ NvU32 Data
+)
+{
+ NV_STATUS RmStatus;
+ void *fp;
+ NvBool isApiLockTaken = NV_FALSE;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+
+ if (nv != NULL)
+ {
+ // LOCK: acquire API lock
+ if ((RmStatus = rmapiLockAcquire(API_LOCK_FLAGS_NONE, RM_LOCK_MODULES_OSAPI)) != NV_OK)
+ {
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return RmStatus;
+ }
+
+ isApiLockTaken = NV_TRUE;
+ }
+
+ RmStatus = RmWriteRegistryDword(nv, regParmStr, Data);
+
+ if (isApiLockTaken == NV_TRUE)
+ {
+ // UNLOCK: release API lock
+ rmapiLockRelease();
+ }
+
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return RmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_write_registry_binary(
+ nvidia_stack_t *sp,
+ nv_state_t *nv,
+ const char *regParmStr,
+ NvU8 *Data,
+ NvU32 cbLen
+)
+{
+ NV_STATUS RmStatus;
+ void *fp;
+ NvBool isApiLockTaken = NV_FALSE;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+
+ if (nv != NULL)
+ {
+ // LOCK: acquire API lock
+ if ((RmStatus = rmapiLockAcquire(API_LOCK_FLAGS_NONE, RM_LOCK_MODULES_OSAPI)) != NV_OK)
+ {
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return RmStatus;
+ }
+
+ isApiLockTaken = NV_TRUE;
+ }
+
+ RmStatus = RmWriteRegistryBinary(nv, regParmStr, Data, cbLen);
+
+ if (isApiLockTaken == NV_TRUE)
+ {
+ // UNLOCK: release API lock
+ rmapiLockRelease();
+ }
+
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return RmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_write_registry_string(
+ nvidia_stack_t *sp,
+ nv_state_t *nv,
+ const char *regParmStr,
+ const char *string,
+ NvU32 stringLength
+)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NvBool isApiLockTaken = NV_FALSE;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+
+ if (nv != NULL)
+ {
+ // LOCK: acquire API lock
+ if ((rmStatus = rmapiLockAcquire(API_LOCK_FLAGS_NONE, RM_LOCK_MODULES_OSAPI)) != NV_OK)
+ {
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+ }
+
+ isApiLockTaken = NV_TRUE;
+ }
+
+ rmStatus = RmWriteRegistryString(nv, regParmStr, string, (stringLength + 1));
+
+ if (isApiLockTaken == NV_TRUE)
+ {
+ // UNLOCK: release API lock
+ rmapiLockRelease();
+ }
+
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return rmStatus;
+}
+
+static NvBool NV_API_CALL rm_is_space(const char ch)
+{
+ //
+ // return true if it is a:
+ // ' ' : (space - decimal 32.)
+ // '\t' : (TAB - decimal 9)
+ // 'LF' : (Line feed, new line - decimal 10)
+ // 'VT' : (Vertical TAB - decimal 11)
+ // 'FF' : (Form feed, new page - decimal 12)
+ // '\r' : (carriage return - decimal 13)
+ //
+ return ((ch == ' ') || ((ch >= '\t') && (ch <= '\r')));
+}
+
+char* NV_API_CALL rm_remove_spaces(const char *in)
+{
+ unsigned int len = os_string_length(in) + 1;
+ const char *in_ptr;
+ char *out, *out_ptr;
+
+ if (os_alloc_mem((void **)&out, len) != NV_OK)
+ return NULL;
+
+ in_ptr = in;
+ out_ptr = out;
+
+ while (*in_ptr != '\0')
+ {
+ if (!rm_is_space(*in_ptr))
+ *out_ptr++ = *in_ptr;
+ in_ptr++;
+ }
+ *out_ptr = '\0';
+
+ return out;
+}
+
+char* NV_API_CALL rm_string_token(char **strp, const char delim)
+{
+ char *s, *token;
+
+ if ((strp == NULL) || (*strp == NULL))
+ return NULL;
+
+ s = token = *strp;
+ *strp = NULL;
+
+ for (; *s != '\0'; s++) {
+ if (*s == delim) {
+ *s = '\0';
+ *strp = ++s;
+ break;
+ }
+ }
+
+ return token;
+}
+
+// Parse string passed in NVRM as module parameter.
+void NV_API_CALL rm_parse_option_string(nvidia_stack_t *sp, const char *nvRegistryDwords)
+{
+ unsigned int i;
+ nv_parm_t *entry;
+ char *option_string = NULL;
+ char *ptr, *token;
+ char *name, *value;
+ NvU32 data;
+
+ if (nvRegistryDwords != NULL)
+ {
+ if ((option_string = rm_remove_spaces(nvRegistryDwords)) == NULL)
+ {
+ return;
+ }
+
+ ptr = option_string;
+
+ while ((token = rm_string_token(&ptr, ';')) != NULL)
+ {
+ if (!(name = rm_string_token(&token, '=')) || !os_string_length(name))
+ {
+ continue;
+ }
+
+ if (!(value = rm_string_token(&token, '=')) || !os_string_length(value))
+ {
+ continue;
+ }
+
+ if (rm_string_token(&token, '=') != NULL)
+ {
+ continue;
+ }
+
+ data = os_strtoul(value, NULL, 0);
+
+ for (i = 0; (entry = &nv_parms[i])->name != NULL; i++)
+ {
+ if (os_string_compare(entry->name, name) == 0)
+ break;
+ }
+
+ if (!entry->name)
+ rm_write_registry_dword(sp, NULL, name, data);
+ else
+ *entry->data = data;
+ }
+
+ // Free the memory allocated by rm_remove_spaces()
+ os_free_mem(option_string);
+ }
+}
+
+NV_STATUS NV_API_CALL rm_run_rc_callback(
+ nvidia_stack_t *sp,
+ nv_state_t *nv
+)
+{
+ OBJGPU *pGpu;
+ void *fp;
+
+ /* make sure our timer's not still running when it shouldn't be */
+ if (nv == NULL)
+ return NV_ERR_GENERIC;
+
+ pGpu = NV_GET_NV_PRIV_PGPU(nv);
+ if (pGpu == NULL)
+ return NV_ERR_GENERIC;
+
+ if (nv->rc_timer_enabled == 0)
+ return NV_ERR_GENERIC;
+
+ if (!FULL_GPU_SANITY_CHECK(pGpu))
+ {
+ return NV_ERR_GENERIC;
+ }
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+
+ osRun1HzCallbacksNow(pGpu);
+
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return NV_OK;
+}
+
+static void _tmrEventServiceTimerWorkItem
+(
+ NvU32 gpuInstance,
+ void *pArgs
+)
+{
+ OBJGPU *pGpu = gpumgrGetGpu(gpuInstance);
+ OBJTMR *pTmr = GPU_GET_TIMER(pGpu);
+ NV_STATUS status = NV_OK;
+
+ status = tmrEventServiceTimer(pGpu, pTmr, (TMR_EVENT *)pArgs);
+
+ if (status != NV_OK)
+ NV_PRINTF(LEVEL_ERROR, "Timer event failed from OS timer callback workitem with status :0x%x\n", status);
+}
+
+static NV_STATUS RmRunNanoTimerCallback(
+ OBJGPU *pGpu,
+ void *pTmrEvent
+)
+{
+ THREAD_STATE_NODE threadState;
+ NV_STATUS status = NV_OK;
+
+ threadStateInitISRAndDeferredIntHandler(&threadState, pGpu,
+ THREAD_STATE_FLAGS_IS_DEFERRED_INT_HANDLER);
+
+ //
+ // OS timers come in ISR context, hence schedule workitem for timer event service.
+ // GPU timer events are also handled in same mammer allowing us to have same functionality
+ // for callback functions.
+ //
+ status = osQueueWorkItem(pGpu,
+ _tmrEventServiceTimerWorkItem,
+ pTmrEvent,
+ (OsQueueWorkItemFlags){
+ .bLockGpuGroupDevice = NV_TRUE,
+ .bDontFreeParams = NV_TRUE});
+ if (status != NV_OK)
+ {
+ NV_PRINTF(LEVEL_ERROR,"Queuing workitem for timer event failed with status :0x%x\n", status);
+ }
+
+ // Out of conflicting thread
+ threadStateFreeISRAndDeferredIntHandler(&threadState,
+ pGpu, THREAD_STATE_FLAGS_IS_DEFERRED_INT_HANDLER);
+
+ return status;
+}
+
+NV_STATUS NV_API_CALL rm_run_nano_timer_callback
+(
+ nvidia_stack_t *sp,
+ nv_state_t *nv,
+ void *pTmrEvent
+)
+{
+ NV_STATUS status;
+ OBJGPU *pGpu = NULL;
+ void *fp;
+
+ if (nv == NULL)
+ return NV_ERR_GENERIC;
+
+ pGpu = NV_GET_NV_PRIV_PGPU(nv);
+ if (pGpu == NULL)
+ return NV_ERR_GENERIC;
+
+ if (!FULL_GPU_SANITY_FOR_PM_RESUME(pGpu))
+ {
+ return NV_ERR_GENERIC;
+ }
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+
+ status = RmRunNanoTimerCallback(pGpu, pTmrEvent);
+
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return status;
+}
+
+void NV_API_CALL rm_execute_work_item(
+ nvidia_stack_t *sp,
+ void *pNvWorkItem
+)
+{
+ void *fp;
+ THREAD_STATE_NODE threadState;
+
+ NV_ENTER_RM_RUNTIME(sp, fp);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ RmExecuteWorkItem(pNvWorkItem);
+
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp, fp);
+}
+
+const char* NV_API_CALL rm_get_device_name(
+ NvU16 device,
+ NvU16 subsystem_vendor,
+ NvU16 subsystem_device
+)
+{
+ unsigned int i;
+ const char *tmpName = NULL;
+
+ for (i = 0; i < NV_ARRAY_ELEMENTS(sChipsReleased); i++)
+ {
+ // if the device ID doesn't match, go to the next entry
+ if (device != sChipsReleased[i].devID)
+ {
+ continue;
+ }
+
+ // if the entry has 0 for the subsystem IDs, then the device
+ // ID match is sufficient, but continue scanning through
+ // sChipsReleased[] in case there is a subsystem ID match later
+ // in the table
+ if (sChipsReleased[i].subSystemVendorID == 0 &&
+ sChipsReleased[i].subSystemID == 0)
+ {
+ tmpName = sChipsReleased[i].name;
+ continue;
+ }
+
+ if (subsystem_vendor == sChipsReleased[i].subSystemVendorID &&
+ subsystem_device == sChipsReleased[i].subSystemID)
+ {
+ tmpName = sChipsReleased[i].name;
+ break;
+ }
+ }
+
+ return (tmpName != NULL) ? tmpName : "Unknown";
+}
+
+NV_STATUS rm_access_registry(
+ NvHandle hClient,
+ NvHandle hObject,
+ NvU32 AccessType,
+ NvP64 clientDevNodeAddress,
+ NvU32 DevNodeLength,
+ NvP64 clientParmStrAddress,
+ NvU32 ParmStrLength,
+ NvP64 clientBinaryDataAddress,
+ NvU32 *pBinaryDataLength,
+ NvU32 *Data,
+ NvU32 *Entry
+)
+{
+ NV_STATUS RmStatus;
+ NvBool bReadOnly = (AccessType == NVOS38_ACCESS_TYPE_READ_DWORD) ||
+ (AccessType == NVOS38_ACCESS_TYPE_READ_BINARY);
+
+ // LOCK: acquire API lock
+ if ((RmStatus = rmapiLockAcquire(bReadOnly ? RMAPI_LOCK_FLAGS_READ : RMAPI_LOCK_FLAGS_NONE,
+ RM_LOCK_MODULES_OSAPI)) == NV_OK)
+ {
+ RmStatus = RmAccessRegistry(hClient,
+ hObject,
+ AccessType,
+ clientDevNodeAddress,
+ DevNodeLength,
+ clientParmStrAddress,
+ ParmStrLength,
+ clientBinaryDataAddress,
+ pBinaryDataLength,
+ Data,
+ Entry);
+
+ // UNLOCK: release API lock
+ rmapiLockRelease();
+ }
+
+ return RmStatus;
+}
+
+NV_STATUS rm_update_device_mapping_info(
+ NvHandle hClient,
+ NvHandle hDevice,
+ NvHandle hMemory,
+ void *pOldCpuAddress,
+ void *pNewCpuAddress
+)
+{
+ NV_STATUS RmStatus;
+
+ // LOCK: acquire API lock
+ if ((RmStatus = rmapiLockAcquire(RMAPI_LOCK_FLAGS_READ, RM_LOCK_MODULES_GPU)) == NV_OK)
+ {
+ RmStatus = RmUpdateDeviceMappingInfo(hClient,
+ hDevice,
+ hMemory,
+ pOldCpuAddress,
+ pNewCpuAddress);
+
+ // UNLOCK: release API lock
+ rmapiLockRelease();
+ }
+
+ return RmStatus;
+}
+
+static NvBool NV_API_CALL rm_is_legacy_device(
+ NvU16 device_id,
+ NvU16 subsystem_vendor,
+ NvU16 subsystem_device,
+ NvBool print_warning
+)
+{
+ return NV_FALSE;
+}
+
+static NvBool NV_API_CALL rm_is_legacy_arch(
+ NvU32 pmc_boot_0,
+ NvU32 pmc_boot_42
+)
+{
+ NvBool legacy = NV_FALSE;
+
+ return legacy;
+}
+
+NV_STATUS NV_API_CALL rm_is_supported_device(
+ nvidia_stack_t *sp,
+ nv_state_t *pNv
+)
+{
+ THREAD_STATE_NODE threadState;
+ NV_STATUS rmStatus;
+ OBJSYS *pSys;
+ OBJHALMGR *pHalMgr;
+ GPUHWREG *reg_mapping;
+ NvU32 myHalPublicID;
+ void *fp;
+ NvU32 pmc_boot_0;
+ NvU32 pmc_boot_42;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ pSys = SYS_GET_INSTANCE();
+ pHalMgr = SYS_GET_HALMGR(pSys);
+
+ reg_mapping = osMapKernelSpace(pNv->regs->cpu_address,
+ os_page_size,
+ NV_MEMORY_UNCACHED,
+ NV_PROTECT_READABLE);
+
+ if (reg_mapping == NULL)
+ {
+ nv_printf(NV_DBG_ERRORS, "NVRM: failed to map registers!\n");
+ rmStatus = NV_ERR_OPERATING_SYSTEM;
+ goto threadfree;
+ }
+ NvU32 pmc_boot_1 = NV_PRIV_REG_RD32(reg_mapping, NV_PMC_BOOT_1);
+ pmc_boot_0 = NV_PRIV_REG_RD32(reg_mapping, NV_PMC_BOOT_0);
+ pmc_boot_42 = NV_PRIV_REG_RD32(reg_mapping, NV_PMC_BOOT_42);
+
+ osUnmapKernelSpace(reg_mapping, os_page_size);
+
+ if ((pmc_boot_0 == 0xFFFFFFFF) && (pmc_boot_42 == 0xFFFFFFFF))
+ {
+ nv_printf(NV_DBG_ERRORS,
+ "NVRM: The NVIDIA GPU %04x:%02x:%02x.%x\n"
+ "NVRM: (PCI ID: %04x:%04x) installed in this system has\n"
+ "NVRM: fallen off the bus and is not responding to commands.\n",
+ pNv->pci_info.domain, pNv->pci_info.bus, pNv->pci_info.slot,
+ pNv->pci_info.function, pNv->pci_info.vendor_id,
+ pNv->pci_info.device_id);
+ rmStatus = NV_ERR_GPU_IS_LOST;
+ goto threadfree;
+ }
+
+ /*
+ * For legacy architectures, rm_is_legacy_arch() prints "legacy" message.
+ * We do not want to print "unsupported" message for legacy architectures
+ * to avoid confusion. Also, the probe should not continue for legacy
+ * architectures. Hence, we set rmStatus to NV_ERR_NOT_SUPPORTED and
+ * goto threadfree.
+ */
+ if (rm_is_legacy_arch(pmc_boot_0, pmc_boot_42))
+ {
+ rmStatus = NV_ERR_NOT_SUPPORTED;
+ goto threadfree;
+ }
+
+ rmStatus = halmgrGetHalForGpu(pHalMgr, pmc_boot_0, pmc_boot_42, &myHalPublicID);
+
+ if (rmStatus != NV_OK)
+ {
+ NvBool bIsFirmwareCapable;
+
+ bIsFirmwareCapable = gpumgrIsDeviceRmFirmwareCapable(pmc_boot_42,
+ FLD_TEST_DRF(_PMC, _BOOT_1, _VGPU, _VF, pmc_boot_1),
+ NV_IS_SOC_DISPLAY_DEVICE(pNv),
+ NULL,
+ NV_FALSE /* bIsTccOrMcdm */);
+ if (!bIsFirmwareCapable)
+ {
+ if (hypervisorIsVgxHyper())
+ {
+ nv_printf(NV_DBG_ERRORS,
+ "NVRM: The NVIDIA GPU %04x:%02x:%02x.%x (PCI ID: %04x:%04x)\n"
+ "NVRM: installed in this vGPU host system is not supported by\n"
+ "NVRM: open nvidia.ko.\n"
+ "NVRM: Please see the 'Open Linux Kernel Modules' and 'GSP\n"
+ "NVRM: Firmware' sections in the NVIDIA Virtual GPU (vGPU)\n"
+ "NVRM: Software documentation, available at docs.nvidia.com.\n",
+ pNv->pci_info.domain, pNv->pci_info.bus, pNv->pci_info.slot,
+ pNv->pci_info.function, pNv->pci_info.vendor_id,
+ pNv->pci_info.device_id);
+ }
+ else
+ {
+ nv_printf(NV_DBG_ERRORS,
+ "NVRM: The NVIDIA GPU %04x:%02x:%02x.%x (PCI ID: %04x:%04x)\n"
+ "NVRM: installed in this system is not supported by open\n"
+ "NVRM: nvidia.ko because it does not include the required GPU\n"
+ "NVRM: System Processor (GSP).\n"
+ "NVRM: Please see the 'Open Linux Kernel Modules' and 'GSP\n"
+ "NVRM: Firmware' sections in the driver README, available on\n"
+ "NVRM: the Linux graphics driver download page at\n"
+ "NVRM: www.nvidia.com.\n",
+ pNv->pci_info.domain, pNv->pci_info.bus, pNv->pci_info.slot,
+ pNv->pci_info.function, pNv->pci_info.vendor_id,
+ pNv->pci_info.device_id);
+ }
+ goto threadfree;
+ }
+ goto print_unsupported;
+ }
+
+ rmStatus = rm_is_vgpu_supported_device(pNv, pmc_boot_1, pmc_boot_42);
+
+ if (rmStatus != NV_OK)
+ {
+ nv_printf(NV_DBG_ERRORS,
+ "NVRM: The NVIDIA vGPU %04x:%02x:%02x.%x (PCI ID: %04x:%04x)\n"
+ "NVRM: installed in this system is not supported by open\n"
+ "NVRM: nvidia.ko.\n"
+ "NVRM: Please see the 'Open Linux Kernel Modules' and 'GSP\n"
+ "NVRM: Firmware' sections in the NVIDIA Virtual GPU (vGPU)\n"
+ "NVRM: Software documentation, available at docs.nvidia.com.\n",
+ pNv->pci_info.domain, pNv->pci_info.bus, pNv->pci_info.slot,
+ pNv->pci_info.function, pNv->pci_info.vendor_id,
+ pNv->pci_info.device_id);
+ goto threadfree;
+ }
+ goto threadfree;
+
+print_unsupported:
+ nv_printf(NV_DBG_ERRORS,
+ "NVRM: The NVIDIA GPU %04x:%02x:%02x.%x (PCI ID: %04x:%04x)\n"
+ "NVRM: installed in this system is not supported by the\n"
+ "NVRM: NVIDIA %s driver release.\n"
+ "NVRM: Please see 'Appendix A - Supported NVIDIA GPU Products'\n"
+ "NVRM: in this release's README, available on the operating system\n"
+ "NVRM: specific graphics driver download page at www.nvidia.com.\n",
+ pNv->pci_info.domain, pNv->pci_info.bus, pNv->pci_info.slot,
+ pNv->pci_info.function, pNv->pci_info.vendor_id,
+ pNv->pci_info.device_id, NV_VERSION_STRING);
+
+threadfree:
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return rmStatus;
+}
+
+NvBool NV_API_CALL rm_is_supported_pci_device(
+ NvU8 pci_class,
+ NvU8 pci_subclass,
+ NvU16 vendor,
+ NvU16 device,
+ NvU16 subsystem_vendor,
+ NvU16 subsystem_device,
+ NvBool print_legacy_warning
+)
+{
+ const NvU16 nv_pci_vendor_id = 0x10DE;
+ const NvU16 nv_pci_id_riva_tnt = 0x0020;
+ const NvU8 nv_pci_class_display = 0x03;
+ const NvU8 nv_pci_subclass_display_vga = 0x00;
+ const NvU8 nv_pci_subclass_display_3d = 0x02;
+
+ if (pci_class != nv_pci_class_display)
+ {
+ return NV_FALSE;
+ }
+
+ if ((pci_subclass != nv_pci_subclass_display_vga) &&
+ (pci_subclass != nv_pci_subclass_display_3d))
+ {
+ return NV_FALSE;
+ }
+
+ if (vendor != nv_pci_vendor_id)
+ {
+ return NV_FALSE;
+ }
+
+ if (device < nv_pci_id_riva_tnt)
+ {
+ return NV_FALSE;
+ }
+
+ if (rm_is_legacy_device(
+ device,
+ subsystem_vendor,
+ subsystem_device,
+ print_legacy_warning))
+ {
+ return NV_FALSE;
+ }
+
+ return NV_TRUE;
+}
+
+/*
+ * Performs the I2C transfers which are related with DP AUX channel
+ */
+static NV_STATUS RmDpAuxI2CTransfer
+(
+ nv_state_t *pNv,
+ NvU32 displayId,
+ NvU8 addr,
+ NvU32 len,
+ NvU8 *pData,
+ NvBool bWrite
+)
+{
+ NV0073_CTRL_DP_AUXCH_I2C_TRANSFER_CTRL_PARAMS *pParams;
+ RM_API *pRmApi = rmapiGetInterface(RMAPI_GPU_LOCK_INTERNAL);
+ NV_STATUS status;
+
+ if (len > NV0073_CTRL_DP_AUXCH_I2C_TRANSFER_MAX_DATA_SIZE)
+ {
+ NV_PRINTF(LEVEL_ERROR,
+ "%s: requested I2C transfer length %u is greater than maximum supported length %u\n",
+ __FUNCTION__, len, NV0073_CTRL_DP_AUXCH_I2C_TRANSFER_MAX_DATA_SIZE);
+ return NV_ERR_NOT_SUPPORTED;
+ }
+
+ pParams = portMemAllocNonPaged(sizeof(*pParams));
+ if (pParams == NULL)
+ {
+ return NV_ERR_NO_MEMORY;
+ }
+
+ portMemSet(pParams, 0, sizeof(*pParams));
+
+ pParams->subDeviceInstance = 0;
+ pParams->displayId = displayId;
+ pParams->addr = addr;
+ pParams->size = len;
+ pParams->bWrite = bWrite;
+
+ if (bWrite)
+ {
+ portMemCopy(pParams->data, NV0073_CTRL_DP_AUXCH_I2C_TRANSFER_MAX_DATA_SIZE,
+ pData, len);
+ }
+
+ status = pRmApi->Control(pRmApi, pNv->rmapi.hClient, pNv->rmapi.hDisp,
+ NV0073_CTRL_CMD_DP_AUXCH_I2C_TRANSFER_CTRL,
+ pParams, sizeof(*pParams));
+
+ if ((status == NV_OK) && !bWrite)
+ {
+ portMemCopy(pData, len, pParams->data, pParams->size);
+ }
+
+ portMemFree(pParams);
+
+ return status;
+}
+
+/*
+ * Performs the I2C transfers which are not related with DP AUX channel
+ */
+static NV_STATUS RmNonDPAuxI2CTransfer
+(
+ nv_state_t *pNv,
+ NvU8 portId,
+ nv_i2c_cmd_t type,
+ NvU8 addr,
+ NvU8 command,
+ NvU32 len,
+ NvU8 *pData
+)
+{
+ NV402C_CTRL_I2C_TRANSACTION_PARAMS *params;
+ RM_API *pRmApi = rmapiGetInterface(RMAPI_GPU_LOCK_INTERNAL);
+ NV_STATUS rmStatus = NV_OK;
+
+ params = portMemAllocNonPaged(sizeof(*params));
+ if (params == NULL)
+ {
+ return NV_ERR_NO_MEMORY;
+ }
+
+ portMemSet(params, 0, sizeof(*params));
+
+ params->portId = portId;
+ // precondition our address (our stack requires this)
+ params->deviceAddress = addr << 1;
+
+ switch (type)
+ {
+ case NV_I2C_CMD_WRITE:
+ params->transData.i2cBlockData.bWrite = NV_TRUE;
+ /* fall through*/
+
+ case NV_I2C_CMD_READ:
+ params->transType = NV402C_CTRL_I2C_TRANSACTION_TYPE_I2C_BLOCK_RW;
+ params->transData.i2cBlockData.messageLength = len;
+ params->transData.i2cBlockData.pMessage = pData;
+ break;
+
+ case NV_I2C_CMD_SMBUS_WRITE:
+ if (len == 2)
+ {
+ params->transData.smbusWordData.bWrite = NV_TRUE;
+ }
+ else
+ {
+ params->transData.smbusByteData.bWrite = NV_TRUE;
+ }
+ /* fall through*/
+
+ case NV_I2C_CMD_SMBUS_READ:
+ if (len == 2)
+ {
+ params->transType = NV402C_CTRL_I2C_TRANSACTION_TYPE_SMBUS_WORD_RW;
+ params->transData.smbusWordData.message = pData[0] | ((NvU16)pData[1] << 8);
+ params->transData.smbusWordData.registerAddress = command;
+ }
+ else
+ {
+ params->transType = NV402C_CTRL_I2C_TRANSACTION_TYPE_SMBUS_BYTE_RW;
+ params->transData.smbusByteData.message = pData[0];
+ params->transData.smbusByteData.registerAddress = command;
+ }
+ break;
+
+ case NV_I2C_CMD_SMBUS_BLOCK_WRITE:
+ if (pData[0] >= len) {
+ portMemFree(params);
+ return NV_ERR_INVALID_ARGUMENT;
+ }
+ params->transData.smbusBlockData.bWrite = NV_TRUE;
+ params->transType = NV402C_CTRL_I2C_TRANSACTION_TYPE_SMBUS_BLOCK_RW;
+ params->transData.smbusBlockData.registerAddress = command;
+ params->transData.smbusBlockData.messageLength = pData[0];
+ params->transData.smbusBlockData.pMessage = pData + 1;
+ break;
+
+ case NV_I2C_CMD_SMBUS_BLOCK_READ:
+ params->transType = NV402C_CTRL_I2C_TRANSACTION_TYPE_SMBUS_BLOCK_RW;
+ params->transData.smbusBlockData.registerAddress = command;
+ params->transData.smbusBlockData.messageLength = len;
+ params->transData.smbusBlockData.pMessage = pData;
+ break;
+
+ case NV_I2C_CMD_SMBUS_QUICK_WRITE:
+ params->transData.smbusQuickData.bWrite = NV_TRUE;
+ /* fall through*/
+
+ case NV_I2C_CMD_SMBUS_QUICK_READ:
+ params->transType = NV402C_CTRL_I2C_TRANSACTION_TYPE_SMBUS_QUICK_RW;
+ break;
+
+ case NV_I2C_CMD_BLOCK_WRITE:
+ params->transData.i2cBufferData.bWrite = NV_TRUE;
+ /* fall through */
+
+ case NV_I2C_CMD_BLOCK_READ:
+ params->transType = NV402C_CTRL_I2C_TRANSACTION_TYPE_I2C_BUFFER_RW;
+ params->transData.i2cBufferData.registerAddress = command;
+ params->transData.i2cBufferData.messageLength = len;
+ params->transData.i2cBufferData.pMessage = pData;
+ break;
+
+ default:
+ portMemFree(params);
+ return NV_ERR_INVALID_ARGUMENT;
+ }
+
+ rmStatus = pRmApi->Control(pRmApi, pNv->rmapi.hClient,
+ pNv->rmapi.hI2C,
+ NV402C_CTRL_CMD_I2C_TRANSACTION,
+ params, sizeof(*params));
+
+ //
+ // For NV_I2C_CMD_SMBUS_READ, copy the read data to original
+ // data buffer.
+ //
+ if (rmStatus == NV_OK && type == NV_I2C_CMD_SMBUS_READ)
+ {
+ if (len == 2)
+ {
+ pData[0] = (params->transData.smbusWordData.message & 0xff);
+ pData[1] = params->transData.smbusWordData.message >> 8;
+ }
+ else
+ {
+ pData[0] = params->transData.smbusByteData.message;
+ }
+ }
+
+ portMemFree(params);
+
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_i2c_transfer(
+ nvidia_stack_t *sp,
+ nv_state_t *pNv,
+ void *pI2cAdapter,
+ nv_i2c_cmd_t type,
+ NvU8 addr,
+ NvU8 command,
+ NvU32 len,
+ NvU8 *pData
+)
+{
+ THREAD_STATE_NODE threadState;
+ nv_priv_t *pNvp = NV_GET_NV_PRIV(pNv);
+ NV_STATUS rmStatus = NV_OK;
+ OBJGPU *pGpu = NULL;
+ NvBool unlockApi = NV_FALSE;
+ NvBool unlockGpu = NV_FALSE;
+ NvU32 x;
+ void *fp;
+ NvU32 numDispId = 0;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ if (pNvp->flags & NV_INIT_FLAG_PUBLIC_I2C)
+ {
+ // LOCK: acquire API lock
+ if ((rmStatus = rmapiLockAcquire(API_LOCK_FLAGS_NONE, RM_LOCK_MODULES_I2C)) != NV_OK)
+ goto finish;
+
+ unlockApi = NV_TRUE;
+
+ // LOCK: acquire GPUs lock
+ if ((rmStatus = rmGpuLocksAcquire(GPUS_LOCK_FLAGS_NONE, RM_LOCK_MODULES_I2C)) != NV_OK)
+ goto finish;
+
+ unlockGpu = NV_TRUE;
+ }
+
+ pGpu = NV_GET_NV_PRIV_PGPU(pNv);
+
+ if (!pGpu)
+ {
+ rmStatus = NV_ERR_GENERIC;
+ goto finish;
+ }
+
+ for (x = 0; x < MAX_I2C_ADAPTERS; x++)
+ {
+ if (pNvp->i2c_adapters[x].pOsAdapter == pI2cAdapter)
+ {
+ break;
+ }
+ }
+
+ if (x == MAX_I2C_ADAPTERS)
+ {
+ rmStatus = NV_ERR_GENERIC;
+ goto finish;
+ }
+
+ for (numDispId = 0; numDispId < MAX_DISP_ID_PER_ADAPTER; numDispId++)
+ {
+ NvU32 displayId = pNvp->i2c_adapters[x].displayId[numDispId];
+
+ if (displayId == INVALID_DISP_ID)
+ {
+ continue;
+ }
+
+ // Handle i2c-over-DpAux adapters separately from regular i2c adapters
+ if (displayId == 0)
+ {
+ rmStatus = RmNonDPAuxI2CTransfer(pNv, pNvp->i2c_adapters[x].port,
+ type, addr, command, len, pData);
+ }
+ else
+ {
+ if ((type != NV_I2C_CMD_READ) && (type != NV_I2C_CMD_WRITE))
+ {
+ rmStatus = NV_ERR_NOT_SUPPORTED;
+ goto semafinish;
+ }
+
+ rmStatus = RmDpAuxI2CTransfer(pNv, displayId, addr, len, pData,
+ type == NV_I2C_CMD_WRITE);
+ }
+semafinish:
+ if (rmStatus == NV_OK)
+ {
+ break;
+ }
+ }
+
+finish:
+ if (unlockGpu)
+ {
+ // UNLOCK: release GPU lock
+ rmGpuLocksRelease(GPUS_LOCK_FLAGS_NONE, NULL);
+ }
+
+ if (unlockApi)
+ {
+ // UNLOCK: release API lock
+ rmapiLockRelease();
+ }
+
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return rmStatus;
+}
+
+static void rm_i2c_add_adapter(
+ nv_state_t *pNv,
+ NvU32 port,
+ NvU32 displayId
+)
+{
+ NvU32 y, free;
+ nv_priv_t *pNvp = NV_GET_NV_PRIV(pNv);
+ NvU32 numDispId = 0;
+
+ for (y = 0, free = MAX_I2C_ADAPTERS; y < MAX_I2C_ADAPTERS; y++)
+ {
+ if (pNvp->i2c_adapters[y].pOsAdapter == NULL)
+ {
+ // Only find the first free entry, and ignore the rest
+ if (free == MAX_I2C_ADAPTERS)
+ {
+ free = y;
+ }
+ }
+ else if (pNvp->i2c_adapters[y].port == port)
+ {
+ break;
+ }
+ }
+
+ if (y < MAX_I2C_ADAPTERS)
+ {
+ for (numDispId = 0; numDispId < MAX_DISP_ID_PER_ADAPTER; numDispId++)
+ {
+ if (pNvp->i2c_adapters[y].displayId[numDispId] == INVALID_DISP_ID)
+ {
+ pNvp->i2c_adapters[y].displayId[numDispId] = displayId;
+ break;
+ }
+ else
+ {
+ NV_PRINTF(LEVEL_INFO,
+ "%s: adapter already exists (port=0x%x, displayId=0x%x)\n",
+ __FUNCTION__, port,
+ pNvp->i2c_adapters[y].displayId[numDispId]);
+ }
+ }
+
+ if (numDispId == MAX_DISP_ID_PER_ADAPTER)
+ {
+ NV_PRINTF(LEVEL_ERROR,
+ "%s: no more free display Id entries in adapter\n",
+ __FUNCTION__);
+ }
+
+ return;
+ }
+
+ if (free == MAX_I2C_ADAPTERS)
+ {
+ NV_PRINTF(LEVEL_ERROR, "%s: no more free adapter entries exist\n",
+ __FUNCTION__);
+ return;
+ }
+
+ pNvp->i2c_adapters[free].pOsAdapter = nv_i2c_add_adapter(pNv, port);
+ pNvp->i2c_adapters[free].port = port;
+ // When port is added, numDispId will be 0.
+ pNvp->i2c_adapters[free].displayId[numDispId] = displayId;
+}
+
+void RmI2cAddGpuPorts(nv_state_t * pNv)
+{
+ NvU32 x = 0;
+ nv_priv_t *pNvp = NV_GET_NV_PRIV(pNv);
+ RM_API *pRmApi = rmapiGetInterface(RMAPI_API_LOCK_INTERNAL);
+ NvU32 displayMask;
+ NV_STATUS status;
+ OBJGPU *pGpu = NV_GET_NV_PRIV_PGPU(pNv);
+ NV0073_CTRL_SYSTEM_GET_SUPPORTED_PARAMS systemGetSupportedParams = { 0 };
+
+ if (IS_VIRTUAL(pGpu) || NV_IS_SOC_DISPLAY_DEVICE(pNv))
+ return;
+
+ // Make displayId as Invalid.
+ for (x = 0; x < MAX_I2C_ADAPTERS; x++)
+ {
+ NvU32 numDispId;
+
+ for (numDispId = 0; numDispId < MAX_DISP_ID_PER_ADAPTER; numDispId++)
+ {
+ pNvp->i2c_adapters[x].displayId[numDispId] = INVALID_DISP_ID;
+ }
+ }
+
+ // First, set up the regular i2c adapters - one per i2c port
+ if (pNv->rmapi.hI2C != 0)
+ {
+ NV402C_CTRL_I2C_GET_PORT_INFO_PARAMS i2cPortInfoParams = { 0 };
+
+ status = pRmApi->Control(pRmApi, pNv->rmapi.hClient, pNv->rmapi.hI2C,
+ NV402C_CTRL_CMD_I2C_GET_PORT_INFO,
+ &i2cPortInfoParams, sizeof(i2cPortInfoParams));
+
+ if (status == NV_OK)
+ {
+ for (x = 0; x < NV_ARRAY_ELEMENTS(i2cPortInfoParams.info); x++)
+ {
+ //
+ // Check if this port is implemented and RM I2C framework has
+ // validated this port. Only limited amount of ports can
+ // be added to the OS framework.
+ //
+ if (FLD_TEST_DRF(402C_CTRL, _I2C_GET_PORT_INFO, _IMPLEMENTED,
+ _YES, i2cPortInfoParams.info[x]) &&
+ FLD_TEST_DRF(402C_CTRL, _I2C_GET_PORT_INFO, _VALID,
+ _YES, i2cPortInfoParams.info[x]))
+ {
+ rm_i2c_add_adapter(pNv, x, 0);
+ }
+ }
+ }
+ }
+
+ //
+ // Now set up the i2c-over-DpAux adapters - one per DP OD
+ //
+ // 1. Perform NV0073_CTRL_SYSTEM_GET_SUPPORTED_PARAMS RM control which
+ // will return the mask for all the display ID's.
+ // 2. Loop for all the display ID's and do
+ // NV0073_CTRL_CMD_SPECIFIC_OR_GET_INFO RM control call. For each
+ // output resource, check for the following requirements:
+ // a. It must be DisplayPort.
+ // b. It must be internal to the GPU (ie, not on the board)
+ // c. It must be directly connected to the physical connector (ie, no DP
+ // 1.2 multistream ODs).
+ // 3. Perform NV0073_CTRL_CMD_SPECIFIC_GET_I2C_PORTID RM control for
+ // getting the I2C port data.
+ //
+ // With these restrictions, we should only end up with at most one OD
+ // per DP connector.
+ //
+
+ if (pNv->rmapi.hDisp == 0)
+ {
+ return;
+ }
+
+ systemGetSupportedParams.subDeviceInstance = 0;
+ status = pRmApi->Control(pRmApi, pNv->rmapi.hClient, pNv->rmapi.hDisp,
+ NV0073_CTRL_CMD_SYSTEM_GET_SUPPORTED,
+ &systemGetSupportedParams, sizeof(systemGetSupportedParams));
+
+ if (status != NV_OK)
+ {
+ return;
+ }
+
+ for (displayMask = systemGetSupportedParams.displayMask;
+ displayMask != 0;
+ displayMask &= ~LOWESTBIT(displayMask))
+ {
+ NV0073_CTRL_SPECIFIC_OR_GET_INFO_PARAMS orInfoParams = { 0 };
+ NvU32 displayId = LOWESTBIT(displayMask);
+
+ orInfoParams.subDeviceInstance = 0;
+ orInfoParams.displayId = displayId;
+
+ status = pRmApi->Control(pRmApi, pNv->rmapi.hClient, pNv->rmapi.hDisp,
+ NV0073_CTRL_CMD_SPECIFIC_OR_GET_INFO,
+ &orInfoParams, sizeof(orInfoParams));
+
+ if ((status == NV_OK) &&
+ (orInfoParams.type == NV0073_CTRL_SPECIFIC_OR_TYPE_SOR) &&
+ ((orInfoParams.protocol == NV0073_CTRL_SPECIFIC_OR_PROTOCOL_SOR_DP_A) ||
+ (orInfoParams.protocol == NV0073_CTRL_SPECIFIC_OR_PROTOCOL_SOR_DP_B)) &&
+ (orInfoParams.location == NV0073_CTRL_SPECIFIC_OR_LOCATION_CHIP) &&
+ (!orInfoParams.bIsDispDynamic))
+ {
+ NV0073_CTRL_SPECIFIC_GET_I2C_PORTID_PARAMS i2cPortIdParams = { 0 };
+
+ i2cPortIdParams.subDeviceInstance = 0;
+ i2cPortIdParams.displayId = displayId;
+
+ status = pRmApi->Control(pRmApi,
+ pNv->rmapi.hClient,
+ pNv->rmapi.hDisp,
+ NV0073_CTRL_CMD_SPECIFIC_GET_I2C_PORTID,
+ &i2cPortIdParams,
+ sizeof(i2cPortIdParams));
+
+ if ((status == NV_OK) &&
+ (i2cPortIdParams.ddcPortId != NV0073_CTRL_SPECIFIC_I2C_PORT_NONE))
+ {
+ rm_i2c_add_adapter(pNv, i2cPortIdParams.ddcPortId - 1, displayId);
+ }
+ }
+ }
+}
+
+void NV_API_CALL rm_i2c_remove_adapters(
+ nvidia_stack_t *sp,
+ nv_state_t *pNv
+)
+{
+ //
+ // Cycle through all adapter entries, and first remove the adapter
+ // from the list from the kernel, then remove the i2c adapter
+ // list once that is completed. This should only be used from exit
+ // module time. Otherwise it could fail to remove some of the
+ // kernel adapters and subsequent transfer requests would result
+ // in crashes.
+ //
+ NvU32 x = 0;
+ nv_priv_t *pNvp = NV_GET_NV_PRIV(pNv);
+ NvU32 numDispId;
+
+ for (x = 0; x < MAX_I2C_ADAPTERS; x++)
+ {
+ if (pNvp->i2c_adapters[x].pOsAdapter != NULL)
+ {
+ nv_i2c_del_adapter(pNv, pNvp->i2c_adapters[x].pOsAdapter);
+
+ pNvp->i2c_adapters[x].pOsAdapter = NULL;
+ pNvp->i2c_adapters[x].port = 0;
+ for (numDispId = 0; numDispId < MAX_DISP_ID_PER_ADAPTER; numDispId++)
+ {
+ pNvp->i2c_adapters[x].displayId[numDispId] = INVALID_DISP_ID;
+ }
+ }
+ }
+}
+
+NvBool NV_API_CALL rm_i2c_is_smbus_capable(
+ nvidia_stack_t *sp,
+ nv_state_t *pNv,
+ void *pI2cAdapter
+)
+{
+ THREAD_STATE_NODE threadState;
+ nv_priv_t *pNvp = NV_GET_NV_PRIV(pNv);
+ NV_STATUS rmStatus = NV_OK;
+ OBJGPU *pGpu = NULL;
+ NvBool unlock = NV_FALSE;
+ NvU32 x;
+ NvBool ret = NV_FALSE;
+ void *fp;
+ NvU32 numDispId = 0;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ if (pNvp->flags & NV_INIT_FLAG_PUBLIC_I2C)
+ {
+ // LOCK: acquire API lock
+ if ((rmStatus = rmapiLockAcquire(API_LOCK_FLAGS_NONE, RM_LOCK_MODULES_I2C)) != NV_OK)
+ goto semafinish;
+
+ unlock = NV_TRUE;
+ }
+
+ pGpu = NV_GET_NV_PRIV_PGPU(pNv);
+
+ if (!pGpu)
+ {
+ goto semafinish;
+ }
+
+ for (x = 0; x < MAX_I2C_ADAPTERS; x++)
+ {
+ if (pNvp->i2c_adapters[x].pOsAdapter == pI2cAdapter)
+ {
+ break;
+ }
+ }
+
+ if (x == MAX_I2C_ADAPTERS)
+ {
+ goto semafinish;
+ }
+
+ // we do not support smbus functions on i2c-over-DPAUX
+ for (numDispId = 0; numDispId < MAX_DISP_ID_PER_ADAPTER; numDispId++)
+ {
+ if (pNvp->i2c_adapters[x].displayId[numDispId] == 0x0)
+ {
+ ret = NV_TRUE;
+ }
+ }
+
+semafinish:
+ if (unlock)
+ {
+ // UNLOCK: release API lock
+ rmapiLockRelease();
+ }
+
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return ret;
+}
+
+NV_STATUS NV_API_CALL rm_perform_version_check(
+ nvidia_stack_t *sp,
+ void *pData,
+ NvU32 dataSize
+)
+{
+ THREAD_STATE_NODE threadState;
+ NV_STATUS rmStatus;
+ void *fp;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ rmStatus = RmPerformVersionCheck(pData, dataSize);
+
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return rmStatus;
+}
+
+//
+// Handles the Power Source Change event(AC/DC) for Notebooks.
+// Notebooks from Maxwell have only one Gpu, so this functions grabs first Gpu
+// from GpuMgr and call subdevice RmControl.
+//
+void NV_API_CALL rm_power_source_change_event(
+ nvidia_stack_t *sp,
+ NvU32 event_val
+)
+{
+ THREAD_STATE_NODE threadState;
+ void *fp;
+ nv_state_t *nv;
+ static NvBool first_event_seen = NV_FALSE;
+ static NvU32 last_event_val = 0;
+ NV_STATUS rmStatus = NV_OK;
+
+ // Some systems generate spurious power source changed ACPI events.
+ // Before entering the PM runtime and waking the GPU, see if the power
+ // state has actually changed. If not, return without waking the GPU.
+ if ((first_event_seen != NV_FALSE) && (last_event_val == event_val))
+ {
+ return;
+ }
+ else
+ {
+ first_event_seen = NV_TRUE;
+ last_event_val = event_val;
+ }
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ // LOCK: acquire API lock
+ if ((rmStatus = rmapiLockAcquire(API_LOCK_FLAGS_NONE, RM_LOCK_MODULES_EVENT)) == NV_OK)
+ {
+ OBJGPU *pGpu = gpumgrGetGpu(0);
+ if (pGpu != NULL)
+ {
+ nv = NV_GET_NV_STATE(pGpu);
+ if ((rmStatus = os_ref_dynamic_power(nv, NV_DYNAMIC_PM_FINE)) ==
+ NV_OK)
+ {
+ // LOCK: acquire GPU lock
+ if ((rmStatus = rmGpuLocksAcquire(GPUS_LOCK_FLAGS_NONE, RM_LOCK_MODULES_EVENT)) ==
+ NV_OK)
+ {
+ rmStatus = RmPowerSourceChangeEvent(nv, event_val);
+
+ // UNLOCK: release GPU lock
+ rmGpuLocksRelease(GPUS_LOCK_FLAGS_NONE, NULL);
+ }
+ os_unref_dynamic_power(nv, NV_DYNAMIC_PM_FINE);
+ }
+ // UNLOCK: release API lock
+ rmapiLockRelease();
+ }
+ }
+
+ if (rmStatus != NV_OK)
+ {
+ NV_PRINTF(LEVEL_ERROR,
+ "%s: Failed to handle Power Source change event, status=0x%x\n",
+ __FUNCTION__, rmStatus);
+ }
+
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+}
+
+void NV_API_CALL rm_request_dnotifier_state(
+ nv_stack_t *sp,
+ nv_state_t *pNv
+)
+{
+ nv_priv_t *nvp = NV_GET_NV_PRIV(pNv);
+
+ if (nvp->b_mobile_config_enabled)
+ {
+ THREAD_STATE_NODE threadState;
+ void *fp;
+ GPU_MASK gpuMask;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ // LOCK: acquire API lock
+ if ((rmapiLockAcquire(API_LOCK_FLAGS_NONE, RM_LOCK_MODULES_ACPI)) == NV_OK)
+ {
+ OBJGPU *pGpu = NV_GET_NV_PRIV_PGPU(pNv);
+
+ // LOCK: acquire per device lock
+ if ((pGpu != NULL) &&
+ ((rmGpuGroupLockAcquire(pGpu->gpuInstance, GPU_LOCK_GRP_SUBDEVICE,
+ GPUS_LOCK_FLAGS_NONE, RM_LOCK_MODULES_ACPI,
+ &gpuMask)) == NV_OK))
+ {
+ RmRequestDNotifierState(pNv);
+
+ // UNLOCK: release per device lock
+ rmGpuGroupLockRelease(gpuMask, GPUS_LOCK_FLAGS_NONE);
+ }
+
+ // UNLOCK: release API lock
+ rmapiLockRelease();
+ }
+
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ }
+}
+
+NV_STATUS NV_API_CALL rm_p2p_dma_map_pages(
+ nvidia_stack_t *sp,
+ nv_dma_device_t *peer,
+ NvU8 *pGpuUuid,
+ NvU64 pageSize,
+ NvU32 pageCount,
+ NvU64 *pDmaAddresses,
+ void **ppPriv
+)
+{
+ THREAD_STATE_NODE threadState;
+ NV_STATUS rmStatus;
+ void *fp;
+ NvU32 i, j;
+ OBJGPU *pGpu;
+ nv_state_t *pNv;
+
+ if (ppPriv == NULL)
+ return NV_ERR_INVALID_ARGUMENT;
+
+ *ppPriv = NULL;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ rmStatus = rmapiLockAcquire(API_LOCK_FLAGS_NONE, RM_LOCK_MODULES_P2P);
+ if (rmStatus != NV_OK)
+ goto done;
+
+ pGpu = gpumgrGetGpuFromUuid(pGpuUuid,
+ DRF_DEF(2080_GPU_CMD, _GPU_GET_GID_FLAGS, _TYPE, _SHA1) |
+ DRF_DEF(2080_GPU_CMD, _GPU_GET_GID_FLAGS, _FORMAT, _BINARY));
+ if (pGpu == NULL)
+ {
+ rmStatus = NV_ERR_INVALID_ARGUMENT;
+ goto unlock;
+ }
+
+ pNv = NV_GET_NV_STATE(pGpu);
+
+ if (pNv->coherent)
+ {
+ rmStatus = RmP2PDmaMapPages(pNv, peer, pageSize, pageCount,
+ pDmaAddresses, ppPriv);
+ goto unlock;
+ }
+
+ // Check if the topology is supported for third party p2p
+ if (!nv_grdma_pci_topology_supported(pNv, peer))
+ {
+ rmStatus = NV_ERR_NOT_SUPPORTED;
+ goto unlock;
+ }
+
+ for (i = 0; i < pageCount; i++)
+ {
+ // Map BAR1 PFNs for non-coherent platforms
+ rmStatus = nv_dma_map_peer(peer, pNv->dma_dev, 0x1,
+ pageSize / os_page_size,
+ &pDmaAddresses[i]);
+ if (rmStatus != NV_OK)
+ {
+ for (j = 0; j < i; j++)
+ {
+ nv_dma_unmap_peer(peer, pageSize / os_page_size,
+ pDmaAddresses[j]);
+ }
+ goto unlock;
+ }
+ }
+
+unlock:
+ rmapiLockRelease();
+
+done:
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_p2p_get_gpu_info(
+ nvidia_stack_t *sp,
+ NvU64 gpuVirtualAddress,
+ NvU64 length,
+ NvU8 **ppGpuUuid,
+ void **ppGpuInfo
+)
+{
+ THREAD_STATE_NODE threadState;
+ NV_STATUS rmStatus;
+ void *fp;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ // LOCK: acquire API lock
+ rmStatus = rmapiLockAcquire(API_LOCK_FLAGS_NONE, RM_LOCK_MODULES_P2P);
+ if (rmStatus == NV_OK)
+ {
+ OBJGPU *pGpu;
+ rmStatus = RmP2PGetGpuByAddress(gpuVirtualAddress,
+ length,
+ &pGpu);
+ if (rmStatus == NV_OK)
+ {
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ const NvU8 *pGid;
+
+ pGid = RmGetGpuUuidRaw(nv);
+ if (pGid == NULL)
+ {
+ rmStatus = NV_ERR_GPU_UUID_NOT_FOUND;
+ }
+ else
+ {
+ rmStatus = os_alloc_mem((void **)ppGpuUuid, GPU_UUID_LEN);
+ if (rmStatus == NV_OK)
+ {
+ os_mem_copy(*ppGpuUuid, pGid, GPU_UUID_LEN);
+ }
+ }
+
+ *ppGpuInfo = (void *) pGpu;
+ }
+
+ // UNLOCK: release API lock
+ rmapiLockRelease();
+ }
+
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_p2p_get_pages_persistent(
+ nvidia_stack_t *sp,
+ NvU64 gpuVirtualAddress,
+ NvU64 length,
+ void **p2pObject,
+ NvU64 *pPhysicalAddresses,
+ NvU32 *pEntries,
+ NvBool bForcePcie,
+ void *pPlatformData,
+ void *pGpuInfo,
+ void **ppMigInfo,
+ NvBool *pMemCpuCacheable
+)
+{
+ THREAD_STATE_NODE threadState;
+ NV_STATUS rmStatus;
+ void *fp;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ // LOCK: acquire API lock
+ if ((rmStatus = rmapiLockAcquire(API_LOCK_FLAGS_NONE, RM_LOCK_MODULES_P2P)) == NV_OK)
+ {
+ rmStatus = RmP2PGetPagesPersistent(gpuVirtualAddress,
+ length,
+ p2pObject,
+ pPhysicalAddresses,
+ pEntries,
+ pMemCpuCacheable,
+ bForcePcie,
+ pPlatformData,
+ pGpuInfo,
+ ppMigInfo);
+ // UNLOCK: release API lock
+ rmapiLockRelease();
+ }
+
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_p2p_get_pages(
+ nvidia_stack_t *sp,
+ NvU64 p2pToken,
+ NvU32 vaSpaceToken,
+ NvU64 gpuVirtualAddress,
+ NvU64 length,
+ NvU64 *pPhysicalAddresses,
+ NvU32 *pWreqMbH,
+ NvU32 *pRreqMbH,
+ NvU32 *pEntries,
+ NvU8 **ppGpuUuid,
+ void *pPlatformData,
+ NvBool *pMemCpuCacheable
+)
+{
+ THREAD_STATE_NODE threadState;
+ NV_STATUS rmStatus;
+ void *fp;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ // LOCK: acquire API lock
+ if ((rmStatus = rmapiLockAcquire(API_LOCK_FLAGS_NONE, RM_LOCK_MODULES_P2P)) == NV_OK)
+ {
+ OBJGPU *pGpu;
+ rmStatus = RmP2PGetPagesWithoutCallbackRegistration(p2pToken,
+ vaSpaceToken,
+ gpuVirtualAddress,
+ length,
+ pPhysicalAddresses,
+ pWreqMbH,
+ pRreqMbH,
+ pEntries,
+ pMemCpuCacheable,
+ &pGpu,
+ pPlatformData);
+ if (rmStatus == NV_OK)
+ {
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ const NvU8 *pGid;
+
+ pGid = RmGetGpuUuidRaw(nv);
+ if (pGid == NULL)
+ {
+ NV_ASSERT_OK(RmP2PPutPages(p2pToken, vaSpaceToken,
+ gpuVirtualAddress,
+ pPlatformData));
+ rmStatus = NV_ERR_GENERIC;
+ }
+ else
+ {
+ rmStatus = os_alloc_mem((void **)ppGpuUuid, GPU_UUID_LEN);
+ if (rmStatus == NV_OK)
+ os_mem_copy(*ppGpuUuid, pGid, GPU_UUID_LEN);
+ }
+
+ *pMemCpuCacheable = nv->coherent;
+ }
+
+ // UNLOCK: release API lock
+ rmapiLockRelease();
+ }
+
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_p2p_register_callback(
+ nvidia_stack_t *sp,
+ NvU64 p2pToken,
+ NvU64 gpuVirtualAddress,
+ NvU64 length,
+ void *pPlatformData,
+ void (*pFreeCallback)(void *pData),
+ void *pData
+)
+{
+ THREAD_STATE_NODE threadState;
+ NV_STATUS rmStatus;
+ void *fp;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ // LOCK: acquire API lock
+ if ((rmStatus = rmapiLockAcquire(API_LOCK_FLAGS_NONE, RM_LOCK_MODULES_P2P)) == NV_OK)
+ {
+ rmStatus = RmP2PRegisterCallback(p2pToken, gpuVirtualAddress, length,
+ pPlatformData, pFreeCallback, pData);
+
+ // UNLOCK: release API lock
+ rmapiLockRelease();
+ }
+
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_p2p_put_pages_persistent(
+ nvidia_stack_t *sp,
+ void *p2pObject,
+ void *pKey,
+ void *pMigInfo
+)
+{
+ THREAD_STATE_NODE threadState;
+ NV_STATUS rmStatus;
+ void *fp;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ // LOCK: acquire API lock
+ if ((rmStatus = rmapiLockAcquire(API_LOCK_FLAGS_NONE, RM_LOCK_MODULES_P2P)) == NV_OK)
+ {
+ rmStatus = RmP2PPutPagesPersistent(p2pObject, pKey, pMigInfo);
+
+ // UNLOCK: release API lock
+ rmapiLockRelease();
+ }
+
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_p2p_put_pages(
+ nvidia_stack_t *sp,
+ NvU64 p2pToken,
+ NvU32 vaSpaceToken,
+ NvU64 gpuVirtualAddress,
+ void *pKey
+)
+{
+ THREAD_STATE_NODE threadState;
+ NV_STATUS rmStatus;
+ void *fp;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ // LOCK: acquire API lock
+ if ((rmStatus = rmapiLockAcquire(API_LOCK_FLAGS_NONE, RM_LOCK_MODULES_P2P)) == NV_OK)
+ {
+ rmStatus = RmP2PPutPages(p2pToken,
+ vaSpaceToken,
+ gpuVirtualAddress,
+ pKey);
+
+ // UNLOCK: release API lock
+ rmapiLockRelease();
+ }
+
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return rmStatus;
+}
+
+char* NV_API_CALL rm_get_gpu_uuid(
+ nvidia_stack_t *sp,
+ nv_state_t *nv
+)
+{
+ NV_STATUS rmStatus;
+ const NvU8 *pGid;
+ char *pGidString;
+
+ THREAD_STATE_NODE threadState;
+ void *fp;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ // Allocate space for the ASCII string
+ rmStatus = os_alloc_mem((void **)&pGidString, GPU_UUID_ASCII_LEN);
+ if (rmStatus != NV_OK)
+ {
+ pGidString = NULL;
+ goto done;
+ }
+
+ // Get the raw UUID; note the pGid is cached, so we do not need to free it
+ pGid = RmGetGpuUuidRaw(nv);
+
+ if (pGid != NULL)
+ {
+ // Convert the raw UUID to ASCII
+ rmStatus = RmGpuUuidRawToString(pGid, pGidString, GPU_UUID_ASCII_LEN);
+ if (rmStatus != NV_OK)
+ {
+ os_free_mem(pGidString);
+ pGidString = NULL;
+ }
+ }
+ else
+ {
+ const char *pTmpString = "GPU-???????\?-???\?-???\?-???\?-????????????";
+
+ portStringCopy(pGidString, GPU_UUID_ASCII_LEN, pTmpString,
+ portStringLength(pTmpString) + 1);
+ }
+
+done:
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return pGidString;
+}
+
+//
+// This function will return the UUID in the binary format
+//
+const NvU8 * NV_API_CALL rm_get_gpu_uuid_raw(
+ nvidia_stack_t *sp,
+ nv_state_t *nv)
+{
+ THREAD_STATE_NODE threadState;
+ void *fp;
+ const NvU8 *pGid;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ pGid = RmGetGpuUuidRaw(nv);
+
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return pGid;
+}
+
+static void rm_set_firmware_logs(
+ nvidia_stack_t *sp,
+ nv_state_t *nv
+)
+{
+ void *fp;
+ NvU32 enableFirmwareLogsRegVal = NV_REG_ENABLE_GPU_FIRMWARE_LOGS_ENABLE_ON_DEBUG;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+
+ (void) RmReadRegistryDword(nv, NV_REG_ENABLE_GPU_FIRMWARE_LOGS,
+ &enableFirmwareLogsRegVal);
+ nv->enable_firmware_logs = gpumgrGetRmFirmwareLogsEnabled(enableFirmwareLogsRegVal);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+}
+
+static NvBool rm_get_is_gsp_capable_vgpu(
+ nvidia_stack_t *sp,
+ nv_state_t *nv
+)
+{
+ void *fp;
+ THREAD_STATE_NODE threadState;
+ NvBool isVgpu = NV_FALSE;
+ OBJSYS *pSys = SYS_GET_INSTANCE();
+ OBJHYPERVISOR *pHypervisor = SYS_GET_HYPERVISOR(pSys);
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ if ((pHypervisor != NULL) && pHypervisor->bIsHVMGuest)
+ {
+ GPUHWREG *reg_mapping;
+ reg_mapping = osMapKernelSpace(nv->regs->cpu_address,
+ os_page_size,
+ NV_MEMORY_UNCACHED,
+ NV_PROTECT_READABLE);
+
+ if (reg_mapping != NULL)
+ {
+ NvU32 pmc_boot_1 = NV_PRIV_REG_RD32(reg_mapping, NV_PMC_BOOT_1);
+ NvU32 pmc_boot_42 = NV_PRIV_REG_RD32(reg_mapping, NV_PMC_BOOT_42);
+
+ osUnmapKernelSpace(reg_mapping, os_page_size);
+
+ if (FLD_TEST_DRF(_PMC, _BOOT_1, _VGPU, _VF, pmc_boot_1) &&
+ gpumgrIsVgxRmFirmwareCapableChip(pmc_boot_42))
+ {
+ isVgpu = NV_TRUE;
+ }
+ }
+ }
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return isVgpu;
+}
+
+void NV_API_CALL rm_set_rm_firmware_requested(
+ nvidia_stack_t *sp,
+ nv_state_t *nv
+)
+{
+ nv->request_firmware = NV_TRUE;
+ nv->allow_fallback_to_monolithic_rm = NV_FALSE;
+ if (rm_get_is_gsp_capable_vgpu(sp, nv))
+ {
+ nv->request_firmware = NV_FALSE;
+ }
+
+ // Check if we want firmware logs
+ if (nv->request_firmware)
+ rm_set_firmware_logs(sp, nv);
+}
+
+//
+// disable GPU SW state persistence
+//
+
+void NV_API_CALL rm_disable_gpu_state_persistence(nvidia_stack_t *sp, nv_state_t *nv)
+{
+ THREAD_STATE_NODE threadState;
+ OBJGPU *pGpu = NV_GET_NV_PRIV_PGPU(nv);
+ void *fp;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ pGpu->setProperty(pGpu, PDB_PROP_GPU_PERSISTENT_SW_STATE, NV_FALSE);
+ osModifyGpuSwStatePersistence(pGpu->pOsGpuInfo, NV_FALSE);
+
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+}
+
+void NV_API_CALL rm_kernel_rmapi_op(nvidia_stack_t *sp, void *ops_cmd)
+{
+ nvidia_kernel_rmapi_ops_t *ops = ops_cmd;
+ void *fp;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+
+ switch (ops->op)
+ {
+ case NV01_FREE:
+ Nv01FreeKernel(&ops->params.free);
+ break;
+
+ case NV01_ALLOC_MEMORY:
+ Nv01AllocMemoryKernel(&ops->params.allocMemory64);
+ break;
+
+ case NV04_ALLOC:
+ Nv04AllocWithAccessKernel(&ops->params.alloc);
+ break;
+
+ case NV04_VID_HEAP_CONTROL:
+ Nv04VidHeapControlKernel(ops->params.pVidHeapControl);
+ break;
+
+ case NV04_MAP_MEMORY:
+ {
+ //
+ // We need to free NVUAP for MEM_SPACE_USER mappings,
+ // since we're not going through the regular path
+ //
+ nv_usermap_access_params_t *pNvuap = NULL;
+ Nv04MapMemoryKernel(&ops->params.mapMemory);
+ pNvuap = (nv_usermap_access_params_t *) tlsEntryGet(TLS_ENTRY_ID_MAPPING_CONTEXT);
+ if (pNvuap != NULL)
+ {
+ NV_ASSERT(tlsEntryRelease(TLS_ENTRY_ID_MAPPING_CONTEXT) == 0);
+ os_free_mem(pNvuap->memArea.pRanges);
+ os_free_mem(pNvuap);
+ }
+ break;
+ }
+
+ case NV04_UNMAP_MEMORY:
+ Nv04UnmapMemoryKernel(&ops->params.unmapMemory);
+ break;
+
+ case NV04_ALLOC_CONTEXT_DMA:
+ Nv04AllocContextDmaKernel(&ops->params.allocContextDma2);
+ break;
+
+ case NV04_MAP_MEMORY_DMA:
+ Nv04MapMemoryDmaKernel(&ops->params.mapMemoryDma);
+ break;
+
+ case NV04_UNMAP_MEMORY_DMA:
+ Nv04UnmapMemoryDmaKernel(&ops->params.unmapMemoryDma);
+ break;
+
+ case NV04_BIND_CONTEXT_DMA:
+ Nv04BindContextDmaKernel(&ops->params.bindContextDma);
+ break;
+
+ case NV04_CONTROL:
+ Nv04ControlKernel(&ops->params.control);
+ break;
+
+ case NV04_DUP_OBJECT:
+ Nv04DupObjectKernel(&ops->params.dupObject);
+ break;
+
+ case NV04_SHARE:
+ Nv04ShareKernel(&ops->params.share);
+ break;
+
+ case NV04_ADD_VBLANK_CALLBACK:
+ Nv04AddVblankCallbackKernel(&ops->params.addVblankCallback);
+ break;
+ }
+
+ NV_EXIT_RM_RUNTIME(sp,fp);
+}
+
+//
+// ACPI method (NVIF/_DSM/WMMX/MXM*/etc.) initialization
+//
+void RmInitAcpiMethods(OBJOS *pOS, OBJSYS *pSys, OBJGPU *pGpu)
+{
+ NvU32 handlesPresent;
+
+ if (pSys->getProperty(pSys, PDB_PROP_SYS_NVIF_INIT_DONE))
+ return;
+
+ nv_acpi_methods_init(&handlesPresent);
+
+ acpiDsmInit(pGpu);
+}
+
+//
+// ACPI method (NVIF/_DSM/WMMX/MXM*/etc.) teardown
+//
+void RmUnInitAcpiMethods(OBJSYS *pSys)
+{
+ pSys->setProperty(pSys, PDB_PROP_SYS_NVIF_INIT_DONE, NV_FALSE);
+
+ nv_acpi_methods_uninit();
+}
+
+//
+// Converts an array of OS page address to an array of RM page addresses.This
+// assumes that:
+// (1) The pteArray is at least pageCount entries large,
+// (2) The pageCount is given in RM pages, and
+// (3) The OS page entries start at index 0.
+//
+void RmInflateOsToRmPageArray(RmPhysAddr *pteArray, NvU64 pageCount)
+{
+ RmInflatePageArray(
+ pteArray,
+ NV_RM_PAGES_TO_OS_PAGES(pageCount),
+ os_page_size,
+ pageCount,
+ NV_RM_PAGE_SIZE
+ );
+}
+
+void RmDeflateRmToOsPageArray(RmPhysAddr *pteArray, NvU64 pageCount)
+{
+ RmDeflatePageArray(
+ pteArray,
+ pageCount,
+ NV_RM_PAGE_SIZE,
+ NV_RM_PAGES_TO_OS_PAGES(pageCount),
+ os_page_size
+ );
+}
+
+NvBool NV_API_CALL
+rm_get_device_remove_flag
+(
+ nvidia_stack_t * sp,
+ NvU32 gpu_id
+)
+{
+ THREAD_STATE_NODE threadState;
+ void *fp;
+ NvBool bRemove;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ if (gpumgrQueryGpuDrainState(gpu_id, NULL, &bRemove) != NV_OK)
+ {
+ bRemove = NV_FALSE;
+ }
+
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return bRemove;
+}
+
+//
+// This API updates only the following fields in nv_ioctl_numa_info_t:
+// - nid
+// - numa_mem_addr
+// - numa_mem_size
+// - offline_addresses
+//
+// Rest of the fields should be updated by caller.
+NV_STATUS NV_API_CALL rm_get_gpu_numa_info(
+ nvidia_stack_t *sp,
+ nv_state_t *nv,
+ nv_ioctl_numa_info_t *numa_info
+)
+{
+ NV2080_CTRL_FB_GET_NUMA_INFO_PARAMS *pParams;
+ RM_API *pRmApi;
+ THREAD_STATE_NODE threadState;
+ void *fp;
+ NV_STATUS status = NV_OK;
+
+ ct_assert(NV_ARRAY_ELEMENTS(numa_info->offline_addresses.addresses) >=
+ NV_ARRAY_ELEMENTS(pParams->numaOfflineAddresses));
+
+ if ((numa_info == NULL) ||
+ (numa_info->offline_addresses.numEntries >
+ NV_ARRAY_ELEMENTS(pParams->numaOfflineAddresses)))
+ {
+ return NV_ERR_INVALID_ARGUMENT;
+ }
+
+ if (NV_IS_SOC_DISPLAY_DEVICE(nv))
+ {
+ numa_info->nid = NV0000_CTRL_NO_NUMA_NODE;
+ numa_info->numa_mem_addr = 0;
+ numa_info->numa_mem_size = 0;
+ numa_info->offline_addresses.numEntries = 0;
+ return NV_OK;
+ }
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+
+ pParams = portMemAllocNonPaged(sizeof(*pParams));
+ if (pParams == NULL)
+ {
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return NV_ERR_NO_MEMORY;
+ }
+
+ portMemSet(pParams, 0, sizeof(*pParams));
+ pParams->numaOfflineAddressesCount =
+ numa_info->offline_addresses.numEntries;
+
+ pRmApi = RmUnixRmApiPrologue(nv, &threadState, RM_LOCK_MODULES_MEM);
+ if (pRmApi == NULL)
+ {
+ status = NV_ERR_INVALID_STATE;
+ goto finish;
+ }
+
+ status = pRmApi->Control(pRmApi, nv->rmapi.hClient, nv->rmapi.hSubDevice,
+ NV2080_CTRL_CMD_FB_GET_NUMA_INFO,
+ pParams, sizeof(*pParams));
+
+ RmUnixRmApiEpilogue(nv, &threadState);
+
+ if (status == NV_OK)
+ {
+ NvU32 i;
+
+ numa_info->nid = pParams->numaNodeId;
+ numa_info->numa_mem_addr = pParams->numaMemAddr;
+ numa_info->numa_mem_size = pParams->numaMemSize;
+ numa_info->offline_addresses.numEntries =
+ pParams->numaOfflineAddressesCount;
+
+ for (i = 0; i < pParams->numaOfflineAddressesCount; i++)
+ {
+ numa_info->offline_addresses.addresses[i] =
+ pParams->numaOfflineAddresses[i];
+ }
+ }
+
+finish:
+ portMemFree(pParams);
+
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return status;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_numa_online(
+ nvidia_stack_t *sp,
+ nv_state_t *nv
+)
+{
+ NV2080_CTRL_FB_UPDATE_NUMA_STATUS_PARAMS params = { 0 };
+ RM_API *pRmApi;
+ THREAD_STATE_NODE threadState;
+ void *fp;
+ NV_STATUS status = NV_OK;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+
+ pRmApi = RmUnixRmApiPrologue(nv, &threadState, RM_LOCK_MODULES_MEM);
+ if (pRmApi == NULL)
+ {
+ status = NV_ERR_INVALID_STATE;
+ goto finish;
+ }
+
+ params.bOnline = NV_TRUE;
+
+ status = pRmApi->Control(pRmApi, nv->rmapi.hClient, nv->rmapi.hSubDevice,
+ NV2080_CTRL_CMD_FB_UPDATE_NUMA_STATUS,
+ &params, sizeof(params));
+
+ RmUnixRmApiEpilogue(nv, &threadState);
+
+finish:
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return status;
+}
+
+
+NV_STATUS NV_API_CALL rm_gpu_numa_offline(
+ nvidia_stack_t *sp,
+ nv_state_t *nv
+)
+{
+ NV2080_CTRL_FB_UPDATE_NUMA_STATUS_PARAMS params = { 0 };
+ RM_API *pRmApi;
+ THREAD_STATE_NODE threadState;
+ void *fp;
+ NV_STATUS status = NV_OK;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+
+ pRmApi = RmUnixRmApiPrologue(nv, &threadState, RM_LOCK_MODULES_MEM);
+ if (pRmApi == NULL)
+ {
+ status = NV_ERR_INVALID_STATE;
+ goto finish;
+ }
+
+ params.bOnline = NV_FALSE;
+
+ status = pRmApi->Control(pRmApi, nv->rmapi.hClient,
+ nv->rmapi.hSubDevice,
+ NV2080_CTRL_CMD_FB_UPDATE_NUMA_STATUS,
+ &params, sizeof(params));
+
+ RmUnixRmApiEpilogue(nv, &threadState);
+
+finish:
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return status;
+}
+
+//
+// A device is considered "sequestered" if it has drain state enabled for it.
+// The kernel interface layer can use this to check the drain state of a device
+// in paths outside of initialization, e.g., when clients attempt to reference
+// count the device.
+//
+NvBool NV_API_CALL rm_is_device_sequestered(
+ nvidia_stack_t *sp,
+ nv_state_t *pNv
+)
+{
+ THREAD_STATE_NODE threadState;
+ void *fp;
+ NvBool bDrain = NV_FALSE;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ //
+ // If gpumgrQueryGpuDrainState succeeds, bDrain will be set as needed.
+ // If gpumgrQueryGpuDrainState fails, bDrain will stay false; we assume
+ // that if core RM can't tell us the drain state, it must not be
+ // attached and the "sequestered" question is not relevant.
+ //
+ (void) gpumgrQueryGpuDrainState(pNv->gpu_id, &bDrain, NULL);
+
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return bDrain;
+}
+
+void NV_API_CALL rm_check_for_gpu_surprise_removal(
+ nvidia_stack_t *sp,
+ nv_state_t *nv
+)
+{
+ THREAD_STATE_NODE threadState;
+ void *fp;
+ NV_STATUS rmStatus;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ // LOCK: acquire API lock.
+ if ((rmStatus = rmapiLockAcquire(RMAPI_LOCK_FLAGS_READ, RM_LOCK_MODULES_GPU)) == NV_OK)
+ {
+ OBJGPU *pGpu = NV_GET_NV_PRIV_PGPU(nv);
+
+ if ((rmStatus = rmDeviceGpuLocksAcquire(pGpu, GPUS_LOCK_FLAGS_NONE, RM_LOCK_MODULES_GPU)) == NV_OK)
+ {
+ osHandleGpuLost(pGpu, NV_TRUE);
+ rmDeviceGpuLocksRelease(pGpu, GPUS_LOCK_FLAGS_NONE, NULL);
+ }
+
+ // UNLOCK: release api lock
+ rmapiLockRelease();
+ }
+
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+}
+
+NV_STATUS NV_API_CALL rm_set_external_kernel_client_count(
+ nvidia_stack_t *sp,
+ nv_state_t *pNv,
+ NvBool bIncr
+)
+{
+ THREAD_STATE_NODE threadState;
+ void *fp;
+ OBJGPU *pGpu;
+ NV_STATUS rmStatus = NV_OK;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ pGpu = NV_GET_NV_PRIV_PGPU(pNv);
+
+ if (pGpu != NULL)
+ {
+ rmStatus = rmDeviceGpuLocksAcquire(pGpu, GPUS_LOCK_FLAGS_NONE,
+ RM_LOCK_MODULES_GPU);
+ if (rmStatus == NV_OK)
+ {
+ rmStatus = gpuSetExternalKernelClientCount(pGpu, bIncr);
+ rmDeviceGpuLocksRelease(pGpu, GPUS_LOCK_FLAGS_NONE, NULL);
+ }
+ }
+
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return rmStatus;
+}
+
+NvBool rm_get_uefi_console_status(
+ nv_state_t *nv
+)
+{
+ NvU32 fbWidth, fbHeight, fbDepth, fbPitch;
+ NvU64 fbSize;
+ NvU64 fbBaseAddress = 0;
+ NvBool bConsoleDevice = NV_FALSE;
+
+ //
+ // nv_get_screen_info() will return dimensions and an address for
+ // any fbdev driver (e.g., efifb, vesafb, etc).
+ //
+ nv_get_screen_info(nv, &fbBaseAddress, &fbWidth, &fbHeight, &fbDepth, &fbPitch, &fbSize);
+
+ bConsoleDevice = (fbSize != 0);
+
+ return bConsoleDevice;
+}
+
+NvU64 rm_get_uefi_console_size(
+ nv_state_t *nv,
+ NvU64 *pFbBaseAddress
+)
+{
+ NvU32 fbWidth, fbHeight, fbDepth, fbPitch;
+ NvU64 fbSize;
+
+ fbSize = fbWidth = fbHeight = fbDepth = fbPitch = 0;
+
+ //
+ // nv_get_screen_info() will return dimensions and an address for
+ // any fbdev driver (e.g., efifb, vesafb, etc).
+ //
+ nv_get_screen_info(nv, pFbBaseAddress, &fbWidth, &fbHeight, &fbDepth, &fbPitch, &fbSize);
+
+ return fbSize;
+}
+
+NvBool NV_API_CALL rm_disable_iomap_wc(void)
+{
+ OBJSYS *pSys = SYS_GET_INSTANCE();
+ OBJCL *pCl = pSys->pCl;
+ return pCl->getProperty(pCl, PDB_PROP_CL_DISABLE_IOMAP_WC) == NV_TRUE;
+}
+
+//
+// Verifies the handle, offset and size and dups hMemory.
+// Must be called with API lock and GPU lock held.
+//
+NV_STATUS NV_API_CALL rm_dma_buf_dup_mem_handle(
+ nvidia_stack_t *sp,
+ nv_state_t *nv,
+ NvHandle hSrcClient,
+ NvHandle hDstClient,
+ NvHandle hDevice,
+ NvHandle hSubdevice,
+ void *pGpuInstanceInfo,
+ NvHandle hMemory,
+ NvU64 offset,
+ NvU64 size,
+ NvU8 mappingType,
+ NvHandle *phMemoryDuped,
+ void **ppMemInfo,
+ NvBool *pbCanMmap,
+ NvU32 *pCacheType,
+ NvBool *pbReadOnlyMem,
+ nv_memory_type_t *pMemoryType
+)
+{
+ MEMORY_DESCRIPTOR *pMemDesc;
+ THREAD_STATE_NODE *pThreadState;
+ NV_STATUS rmStatus = NV_ERR_NO_MEMORY;
+ OBJGPU *pGpu;
+ void *fp;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ pThreadState = threadStateAlloc(THREAD_STATE_FLAGS_NONE);
+ NV_ASSERT_OR_GOTO(pThreadState != NULL, Done);
+
+ pGpu = NV_GET_NV_PRIV_PGPU(nv);
+
+ NV_ASSERT(rmapiLockIsOwner());
+
+ NV_ASSERT(rmDeviceGpuLockIsOwner(gpuGetInstance(pGpu)));
+
+ rmStatus = RmDmabufVerifyMemHandle(pGpu, hSrcClient, hMemory,
+ offset, size, pGpuInstanceInfo,
+ &pMemDesc);
+ if (rmStatus == NV_OK)
+ {
+ RM_API *pRmApi = rmapiGetInterface(RMAPI_GPU_LOCK_INTERNAL);
+ NvHandle hMemoryDuped = 0;
+
+ rmStatus = pRmApi->DupObject(pRmApi,
+ hDstClient,
+ hDevice,
+ &hMemoryDuped,
+ hSrcClient,
+ hMemory,
+ 0);
+ if (rmStatus == NV_OK)
+ {
+ *phMemoryDuped = hMemoryDuped;
+ }
+ else if (rmStatus == NV_ERR_INVALID_OBJECT_PARENT)
+ {
+ hMemoryDuped = 0;
+
+ // If duping under Device fails, try duping under Subdevice
+ rmStatus = pRmApi->DupObject(pRmApi,
+ hDstClient,
+ hSubdevice,
+ &hMemoryDuped,
+ hSrcClient,
+ hMemory,
+ 0);
+ if (rmStatus == NV_OK)
+ {
+ *phMemoryDuped = hMemoryDuped;
+ }
+ }
+ *ppMemInfo = (void *) pMemDesc;
+
+ *pCacheType = RmDmabufMmapGetCpuCacheType(pGpu, pMemDesc, mappingType);
+ *pbReadOnlyMem = memdescGetFlag(pMemDesc, MEMDESC_FLAGS_USER_READ_ONLY);
+
+ if (memdescGetFlag(pMemDesc, MEMDESC_FLAGS_PEER_IO_MEM))
+ {
+ *pMemoryType = NV_MEMORY_TYPE_DEVICE_MMIO;
+ }
+ else if (memdescGetAddressSpace(pMemDesc) == ADDR_SYSMEM)
+ {
+ *pMemoryType = NV_MEMORY_TYPE_SYSTEM;
+ }
+ else
+ {
+ // TODO: Assume NV_MEMORY_TYPE_FRAMEBUFFER is for now.
+ // Add Proper handling for NV_MEMORY_TYPE_REGISTERS.
+ *pMemoryType = NV_MEMORY_TYPE_FRAMEBUFFER;
+ }
+
+ // mmap is allowed on 0FB chips(iGPU) for sysmem and on dGPU for vidmem only
+ *pbCanMmap = (pGpu->pGpuArch->bGpuArchIsZeroFb ||
+ (memdescGetAddressSpace(pMemDesc) == ADDR_FBMEM));
+ }
+
+Done:
+ if (pThreadState != NULL)
+ threadStateFree(pThreadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return rmStatus;
+}
+
+//
+// Frees dup'd hMemory.
+// Must be called with API lock and GPU lock held.
+//
+void NV_API_CALL rm_dma_buf_undup_mem_handle(
+ nvidia_stack_t *sp,
+ nv_state_t *nv,
+ NvHandle hClient,
+ NvHandle hMemory
+)
+{
+ THREAD_STATE_NODE threadState;
+ RM_API *pRmApi;
+ OBJGPU *pGpu;
+ void *fp;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ pGpu = NV_GET_NV_PRIV_PGPU(nv);
+
+ NV_ASSERT(rmapiLockIsOwner());
+
+ NV_ASSERT(rmDeviceGpuLockIsOwner(gpuGetInstance(pGpu)));
+
+ pRmApi = rmapiGetInterface(RMAPI_GPU_LOCK_INTERNAL);
+
+ pRmApi->Free(pRmApi, hClient, hMemory);
+
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+}
+
+//
+// Maps a handle to system physical addresses:
+// C2C for coherent platforms with DEFAULT mapping type
+// BAR1(static & dynamic) for non-coherent platforms and for
+// coherent platforms with mapping type FORCE_PCIE
+// Must be called with API lock and GPU lock held for dynamic BAR1.
+//
+NV_STATUS NV_API_CALL rm_dma_buf_map_mem_handle(
+ nvidia_stack_t *sp,
+ nv_state_t *nv,
+ NvHandle hClient,
+ NvHandle hMemory,
+ MemoryRange memRange,
+ NvU8 mappingType,
+ void *pMemInfo,
+ NvBool bStaticPhysAddrs,
+ MemoryArea *pMemArea
+)
+{
+ THREAD_STATE_NODE *pThreadState;
+ NV_STATUS rmStatus = NV_ERR_INVALID_ARGUMENT;
+ OBJGPU *pGpu;
+ MEMORY_DESCRIPTOR *pMemDesc;
+ void *fp;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ pThreadState = threadStateAlloc(THREAD_STATE_FLAGS_NONE);
+ if (pThreadState == NULL)
+ {
+ NV_ASSERT(0);
+ rmStatus = NV_ERR_NO_MEMORY;
+ goto Done;
+ }
+
+ NV_ASSERT_OR_GOTO(((pMemArea != NULL) &&
+ (pMemInfo != NULL)) &&
+ (memRange.size != 0), Done);
+
+ pGpu = NV_GET_NV_PRIV_PGPU(nv);
+ pMemDesc = (MEMORY_DESCRIPTOR *) pMemInfo;
+
+ if (((pGpu->getProperty(pGpu, PDB_PROP_GPU_COHERENT_CPU_MAPPING)) ||
+ (pGpu->pGpuArch->bGpuArchIsZeroFb)) &&
+ (mappingType == NV_DMABUF_EXPORT_MAPPING_TYPE_DEFAULT))
+ {
+ KernelMemorySystem *pKernelMemorySystem = GPU_GET_KERNEL_MEMORY_SYSTEM(pGpu);
+ NvBool contiguity = memdescCheckContiguity(pMemDesc, AT_CPU);
+
+ // On localized allocations over C2C/nvlink mappings, RDMA is not supported
+ if (memdescGetFlag(pMemDesc, MEMDESC_FLAGS_ALLOC_AS_LOCALIZED))
+ {
+ NV_PRINTF(LEVEL_ERROR, "RDMA is not supported for localized memory"
+ " over coherent mappings\n");
+ rmStatus = NV_ERR_NOT_SUPPORTED;
+ goto Done;
+ }
+
+ if (contiguity)
+ {
+ NvU64 physAddr = memdescGetPhysAddr(pMemDesc, AT_CPU, memRange.start);
+
+ NV_ASSERT_OK_OR_GOTO(rmStatus, os_alloc_mem((void **) &pMemArea->pRanges,
+ sizeof(MemoryRange)), Done);
+
+ pMemArea->pRanges[0].start = pKernelMemorySystem->coherentCpuFbBase + physAddr;
+ pMemArea->pRanges[0].size = memRange.size;
+ pMemArea->numRanges = 1;
+ }
+ else
+ {
+ NvU64 idx = 0;
+ NvU64 memdescPageSize = memdescGetPageSize(pMemDesc, AT_CPU);
+ NvU64 origEnd = memRange.start + memRange.size;
+ NvU64 realStart = NV_ALIGN_DOWN64(memRange.start, memdescPageSize);
+ NvU64 realEnd = NV_ALIGN_UP64(memRange.start + memRange.size, memdescPageSize);
+ NvU64 realSize = realEnd - realStart;
+ NvU64 pageCount = realSize / memdescPageSize;
+
+ NV_ASSERT_OK_OR_GOTO(rmStatus, os_alloc_mem((void **) &pMemArea->pRanges,
+ pageCount * sizeof(MemoryRange)), Done);
+
+ for(idx = 0; idx < pageCount; idx++)
+ {
+ NvU64 physAddr = memdescGetPhysAddr(pMemDesc, AT_CPU,
+ realStart + (idx * memdescPageSize));
+ pMemArea->pRanges[idx].start = pKernelMemorySystem->coherentCpuFbBase + physAddr;
+ pMemArea->pRanges[idx].size = memdescPageSize;
+ }
+
+ pMemArea->pRanges[0].start += (memRange.start - realStart);
+ pMemArea->pRanges[0].size -= (memRange.start - realStart);
+ pMemArea->pRanges[pageCount - 1llu].size -= (realEnd - origEnd);
+
+ pMemArea->numRanges = pageCount;
+ }
+ }
+ else
+ {
+ Device *pDevice = NULL;
+ RsClient *pClient;
+ NvU64 idx;
+ NvU64 barOffset;
+ KernelBus *pKernelBus;
+ NvBool bForcePcie;
+
+ pKernelBus = GPU_GET_KERNEL_BUS(pGpu);
+
+ if (!bStaticPhysAddrs)
+ {
+ // Dynamic BAR1 requires RMAPI and GPU lock to be held
+ NV_ASSERT(rmapiLockIsOwner());
+ NV_ASSERT(rmDeviceGpuLockIsOwner(gpuGetInstance(pGpu)));
+
+ NV_ASSERT_OK_OR_GOTO(rmStatus,
+ serverGetClientUnderLock(&g_resServ, hClient, &pClient),
+ Done);
+
+ NV_ASSERT_OK_OR_GOTO(rmStatus,
+ deviceGetByGpu(pClient, pGpu, NV_TRUE, &pDevice),
+ Done);
+ }
+
+ NV_CHECK_OR_GOTO(LEVEL_ERROR,
+ memdescGetAddressSpace(pMemDesc) == ADDR_FBMEM,
+ Done);
+
+ //
+ // We don't take locks for static BAR1.
+ // Thus, we operate directly on the memdesc passed to
+ // bypass the client lookup which requires client locks.
+ //
+ NV_ASSERT_OK_OR_GOTO(rmStatus,
+ kbusMapFbAperture_HAL(pGpu, pKernelBus, pMemDesc, memRange, pMemArea,
+ (BUS_MAP_FB_FLAGS_MAP_UNICAST | BUS_MAP_FB_FLAGS_ALLOW_DISCONTIG),
+ pDevice),
+ Done);
+
+ bForcePcie = (mappingType == NV_DMABUF_EXPORT_MAPPING_TYPE_FORCE_PCIE);
+
+ NV_ASSERT_OK_OR_GOTO(rmStatus,
+ kbusGetGpuFbPhysAddressForRdma(pGpu, pKernelBus,
+ bForcePcie, &barOffset),
+ Done);
+
+ for (idx = 0; idx < pMemArea->numRanges; idx++)
+ {
+ pMemArea->pRanges[idx].start += barOffset;
+ }
+ }
+
+Done:
+ if (pThreadState != NULL)
+ threadStateFree(pThreadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return rmStatus;
+}
+
+//
+// Unmaps a handle that was mapped to system physical addresses.
+// Must be called with API lock and GPU lock held for dynamic BAR1.
+//
+void NV_API_CALL rm_dma_buf_unmap_mem_handle(
+ nvidia_stack_t *sp,
+ nv_state_t *nv,
+ NvHandle hClient,
+ NvHandle hMemory,
+ NvU8 mappingType,
+ void *pMemInfo,
+ NvBool bStaticPhysAddrs,
+ MemoryArea memArea
+)
+{
+ THREAD_STATE_NODE threadState;
+ OBJGPU *pGpu;
+ void *fp;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ pGpu = NV_GET_NV_PRIV_PGPU(nv);
+
+ if ((pGpu->getProperty(pGpu, PDB_PROP_GPU_COHERENT_CPU_MAPPING) ||
+ pGpu->pGpuArch->bGpuArchIsZeroFb) &&
+ (mappingType == NV_DMABUF_EXPORT_MAPPING_TYPE_DEFAULT))
+ {
+ os_free_mem(memArea.pRanges);
+ }
+ else
+ {
+ KernelBus *pKernelBus;
+ NvU64 idx;
+ NvU64 barOffset;
+ MEMORY_DESCRIPTOR *pMemDesc = (MEMORY_DESCRIPTOR *) pMemInfo;
+ NvBool bForcePcie = (mappingType == NV_DMABUF_EXPORT_MAPPING_TYPE_FORCE_PCIE);
+
+ pKernelBus = GPU_GET_KERNEL_BUS(pGpu);
+
+ NV_ASSERT_OK(kbusGetGpuFbPhysAddressForRdma(pGpu, pKernelBus,
+ bForcePcie, &barOffset));
+
+ for (idx = 0; idx < memArea.numRanges; idx++)
+ {
+ memArea.pRanges[idx].start -= barOffset;
+ }
+
+ if (!bStaticPhysAddrs)
+ {
+ // Dynamic BAR1 requires RMAPI and GPU lock to be held
+ NV_ASSERT(rmapiLockIsOwner());
+ NV_ASSERT(rmDeviceGpuLockIsOwner(gpuGetInstance(pGpu)));
+ }
+
+ //
+ // We don't take locks for static BAR1.
+ // Thus, we operate directly on the memdesc passed to
+ // bypass the client lookup which requires client locks.
+ //
+ NV_ASSERT_OK(kbusUnmapFbAperture_HAL(pGpu, pKernelBus, pMemDesc, memArea,
+ BUS_MAP_FB_FLAGS_MAP_UNICAST));
+ }
+
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+}
+
+NV_STATUS NV_API_CALL rm_dma_buf_get_client_and_device(
+ nvidia_stack_t *sp,
+ nv_state_t *nv,
+ NvHandle hClient,
+ NvHandle hMemory,
+ NvU8 mappingType,
+ NvHandle *phClient,
+ NvHandle *phDevice,
+ NvHandle *phSubdevice,
+ void **ppGpuInstanceInfo,
+ NvBool *pbStaticPhysAddrs,
+ NvBool *pbAcquireReleaseAllGpuLockOnDup
+)
+{
+ THREAD_STATE_NODE threadState;
+ NV_STATUS rmStatus;
+ void *fp;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ // LOCK: acquire API lock
+ rmStatus = rmapiLockAcquire(API_LOCK_FLAGS_NONE, RM_LOCK_MODULES_OSAPI);
+ if (rmStatus == NV_OK)
+ {
+ OBJGPU *pGpu = NV_GET_NV_PRIV_PGPU(nv);
+
+ rmStatus = rmDeviceGpuLocksAcquire(pGpu, GPUS_LOCK_FLAGS_NONE, RM_LOCK_MODULES_OSAPI);
+ if (rmStatus == NV_OK)
+ {
+ rmStatus = RmDmabufGetClientAndDevice(pGpu, hClient, hMemory, mappingType,
+ phClient, phDevice,
+ phSubdevice, ppGpuInstanceInfo);
+ if (rmStatus == NV_OK)
+ {
+ *pbStaticPhysAddrs = ((pGpu->getProperty(pGpu, PDB_PROP_GPU_COHERENT_CPU_MAPPING) ||
+ pGpu->pGpuArch->bGpuArchIsZeroFb) &&
+ (mappingType == NV_DMABUF_EXPORT_MAPPING_TYPE_DEFAULT)) ||
+ kbusIsStaticBar1Enabled(pGpu, GPU_GET_KERNEL_BUS(pGpu));
+ }
+
+ *pbAcquireReleaseAllGpuLockOnDup = pGpu->pGpuArch->bGpuArchIsZeroFb;
+
+ rmDeviceGpuLocksRelease(pGpu, GPUS_LOCK_FLAGS_NONE, NULL);
+ }
+
+ // UNLOCK: release API lock
+ rmapiLockRelease();
+ }
+
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return rmStatus;
+}
+
+void NV_API_CALL rm_dma_buf_put_client_and_device(
+ nvidia_stack_t *sp,
+ nv_state_t *nv,
+ NvHandle hClient,
+ NvHandle hDevice,
+ NvHandle hSubdevice,
+ void *pGpuInstanceInfo
+)
+{
+ THREAD_STATE_NODE threadState;
+ NV_STATUS rmStatus;
+ void *fp;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ // LOCK: acquire API lock
+ rmStatus = rmapiLockAcquire(API_LOCK_FLAGS_NONE, RM_LOCK_MODULES_OSAPI);
+ if (rmStatus == NV_OK)
+ {
+ OBJGPU *pGpu = NV_GET_NV_PRIV_PGPU(nv);
+
+ rmStatus = rmDeviceGpuLocksAcquire(pGpu, GPUS_LOCK_FLAGS_NONE, RM_LOCK_MODULES_OSAPI);
+ if (rmStatus == NV_OK)
+ {
+ RmDmabufPutClientAndDevice(pGpu, hClient, hDevice, hSubdevice,
+ pGpuInstanceInfo);
+
+ rmDeviceGpuLocksRelease(pGpu, GPUS_LOCK_FLAGS_NONE, NULL);
+ }
+
+ // UNLOCK: release API lock
+ rmapiLockRelease();
+ }
+ NV_ASSERT_OK(rmStatus);
+
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+}
+
+//
+// Fetches GSP ucode data for usage during RM Init
+// NOTE: Used only on VMWware
+//
+
+void NV_API_CALL rm_vgpu_vfio_set_driver_vm(
+ nvidia_stack_t *sp,
+ NvBool is_driver_vm
+)
+{
+ OBJSYS *pSys;
+ OBJHYPERVISOR *pHypervisor;
+ void *fp;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+
+ pSys = SYS_GET_INSTANCE();
+ pHypervisor = SYS_GET_HYPERVISOR(pSys);
+
+ pHypervisor->setProperty(pHypervisor, PDB_PROP_HYPERVISOR_DRIVERVM_ENABLED, is_driver_vm);
+
+ NV_EXIT_RM_RUNTIME(sp,fp);
+}
+
+NvBool NV_API_CALL rm_is_altstack_in_use(void)
+{
+#if defined(__use_altstack__)
+ return NV_TRUE;
+#else
+ return NV_FALSE;
+#endif
+}
+
+void NV_API_CALL rm_acpi_nvpcf_notify(
+ nvidia_stack_t *sp
+)
+{
+ void *fp;
+ THREAD_STATE_NODE threadState;
+ NV_STATUS rmStatus = NV_OK;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ // LOCK: acquire API lock
+ if ((rmStatus = rmapiLockAcquire(API_LOCK_FLAGS_NONE,
+ RM_LOCK_MODULES_EVENT)) == NV_OK)
+ {
+ OBJGPU *pGpu = gpumgrGetGpu(0);
+ if (pGpu != NULL)
+ {
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ if ((rmStatus = os_ref_dynamic_power(nv, NV_DYNAMIC_PM_FINE)) ==
+ NV_OK)
+ {
+ gpuNotifySubDeviceEvent(pGpu, NV2080_NOTIFIERS_NVPCF_EVENTS,
+ NULL, 0, 0, 0);
+ }
+ os_unref_dynamic_power(nv, NV_DYNAMIC_PM_FINE);
+ }
+ rmapiLockRelease();
+ }
+
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+}
+
+static void rm_notify_gpu_addition_removal_helper(
+ nv_state_t *nv,
+ NvBool bBind)
+{
+ THREAD_STATE_NODE threadState;
+
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ if (rmapiLockAcquire(API_LOCK_FLAGS_NONE, RM_LOCK_MODULES_OSAPI) == NV_OK)
+ {
+ NV0000_CTRL_SYSTEM_EVENT_DATA_GPU_BIND_UNBIND eventData = { 0 };
+
+ eventData.gpuId = nv->gpu_id;
+ eventData.bBind = bBind;
+
+ CliAddSystemEvent(NV0000_NOTIFIERS_GPU_BIND_UNBIND_EVENT, &eventData, NULL);
+ rmapiLockRelease();
+ }
+ else
+ {
+ NV_PRINTF(LEVEL_ERROR, "Fail to acquire rmApi lock. Skip notification.");
+ }
+
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+}
+
+void NV_API_CALL rm_notify_gpu_addition(
+ nvidia_stack_t *sp,
+ nv_state_t *nv)
+{
+ void *fp = NULL;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rm_notify_gpu_addition_removal_helper(nv, NV_TRUE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+}
+
+void NV_API_CALL rm_notify_gpu_removal(
+ nvidia_stack_t *sp,
+ nv_state_t *nv)
+{
+ void *fp = NULL;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rm_notify_gpu_addition_removal_helper(nv, NV_FALSE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+}
+
+NvBool NV_API_CALL rm_wait_for_bar_firewall(
+ nvidia_stack_t * sp,
+ NvU32 domain,
+ NvU8 bus,
+ NvU8 device,
+ NvU8 function,
+ NvU16 devId,
+ NvU16 subsystemId
+)
+{
+ NvBool ret;
+ void *fp = NULL;
+
+ // no state set up yet for threadstate or RM locks
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ ret = gpumgrWaitForBarFirewall(domain, bus, device, function, devId, subsystemId);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return ret;
+}
+
+static NvU32 devfreq_clk_to_domain(
+ TEGRASOC_DEVFREQ_CLK devfreqClk
+)
+{
+ NvU32 clkDomain = NV2080_CTRL_CLK_DOMAIN_TEGRA_UNDEFINED;
+ switch (devfreqClk)
+ {
+ case TEGRASOC_DEVFREQ_CLK_GPC:
+ clkDomain = NV2080_CTRL_CLK_DOMAIN_TEGRA_GPCCLK;
+ break;
+
+ case TEGRASOC_DEVFREQ_CLK_NVD:
+ clkDomain = NV2080_CTRL_CLK_DOMAIN_TEGRA_NVDCLK;
+ break;
+
+ default:
+ break;
+ }
+
+ return clkDomain;
+}
+
+NV_STATUS NV_API_CALL rm_pmu_perfmon_get_load(
+ nvidia_stack_t *sp,
+ nv_state_t *nv,
+ NvU32 *load,
+ TEGRASOC_DEVFREQ_CLK devfreqClk
+)
+{
+ NV2080_CTRL_PERF_GET_TEGRA_PERFMON_SAMPLE_PARAMS params = { 0 };
+ NvU32 clkDomain = devfreq_clk_to_domain(devfreqClk);
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+ RM_API *pRmApi;
+ NV_STATUS status;
+ void *fp;
+
+ if (clkDomain == NV2080_CTRL_CLK_DOMAIN_TEGRA_UNDEFINED)
+ {
+ return NV_ERR_INVALID_ARGUMENT;
+ }
+
+ if (nvp->dynamic_power.state == NV_DYNAMIC_POWER_STATE_IDLE_INDICATED)
+ {
+ *load = 0;
+ return NV_OK;
+ }
+
+ NV_ENTER_RM_RUNTIME(sp, fp);
+
+ if (rmapiLockAcquire(API_LOCK_FLAGS_NONE, RM_LOCK_MODULES_OSAPI) == NV_OK)
+ {
+ pRmApi = rmapiGetInterface(RMAPI_API_LOCK_INTERNAL);
+ if (pRmApi == NULL)
+ {
+ status = NV_ERR_INVALID_STATE;
+ rmapiLockRelease();
+ goto rm_pmu_perfmon_get_load_exit;
+ }
+
+ params.clkDomain = clkDomain;
+ status = pRmApi->Control(pRmApi, nv->rmapi.hClient, nv->rmapi.hSubDevice,
+ NV2080_CTRL_CMD_PERF_GET_TEGRA_PERFMON_SAMPLE,
+ &params, sizeof(params));
+ if (status == NV_OK)
+ {
+ *load = params.clkPercentBusy;
+ }
+
+ rmapiLockRelease();
+ }
+ else
+ {
+ status = NV_ERR_INVALID_STATE;
+ }
+
+rm_pmu_perfmon_get_load_exit:
+ NV_EXIT_RM_RUNTIME(sp, fp);
+
+ return status;
+}
diff --git a/userspace/sdks/nv570/nvalloc/unix/src/osinit.c b/userspace/sdks/nv570/nvalloc/unix/src/osinit.c
new file mode 100644
index 0000000..b3fd343
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/src/osinit.c
@@ -0,0 +1,2768 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 1999-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**************************************************************************************************************
+*
+* Description:
+* UNIX-general, device-independent initialization code for
+* the resource manager.
+*
+*
+**************************************************************************************************************/
+
+#include <nv_ref.h>
+#include <nv.h> // NV device driver interface
+#include <nv-reg.h>
+#include <nv-priv.h>
+#include <nvos.h>
+#include <nvrm_registry.h>
+#include <platform/sli/sli.h>
+#include <nverror.h>
+#include <osapi.h>
+#include <core/system.h>
+#include <os/os.h>
+#include "gpu/gpu.h"
+#include <gpu/timer/objtmr.h>
+#include "gpu/bus/kern_bus.h"
+#include "nverror.h"
+#include <nv-nb-regs.h>
+#include <gpu/bif/kernel_bif.h>
+#include <gpu/mem_mgr/mem_mgr.h>
+#include <gpu/mem_sys/kern_mem_sys.h>
+#include "kernel/gpu/intr/intr.h"
+#include <mem_mgr/io_vaspace.h>
+#include <gpu/disp/kern_disp.h>
+#include <platform/chipset/chipset.h>
+#include <kernel/gpu/rc/kernel_rc.h>
+#include <kernel/gpu/fifo/kernel_fifo.h>
+#include <nv-firmware-chip-family-select.h>
+#include <kernel/gpu/gsp/kernel_gsp.h>
+#include "liblogdecode.h"
+
+#include <mem_mgr/virt_mem_mgr.h>
+#include <virtualization/kernel_vgpu_mgr.h>
+
+#include <rmosxfac.h>
+#include <gpu_mgr/gpu_mgr.h>
+#include <core/thread_state.h>
+#include <core/locks.h>
+#include <rmapi/client.h>
+#include <ctrl/ctrl2080/ctrl2080gpu.h>
+#include <class/cl00f2.h>
+
+#include <platform/chipset/pci_pbi.h>
+
+#include "platform/nbsi/nbsi_read.h"
+#include "gpu_mgr/gpu_db.h"
+#include <class/cl0080.h>
+#include <class/cl0073.h>
+#include <class/cl2080.h>
+#include <class/cl402c.h>
+#include <ctrl/ctrl2080/ctrl2080gsp.h>
+
+#include <gpu/dce_client/dce_client.h>
+// RMCONFIG: need definition of REGISTER_ALL_HALS()
+#include "g_hal_register.h"
+
+typedef enum
+{
+ RM_INIT_OK,
+
+ /* general os errors */
+ RM_INIT_REG_SETUP_FAILED = 0x10,
+ RM_INIT_SYS_ENVIRONMENT_FAILED,
+
+ /* gpu errors */
+ RM_INIT_GPU_GPUMGR_ALLOC_GPU_FAILED = 0x20,
+ RM_INIT_GPU_GPUMGR_CREATE_DEV_FAILED,
+ RM_INIT_GPU_GPUMGR_ATTACH_GPU_FAILED,
+ RM_INIT_GPU_PRE_INIT_FAILED,
+ RM_INIT_GPU_STATE_INIT_FAILED,
+ RM_INIT_GPU_LOAD_FAILED,
+ RM_INIT_GPU_DMA_CONFIGURATION_FAILED,
+ RM_INIT_GPU_GPUMGR_EXPANDED_VISIBILITY_FAILED,
+
+ /* vbios errors */
+ RM_INIT_VBIOS_FAILED = 0x30,
+ RM_INIT_VBIOS_POST_FAILED,
+ RM_INIT_VBIOS_X86EMU_FAILED,
+
+ /* scalability errors */
+ RM_INIT_SCALABILITY_FAILED = 0x40,
+
+ /* general core rm errors */
+ RM_INIT_WATCHDOG_FAILED,
+ RM_FIFO_GET_UD_BAR1_MAP_INFO_FAILED,
+ RM_GPUDB_REGISTER_FAILED,
+
+ RM_INIT_ALLOC_RMAPI_FAILED,
+ RM_INIT_GPUINFO_WITH_RMAPI_FAILED,
+
+ /* rm firmware errors */
+ RM_INIT_FIRMWARE_POLICY_FAILED = 0x60,
+ RM_INIT_FIRMWARE_FETCH_FAILED,
+ RM_INIT_FIRMWARE_INIT_FAILED,
+
+ RM_INIT_MAX_FAILURES
+} rm_init_status;
+
+typedef rm_init_status RM_INIT_STATUS;
+
+typedef struct {
+ RM_INIT_STATUS initStatus;
+ NV_STATUS rmStatus;
+ NvU32 line;
+} UNIX_STATUS;
+
+#define INIT_UNIX_STATUS { RM_INIT_OK, NV_OK, 0 }
+#define RM_INIT_SUCCESS(init) ((init) == RM_INIT_OK)
+
+#define RM_SET_ERROR(status, err) { (status).initStatus = (err); \
+ (status).line = __LINE__; }
+
+
+static inline NvU64 nv_encode_pci_info(nv_pci_info_t *pci_info)
+{
+ return gpuEncodeDomainBusDevice(pci_info->domain, pci_info->bus, pci_info->slot);
+}
+
+static inline NvU32 nv_generate_id_from_pci_info(nv_pci_info_t *pci_info)
+{
+ return gpuGenerate32BitId(pci_info->domain, pci_info->bus, pci_info->slot);
+}
+
+static void nv_set_probed_gpu_flags(nv_state_t *nv)
+{
+ NvU32 flags = 0;
+
+ if (NV_IS_SOC_DISPLAY_DEVICE(nv))
+ {
+ flags |= DRF_DEF(0000, _CTRL_GPU_PROBED_ID_FLAGS, _SOC_DISPLAY, _TRUE);
+ }
+
+ gpumgrSetProbedFlags(nv->gpu_id, flags);
+}
+
+static inline void nv_os_map_kernel_space(nv_state_t *nv, nv_aperture_t *aperture)
+{
+ NV_ASSERT(aperture->map == NULL);
+
+ // let's start off assuming a standard device and map the registers
+ // normally. It is unfortunate to hard-code the register size here, but we don't
+ // want to fail trying to map all of a multi-devices' register space
+ aperture->map = osMapKernelSpace(aperture->cpu_address,
+ aperture->size,
+ NV_MEMORY_UNCACHED,
+ NV_PROTECT_READ_WRITE);
+ aperture->map_u = (nv_phwreg_t)aperture->map;
+}
+
+// local prototypes
+static NV_STATUS initCoreLogic(OBJGPU *);
+static void initVendorSpecificRegistry(OBJGPU *, NvU16);
+static NV_STATUS teardownCoreLogic(OBJOS *, OBJGPU *);
+static void initUnixSpecificRegistry(OBJGPU *);
+
+NV_STATUS osRmInitRm(void)
+{
+ OBJSYS *pSys = SYS_GET_INSTANCE();
+ NV_STATUS status;
+
+ if (os_is_efi_enabled())
+ {
+ pSys->setProperty(pSys, PDB_PROP_SYS_IS_UEFI, NV_TRUE);
+ }
+
+ // have to init this before the debug subsystem, which will
+ // try to check the value of ResmanDebugLevel
+ RmInitRegistry();
+
+ NvU32 data = 0;
+ if ((osReadRegistryDword(NULL,
+ NV_REG_ENABLE_PCIE_GEN3, &data) == NV_OK) &&
+ (data != 0))
+ {
+ data = DRF_DEF(_REG_STR, _RM_PCIE, _LINK_SPEED_ALLOW_GEN3, _ENABLE);
+
+ osWriteRegistryDword(NULL,
+ NV_REG_STR_RM_PCIE_LINK_SPEED, data);
+ }
+
+ if (!(osReadRegistryDword(NULL,
+ NV_REG_INITIALIZE_SYSTEM_MEMORY_ALLOCATIONS,
+ &data) == NV_OK) || data)
+ {
+ pSys->setProperty(pSys,
+ PDB_PROP_SYS_INITIALIZE_SYSTEM_MEMORY_ALLOCATIONS,
+ NV_TRUE);
+ }
+
+ if ((osReadRegistryDword(NULL,
+ NV_REG_ENABLE_STREAM_MEMOPS,
+ &data) == NV_OK) && (data != 0))
+ {
+ data = DRF_DEF(_REG_STR, _RM_STREAM_MEMOPS, _ENABLE, _YES);
+ osWriteRegistryDword(NULL, NV_REG_STR_RM_STREAM_MEMOPS, data);
+ }
+
+ if ((osReadRegistryDword(NULL,
+ NV_REG_STR_RM_FORCE_BAR_PATH,
+ &data) == NV_OK) && (data == 1))
+ {
+ //
+ // Exposing the GPU memory as NUMA node memory requires coherent CPU
+ // mappings over NVLink. If those mappings are disabled, also disable
+ // NUMA-onlining of the device memory.
+ //
+ osWriteRegistryDword(NULL,
+ NV_REG_ENABLE_USER_NUMA_MANAGEMENT, 0);
+ }
+
+ if ((osReadRegistryDword(NULL,
+ NV_REG_NVLINK_DISABLE, &data) == NV_OK) &&
+ (data == 1))
+ {
+ osWriteRegistryDword(NULL, NV_REG_STR_RM_NVLINK_CONTROL, 0x1);
+ }
+
+ if ((osReadRegistryDword(NULL,
+ NV_REG_ENABLE_PCIE_RELAXED_ORDERING_MODE, &data) == NV_OK) &&
+ (data == 1))
+ {
+ osWriteRegistryDword(NULL,
+ NV_REG_STR_RM_SET_PCIE_TLP_RELAXED_ORDERING,
+ NV_REG_STR_RM_SET_PCIE_TLP_RELAXED_ORDERING_ENABLE);
+ }
+
+ // init the debug subsystem if necessary
+ os_dbg_init();
+ nvDbgInitRmMsg(NULL);
+
+ // Force nvlog reinit since module params are now available
+ NVLOG_UPDATE();
+
+ // Register all supported hals
+ status = REGISTER_ALL_HALS();
+ if (status != NV_OK)
+ {
+ RmDestroyRegistry(NULL);
+ return status;
+ }
+
+ rm_check_s0ix_regkey_and_platform_support();
+
+ // Setup any ThreadState defaults
+ threadStateInitSetupFlags(THREAD_STATE_SETUP_FLAGS_ENABLED |
+ THREAD_STATE_SETUP_FLAGS_TIMEOUT_ENABLED |
+ THREAD_STATE_SETUP_FLAGS_SLI_LOGIC_ENABLED |
+ THREAD_STATE_SETUP_FLAGS_DO_NOT_INCLUDE_SLEEP_TIME_ENABLED);
+
+ return NV_OK;
+}
+
+void RmShutdownRm(void)
+{
+ NV_PRINTF(LEVEL_INFO, "shutdown rm\n");
+
+ RmDestroyRegistry(NULL);
+
+ // Free objects created with RmInitRm, including the system object
+ RmDestroyRm();
+}
+
+//
+// osAttachGpu
+//
+// This routine is used as a callback by the gpumgrAttachGpu
+// interface to allow os-dependent code to set up any state
+// before engine construction begins.
+//
+NV_STATUS osAttachGpu(
+ OBJGPU *pGpu,
+ void *pOsGpuInfo
+)
+{
+ nv_state_t *nv = (nv_state_t *)pOsGpuInfo;
+ nv_priv_t *nvp;
+
+ nvp = NV_GET_NV_PRIV(nv);
+
+ nvp->pGpu = pGpu;
+
+ NV_SET_NV_STATE(pGpu, (void *)nv);
+
+ initUnixSpecificRegistry(pGpu);
+
+ // Assign default values to Registry keys for VGX
+ if (os_is_vgx_hyper())
+ {
+ initVGXSpecificRegistry(pGpu);
+ }
+
+ return NV_OK;
+}
+
+NV_STATUS osDpcAttachGpu(
+ OBJGPU *pGpu,
+ void *pOsGpuInfo
+)
+{
+ return NV_OK; // Nothing to do for unix
+}
+
+void osDpcDetachGpu(
+ OBJGPU *pGpu
+)
+{
+ return; // Nothing to do for unix
+}
+
+NV_STATUS
+osHandleGpuLost
+(
+ OBJGPU *pGpu,
+ NvBool bEmitXid
+)
+{
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+ NvU32 pmc_boot_0;
+
+ // Determine if we've already run the handler
+ if (!pGpu->getProperty(pGpu, PDB_PROP_GPU_IS_CONNECTED))
+ {
+ return NV_OK;
+ }
+
+ pmc_boot_0 = NV_PRIV_REG_RD32(nv->regs->map_u, NV_PMC_BOOT_0);
+ if (pmc_boot_0 != nvp->pmc_boot_0)
+ {
+ //
+ // This doesn't support PEX Reset and Recovery yet.
+ // This will help to prevent accessing registers of a GPU
+ // which has fallen off the bus.
+ //
+ if (bEmitXid)
+ {
+ nvErrorLog_va((void *)pGpu, ROBUST_CHANNEL_GPU_HAS_FALLEN_OFF_THE_BUS,
+ "GPU has fallen off the bus.");
+ }
+
+ gpuNotifySubDeviceEvent(pGpu, NV2080_NOTIFIERS_GPU_UNAVAILABLE, NULL,
+ 0, ROBUST_CHANNEL_GPU_HAS_FALLEN_OFF_THE_BUS, 0);
+
+ NV_DEV_PRINTF(NV_DBG_ERRORS, nv, "GPU has fallen off the bus.\n");
+
+ if (pGpu->boardInfo != NULL && pGpu->boardInfo->serialNumber[0] != '\0')
+ {
+ NV_DEV_PRINTF(NV_DBG_ERRORS, nv,
+ "GPU serial number is %s.\n",
+ pGpu->boardInfo->serialNumber);
+ }
+
+ gpuSetDisconnectedProperties(pGpu);
+
+ if (IS_GSP_CLIENT(pGpu))
+ {
+ KernelRc *pKernelRc = GPU_GET_KERNEL_RC(pGpu);
+
+ // Notify all channels of the error so that UVM can fail gracefully
+ if (pKernelRc != NULL)
+ {
+ krcRcAndNotifyAllChannels(pGpu, pKernelRc, ROBUST_CHANNEL_GPU_HAS_FALLEN_OFF_THE_BUS, NV_FALSE);
+ }
+ }
+
+ // Initiate a crash dump immediately.
+ RmLogGpuCrash(pGpu);
+
+ // Set SURPRISE_REMOVAL flag for eGPU to help in device removal.
+ if (pGpu->getProperty(pGpu, PDB_PROP_GPU_IS_EXTERNAL_GPU))
+ {
+ nv->flags |= NV_FLAG_IN_SURPRISE_REMOVAL;
+ }
+
+ DBG_BREAKPOINT();
+ }
+
+ return NV_OK;
+}
+
+/*!
+ * @brief Traverse bus topology till Gpu's root port.
+ * If any of the intermediate bridge has TB3 supported vendorId and hotplug
+ * capability(not necessarily same bridge), mark the Gpu as External Gpu.
+ *
+ * @params[in] pGpu OBJGPU pointer
+ * @params[in] pCl OBJCL pointer
+ *
+* @return NV_OK
+* Identified to be eGPU
+* @return others
+ * Not an eGPU / error on identfying
+ *
+ */
+NvBool
+RmCheckForExternalGpu
+(
+ OBJGPU *pGpu,
+ OBJCL *pCl
+)
+{
+ NvU8 bus;
+ NvU32 domain;
+ void *handleUp;
+ NvU8 busUp, devUp, funcUp;
+ NvU16 vendorIdUp, deviceIdUp;
+ NvU32 portCaps, pciCaps, slotCaps;
+ NvU32 PCIECapPtr;
+ RM_API *pRmApi;
+ NV_STATUS status, rmStatus;
+ NvBool bTb3Bridge = NV_FALSE, bSlotHotPlugSupport = NV_FALSE;
+ NvBool iseGPUBridge = NV_FALSE;
+
+ pRmApi = GPU_GET_PHYSICAL_RMAPI(pGpu);
+ domain = gpuGetDomain(pGpu);
+ bus = gpuGetBus(pGpu);
+ do
+ {
+ // Find the upstream bridge
+ handleUp = clFindP2PBrdg(pCl, domain, bus, &busUp, &devUp, &funcUp, &vendorIdUp, &deviceIdUp);
+ if (!handleUp)
+ {
+ return iseGPUBridge;
+ }
+
+ if (vendorIdUp == PCI_VENDOR_ID_INTEL)
+ {
+ // Check for the supported TB3(ThunderBolt 3) bridges.
+ NV2080_CTRL_INTERNAL_GET_EGPU_BRIDGE_INFO_PARAMS params = { 0 };
+
+ // LOCK: acquire GPUs lock
+ rmStatus = rmGpuLocksAcquire(GPUS_LOCK_FLAGS_NONE,
+ RM_LOCK_MODULES_INIT);
+ if (rmStatus != NV_OK)
+ {
+ return iseGPUBridge;
+ }
+ params.pciDeviceId = deviceIdUp;
+ status = pRmApi->Control(pRmApi,
+ pGpu->hInternalClient,
+ pGpu->hInternalSubdevice,
+ NV2080_CTRL_CMD_INTERNAL_GET_EGPU_BRIDGE_INFO,
+ &params,
+ sizeof(params));
+ // UNLOCK: release GPUs lock
+ rmGpuLocksRelease(GPUS_LOCK_FLAGS_NONE, NULL);
+
+ if (status != NV_OK)
+ {
+ NV_PRINTF(LEVEL_ERROR,
+ "Error 0x%08x on eGPU Approval for Bridge ID: 0x%08x\n", status, deviceIdUp);
+ DBG_BREAKPOINT();
+ return iseGPUBridge;
+ }
+ else
+ {
+ // Check for the approved eGPU BUS TB3
+ if (params.iseGPUBridge &&
+ params.approvedBusType == NV2080_CTRL_INTERNAL_EGPU_BUS_TYPE_TB3)
+ {
+ bTb3Bridge = NV_TRUE;
+ }
+ }
+ }
+
+ if (NV_OK != clSetPortPcieCapOffset(pCl, handleUp, &PCIECapPtr))
+ {
+ // PCIE bridge but no cap pointer.
+ break;
+ }
+
+ // Get the PCIE capabilities.
+ pciCaps = osPciReadDword(handleUp, CL_PCIE_CAP - CL_PCIE_BEGIN + PCIECapPtr);
+ if (CL_PCIE_CAP_SLOT & pciCaps)
+ {
+ // Get the slot capabilities.
+ slotCaps = osPciReadDword(handleUp, CL_PCIE_SLOT_CAP - CL_PCIE_BEGIN + PCIECapPtr);
+
+ if ((CL_PCIE_SLOT_CAP_HOTPLUG_CAPABLE & slotCaps) &&
+ (CL_PCIE_SLOT_CAP_HOTPLUG_SURPRISE & slotCaps))
+ {
+ bSlotHotPlugSupport = NV_TRUE;
+ }
+ }
+
+ if (bTb3Bridge && bSlotHotPlugSupport)
+ {
+ iseGPUBridge = NV_TRUE;
+ break;
+ }
+
+ bus = busUp;
+
+ // Get port caps to check if PCIE bridge is the root port
+ portCaps = osPciReadDword(handleUp, CL_PCIE_CAP - CL_PCIE_BEGIN + PCIECapPtr);
+
+ } while (!CL_IS_ROOT_PORT(portCaps));
+ return iseGPUBridge;
+}
+
+static NV_STATUS
+RmGetFirmwareVersion
+(
+ nv_state_t *pNv,
+ RM_API *pRmApi
+)
+{
+ NV2080_CTRL_GSP_GET_FEATURES_PARAMS gsp_params;
+ NV_STATUS rmStatus = NV_OK;
+ pNv->cached_gpu_info.firmware_version[0] = '\0';
+
+ rmStatus = pRmApi->Control(pRmApi, pNv->rmapi.hClient, pNv->rmapi.hSubDevice,
+ NV2080_CTRL_CMD_GSP_GET_FEATURES, &gsp_params,
+ sizeof(gsp_params));
+
+ if (rmStatus != NV_OK)
+ {
+ if (RMCFG_FEATURE_GSP_CLIENT_RM && pNv->request_firmware)
+ {
+ const char *pTmpString = "N/A";
+ portStringCopy(pNv->cached_gpu_info.firmware_version,
+ sizeof(pNv->cached_gpu_info.firmware_version),
+ pTmpString, portStringLength(pTmpString) + 1);
+ }
+ NV_PRINTF(LEVEL_INFO,
+ "%s: Failed to query gpu firmware version, status=0x%x\n",
+ __FUNCTION__, rmStatus);
+ }
+ else
+ {
+ portMemCopy(pNv->cached_gpu_info.firmware_version,
+ sizeof(pNv->cached_gpu_info.firmware_version),
+ gsp_params.firmwareVersion, sizeof(gsp_params.firmwareVersion));
+ }
+
+ return NV_OK;
+}
+
+static NV_STATUS
+RmGetVbiosVersion
+(
+ nv_state_t *pNv,
+ RM_API *pRmApi
+)
+{
+ NV2080_CTRL_BIOS_GET_INFO_V2_PARAMS *vbios_params;
+ const size_t vbiosStringLen = 15; // "xx.xx.xx.xx.xx"
+ NV_STATUS rmStatus = NV_OK;
+
+ vbios_params = portMemAllocNonPaged(sizeof(*vbios_params));
+ if (vbios_params == NULL)
+ {
+ return NV_ERR_NO_MEMORY;;
+ }
+
+ portMemSet(vbios_params, 0, sizeof(*vbios_params));
+
+ vbios_params->biosInfoList[0].index = NV2080_CTRL_BIOS_INFO_INDEX_REVISION;
+ vbios_params->biosInfoList[1].index = NV2080_CTRL_BIOS_INFO_INDEX_OEM_REVISION;
+ vbios_params->biosInfoListSize = 2;
+
+ rmStatus = pRmApi->Control(pRmApi, pNv->rmapi.hClient,
+ pNv->rmapi.hSubDevice, NV2080_CTRL_CMD_BIOS_GET_INFO_V2,
+ vbios_params, sizeof(*vbios_params));
+
+ if (rmStatus == NV_OK)
+ {
+ const NvU32 biosRevision = vbios_params->biosInfoList[0].data;
+ const NvU32 biosOEMRevision = vbios_params->biosInfoList[1].data;
+
+ os_snprintf(pNv->cached_gpu_info.vbios_version, vbiosStringLen,
+ "%02x.%02x.%02x.%02x.%02x",
+ (biosRevision & 0xff000000) >> 24,
+ (biosRevision & 0x00ff0000) >> 16,
+ (biosRevision & 0x0000ff00) >> 8,
+ (biosRevision & 0x000000ff) >> 0,
+ biosOEMRevision);
+ }
+ else
+ {
+ NV_PRINTF(LEVEL_INFO,
+ "%s: Failed to query vbios version, status=0x%x\n",
+ __FUNCTION__, rmStatus);
+ }
+ portMemFree(vbios_params);
+
+ return NV_OK;
+}
+
+/*
+ * Initialize the required GPU information by doing RMAPI control calls
+ * and store the same in the UNIX specific data structures.
+ */
+static NV_STATUS
+RmInitGpuInfoWithRmApi
+(
+ OBJGPU *pGpu
+)
+{
+ RM_API *pRmApi = rmapiGetInterface(RMAPI_GPU_LOCK_INTERNAL);
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+ NV2080_CTRL_GPU_GET_INFO_V2_PARAMS *pGpuInfoParams = { 0 };
+ NV_STATUS status;
+ const NvU8 *uuid;
+
+ // LOCK: acquire GPUs lock
+ status = rmGpuLocksAcquire(GPUS_LOCK_FLAGS_NONE, RM_LOCK_MODULES_INIT);
+ if (status != NV_OK)
+ {
+ return status;
+ }
+
+ pGpuInfoParams = portMemAllocNonPaged(sizeof(*pGpuInfoParams));
+ if (pGpuInfoParams == NULL)
+ {
+ // UNLOCK: release GPUs lock
+ rmGpuLocksRelease(GPUS_LOCK_FLAGS_NONE, NULL);
+
+ return NV_ERR_NO_MEMORY;
+ }
+
+
+ portMemSet(pGpuInfoParams, 0, sizeof(*pGpuInfoParams));
+
+ pGpuInfoParams->gpuInfoListSize = 3;
+ pGpuInfoParams->gpuInfoList[0].index = NV2080_CTRL_GPU_INFO_INDEX_MOBILE_CONFIG_ENABLED;
+ pGpuInfoParams->gpuInfoList[1].index = NV2080_CTRL_GPU_INFO_INDEX_DMABUF_CAPABILITY;
+ pGpuInfoParams->gpuInfoList[2].index = NV2080_CTRL_GPU_INFO_INDEX_COHERENT_GPU_MEMORY_MODE;
+
+ status = pRmApi->Control(pRmApi, nv->rmapi.hClient,
+ nv->rmapi.hSubDevice,
+ NV2080_CTRL_CMD_GPU_GET_INFO_V2,
+ pGpuInfoParams, sizeof(*pGpuInfoParams));
+
+ if (status == NV_OK)
+ {
+ nvp->b_mobile_config_enabled =
+ (pGpuInfoParams->gpuInfoList[0].data ==
+ NV2080_CTRL_GPU_INFO_INDEX_MOBILE_CONFIG_ENABLED_YES);
+ nv->dma_buf_supported =
+ (pGpuInfoParams->gpuInfoList[1].data ==
+ NV2080_CTRL_GPU_INFO_INDEX_DMABUF_CAPABILITY_YES);
+ }
+
+ nv->coherent =
+ (pGpu->getProperty(pGpu, PDB_PROP_GPU_COHERENT_CPU_MAPPING) ||
+ pGpu->pGpuArch->bGpuArchIsZeroFb);
+
+ //
+ // If coherent GPU memory mode is NONE, then GPU memory has struct page
+ // on coherent platforms and no struct page on non-coherent ones.
+ // If the mode is enabled and _NUMA, then GPU memory has struct page.
+ // If the mode is enabled and _DRIVER, then GPU memory doesn't have struct page.
+ // Tegra iGPU also falls under struct page category, although
+ // COHERENT_GPU_MEMORY_MODE doesn't apply there.
+ //
+ if (pGpuInfoParams->gpuInfoList[2].data ==
+ NV2080_CTRL_GPU_INFO_INDEX_COHERENT_GPU_MEMORY_MODE_NONE)
+ {
+ nv->mem_has_struct_page = nv->coherent;
+ }
+ else
+ {
+ // If mode is not _NONE, we're already on a PDB_PROP_GPU_COHERENT_CPU_MAPPING platform.
+ nv->mem_has_struct_page = pGpu->pGpuArch->bGpuArchIsZeroFb ||
+ (pGpuInfoParams->gpuInfoList[2].data ==
+ NV2080_CTRL_GPU_INFO_INDEX_COHERENT_GPU_MEMORY_MODE_NUMA);
+ }
+
+ switch (pGpuInfoParams->gpuInfoList[2].data)
+ {
+ case NV2080_CTRL_GPU_INFO_INDEX_COHERENT_GPU_MEMORY_MODE_NONE:
+ nv->coherent_gpu_mem_mode = NV_COHERENT_GPU_MEM_MODE_NONE;
+ break;
+ case NV2080_CTRL_GPU_INFO_INDEX_COHERENT_GPU_MEMORY_MODE_NUMA:
+ nv->coherent_gpu_mem_mode = NV_COHERENT_GPU_MEM_MODE_NUMA;
+ break;
+ case NV2080_CTRL_GPU_INFO_INDEX_COHERENT_GPU_MEMORY_MODE_DRIVER:
+ nv->coherent_gpu_mem_mode = NV_COHERENT_GPU_MEM_MODE_DRIVER;
+ break;
+ }
+
+ portMemFree(pGpuInfoParams);
+
+ if (status != NV_OK)
+ {
+ goto finish;
+ }
+
+ uuid = RmGetGpuUuidRaw(nv);
+ if (uuid == NULL)
+ {
+ status = NV_ERR_GPU_UUID_NOT_FOUND;
+ goto finish;
+ }
+
+ status = RmGetFirmwareVersion(nv, pRmApi);
+ if (status != NV_OK)
+ {
+ goto finish;
+ }
+
+ status = RmGetVbiosVersion(nv, pRmApi);
+
+finish:
+ // UNLOCK: release GPUs lock
+ rmGpuLocksRelease(GPUS_LOCK_FLAGS_NONE, NULL);
+
+ return status;
+}
+
+static void RmSetSocDispDeviceMappings(
+ GPUATTACHARG *gpuAttachArg,
+ nv_state_t *nv
+)
+{
+ gpuAttachArg->socDeviceArgs.deviceMapping[SOC_DEV_MAPPING_DISP].gpuNvAddr = (GPUHWREG*) nv->regs->map;
+ gpuAttachArg->socDeviceArgs.deviceMapping[SOC_DEV_MAPPING_DISP].gpuNvPAddr = nv->regs->cpu_address;
+ gpuAttachArg->socDeviceArgs.deviceMapping[SOC_DEV_MAPPING_DISP].gpuNvLength = (NvU32) nv->regs->size;
+}
+
+static void RmSetSocDpauxDeviceMappings(
+ GPUATTACHARG *gpuAttachArg,
+ nv_state_t *nv
+)
+{
+}
+
+static void RmSetSocHdacodecDeviceMappings(
+ GPUATTACHARG *gpuAttachArg,
+ nv_state_t *nv
+)
+{
+}
+
+static void RmSetSocMipiCalDeviceMappings(
+ GPUATTACHARG *gpuAttachArg,
+ nv_state_t *nv
+)
+{
+}
+
+static void
+osInitNvMapping(
+ nv_state_t *nv,
+ NvU32 *pDeviceReference,
+ UNIX_STATUS *status
+)
+{
+ OBJGPU *pGpu;
+ OBJSYS *pSys = SYS_GET_INSTANCE();
+ GPUATTACHARG *gpuAttachArg;
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+ NvU32 deviceInstance;
+ NvU32 data = 0;
+ NvU32 dispIsoStreamId;
+ NvU32 dispNisoStreamId;
+
+ NV_PRINTF(LEVEL_INFO, "osInitNvMapping:\n");
+
+ // allocate the next available gpu device number
+ status->rmStatus = gpumgrAllocGpuInstance(pDeviceReference);
+ if (status->rmStatus != NV_OK)
+ {
+ NV_PRINTF(LEVEL_ERROR, "*** Cannot get valid gpu instance\n");
+ RM_SET_ERROR(*status, RM_INIT_GPU_GPUMGR_ALLOC_GPU_FAILED);
+ return;
+ }
+
+ // RM_BASIC_LOCK_MODEL: allocate GPU lock
+ status->rmStatus = rmGpuLockAlloc(*pDeviceReference);
+ if (status->rmStatus != NV_OK)
+ {
+ NV_PRINTF(LEVEL_ERROR, "*** cannot allocate GPU lock\n");
+ RM_SET_ERROR(*status, RM_INIT_GPU_GPUMGR_ALLOC_GPU_FAILED);
+ return;
+ }
+
+ // attach default single-entry broadcast device for this gpu
+ status->rmStatus = gpumgrCreateDevice(&deviceInstance, NVBIT(*pDeviceReference), NULL);
+ if (status->rmStatus != NV_OK)
+ {
+ NV_PRINTF(LEVEL_ERROR, "*** Cannot attach bc gpu\n");
+ RM_SET_ERROR(*status, RM_INIT_GPU_GPUMGR_CREATE_DEV_FAILED);
+ // RM_BASIC_LOCK_MODEL: free GPU lock
+ rmGpuLockFree(*pDeviceReference);
+ return;
+ }
+
+ // init attach state
+ gpuAttachArg = portMemAllocNonPaged(sizeof(GPUATTACHARG));
+ if (gpuAttachArg == NULL)
+ {
+ NV_PRINTF(LEVEL_ERROR, "*** Cannot allocate gpuAttachArg\n");
+ RM_SET_ERROR(*status, RM_INIT_GPU_GPUMGR_ALLOC_GPU_FAILED);
+ // RM_BASIC_LOCK_MODEL: free GPU lock
+ rmGpuLockFree(*pDeviceReference);
+ return;
+ }
+
+ portMemSet(gpuAttachArg, 0, sizeof(GPUATTACHARG));
+
+ if (NV_IS_SOC_DISPLAY_DEVICE(nv))
+ {
+ gpuAttachArg->socDeviceArgs.specified = NV_TRUE;
+
+ RmSetSocDispDeviceMappings(gpuAttachArg, nv);
+
+ RmSetSocDpauxDeviceMappings(gpuAttachArg, nv);
+
+ RmSetSocHdacodecDeviceMappings(gpuAttachArg, nv);
+
+ RmSetSocMipiCalDeviceMappings(gpuAttachArg, nv);
+
+ gpuAttachArg->socDeviceArgs.socChipId0 = nv->disp_sw_soc_chip_id;
+
+ gpuAttachArg->socDeviceArgs.iovaspaceId = nv->iovaspace_id;
+ }
+ else
+ {
+ gpuAttachArg->fbPhysAddr = nv->fb->cpu_address;
+ gpuAttachArg->fbBaseAddr = (GPUHWREG*) 0; // not mapped
+ gpuAttachArg->devPhysAddr = nv->regs->cpu_address;
+ gpuAttachArg->regBaseAddr = (GPUHWREG*) nv->regs->map;
+ gpuAttachArg->intLine = 0; // don't know yet
+ gpuAttachArg->instPhysAddr = nv->bars[NV_GPU_BAR_INDEX_IMEM].cpu_address;
+ gpuAttachArg->instBaseAddr = (GPUHWREG*) 0; // not mapped
+
+ gpuAttachArg->regLength = nv->regs->size;
+ gpuAttachArg->fbLength = nv->fb->size;
+ gpuAttachArg->instLength = nv->bars[NV_GPU_BAR_INDEX_IMEM].size;
+
+ gpuAttachArg->iovaspaceId = nv->iovaspace_id;
+ gpuAttachArg->cpuNumaNodeId = nv->cpu_numa_node_id;
+
+ if (nv->iovaspace_id != NV_IOVA_DOMAIN_NONE)
+ {
+ // Default - PCIe GPUs are connected via NISO IOMMU
+ nv->iommus.iso_iommu_present = NV_FALSE;
+ nv->iommus.niso_iommu_present = NV_TRUE;
+ }
+ }
+
+ //
+ // we need this to check if we are running on virtual GPU
+ // in gpuBindHal function later.
+ //
+ if (!NV_IS_SOC_DISPLAY_DEVICE(nv))
+ {
+ gpuAttachArg->nvDomainBusDeviceFunc = nv_encode_pci_info(&nv->pci_info);
+ }
+
+ gpuAttachArg->bRequestFwClientRm = nv->request_fw_client_rm;
+
+ gpuAttachArg->pOsAttachArg = (void *)nv;
+
+ // use gpu manager to attach gpu
+ status->rmStatus = gpumgrAttachGpu(*pDeviceReference, gpuAttachArg);
+ portMemFree(gpuAttachArg);
+ if (status->rmStatus != NV_OK)
+ {
+ gpumgrDestroyDevice(deviceInstance);
+ RM_SET_ERROR(*status, RM_INIT_GPU_GPUMGR_ATTACH_GPU_FAILED);
+ NV_PRINTF(LEVEL_ERROR, "*** Cannot attach gpu\n");
+ // RM_BASIC_LOCK_MODEL: free GPU lock
+ rmGpuLockFree(*pDeviceReference);
+ return;
+ }
+ nvp->flags |= NV_INIT_FLAG_GPUMGR_ATTACH;
+
+ pGpu = gpumgrGetGpu(*pDeviceReference);
+
+ sysInitRegistryOverrides(pSys);
+
+ sysApplyLockingPolicy(pSys);
+
+ pGpu->busInfo.IntLine = nv->interrupt_line;
+
+ if (nv->fb != NULL)
+ {
+ pGpu->registerAccess.gpuFbAddr = (GPUHWREG*) nv->fb->map;
+ pGpu->busInfo.gpuPhysFbAddr = nv->fb->cpu_address;
+ }
+
+ // set default parent gpu
+ gpumgrSetParentGPU(pGpu, pGpu);
+
+ NV_PRINTF(LEVEL_INFO, "device instance : %d\n", *pDeviceReference);
+ NV_PRINTF(LEVEL_INFO, "NV regs using linear address : 0x%p\n",
+ pGpu->deviceMappings[SOC_DEV_MAPPING_DISP].gpuNvAddr);
+ NV_PRINTF(LEVEL_INFO,
+ "NV fb using linear address : 0x%p\n", pGpu->registerAccess.gpuFbAddr);
+
+ if (!os_is_vgx_hyper())
+ {
+ pGpu->setProperty(pGpu, PDB_PROP_GPU_ALLOW_PAGE_RETIREMENT, NV_TRUE);
+ }
+ else
+ {
+ {
+ pGpu->setProperty(pGpu, PDB_PROP_GPU_ALLOW_PAGE_RETIREMENT, NV_TRUE);
+ }
+ }
+
+ if ((osReadRegistryDword(NULL,
+ NV_REG_PRESERVE_VIDEO_MEMORY_ALLOCATIONS,
+ &data) == NV_OK) && data)
+ {
+ if (data == NV_REG_PRESERVE_VIDEO_MEMORY_ALLOCATIONS_ENABLED)
+ {
+ nv->preserve_vidmem_allocations = NV_TRUE;
+ }
+ else if (data == NV_REG_PRESERVE_VIDEO_MEMORY_ALLOCATIONS_AUTO)
+ {
+ /* If the kernel supports suspend notifiers, enable video memory allocations */
+ nv->preserve_vidmem_allocations = os_supports_kernel_suspend_notifiers();
+ }
+
+ if (nv->preserve_vidmem_allocations && nv_dev_needs_vidmem_preservation(nv))
+ {
+ KernelMemorySystem *pKernelMemorySystem = GPU_GET_KERNEL_MEMORY_SYSTEM(pGpu);
+ MemoryManager *pMemoryManager = GPU_GET_MEMORY_MANAGER(pGpu);
+
+ memmgrSetPmaForcePersistence(pMemoryManager, NV_TRUE);
+
+ // Monolithic uses Fifolite channel which doesn't support Virtual mode
+ if (!pMemoryManager->bUseVirtualCopyOnSuspend)
+ {
+ pKernelMemorySystem->bPreserveComptagBackingStoreOnSuspend = NV_TRUE;
+ }
+ }
+ }
+
+ // Check if SMMU can be enabled on PushBuffer Aperture
+ nv_get_disp_smmu_stream_ids(nv, &dispIsoStreamId, &dispNisoStreamId);
+ if (dispNisoStreamId != NV_U32_MAX)
+ {
+ pGpu->setProperty(pGpu, PDB_PROP_GPU_DISP_PB_REQUIRES_SMMU_BYPASS, NV_FALSE);
+ }
+ else
+ {
+ pGpu->setProperty(pGpu, PDB_PROP_GPU_DISP_PB_REQUIRES_SMMU_BYPASS, NV_TRUE);
+ }
+
+ if (pGpu->getProperty(pGpu, PDB_PROP_GPU_TRIGGER_PCIE_FLR))
+ {
+ nv->flags |= NV_FLAG_TRIGGER_FLR;
+ }
+
+ if (pGpu->getProperty(pGpu, PDB_PROP_GPU_IS_SOC_SDM))
+ {
+ nv->flags |= NV_FLAG_HAS_CONSOLE_IN_SYSMEM_CARVEOUT;
+ }
+}
+
+static NV_STATUS
+osInitScalability(
+ OBJGPU *pGpu
+)
+{
+ OBJSYS *pSys = SYS_GET_INSTANCE();
+ OBJCL *pCl = SYS_GET_CL(pSys);
+
+ // We need PCI-E chipset information very early.
+ if (pCl != NULL)
+ {
+ return clInitPcie(pGpu, pCl);
+ }
+ else
+ {
+ return NV_ERR_NOT_SUPPORTED;
+ }
+}
+
+static NV_STATUS
+osTeardownScalability(
+ OBJGPU *pGpu
+)
+{
+ OBJSYS *pSys = SYS_GET_INSTANCE();
+ OBJCL *pCl = SYS_GET_CL(pSys);
+
+ return clTeardownPcie(pGpu, pCl);
+}
+
+static NV_STATUS
+RmInitNvHal(
+ nv_state_t *nv,
+ NvU32 deviceReference,
+ UNIX_STATUS *status
+)
+{
+ OBJGPU *pGpu = gpumgrGetGpu(deviceReference);
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+
+ PORT_UNREFERENCED_VARIABLE(pGpu);
+
+ nvp->flags |= NV_INIT_FLAG_HAL;
+
+ nvp->flags |= NV_INIT_FLAG_HAL_COMPONENTS;
+
+ return NV_OK;
+}
+
+static void
+RmDeterminePrimaryDevice(OBJGPU *pGpu)
+{
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+
+ // Skip updating nv->primary_vga while RM is recovering after GPU reset
+ if (nv->flags & NV_FLAG_IN_RECOVERY)
+ {
+ return;
+ }
+
+ //
+ // In case of Passthru, GPU will always be secondary
+ //
+ if (IS_PASSTHRU(pGpu))
+ {
+ return;
+ }
+
+ //
+ // In case of VIRTUAL GPU, there is no display, hence it will be secondary
+ //
+ if (IS_VIRTUAL(pGpu))
+ {
+ return;
+ }
+
+ //
+ // If GPU is driving any frame buffer console(vesafb, efifb etc)
+ // mark the console as client driven and GPU as Primary.
+ //
+ nv->client_managed_console = rm_get_uefi_console_status(nv);
+
+ pGpu->setProperty(pGpu, PDB_PROP_GPU_PRIMARY_DEVICE,
+ (nv->client_managed_console || !!nv->primary_vga));
+}
+
+static void
+RmSetConsolePreservationParams(OBJGPU *pGpu)
+{
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ NvU64 fbBaseAddress = 0;
+ NvU64 fbConsoleSize = 0;
+ MemoryManager *pMemoryManager = GPU_GET_MEMORY_MANAGER(pGpu);
+ KernelBus *pKernelBus = GPU_GET_KERNEL_BUS(pGpu);
+ //
+ // PDB_PROP_GPU_PRIMARY_DEVICE should be NV_FALSE for vGPU configuration so
+ // return early
+ //
+ if (os_is_vgx_hyper() || IS_VIRTUAL(pGpu))
+ return;
+
+ if (!gpuFuseSupportsDisplay_HAL(pGpu))
+ {
+ return;
+ }
+
+ //
+ // If this is the zero FB SOC GPU with a console in system carveout, then
+ // the console memory is not mapped onto the BAR. The kernel can directly
+ // access the console memory, while the GPU accesses system carveout memory
+ // through the SMMU.
+ // The carveout is a reserved region of system memory that doesn't get used
+ // in standard memory allocation.
+ //
+ // In this scenario, you don't need to reserve console memory or BAR mapping.
+ //
+ if (NV_HAS_CONSOLE_IN_SYSMEM_CARVEOUT(nv))
+ {
+ return;
+ }
+
+ //
+ // Check the OS layer for any video memory used by a console
+ // driver that should be reserved.
+ //
+ // If the console driver is using some amount of memory, its
+ // mapping is presumably either pointing at the start of BAR1
+ // (this is the mapping the EFI GOP driver provides for
+ // efifb), or the upper 16MB of BAR2 (this is the mapping the
+ // VBIOS provides for, e.g., vesafb).
+ //
+ // In the BAR2 case, there is nothing more to do: the upper
+ // 16MB of BAR2 will remain in physical mode
+ // (see the documentation for NV_PBUS_BAR2_BLOCK in dev_bus.ref),
+ // and the console driver can continue to access it.
+ //
+ // In the BAR1 case, RM will put all of BAR1 into virtual
+ // mode, so we need to create a BAR1 mapping for the console
+ // driver to use.
+ //
+ fbConsoleSize = rm_get_uefi_console_size(nv, &fbBaseAddress);
+
+ if ((fbConsoleSize > 0) && (fbBaseAddress != 0) && (pKernelBus != NULL))
+ {
+ pKernelBus->bPreserveBar1ConsoleEnabled =
+ (fbBaseAddress == nv->fb->cpu_address);
+ }
+
+ //
+ // Case for legacy console, where OS will not give console size
+ // and primary_vga will be set for the device.
+ // Hence, reserving default size for VGA text modes.
+ //
+ if ((fbConsoleSize == 0) && nv->primary_vga)
+ {
+ fbConsoleSize = 0x40000;
+ }
+
+ if (pGpu->getProperty(pGpu, PDB_PROP_GPU_TEGRA_SOC_NVDISPLAY))
+ {
+ pMemoryManager->Ram.ReservedConsoleDispMemSize = fbConsoleSize;
+ pMemoryManager->Ram.ReservedConsoleDispMemBase = fbBaseAddress;
+ }
+ else
+ {
+ pMemoryManager->Ram.ReservedConsoleDispMemSize = NV_ALIGN_UP(fbConsoleSize, 0x10000);
+ }
+}
+
+static NV_STATUS
+RmInitDeviceDma(
+ nv_state_t *nv
+)
+{
+ if (nv->iovaspace_id != NV_IOVA_DOMAIN_NONE)
+ {
+ OBJSYS *pSys = SYS_GET_INSTANCE();
+ OBJVMM *pVmm = SYS_GET_VMM(pSys);
+ OBJVASPACE *pIOVAS;
+ NV_STATUS status = vmmCreateVaspace(pVmm, IO_VASPACE_A,
+ nv->iovaspace_id, 0, 0ULL, ~0ULL,
+ 0ULL, 0ULL,
+ NULL, VASPACE_FLAGS_ENABLE_VMM,
+ &pIOVAS);
+ if (status != NV_OK)
+ {
+ return status;
+ }
+ }
+
+ return NV_OK;
+}
+
+static void
+RmTeardownDeviceDma(
+ nv_state_t *nv
+)
+{
+ if (nv->iovaspace_id != NV_IOVA_DOMAIN_NONE)
+ {
+ OBJSYS *pSys = SYS_GET_INSTANCE();
+ OBJVMM *pVmm = SYS_GET_VMM(pSys);
+ OBJVASPACE *pIOVAS;
+
+ if (NV_OK == vmmGetVaspaceFromId(pVmm, nv->iovaspace_id, IO_VASPACE_A, &pIOVAS))
+ {
+ vmmDestroyVaspace(pVmm, pIOVAS);
+ }
+ }
+}
+
+static void
+RmEnableDeviceClks(nv_state_t *nv)
+{
+ NvU32 freqKHz = 0;
+ NvU32 i;
+ NV_STATUS ret;
+
+ for (i = TEGRASOC_WHICH_CLK_GPU_FIRST; i <= TEGRASOC_WHICH_CLK_GPU_LAST; i++)
+ {
+ ret = nv_get_max_freq(nv, i, &freqKHz);
+ if (ret != NV_OK)
+ {
+ NV_PRINTF(LEVEL_INFO, "NVRM: Max Freq fetch failed for Clk:%d\n", i);
+ continue;
+ }
+
+ ret = nv_enable_clk(nv, i);
+ if (ret != NV_OK)
+ {
+ NV_PRINTF(LEVEL_INFO, "NVRM: Clk prepare enable failed for Clk:%d\n", i);
+ continue;
+ }
+
+ ret = nv_set_freq(nv, i, freqKHz);
+ if (ret != NV_OK)
+ {
+ NV_PRINTF(LEVEL_INFO, "NVRM: Set Freq failed for Clk:%d\n", i);
+ }
+ else
+ {
+ NV_PRINTF(LEVEL_INFO, "NVRM: Set Freq:%d for Clk:%d\n", freqKHz, i);
+ }
+ }
+}
+
+static void
+RmDisableDeviceClks(nv_state_t *nv)
+{
+ NvU32 i;
+
+ for (i = TEGRASOC_WHICH_CLK_GPU_FIRST; i <= TEGRASOC_WHICH_CLK_GPU_LAST; i++)
+ {
+ nv_disable_clk(nv, i);
+ }
+}
+
+static void
+RmInitNvDevice(
+ NvU32 deviceReference,
+ UNIX_STATUS *status
+)
+{
+ // set the device context
+ OBJGPU *pGpu = gpumgrGetGpu(deviceReference);
+ OBJSYS *pSys = SYS_GET_INSTANCE();
+ OBJCL *pCl = SYS_GET_CL(pSys);
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+
+ NV_PRINTF(LEVEL_INFO, "RmInitNvDevice:\n");
+
+ NV_PRINTF(LEVEL_INFO,
+ "device instance : 0x%08x\n", deviceReference);
+
+ // initialize all engines -- calls back osInitMapping()
+ status->rmStatus = gpumgrStatePreInitGpu(pGpu);
+ if (status->rmStatus != NV_OK)
+ {
+ NV_PRINTF(LEVEL_ERROR, "*** Cannot pre-initialize the device\n");
+ RM_SET_ERROR(*status, RM_INIT_GPU_PRE_INIT_FAILED);
+ return;
+ }
+
+ // Configure eGPU setting
+ if (RmCheckForExternalGpu(pGpu, pCl))
+ {
+ pGpu->setProperty(pGpu, PDB_PROP_GPU_IS_EXTERNAL_GPU, NV_TRUE);
+ nv->is_external_gpu = NV_TRUE;
+ }
+ status->rmStatus = gpumgrStateInitGpu(pGpu);
+ if (status->rmStatus != NV_OK)
+ {
+ NV_PRINTF(LEVEL_ERROR, "*** Cannot initialize the device\n");
+ RM_SET_ERROR(*status, RM_INIT_GPU_STATE_INIT_FAILED);
+ return;
+ }
+ nvp->flags |= NV_INIT_FLAG_GPU_STATE;
+
+ KernelBif *pKernelBif = GPU_GET_KERNEL_BIF(pGpu);
+ //
+ // Make sure bifIsMSIEnabled() gets a chance to look up the OS PCI
+ // handle for this GPU. This must happen after GPU state
+ // initialization.
+ //
+ if (pKernelBif != NULL)
+ {
+ kbifCheckAndRearmMSI(pGpu, pKernelBif);
+ }
+
+ // Set RM's interrupt enable state to zero here so that interrupts
+ // won't be enabled during loading
+ Intr *pIntr = GPU_GET_INTR(pGpu);
+ if (pIntr != NULL)
+ {
+ intrSetIntrEn(pIntr, INTERRUPT_TYPE_DISABLED);
+ }
+
+ status->rmStatus = gpumgrStateLoadGpu(pGpu, GPU_STATE_DEFAULT);
+ if (status->rmStatus != NV_OK)
+ {
+ NV_PRINTF(LEVEL_ERROR,
+ "*** Cannot load state into the device\n");
+ RM_SET_ERROR(*status, RM_INIT_GPU_LOAD_FAILED);
+ return;
+ }
+ nvp->flags |= NV_INIT_FLAG_GPU_STATE_LOAD;
+
+ // Setup GPU scalability
+ (void) RmInitScalability(pGpu);
+
+ return;
+}
+
+NV_STATUS osInitMapping(
+ OBJGPU *pGpu
+)
+{
+ OBJSYS *pSys = SYS_GET_INSTANCE();
+ OBJCL *pCl = SYS_GET_CL(pSys);
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+
+ NV_PRINTF(LEVEL_INFO, "osInitMapping:\n");
+
+ // Some PCI BIOSs leave the ROM mapped. This causes problems if it overlays system RAM. Just disable it.
+ GPU_BUS_CFG_WR32(pGpu, NV_CONFIG_PCI_NV_12, 0);
+
+ // make sure our PCI latency timer is sufficient (max it out)
+ GPU_BUS_CFG_WR32(pGpu, NV_CONFIG_PCI_NV_3,
+ DRF_DEF(_CONFIG, _PCI_NV_3, _LATENCY_TIMER, _248_CLOCKS));
+
+ if (pCl != NULL)
+ {
+ initCoreLogic(pGpu);
+ }
+ nvp->flags |= NV_INIT_FLAG_CORE_LOGIC;
+
+ return NV_OK;
+
+} // end of osInitMapping()
+
+static NV_STATUS
+initCoreLogic(
+ OBJGPU *pGpu
+)
+{
+ OBJSYS *pSys = SYS_GET_INSTANCE();
+ OBJCL *pCl = SYS_GET_CL(pSys);
+
+ return clInit(pGpu, pCl);
+}
+
+static NV_STATUS
+teardownCoreLogic(
+ OBJOS *pOS,
+ OBJGPU *pGpu
+)
+{
+ OBJSYS *pSys = SYS_GET_INSTANCE();
+ OBJCL *pCl = SYS_GET_CL(pSys);
+
+ return clTeardown(pGpu, pCl);
+}
+
+static void RmTeardownDpauxRegisters(
+ nv_state_t *nv
+)
+{
+}
+
+static void RmTeardownHdacodecRegisters(
+ nv_state_t *nv
+)
+{
+}
+
+static void RmTeardownMipiCalRegisters(
+ nv_state_t *nv
+)
+{
+}
+
+static NV_STATUS
+RmTeardownRegisters(
+ nv_state_t *nv
+)
+{
+ NV_DEV_PRINTF(NV_DBG_SETUP, nv, "Tearing down registers\n");
+
+ if (nv->regs && nv->regs->map)
+ {
+ osUnmapKernelSpace(nv->regs->map, nv->regs->size);
+ nv->regs->map = 0;
+ nv->regs->map_u = NULL;
+ }
+
+ RmTeardownDpauxRegisters(nv);
+
+ RmTeardownHdacodecRegisters(nv);
+
+ RmTeardownMipiCalRegisters(nv);
+
+ return NV_OK;
+}
+
+static NV_STATUS
+RmSetupDpauxRegisters(
+ nv_state_t *nv,
+ UNIX_STATUS *status
+)
+{
+
+ return NV_OK;
+}
+
+static NV_STATUS
+RmSetupHdacodecRegisters(
+ nv_state_t *nv,
+ UNIX_STATUS *status
+)
+{
+
+ return NV_OK;
+}
+
+static NV_STATUS
+RmSetupMipiCalRegisters(
+ nv_state_t *nv,
+ UNIX_STATUS *status
+)
+{
+
+ return NV_OK;
+}
+
+static void
+RmSetupRegisters(
+ nv_state_t *nv,
+ UNIX_STATUS *status
+)
+{
+ NV_STATUS ret;
+
+ NV_DEV_PRINTF(NV_DBG_SETUP, nv, "RmSetupRegisters for 0x%x:0x%x\n",
+ nv->pci_info.vendor_id, nv->pci_info.device_id);
+ NV_DEV_PRINTF(NV_DBG_SETUP, nv, "pci config info:\n");
+ NV_DEV_PRINTF(NV_DBG_SETUP, nv, " registers look like: 0x%" NvU64_fmtx " 0x%" NvU64_fmtx,
+ nv->regs->cpu_address, nv->regs->size);
+
+ if (nv->fb != NULL)
+ {
+ NV_DEV_PRINTF(NV_DBG_SETUP, nv, " fb looks like: 0x%" NvU64_fmtx " 0x%" NvU64_fmtx "\n",
+ nv->fb->cpu_address, nv->fb->size);
+ }
+
+ nv_os_map_kernel_space(nv, nv->regs);
+
+ if (nv->regs->map == NULL)
+ {
+ NV_DEV_PRINTF(NV_DBG_ERRORS, nv, "Failed to map regs registers!!\n");
+ RM_SET_ERROR(*status, RM_INIT_REG_SETUP_FAILED);
+ status->rmStatus = NV_ERR_OPERATING_SYSTEM;
+ return;
+ }
+ NV_DEV_PRINTF(NV_DBG_SETUP, nv, "Successfully mapped framebuffer and registers\n");
+ NV_DEV_PRINTF(NV_DBG_SETUP, nv, "final mappings:\n");
+ NV_DEV_PRINTF(NV_DBG_SETUP, nv, " regs: 0x%" NvU64_fmtx " 0x%" NvU64_fmtx " 0x%p\n",
+ nv->regs->cpu_address, nv->regs->size, nv->regs->map);
+
+ ret = RmSetupDpauxRegisters(nv, status);
+ if (ret != NV_OK)
+ goto err_unmap_disp_regs;
+
+ ret = RmSetupHdacodecRegisters(nv, status);
+ if (ret != NV_OK)
+ {
+ RmTeardownDpauxRegisters(nv);
+ goto err_unmap_disp_regs;
+ }
+
+ ret = RmSetupMipiCalRegisters(nv, status);
+ if (ret != NV_OK)
+ {
+ RmTeardownHdacodecRegisters(nv);
+ RmTeardownDpauxRegisters(nv);
+ goto err_unmap_disp_regs;
+ }
+
+ return;
+
+err_unmap_disp_regs:
+ if (nv->regs && nv->regs->map)
+ {
+ osUnmapKernelSpace(nv->regs->map, nv->regs->size);
+ nv->regs->map = 0;
+ }
+
+ return;
+}
+
+NvBool RmInitPrivateState(
+ nv_state_t *pNv
+)
+{
+ nv_priv_t *nvp;
+ NvU32 gpuId;
+ NvU32 socChipId0 = 0;
+ NvU32 pmc_boot_0 = 0;
+ NvU32 pmc_boot_1 = 0;
+ NvU32 pmc_boot_42 = 0;
+ NvU32 dmaAddrWidth = 0;
+ NvU64 gpuDomainBusDevice = 0;
+
+ NV_SET_NV_PRIV(pNv, NULL);
+
+ if (NV_IS_SOC_DISPLAY_DEVICE(pNv))
+ socChipId0 = pNv->disp_sw_soc_chip_id;
+ else
+ {
+ pNv->regs->map_u = os_map_kernel_space(pNv->regs->cpu_address,
+ os_page_size,
+ NV_MEMORY_UNCACHED);
+ if (pNv->regs->map_u == NULL)
+ {
+ NV_PRINTF(LEVEL_ERROR,
+ "failed to map GPU registers (DISABLE_INTERRUPTS).\n");
+ return NV_FALSE;
+ }
+
+ pmc_boot_0 = NV_PRIV_REG_RD32(pNv->regs->map_u, NV_PMC_BOOT_0);
+ pmc_boot_1 = NV_PRIV_REG_RD32(pNv->regs->map_u, NV_PMC_BOOT_1);
+ pmc_boot_42 = NV_PRIV_REG_RD32(pNv->regs->map_u, NV_PMC_BOOT_42);
+
+ os_unmap_kernel_space(pNv->regs->map_u, os_page_size);
+ pNv->regs->map_u = NULL;
+ }
+
+ if (os_alloc_mem((void **)&nvp, sizeof(*nvp)) != NV_OK)
+ {
+ NV_PRINTF(LEVEL_ERROR,
+ "failed to allocate private device state.\n");
+ return NV_FALSE;
+ }
+
+ if (!NV_IS_SOC_DISPLAY_DEVICE(pNv))
+ {
+ gpuId = nv_generate_id_from_pci_info(&pNv->pci_info);
+ gpuDomainBusDevice = nv_encode_pci_info(&pNv->pci_info);
+ }
+ else
+ {
+ gpuId = NV0000_CTRL_GPU_INVALID_ID - 1;
+ gpuDomainBusDevice = 0;
+ }
+
+ if (gpumgrRegisterGpuId(gpuId, gpuDomainBusDevice) != NV_OK)
+ {
+ NV_PRINTF(LEVEL_ERROR,
+ "failed to register GPU with GPU manager.\n");
+ os_free_mem(nvp);
+ return NV_FALSE;
+ }
+
+ pNv->gpu_id = gpuId;
+
+ nv_set_probed_gpu_flags(pNv);
+
+ pNv->iovaspace_id = nv_requires_dma_remap(pNv) ? gpuId :
+ NV_IOVA_DOMAIN_NONE;
+ pNv->cpu_numa_node_id = NV0000_CTRL_NO_NUMA_NODE;
+
+ // Get the GpuArch instance for this architecture to determine the DMA address width.
+ GpuArch *pGpuArch = gpumgrGetGpuArch(pmc_boot_42, socChipId0, TEGRA_CHIP_TYPE_DEFAULT);
+ if (pGpuArch == NULL)
+ {
+ NV_PRINTF(LEVEL_ERROR, "failed to get GpuArch for 0x%x/0x%x.\n",
+ pmc_boot_42, socChipId0);
+ gpumgrUnregisterGpuId(gpuId);
+ os_free_mem(nvp);
+ return NV_FALSE;
+ }
+
+ dmaAddrWidth = gpuarchGetDmaAddrWidth(pGpuArch);
+ if (dmaAddrWidth == 0)
+ {
+ dmaAddrWidth = gpuarchGetSystemPhysAddrWidth(pGpuArch);
+ }
+ nv_set_dma_address_size(pNv, dmaAddrWidth);
+
+ pNv->is_tegra_pci_igpu = !NV_IS_SOC_DISPLAY_DEVICE(pNv) && pGpuArch->bGpuArchIsZeroFb;
+ // Only certain Tegra PCI iGPUs support Rail-Gating
+ pNv->supports_tegra_igpu_rg = pNv->is_tegra_pci_igpu && pGpuArch->bGpuarchSupportsIgpuRg;
+
+ pNv->sysmem_mapped_console = pGpuArch->bGpuArchIsZeroFb;
+
+ kvgpumgrAttachGpu(pNv->gpu_id);
+
+ os_mem_set(nvp, 0, sizeof(*nvp));
+ nvp->status = NV_ERR_INVALID_STATE;
+ nvp->pmc_boot_0 = pmc_boot_0;
+ nvp->pmc_boot_1 = pmc_boot_1;
+ nvp->pmc_boot_42 = pmc_boot_42;
+ nvp->db_supported = -1;
+ NV_SET_NV_PRIV(pNv, nvp);
+
+ return NV_TRUE;
+}
+
+void RmClearPrivateState(
+ nv_state_t *pNv
+)
+{
+ nv_priv_t *nvp = NV_GET_NV_PRIV(pNv);
+ NvU32 status;
+ void *pVbiosCopy = NULL;
+ void *pRegistryCopy = NULL;
+ NvU32 vbiosSize;
+ nv_i2c_adapter_entry_t i2c_adapters[MAX_I2C_ADAPTERS];
+ nv_dynamic_power_t dynamicPowerCopy;
+ NvU32 x = 0;
+ NvU32 pmc_boot_0, pmc_boot_1, pmc_boot_42;
+ NvBool pr3_acpi_method_present = 0;
+ int db_supported;
+
+ //
+ // Do not clear private state after GPU resets, it is used while
+ // recovering the GPU. Only clear the pGpu pointer, which is
+ // restored during next initialization cycle.
+ //
+ if (pNv->flags & NV_FLAG_IN_RECOVERY)
+ {
+ nvp->pGpu = NULL;
+ }
+
+ status = nvp->status;
+ pVbiosCopy = nvp->pVbiosCopy;
+ vbiosSize = nvp->vbiosSize;
+ pRegistryCopy = nvp->pRegistry;
+ dynamicPowerCopy = nvp->dynamic_power;
+ pmc_boot_0 = nvp->pmc_boot_0;
+ pmc_boot_1 = nvp->pmc_boot_1;
+ pmc_boot_42 = nvp->pmc_boot_42;
+ pr3_acpi_method_present = nvp->pr3_acpi_method_present;
+ db_supported = nvp->db_supported;
+
+ for (x = 0; x < MAX_I2C_ADAPTERS; x++)
+ {
+ i2c_adapters[x] = nvp->i2c_adapters[x];
+ }
+
+ portMemSet(nvp, 0, sizeof(nv_priv_t));
+
+ nvp->status = status;
+ nvp->pVbiosCopy = pVbiosCopy;
+ nvp->vbiosSize = vbiosSize;
+ nvp->pRegistry = pRegistryCopy;
+ nvp->dynamic_power = dynamicPowerCopy;
+ nvp->pmc_boot_0 = pmc_boot_0;
+ nvp->pmc_boot_1 = pmc_boot_1;
+ nvp->pmc_boot_42 = pmc_boot_42;
+ nvp->pr3_acpi_method_present = pr3_acpi_method_present;
+ nvp->db_supported = db_supported;
+
+ for (x = 0; x < MAX_I2C_ADAPTERS; x++)
+ {
+ nvp->i2c_adapters[x] = i2c_adapters[x];
+ }
+
+ nvp->flags |= NV_INIT_FLAG_PUBLIC_I2C;
+}
+
+void RmFreePrivateState(
+ nv_state_t *pNv
+)
+{
+ nv_priv_t *nvp = NV_GET_NV_PRIV(pNv);
+
+ gpumgrUnregisterGpuId(pNv->gpu_id);
+
+ kvgpumgrDetachGpu(pNv->gpu_id);
+
+ RmDestroyRegistry(pNv);
+
+ if (nvp != NULL)
+ {
+ portMemFree(nvp->pVbiosCopy);
+ os_free_mem(nvp);
+ }
+
+ NV_SET_NV_PRIV(pNv, NULL);
+}
+
+NvBool RmPartiallyInitAdapter(
+ nv_state_t *nv
+)
+{
+ NV_PRINTF(LEVEL_INFO, "%s: %04x:%02x:%02x.0\n", __FUNCTION__,
+ nv->pci_info.domain, nv->pci_info.bus, nv->pci_info.slot);
+
+ nv_start_rc_timer(nv);
+
+ return NV_TRUE;
+}
+
+static NV_STATUS
+RmInitX86Emu(
+ OBJGPU *pGpu
+)
+{
+ NV_STATUS status = NV_OK;
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ PORT_UNREFERENCED_VARIABLE(nv);
+
+#if NVCPU_IS_X86_64
+ status = RmInitX86EmuState(pGpu);
+#else
+ // We don't expect a "primary VGA" adapter on non-amd64 platforms
+ NV_ASSERT(!NV_PRIMARY_VGA(nv));
+#endif
+
+ return status;
+}
+
+static NV_STATUS RmRegisterGpudb(
+ OBJGPU *pGpu
+)
+{
+ NV_STATUS rmStatus;
+ const NvU8 *pGid;
+ nv_state_t *pNv = NV_GET_NV_STATE(pGpu);
+
+ pGid = RmGetGpuUuidRaw(pNv);
+ if (pGid == NULL)
+ {
+ NV_PRINTF(LEVEL_ERROR, "Failed to get UUID\n");
+ return NV_ERR_OPERATING_SYSTEM;
+ }
+
+ rmStatus = gpudbRegisterGpu(pGid, &pGpu->gpuClData.upstreamPort.addr,
+ pGpu->busInfo.nvDomainBusDeviceFunc);
+ if (rmStatus != NV_OK)
+ {
+ NV_PRINTF(LEVEL_ERROR, "Failed to register GPU with GPU data base\n");
+ }
+
+ return rmStatus;
+}
+
+static void RmUnixFreeRmApi(
+ nv_state_t *nv
+)
+{
+ if (rmGpuLocksAcquire(GPUS_LOCK_FLAGS_NONE, RM_LOCK_MODULES_DESTROY) == NV_OK)
+ {
+ RM_API *pRmApi = rmapiGetInterface(RMAPI_GPU_LOCK_INTERNAL);
+
+ if (nv->rmapi.hClient != 0)
+ {
+ pRmApi->Free(pRmApi, nv->rmapi.hClient, nv->rmapi.hClient);
+ }
+
+ portMemSet(&nv->rmapi, 0, sizeof(nv->rmapi));
+
+ rmGpuLocksRelease(GPUS_LOCK_FLAGS_NONE, NULL);
+ }
+}
+
+static NvBool RmUnixAllocRmApi(
+ nv_state_t *nv,
+ NvU32 deviceId
+)
+{
+ NV_STATUS status = NV_OK;
+ NV0080_ALLOC_PARAMETERS deviceParams = { 0 };
+ NV2080_ALLOC_PARAMETERS subDeviceParams = { 0 };
+ RM_API *pRmApi = rmapiGetInterface(RMAPI_GPU_LOCK_INTERNAL);
+
+ portMemSet(&nv->rmapi, 0, sizeof(nv->rmapi));
+
+ // LOCK: acquire GPUs lock
+ status = rmGpuLocksAcquire(GPUS_LOCK_FLAGS_NONE, RM_LOCK_MODULES_INIT);
+ if (status != NV_OK)
+ {
+ return status;
+ }
+
+ if (pRmApi->AllocWithHandle(
+ pRmApi,
+ NV01_NULL_OBJECT,
+ NV01_NULL_OBJECT,
+ NV01_NULL_OBJECT,
+ NV01_ROOT,
+ &nv->rmapi.hClient,
+ sizeof(nv->rmapi.hClient)) != NV_OK)
+ {
+ goto fail;
+ }
+
+ deviceParams.deviceId = deviceId;
+
+ if (pRmApi->Alloc(
+ pRmApi,
+ nv->rmapi.hClient,
+ nv->rmapi.hClient,
+ &nv->rmapi.hDevice,
+ NV01_DEVICE_0,
+ &deviceParams,
+ sizeof(deviceParams)) != NV_OK)
+ {
+ goto fail;
+ }
+
+ subDeviceParams.subDeviceId = 0;
+
+ if (pRmApi->Alloc(
+ pRmApi,
+ nv->rmapi.hClient,
+ nv->rmapi.hDevice,
+ &nv->rmapi.hSubDevice,
+ NV20_SUBDEVICE_0,
+ &subDeviceParams,
+ sizeof(subDeviceParams)) != NV_OK)
+ {
+ goto fail;
+ }
+
+ //
+ // The NV40_I2C allocation expected to fail, if it is disabled
+ // with RM config.
+ //
+ if (pRmApi->Alloc(
+ pRmApi,
+ nv->rmapi.hClient,
+ nv->rmapi.hSubDevice,
+ &nv->rmapi.hI2C,
+ NV40_I2C,
+ NULL,
+ 0) != NV_OK)
+ {
+ nv->rmapi.hI2C = 0;
+ }
+
+ //
+ // The NV04_DISPLAY_COMMON allocation expected to fail for displayless
+ // system. nv->rmapi.hDisp value needs to be checked before doing display
+ // related control calls.
+ //
+ if (pRmApi->Alloc(
+ pRmApi,
+ nv->rmapi.hClient,
+ nv->rmapi.hDevice,
+ &nv->rmapi.hDisp,
+ NV04_DISPLAY_COMMON,
+ NULL,
+ 0) != NV_OK)
+ {
+ nv->rmapi.hDisp = 0;
+ }
+
+ // UNLOCK: release GPUs lock
+ rmGpuLocksRelease(GPUS_LOCK_FLAGS_NONE, NULL);
+
+ return NV_TRUE;
+
+fail:
+ // UNLOCK: release GPUs lock
+ rmGpuLocksRelease(GPUS_LOCK_FLAGS_NONE, NULL);
+
+ RmUnixFreeRmApi(nv);
+ return NV_FALSE;
+}
+
+static NV_STATUS RmFetchGspRmImages
+(
+ nv_state_t *nv,
+ GSP_FIRMWARE *pGspFw,
+ const void **gspFwHandle,
+ const void **gspFwLogHandle,
+ const void **gspUcodesHandle
+)
+{
+ nv_firmware_chip_family_t chipFamily;
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+ NvU32 gpuArch = (decodePmcBoot42Architecture(nvp->pmc_boot_42) <<
+ GPU_ARCH_SHIFT);
+ NvU32 gpuImpl = DRF_VAL(_PMC, _BOOT_42, _IMPLEMENTATION, nvp->pmc_boot_42);
+
+ chipFamily = nv_firmware_get_chip_family(gpuArch, gpuImpl);
+
+ portMemSet(pGspFw, 0, sizeof(*pGspFw));
+
+ *gspFwHandle = nv_get_firmware(nv, NV_FIRMWARE_TYPE_GSP,
+ chipFamily,
+ &pGspFw->pBuf,
+ &pGspFw->size);
+
+ NvBool bFirmwareLoadSuccessful = *gspFwHandle != NULL;
+
+ //
+ // GR-3428 development: Temporarily gated by regkey so this code can be
+ // decoupled from the build infra changes to package up ucodes.bin.
+ //
+ // Because loading the bindata ends up calling request_firmware() on Linux,
+ // and that function will always print an error to dmesg if the requested
+ // file is not found, we use this to skip trying to load it.
+ //
+ // Check will be removed once ucodes.bin becomes part of the driver package.
+ //
+ NvU32 data = 0;
+ if ((osReadRegistryDword(NULL, "GR3428ReadUcodesBin", &data) == NV_OK) && data)
+ {
+ *gspUcodesHandle = nv_get_firmware(nv, NV_FIRMWARE_TYPE_UCODES,
+ chipFamily,
+ &pGspFw->pUcodesBin,
+ &pGspFw->ucodesBinSize);
+ bFirmwareLoadSuccessful &= *gspUcodesHandle != NULL;
+ }
+
+ if (!bFirmwareLoadSuccessful && !nv->allow_fallback_to_monolithic_rm)
+ {
+ NV_PRINTF(LEVEL_ERROR, "No firmware image found\n");
+ return NV_ERR_NOT_SUPPORTED;
+ }
+ else if (bFirmwareLoadSuccessful)
+ {
+#if LIBOS_LOG_DECODE_ENABLE
+ if (nv->enable_firmware_logs)
+ {
+ *gspFwLogHandle = nv_get_firmware(nv, NV_FIRMWARE_TYPE_GSP_LOG,
+ chipFamily,
+ &pGspFw->pLogElf,
+ &pGspFw->logElfSize);
+ if (*gspFwLogHandle == NULL)
+ {
+ NV_PRINTF(LEVEL_ERROR, "Failed to load gsp_log_*.bin, no GSP-RM logs will be printed (non-fatal)\n");
+ }
+ }
+#endif
+ nv->request_fw_client_rm = NV_TRUE;
+ }
+ else
+ {
+ nv->request_fw_client_rm = NV_FALSE;
+ }
+
+ return NV_OK;
+}
+
+static void _checkP2pChipsetSupport(
+ nv_state_t *nv
+)
+{
+ OBJSYS *pSys = SYS_GET_INSTANCE();
+ OBJCL *pCl = SYS_GET_CL(pSys);
+
+ // Check for PCIe P2P chipset support
+ if (!pCl->bPciePeerWriteCapable ||
+ !pCl->bPciePeerReadCapable)
+ {
+ nv->flags |= NV_FLAG_PCI_P2P_UNSUPPORTED_CHIPSET;
+ }
+}
+
+NvBool RmInitAdapter(
+ nv_state_t *nv
+)
+{
+ NvU32 devicereference = 0;
+ UNIX_STATUS status = INIT_UNIX_STATUS;
+ nv_priv_t *nvp;
+ NvBool retVal = NV_FALSE;
+ OBJSYS *pSys;
+ OBJGPU *pGpu = NULL;
+ OBJOS *pOS;
+ KernelDisplay *pKernelDisplay;
+ const void *gspFwHandle = NULL;
+ const void *gspFwLogHandle = NULL;
+ const void *gspUcodesHandle = NULL;
+
+ GSP_FIRMWARE gspFw = {0};
+ PORT_UNREFERENCED_VARIABLE(gspFw);
+
+ NV_DEV_PRINTF(NV_DBG_SETUP, nv, "RmInitAdapter\n");
+
+ nv->flags &= ~NV_FLAG_PASSTHRU;
+ nv->flags &= ~NV_FLAG_PCI_P2P_UNSUPPORTED_CHIPSET;
+
+ RmSetupRegisters(nv, &status);
+ if (! RM_INIT_SUCCESS(status.initStatus) )
+ goto failed;
+
+ nvp = NV_GET_NV_PRIV(nv);
+ nvp->status = NV_ERR_OPERATING_SYSTEM;
+
+ status.rmStatus = RmInitDeviceDma(nv);
+ if (status.rmStatus != NV_OK)
+ {
+ NV_PRINTF(LEVEL_ERROR, "Cannot configure the device for DMA\n");
+ RM_SET_ERROR(status, RM_INIT_GPU_DMA_CONFIGURATION_FAILED);
+ goto shutdown;
+ }
+
+ nvp->flags |= NV_INIT_FLAG_DMA;
+
+ pSys = SYS_GET_INSTANCE();
+
+ //
+ // Get firmware from the OS, if requested, and decide if RM will run as a
+ // firmware client.
+ //
+ if (nv->request_firmware)
+ {
+ if (!NV_IS_SOC_DISPLAY_DEVICE(nv))
+ {
+ status.rmStatus = RmFetchGspRmImages(nv, &gspFw, &gspFwHandle, &gspFwLogHandle, &gspUcodesHandle);
+ if (status.rmStatus != NV_OK)
+ {
+ RM_SET_ERROR(status, RM_INIT_FIRMWARE_FETCH_FAILED);
+ goto shutdown;
+ }
+ }
+ else
+ {
+ nv->request_fw_client_rm = NV_TRUE;
+ }
+ }
+
+ //
+ // Initialization path requires expanded GPU visibility in GPUMGR
+ // in order to access the GPU undergoing initialization.
+ //
+ status.rmStatus = gpumgrThreadEnableExpandedGpuVisibility();
+ if (status.rmStatus != NV_OK)
+ {
+ RM_SET_ERROR(status, RM_INIT_GPU_GPUMGR_EXPANDED_VISIBILITY_FAILED);
+ goto shutdown;
+ }
+
+
+ // initialize the RM device register mapping
+ osInitNvMapping(nv, &devicereference, &status);
+ if (! RM_INIT_SUCCESS(status.initStatus) )
+ {
+ switch (status.rmStatus)
+ {
+ case NV_ERR_NOT_SUPPORTED:
+ nvp->status = NV_ERR_NOT_SUPPORTED;
+ break;
+ }
+ NV_PRINTF(LEVEL_ERROR,
+ "osInitNvMapping failed, bailing out of RmInitAdapter\n");
+ goto shutdown;
+ }
+
+ //
+ // now we can have a pdev for the first time...
+ //
+ pGpu = gpumgrGetGpu(devicereference);
+
+ gpumgrSetCurrentGpuInstance(pGpu->gpuInstance);
+
+ pOS = SYS_GET_OS(pSys);
+
+ status.rmStatus = osInitScalability(pGpu);
+ if (status.rmStatus == NV_OK)
+ {
+ nvp->flags |= NV_INIT_FLAG_SCALABILITY;
+ }
+ else if (status.rmStatus != NV_ERR_NOT_SUPPORTED)
+ {
+ RM_SET_ERROR(status, RM_INIT_SCALABILITY_FAILED);
+ goto shutdown;
+ }
+
+ // Boot GSP-RM proxy through COT command either via FSP or SEC2
+ if (!IS_GSP_CLIENT(pGpu) && !IS_VIRTUAL(pGpu))
+ {
+ status.rmStatus = gpuBootGspRmProxy(pGpu);
+ if (status.rmStatus != NV_OK)
+ {
+ NV_PRINTF(LEVEL_ERROR, "GSP-RM proxy boot command failed.\n");
+ RM_SET_ERROR(status, RM_INIT_FIRMWARE_INIT_FAILED);
+ goto shutdown;
+ }
+ }
+
+ RmDeterminePrimaryDevice(pGpu);
+
+ RmSetConsolePreservationParams(pGpu);
+
+ RmInitAcpiMethods(pOS, pSys, pGpu);
+
+ // This needs to run before GSP-RM is booted, or else it will timeout
+ if (pGpu->getProperty(pGpu, PDB_PROP_GPU_CLKS_IN_TEGRA_SOC))
+ {
+ NV_PRINTF(LEVEL_INFO, "Enable Clocks to Max\n");
+ RmEnableDeviceClks(nv);
+ }
+
+ //
+ // If GSP fw RM support is enabled then start the GSP microcode
+ // (including the task running the full instance of the RM) and
+ // exchange the necessary initial RPC messages before continuing
+ // with GPU initialization here.
+ //
+ if (IS_GSP_CLIENT(pGpu))
+ {
+ status.rmStatus = kgspInitRm(pGpu, GPU_GET_KERNEL_GSP(pGpu), &gspFw);
+ if (status.rmStatus != NV_OK)
+ {
+ NV_PRINTF(LEVEL_ERROR, "Cannot initialize GSP firmware RM\n");
+ RM_SET_ERROR(status, RM_INIT_FIRMWARE_INIT_FAILED);
+ goto shutdown;
+ }
+ }
+ else if (IS_DCE_CLIENT(pGpu))
+ {
+ status.rmStatus = dceclientDceRmInit(pGpu, GPU_GET_DCECLIENTRM(pGpu), NV_TRUE);
+ if (status.rmStatus != NV_OK)
+ {
+ NV_PRINTF(LEVEL_ERROR, "Cannot initialize DCE firmware RM\n");
+ RM_SET_ERROR(status, RM_INIT_FIRMWARE_INIT_FAILED);
+ goto shutdown;
+ }
+ }
+ else if (nv->request_fw_client_rm)
+ {
+ // We were expecting to enable GSP-RM but something went wrong.
+ if (!nv->allow_fallback_to_monolithic_rm)
+ {
+ RM_SET_ERROR(status, RM_INIT_FIRMWARE_POLICY_FAILED);
+ goto shutdown;
+ }
+ else
+ {
+ NV_PRINTF(LEVEL_NOTICE, "Falling back to monolithic RM\n");
+ }
+ }
+
+ pKernelDisplay = GPU_GET_KERNEL_DISPLAY(pGpu);
+ if (pKernelDisplay != NULL)
+ {
+ kdispSetWarPurgeSatellitesOnCoreFree(pKernelDisplay, NV_TRUE);
+ }
+
+ if (IS_PASSTHRU(pGpu))
+ nv->flags |= NV_FLAG_PASSTHRU;
+
+ RmInitNvHal(nv, devicereference, &status);
+ if (!RM_INIT_SUCCESS(status.initStatus))
+ {
+ NV_PRINTF(LEVEL_ERROR,
+ "RmInitNvHal() failed, bailing out of RmInitAdapter!\n");
+ goto shutdown;
+ }
+
+ status.rmStatus = RmInitX86Emu(pGpu);
+ if (status.rmStatus != NV_OK)
+ {
+ RM_SET_ERROR(status, RM_INIT_VBIOS_X86EMU_FAILED);
+ NV_PRINTF(LEVEL_ERROR,
+ "RmInitX86Emu failed, bailing out of RmInitAdapter\n");
+ goto shutdown;
+ }
+
+
+ initVendorSpecificRegistry(pGpu, nv->pci_info.device_id);
+
+ if (!IS_VIRTUAL(pGpu) && !NV_IS_SOC_DISPLAY_DEVICE(nv))
+ {
+ initNbsiTable(pGpu);
+ }
+
+ // finally, initialize the device
+ RmInitNvDevice(devicereference, &status);
+ if (! RM_INIT_SUCCESS(status.initStatus) )
+ {
+ NV_PRINTF(LEVEL_ERROR,
+ "RmInitNvDevice failed, bailing out of RmInitAdapter\n");
+ switch (status.rmStatus)
+ {
+ case NV_ERR_INSUFFICIENT_POWER:
+ nvp->status = NV_ERR_INSUFFICIENT_POWER;
+ NV_DEV_PRINTF(NV_DBG_ERRORS, nv,
+ "GPU does not have the necessary power cables connected.\n");
+ break;
+ }
+ goto shutdown;
+ }
+
+ //
+ // Expanded GPU visibility in GPUMGR is no longer needed once the
+ // GPU is initialized.
+ //
+ gpumgrThreadDisableExpandedGpuVisibility();
+
+ // LOCK: acquire GPUs lock
+ status.rmStatus = rmGpuLocksAcquire(GPUS_LOCK_FLAGS_NONE,
+ RM_LOCK_MODULES_INIT);
+ if (status.rmStatus != NV_OK)
+ {
+ goto shutdown;
+ }
+
+ status.rmStatus = osVerifySystemEnvironment(pGpu);
+
+ // UNLOCK: release GPUs lock
+ rmGpuLocksRelease(GPUS_LOCK_FLAGS_NONE, NULL);
+
+ if (status.rmStatus != NV_OK)
+ {
+ RM_SET_ERROR(status, RM_INIT_SYS_ENVIRONMENT_FAILED);
+ switch (status.rmStatus)
+ {
+ case NV_ERR_IRQ_NOT_FIRING:
+ nvp->status = NV_ERR_IRQ_NOT_FIRING;
+ break;
+ }
+ NV_PRINTF(LEVEL_ERROR, "osVerifySystemEnvironment failed, bailing!\n");
+ goto shutdown;
+ }
+
+ Intr *pIntr = GPU_GET_INTR(pGpu);
+ if (pIntr != NULL)
+ {
+ intrSetIntrEn(pIntr, INTERRUPT_TYPE_HARDWARE);
+ }
+
+ // LOCK: acquire GPUs lock
+ status.rmStatus = rmGpuLocksAcquire(GPUS_LOCK_FLAGS_NONE,
+ RM_LOCK_MODULES_INIT);
+ if (status.rmStatus != NV_OK)
+ {
+ goto shutdown;
+ }
+
+ KernelRc *pKernelRc = GPU_GET_KERNEL_RC(pGpu);
+ // initialize the watchdog (disabled by default)
+ status.rmStatus = pKernelRc != NULL ? krcWatchdogInit_HAL(pGpu, pKernelRc, NULL) :
+ NV_ERR_NOT_SUPPORTED;
+ if (status.rmStatus == NV_OK)
+ {
+ krcWatchdogDisable(pKernelRc, NULL);
+ nvp->flags |= NV_INIT_FLAG_FIFO_WATCHDOG;
+ }
+ else if (status.rmStatus == NV_ERR_NOT_SUPPORTED)
+ {
+ NV_PRINTF(LEVEL_INFO,
+ "krcWatchdogInit returned _NOT_SUPPORTED. For Kepler GPUs in PGOB mode, this is normal\n");
+ }
+ else
+ {
+ RM_SET_ERROR(status, RM_INIT_WATCHDOG_FAILED);
+ NV_PRINTF(LEVEL_ERROR,
+ "krcWatchdogInit failed, bailing out of RmInitAdapter\n");
+ // UNLOCK: release GPUs lock
+ rmGpuLocksRelease(GPUS_LOCK_FLAGS_NONE, NULL);
+ goto shutdown;
+ }
+
+ // UNLOCK: release GPUs lock
+ rmGpuLocksRelease(GPUS_LOCK_FLAGS_NONE, NULL);
+ nv_start_rc_timer(nv);
+
+ nvp->status = NV_OK;
+
+ if (!RmUnixAllocRmApi(nv, devicereference)) {
+ RM_SET_ERROR(status, RM_INIT_ALLOC_RMAPI_FAILED);
+ status.rmStatus = NV_ERR_GENERIC;
+ goto shutdown;
+ }
+
+ if (!NV_IS_SOC_DISPLAY_DEVICE(nv))
+ {
+ status.rmStatus = RmInitGpuInfoWithRmApi(pGpu);
+ if (status.rmStatus != NV_OK)
+ {
+ RM_SET_ERROR(status, RM_INIT_GPUINFO_WITH_RMAPI_FAILED);
+ goto shutdown;
+ }
+ }
+
+ // i2c only on master device??
+ RmI2cAddGpuPorts(nv);
+ nvp->flags |= NV_INIT_FLAG_PUBLIC_I2C;
+
+ // This fifo hal call will fail on pre-fermi gpus. In that case, userd
+ // info will remain 0 and skipped by fb mmap code
+ KernelFifo *pKernelFifo = GPU_GET_KERNEL_FIFO(pGpu);
+ NvU64 udaddr = 0;
+ NvU32 udsize = 0;
+ if (pKernelFifo != NULL)
+ {
+ status.rmStatus = kfifoGetUserdBar1MapInfo_HAL(pGpu, pKernelFifo, &udaddr, &udsize);
+ if (status.rmStatus == NV_OK)
+ {
+ nv->ud.cpu_address = (nv->fb->cpu_address + udaddr);
+ nv->ud.size = udsize;
+ }
+ else if (status.rmStatus != NV_ERR_NOT_SUPPORTED)
+ {
+ RM_SET_ERROR(status, RM_FIFO_GET_UD_BAR1_MAP_INFO_FAILED);
+ NV_PRINTF(LEVEL_ERROR,
+ "kfifoGetUserdBar1MapInfo failed, bailing out of RmInitAdapter\n");
+ goto shutdown;
+ }
+ }
+
+ nv->flags &= ~NV_FLAG_IN_RECOVERY;
+
+ pSys->setProperty(pSys, PDB_PROP_SYS_SYSTEM_EVENTS_SUPPORTED, NV_TRUE);
+
+ RmInitPowerManagement(nv);
+
+ if (!NV_IS_SOC_DISPLAY_DEVICE(nv))
+ {
+ status.rmStatus = RmRegisterGpudb(pGpu);
+ if (status.rmStatus != NV_OK)
+ {
+ RM_SET_ERROR(status, RM_GPUDB_REGISTER_FAILED);
+ goto shutdown;
+ }
+ }
+
+ if (nvp->b_mobile_config_enabled)
+ {
+ NvU32 ac_plugged = 0;
+ if (nv_acpi_get_powersource(&ac_plugged) == NV_OK)
+ {
+ // LOCK: acquire GPU lock
+ if (rmGpuLocksAcquire(GPUS_LOCK_FLAGS_NONE, RM_LOCK_MODULES_NONE) == NV_OK)
+ {
+ //
+ // As we have already acquired the API Lock here, we are calling
+ // RmPowerSourceChangeEvent directly instead of rm_power_source_change_event.
+ //
+ RmPowerSourceChangeEvent(nv, !ac_plugged);
+
+ // UNLOCK: release GPU lock
+ rmGpuLocksRelease(GPUS_LOCK_FLAGS_NONE, NULL);
+ }
+ }
+ }
+
+ _checkP2pChipsetSupport(nv);
+
+ NV_DEV_PRINTF(NV_DBG_SETUP, nv, "RmInitAdapter succeeded!\n");
+
+ retVal = NV_TRUE;
+ goto done;
+
+ shutdown:
+ nv->flags &= ~NV_FLAG_IN_RECOVERY;
+
+ gpumgrThreadDisableExpandedGpuVisibility();
+
+ // call ShutdownAdapter to undo anything we've done above
+ RmShutdownAdapter(nv);
+
+ failed:
+ NV_DEV_PRINTF(NV_DBG_ERRORS, nv, "RmInitAdapter failed! (0x%x:0x%x:%d)\n",
+ status.initStatus, status.rmStatus, status.line);
+
+done:
+ nv_put_firmware(gspFwHandle);
+ nv_put_firmware(gspFwLogHandle);
+ nv_put_firmware(gspUcodesHandle);
+
+ gpumgrSetCurrentGpuInstance(NV_U32_MAX);
+
+ return retVal;
+}
+
+void RmShutdownAdapter(
+ nv_state_t *nv
+)
+{
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+ OBJGPU *pGpu = NV_GET_NV_PRIV_PGPU(nv);
+ NV_STATUS rmStatus;
+
+ if ((pGpu != NULL) && (nvp->flags & NV_INIT_FLAG_GPUMGR_ATTACH))
+ {
+ NvU32 gpuInstance = gpuGetInstance(pGpu);
+ NvU32 deviceInstance = gpuGetDeviceInstance(pGpu);
+ OBJSYS *pSys = SYS_GET_INSTANCE();
+
+ RmUnixFreeRmApi(nv);
+
+ nv->ud.cpu_address = 0;
+ nv->ud.size = 0;
+
+ //
+ // LOCK: lock all clients in case of eGPU hot unplug, which
+ // will not wait for all existing RM clients to stop using the GPU.
+ //
+ if (!nv->is_external_gpu || serverLockAllClients(&g_resServ) == NV_OK)
+ {
+ // LOCK: acquire GPUs lock
+ if (rmGpuLocksAcquire(GPUS_LOCK_FLAGS_NONE, RM_LOCK_MODULES_DESTROY) == NV_OK)
+ {
+ //
+ // Shutdown path requires expanded GPU visibility in GPUMGR in order
+ // to access the GPU undergoing shutdown which may not be fully
+ // initialized, and to continue accessing the GPU undergoing shutdown
+ // after state destroy.
+ //
+ NV_ASSERT_OK(gpumgrThreadEnableExpandedGpuVisibility());
+
+ RmDestroyPowerManagement(nv);
+
+ freeNbsiTable(pGpu);
+
+ OBJCL *pCl = SYS_GET_CL(pSys);
+ OBJOS *pOS = GPU_GET_OS(pGpu);
+ if (pCl != NULL)
+ {
+ if (nvp->flags & NV_INIT_FLAG_CORE_LOGIC)
+ {
+ teardownCoreLogic(pOS, pGpu);
+ }
+ else if (nvp->flags & NV_INIT_FLAG_SCALABILITY)
+ {
+ osTeardownScalability(pGpu);
+ }
+ }
+
+ if (nvp->flags & NV_INIT_FLAG_FIFO_WATCHDOG)
+ {
+ krcWatchdogShutdown(pGpu, GPU_GET_KERNEL_RC(pGpu), NULL);
+ nvp->flags &= ~NV_INIT_FLAG_FIFO_WATCHDOG;
+ }
+
+ rmapiSetDelPendingClientResourcesFromGpuMask(NVBIT(gpuInstance));
+ rmapiDelPendingDevices(NVBIT(gpuInstance));
+
+ if (nvp->flags & NV_INIT_FLAG_GPU_STATE_LOAD)
+ {
+ rmStatus = gpuStateUnload(pGpu, GPU_STATE_DEFAULT);
+ NV_ASSERT(rmStatus == NV_OK);
+ }
+
+ if (nvp->flags & NV_INIT_FLAG_GPU_STATE)
+ {
+ rmStatus = gpuStateDestroy(pGpu);
+ NV_ASSERT(rmStatus == NV_OK);
+ }
+
+ if (IS_DCE_CLIENT(pGpu))
+ {
+ rmStatus = dceclientDceRmInit(pGpu, GPU_GET_DCECLIENTRM(pGpu), NV_FALSE);
+ if (rmStatus != NV_OK)
+ {
+ NV_PRINTF(LEVEL_ERROR, "DCE firmware RM Shutdown failure\n");
+ }
+ }
+
+ if (pGpu->getProperty(pGpu, PDB_PROP_GPU_CLKS_IN_TEGRA_SOC))
+ {
+ NV_PRINTF(LEVEL_INFO, "Disable Clocks\n");
+ RmDisableDeviceClks(nv);
+ }
+
+ //if (nvp->flags & NV_INIT_FLAG_HAL)
+ // destroyHal(pDev);
+
+#if NVCPU_IS_X86_64
+ RmFreeX86EmuState(pGpu);
+#endif
+
+ gpumgrDetachGpu(gpuInstance);
+ gpumgrDestroyDevice(deviceInstance);
+
+ //
+ // Expanded GPU visibility in GPUMGR is no longer needed once the
+ // GPU is removed from GPUMGR.
+ //
+ gpumgrThreadDisableExpandedGpuVisibility();
+
+ if (nvp->flags & NV_INIT_FLAG_DMA)
+ {
+ RmTeardownDeviceDma(nv);
+ }
+
+ RmClearPrivateState(nv);
+
+ RmUnInitAcpiMethods(pSys);
+
+ // UNLOCK: release GPUs lock
+ rmGpuLocksRelease(GPUS_LOCK_FLAGS_NONE, NULL);
+
+ // RM_BASIC_LOCK_MODEL: free GPU lock
+ rmGpuLockFree(deviceInstance);
+ }
+
+ // UNLOCK: unlock all clients for eGPU hot unplug path
+ if (nv->is_external_gpu)
+ serverUnlockAllClients(&g_resServ);
+ }
+ }
+ else
+ {
+ RmClearPrivateState(nv);
+ }
+
+ RmTeardownRegisters(nv);
+}
+
+void RmPartiallyDisableAdapter(
+ nv_state_t *nv
+)
+{
+ NV_PRINTF(LEVEL_INFO, "%s: RM is in SW Persistence mode\n", __FUNCTION__);
+
+ nv_stop_rc_timer(nv);
+}
+
+void RmDisableAdapter(
+ nv_state_t *nv
+)
+{
+ NV_STATUS rmStatus;
+ OBJGPU *pGpu = NV_GET_NV_PRIV_PGPU(nv);
+ NvU32 gpuMask;
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+
+ if (pGpu == NULL)
+ {
+ return;
+ }
+
+ gpumgrSetCurrentGpuInstance(pGpu->gpuInstance);
+
+ //
+ // Normally, we re-enable interrupts when we release the lock
+ // after RmDisableAdapter(), before disabling the bottom-half ISR.
+ // If an interrupt came in in that time window, but the bottom half
+ // wasn't scheduled to run in time, the semaphore acquired by the
+ // top-half would never be released afterwards (since the bottom-half
+ // would never run). This call to intrSetIntrEn() ensures that this won't
+ // happen, by making sure interrupts remain disabled on the GPU in question after
+ // RmDisableAdapter().
+ //
+ Intr *pIntr = GPU_GET_INTR(pGpu);
+ if (pIntr != NULL)
+ {
+ intrSetIntrEn(pIntr, INTERRUPT_TYPE_DISABLED);
+ }
+
+ if (pGpu->getProperty(pGpu, PDB_PROP_GPU_IN_SECONDARY_BUS_RESET) ||
+ pGpu->getProperty(pGpu, PDB_PROP_GPU_IN_FULLCHIP_RESET))
+ {
+ pGpu->setProperty(pGpu, PDB_PROP_GPU_IN_TIMEOUT_RECOVERY, NV_TRUE);
+ nv->flags |= NV_FLAG_IN_RECOVERY;
+ }
+
+ //
+ // LOCK: lock all clients in case of eGPU hot unplug, which
+ // will not wait for all existing RM clients to stop using the GPU.
+ //
+ if (!nv->is_external_gpu || serverLockAllClients(&g_resServ) == NV_OK)
+ {
+
+ // LOCK: acquire GPUs lock
+ if (rmGpuLocksAcquire(GPUS_LOCK_FLAGS_NONE, RM_LOCK_MODULES_DESTROY) == NV_OK)
+ {
+ //
+ // Free the client allocated resources.
+ //
+ // Note this doesn't free RM internal resource allocations. Those are
+ // freed during gpuStateUnload.
+ //
+ gpuMask = gpumgrGetGpuMask(pGpu);
+
+ rmapiSetDelPendingClientResourcesFromGpuMask(gpuMask);
+ rmapiDelPendingDevices(gpuMask);
+
+ nv_stop_rc_timer(nv);
+
+ OBJSYS *pSys = SYS_GET_INSTANCE();
+ OBJCL *pCl = SYS_GET_CL(pSys);
+ OBJOS *pOS = SYS_GET_OS(pSys);
+ if (pCl != NULL)
+ {
+ teardownCoreLogic(pOS, pGpu);
+ nvp->flags &= ~NV_INIT_FLAG_CORE_LOGIC;
+ }
+
+ if (nvp->flags & NV_INIT_FLAG_FIFO_WATCHDOG)
+ {
+ krcWatchdogShutdown(pGpu, GPU_GET_KERNEL_RC(pGpu), NULL);
+ nvp->flags &= ~NV_INIT_FLAG_FIFO_WATCHDOG;
+ }
+
+ if (nvp->flags & NV_INIT_FLAG_GPU_STATE_LOAD)
+ {
+ rmStatus = gpuStateUnload(pGpu, GPU_STATE_DEFAULT);
+ NV_ASSERT(rmStatus == NV_OK);
+ nvp->flags &= ~NV_INIT_FLAG_GPU_STATE_LOAD;
+ }
+
+ // UNLOCK: release GPUs lock
+ rmGpuLocksRelease(GPUS_LOCK_FLAGS_NONE, NULL);
+ }
+
+ // UNLOCK: unlock all clients for eGPU hot unplug path
+ if (nv->is_external_gpu)
+ serverUnlockAllClients(&g_resServ);
+ }
+
+ gpumgrSetCurrentGpuInstance(NV_U32_MAX);
+}
+
+NV_STATUS RmGetAdapterStatus(
+ nv_state_t *pNv,
+ NvU32 *pStatus
+)
+{
+ //
+ // This status is determined in RmInitAdapter(); the glue layer
+ // requests it when the adapter failed to initialize to learn
+ // more about the error condition. This is currently limited to
+ // osVerifySystemEnvironment() failures.
+ //
+ nv_priv_t *nvp;
+
+ nvp = NV_GET_NV_PRIV(pNv);
+ if (nvp == NULL)
+ {
+ return NV_ERR_INVALID_STATE;
+ }
+
+ *pStatus = nvp->status;
+ return NV_OK;
+}
+
+static void initVendorSpecificRegistry(
+ OBJGPU *pGpu,
+ NvU16 device_id
+)
+{
+ NV_STATUS rmStatus;
+ NvU32 i;
+ NvU32 subsystem_id;
+ NvU32 subsystem_vendor_id;
+ NvU32 subsystem_device_id;
+ NvU32 vendor_id = 0;
+
+ if (!pGpu)
+ return;
+
+ if (pGpu->bIsSOC)
+ return;
+
+ rmStatus = GPU_BUS_CFG_RD32(pGpu,
+ NV_CONFIG_PCI_NV_11, &subsystem_id);
+ if (rmStatus != NV_OK)
+ {
+ NV_PRINTF(LEVEL_ERROR,
+ "%s: Cannot read NV_CONFIG_PCI_NV_11\n", __FUNCTION__);
+ return;
+ }
+
+ subsystem_vendor_id = (subsystem_id & 0xffff);
+ subsystem_device_id = (subsystem_id >> 16);
+
+ for (i = 0; (nb_id_table[i].subsystem_vendor_id) != 0; i++)
+ {
+ if ((nb_id_table[i].subsystem_vendor_id == subsystem_vendor_id) &&
+ (nb_id_table[i].subsystem_device_id == subsystem_device_id) &&
+ (nb_id_table[i].gpu_device_id == device_id))
+ {
+ vendor_id = subsystem_vendor_id;
+ break;
+ }
+ }
+
+ if (vendor_id != 0)
+ {
+ for (i = 0; nb_reg_table[i].vendor_id != 0; i++)
+ {
+ if (nb_reg_table[i].vendor_id == vendor_id)
+ {
+ osWriteRegistryDword(pGpu, nb_reg_table[i].name,
+ nb_reg_table[i].data);
+ }
+ }
+ }
+}
+
+static void initUnixSpecificRegistry(
+ OBJGPU *pGpu
+)
+{
+ // By default, enable GPU reset on Unix
+ osWriteRegistryDword(pGpu, "RMSecBusResetEnable", 1);
+ osWriteRegistryDword(pGpu, "RMForcePcieConfigSave", 1);
+
+}
+
+void
+osRemoveGpu(
+ NvU32 domain,
+ NvU8 bus,
+ NvU8 device
+)
+{
+ void *handle;
+
+ handle = os_pci_init_handle(domain, bus, device, 0, NULL, NULL);
+ if (handle != NULL)
+ {
+ os_pci_remove(handle);
+ }
+}
+
+/*
+ * Check to see if this board supports GPU exclusion.
+ */
+static NvBool RmIsExcludingAllowed(
+ nv_state_t *pNv
+)
+{
+ NvU32 feature = 0;
+ NvU32 brand;
+
+ // DGX-2/HGX-2 systems pre-date the PBI call
+ if (pNv->pci_info.device_id == 0x1db8)
+ return NV_TRUE;
+
+ if (pciPbiGetFeature(pNv->handle, &feature) != NV_OK)
+ return NV_FALSE;
+
+ brand = DRF_VAL(_PBI, _EXECUTE_ROUTINE, _GET_FEATURE_EXCLUSION, feature);
+
+ return (brand == NV_PBI_EXECUTE_ROUTINE_GET_FEATURE_EXCLUSION_ALLOWED);
+}
+
+NV_STATUS RmExcludeAdapter(
+ nv_state_t *nv
+)
+{
+ NV_STATUS rmStatus;
+
+ if (!RmIsExcludingAllowed(nv))
+ return NV_ERR_NOT_SUPPORTED;
+
+ rmStatus = gpumgrExcludeGpuId(nv->gpu_id);
+ if (rmStatus != NV_OK)
+ {
+ NV_PRINTF(LEVEL_ERROR, "failed to exclude GPU: 0x%x\n", rmStatus);
+ return rmStatus;
+ }
+
+ /*
+ * GPU exclusion only happens during initialization, and therefore there
+ * is no need to stop activity on the GPU
+ */
+
+ return rmStatus;
+}
diff --git a/userspace/sdks/nv570/nvalloc/unix/src/osmemdesc.c b/userspace/sdks/nv570/nvalloc/unix/src/osmemdesc.c
new file mode 100644
index 0000000..84730cb
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/src/osmemdesc.c
@@ -0,0 +1,1325 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2012-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/******************* OS Memory Descriptor APIS *****************************\
+* *
+* This contains routines to create and destroy OS memory descriptor *
+* *
+****************************************************************************/
+
+#include <nv.h> // NV device driver interface
+#include <os/os.h>
+#include <osapi.h>
+#include <nvos.h>
+#include <rmapi/client.h>
+#include <rmapi/rs_utils.h>
+#include <gpu_mgr/gpu_mgr.h>
+
+#include "gpu/bif/kernel_bif.h"
+
+static NV_STATUS osCreateOsDescriptorFromPageArray(OBJGPU *, NvP64, NvHandle, NvU32, NvU64 *, MEMORY_DESCRIPTOR **, void **);
+static void osDestroyOsDescriptorPageArray(PMEMORY_DESCRIPTOR);
+
+static NV_STATUS osCreateOsDescriptorFromIoMemory(OBJGPU *, NvP64, NvHandle, NvU32, NvU64 *, MEMORY_DESCRIPTOR **, void**);
+static void osDestroyOsDescriptorFromIoMemory(PMEMORY_DESCRIPTOR);
+
+static NV_STATUS osCreateOsDescriptorFromPhysAddr(OBJGPU *, NvP64, NvHandle, NvU32, NvU64 *, MEMORY_DESCRIPTOR **, void**);
+static void osDestroyOsDescriptorFromPhysAddr(PMEMORY_DESCRIPTOR);
+
+static NV_STATUS osCreateOsDescriptorFromFileHandle(OBJGPU *, NvP64, NvHandle, NvU32, NvU64 *, MEMORY_DESCRIPTOR **, void**);
+static NV_STATUS osCreateOsDescriptorFromDmaBufPtr(OBJGPU *, NvP64, NvHandle, NvU32, NvU64 *, MEMORY_DESCRIPTOR **, void**);
+static void osDestroyOsDescriptorFromDmaBuf(PMEMORY_DESCRIPTOR);
+static NV_STATUS osCreateOsDescriptorFromSgtPtr(OBJGPU *, NvP64, NvHandle, NvU32, NvU64 *, MEMORY_DESCRIPTOR **, void**);
+static void osDestroyOsDescriptorFromSgt(PMEMORY_DESCRIPTOR);
+
+static NV_STATUS osCheckGpuBarsOverlapAddrRange(NvRangeU64 addrRange);
+
+NV_STATUS
+osCreateMemFromOsDescriptor
+(
+ OBJGPU *pGpu,
+ NvP64 pDescriptor,
+ NvHandle hClient,
+ NvU32 flags,
+ NvU64 *pLimit,
+ MEMORY_DESCRIPTOR **ppMemDesc,
+ NvU32 descriptorType,
+ RS_PRIV_LEVEL privilegeLevel
+)
+{
+ RmClient* pClient;
+ NV_STATUS rmStatus;
+ void *pPrivate;
+
+ pClient = serverutilGetClientUnderLock(hClient);
+ if ((pDescriptor == NvP64_NULL) ||
+ (*pLimit == 0) ||
+ (pClient == NULL))
+ {
+ return NV_ERR_INVALID_PARAM_STRUCT;
+ }
+
+ //
+ // For the sake of simplicity, unmatched RM and OS page
+ // sizes are not currently supported in this path, except for
+ // aarch64.
+ //
+ // Also, the nvmap handle is sent which can be any random number so
+ // the virtual address alignment sanity check can't be done here.
+ //
+ if (!NVCPU_IS_AARCH64 &&
+ (NV_RM_PAGE_SIZE != os_page_size))
+ {
+ return NV_ERR_NOT_SUPPORTED;
+ }
+
+ //
+ // The two checks below use cached privilege because they
+ // concern the privilege level of the client, and not the
+ // privilege level of the calling context which may be
+ // overridden to KERNEL at some internal callsites.
+ //
+
+ //
+ // The RM cannot obtain a table of physical addresses
+ // for a kernel virtual address range on all of
+ // the supported UNIX platforms. Since this path is
+ // not really compelling for kernel allocations on any
+ // of those platforms, it is not supported.
+ // For UVM, they could have pre-allocated sysmem to register
+ // with RM so we put in an exception for that case.
+ //
+ if ((rmclientGetCachedPrivilege(pClient) >= RS_PRIV_LEVEL_KERNEL) &&
+ (descriptorType != NVOS32_DESCRIPTOR_TYPE_OS_PHYS_ADDR) &&
+ (descriptorType != NVOS32_DESCRIPTOR_TYPE_OS_FILE_HANDLE) &&
+ (descriptorType != NVOS32_DESCRIPTOR_TYPE_OS_DMA_BUF_PTR) &&
+ (descriptorType != NVOS32_DESCRIPTOR_TYPE_OS_SGT_PTR))
+ {
+ return NV_ERR_NOT_SUPPORTED;
+ }
+
+ //
+ // NVOS32_DESCRIPTOR_TYPE_OS_DMA_BUF_PTR and
+ // NVOS32_DESCRIPTOR_TYPE_OS_SGT_PTR can only be utilized by kernel space
+ // rm-clients.
+ //
+ if ((rmclientGetCachedPrivilege(pClient) < RS_PRIV_LEVEL_KERNEL) &&
+ ((descriptorType == NVOS32_DESCRIPTOR_TYPE_OS_DMA_BUF_PTR) ||
+ (descriptorType == NVOS32_DESCRIPTOR_TYPE_OS_SGT_PTR)))
+ {
+ return NV_ERR_NOT_SUPPORTED;
+ }
+
+ switch (descriptorType)
+ {
+ case NVOS32_DESCRIPTOR_TYPE_VIRTUAL_ADDRESS:
+ rmStatus = NV_ERR_NOT_SUPPORTED;
+ break;
+ case NVOS32_DESCRIPTOR_TYPE_OS_PHYS_ADDR:
+ if (privilegeLevel < RS_PRIV_LEVEL_KERNEL)
+ {
+ rmStatus = NV_ERR_NOT_SUPPORTED;
+ break;
+ }
+ rmStatus = osCreateOsDescriptorFromPhysAddr(pGpu, pDescriptor,
+ hClient, flags, pLimit, ppMemDesc, &pPrivate);
+ break;
+ case NVOS32_DESCRIPTOR_TYPE_OS_IO_MEMORY:
+ rmStatus = osCreateOsDescriptorFromIoMemory(pGpu, pDescriptor,
+ hClient, flags, pLimit, ppMemDesc, &pPrivate);
+ break;
+ case NVOS32_DESCRIPTOR_TYPE_OS_PAGE_ARRAY:
+ rmStatus = osCreateOsDescriptorFromPageArray(pGpu, pDescriptor,
+ hClient, flags, pLimit, ppMemDesc, &pPrivate);
+ break;
+ case NVOS32_DESCRIPTOR_TYPE_OS_FILE_HANDLE:
+ rmStatus = osCreateOsDescriptorFromFileHandle(pGpu, pDescriptor,
+ hClient, flags, pLimit, ppMemDesc, &pPrivate);
+ break;
+ case NVOS32_DESCRIPTOR_TYPE_OS_DMA_BUF_PTR:
+ rmStatus = osCreateOsDescriptorFromDmaBufPtr(pGpu, pDescriptor,
+ hClient, flags, pLimit, ppMemDesc, &pPrivate);
+ break;
+ case NVOS32_DESCRIPTOR_TYPE_OS_SGT_PTR:
+ rmStatus = osCreateOsDescriptorFromSgtPtr(pGpu, pDescriptor,
+ hClient, flags, pLimit, ppMemDesc, &pPrivate);
+ break;
+ default:
+ rmStatus = NV_ERR_INVALID_ARGUMENT;
+ break;
+ }
+
+ return rmStatus;
+}
+
+static NV_STATUS
+osCreateMemdescFromPages
+(
+ OBJGPU *pGpu,
+ NvU64 size,
+ NvU32 flags,
+ NvU32 cacheType,
+ MEMORY_DESCRIPTOR **ppMemDesc,
+ void *pImportPriv,
+ void **ppPrivate
+)
+{
+ NV_STATUS rmStatus = NV_OK;
+ MEMORY_DESCRIPTOR *pMemDesc;
+ NvU64 memdescFlags = MEMDESC_FLAGS_NONE;
+ NvU32 gpuCachedFlags;
+ NvBool bUnprotected = NV_FALSE;
+ NvU64 osPageCount;
+
+ //
+ // Align size up to os page size. This is important in
+ // order to support submemdesc mappings at native page size.
+ // Once dynamic tracking is enabled this will not be needed
+ // as all submemory will get tracked at its native page size.
+ //
+ size = NV_ALIGN_UP64(size, os_page_size);
+
+ osPageCount = size >> os_page_shift;
+
+ if (FLD_TEST_DRF(OS02, _FLAGS, _ALLOC_NISO_DISPLAY, _YES, flags))
+ {
+ memdescFlags |= MEMDESC_FLAGS_MEMORY_TYPE_DISPLAY_NISO;
+ }
+
+ if (FLD_TEST_DRF(OS02, _FLAGS, _MEMORY_PROTECTION, _UNPROTECTED, flags))
+ {
+ memdescFlags |= MEMDESC_FLAGS_ALLOC_IN_UNPROTECTED_MEMORY;
+ bUnprotected = NV_TRUE;
+ }
+
+ if (FLD_TEST_DRF(OS02, _FLAGS, _ALLOC_USER_READ_ONLY, _YES, flags))
+ {
+ memdescFlags |= MEMDESC_FLAGS_USER_READ_ONLY;
+ memdescFlags |= MEMDESC_FLAGS_DEVICE_READ_ONLY;
+ }
+
+ if (FLD_TEST_DRF(OS02, _FLAGS, _ALLOC_DEVICE_READ_ONLY, _YES, flags))
+ {
+ memdescFlags |= MEMDESC_FLAGS_DEVICE_READ_ONLY;
+ }
+
+ rmStatus = memdescCreate(ppMemDesc, pGpu, size, 0,
+ NV_MEMORY_NONCONTIGUOUS, ADDR_SYSMEM,
+ cacheType, memdescFlags);
+ if (rmStatus != NV_OK)
+ {
+ return rmStatus;
+ }
+
+ if (FLD_TEST_DRF(OS02, _FLAGS, _GPU_CACHEABLE, _YES, flags))
+ gpuCachedFlags = NV_MEMORY_CACHED;
+ else
+ gpuCachedFlags = NV_MEMORY_UNCACHED;
+
+ pMemDesc = *ppMemDesc;
+ rmStatus = nv_register_user_pages(NV_GET_NV_STATE(pGpu),
+ osPageCount,
+ memdescGetPteArray(pMemDesc, AT_CPU), pImportPriv,
+ ppPrivate, bUnprotected);
+ if (rmStatus != NV_OK)
+ {
+ memdescDestroy(pMemDesc);
+ return rmStatus;
+ }
+
+ memdescSetGpuCacheAttrib(pMemDesc, gpuCachedFlags);
+ memdescSetFlag(pMemDesc, MEMDESC_FLAGS_KERNEL_MODE, NV_FALSE);
+ memdescSetFlag(pMemDesc, MEMDESC_FLAGS_EXT_PAGE_ARRAY_MEM, NV_TRUE);
+
+ if (IS_DISCONTIG_AND_DYNGRAN_ENABLED(pMemDesc))
+ {
+ NV_ASSERT_OR_GOTO((os_page_size & (pMemDesc->pageArrayGranularity - 1ULL)) == 0, cleanup);
+ NV_ASSERT_OK_OR_GOTO(rmStatus, memdescSetAllocSizeFields(pMemDesc, size, os_page_size), cleanup);
+ }
+ else
+ {
+ NV_ASSERT_OK_OR_GOTO(rmStatus, memdescSetAllocSizeFields(pMemDesc, size, NV_RM_PAGE_SIZE), cleanup);
+ }
+
+ if (!NV_IS_ALIGNED64(memdescGetPhysAddr(pMemDesc, AT_CPU, 0), os_page_size))
+ {
+ rmStatus = NV_ERR_INVALID_ARGUMENT;
+ NV_ASSERT_OR_GOTO(0, cleanup);
+ }
+
+
+ //
+ // If the OS layer doesn't think in RM page size, we need to inflate the
+ // PTE array into RM pages.
+ //
+ if (IS_DISCONTIG_AND_DYNGRAN_ENABLED(pMemDesc))
+ {
+ // Because os_page_size == pMemDesc->pageArrayGranularity, we don't need to do any page array conversion.
+ NV_ASSERT_OR_ELSE(os_page_size == pMemDesc->pageArrayGranularity, rmStatus = NV_ERR_INVALID_ARGUMENT; goto cleanup);
+ }
+ else if ((NV_RM_PAGE_SIZE < os_page_size) &&
+ !memdescGetContiguity(pMemDesc, AT_CPU))
+ {
+ RmInflateOsToRmPageArray(memdescGetPteArray(pMemDesc, AT_CPU), pMemDesc->PageCount);
+ }
+
+ //
+ // memdescMapIommu() requires the OS-private data to be set on the memory
+ // descriptor, but we don't want to wire up the teardown callback just yet:
+ // that callback needs to unpin the pages, but that will already be done
+ // as part of failure handling further up the stack if memdescMapIommu()
+ // fails. So we only set up the priv-data cleanup callback once we're sure
+ // this call will succeed.
+ //
+ memdescSetMemData(pMemDesc, *ppPrivate, NULL);
+
+ rmStatus = memdescMapIommu(pMemDesc, pGpu->busInfo.iovaspaceId);
+cleanup:
+ if (rmStatus != NV_OK)
+ {
+ if (IS_DISCONTIG_AND_DYNGRAN_ENABLED(pMemDesc))
+ {
+ // Because os_page_size == pMemDesc->pageArrayGranularity, we don't need to do any page array conversion.
+ NV_ASSERT(os_page_size == pMemDesc->pageArrayGranularity);
+ }
+ else if ((NV_RM_PAGE_SIZE < os_page_size) &&
+ !memdescGetContiguity(pMemDesc, AT_CPU))
+ {
+ RmDeflateRmToOsPageArray(memdescGetPteArray(pMemDesc, AT_CPU),
+ pMemDesc->PageCount);
+ }
+
+ nv_unregister_user_pages(NV_GET_NV_STATE(pGpu),
+ osPageCount,
+ NULL /* import_priv */, ppPrivate);
+ memdescDestroy(pMemDesc);
+ return rmStatus;
+ }
+
+ return NV_OK;
+}
+
+static NV_STATUS
+osCreateOsDescriptorFromPageArray
+(
+ OBJGPU *pGpu,
+ NvP64 pDescriptor,
+ NvHandle hClient,
+ NvU32 flags,
+ NvU64 *pLimit,
+ MEMORY_DESCRIPTOR **ppMemDesc,
+ void **ppPrivate
+)
+{
+ NV_STATUS rmStatus;
+
+ *ppPrivate = NvP64_VALUE(pDescriptor);
+
+ //
+ // Since the only type of memory permitted in this path
+ // is anonymous user memory, certain restrictions
+ // apply for the allocation flags:
+ //
+ // 1) anonymous memory is write-back cacheable, hence
+ // the _COHERENCY flag must match.
+ //
+ // 2) the RM has no control over the location of the
+ // associated pages in memory and thus cannot
+ // honor requests for contiguous memory.
+ //
+ // These restrictions are enforced here to avoid subtle
+ // bugs later on.
+ //
+ if ((!FLD_TEST_DRF(OS02, _FLAGS, _COHERENCY, _CACHED, flags) &&
+ !FLD_TEST_DRF(OS02, _FLAGS, _COHERENCY, _WRITE_BACK, flags)) ||
+ FLD_TEST_DRF(OS02, _FLAGS, _PHYSICALITY, _CONTIGUOUS, flags))
+ {
+ return NV_ERR_INVALID_FLAGS;
+ }
+
+ rmStatus = osCreateMemdescFromPages(pGpu, (*pLimit + 1), flags,
+ NV_MEMORY_CACHED, ppMemDesc,
+ NULL /* pImportPriv */, ppPrivate);
+ if (rmStatus != NV_OK)
+ {
+ return rmStatus;
+ }
+
+ // All is well - wire up the cleanup callback now
+ memdescSetMemData(*ppMemDesc, memdescGetMemData(*ppMemDesc),
+ osDestroyOsDescriptorPageArray);
+
+ return NV_OK;
+}
+
+/*!
+ * @brief Checks if the given address range overlaps with the BARs for any of
+ * the GPUs.
+ */
+static NV_STATUS
+osCheckGpuBarsOverlapAddrRange
+(
+ NvRangeU64 addrRange
+)
+{
+ NvRangeU64 gpuPhysAddrRange;
+ NvRangeU64 gpuPhysFbAddrRange;
+ NvRangeU64 gpuPhysInstAddrRange;
+ NvU32 gpuInstance;
+ OBJGPU *pGpu;
+ NvU32 gpuMask;
+ NV_STATUS rmStatus;
+
+ rmStatus = gpumgrGetGpuAttachInfo(NULL, &gpuMask);
+ NV_ASSERT_OR_RETURN(rmStatus == NV_OK, rmStatus);
+
+ gpuInstance = 0;
+ while ((pGpu = gpumgrGetNextGpu(gpuMask, &gpuInstance)) != NULL)
+ {
+ NV_INIT_RANGE(gpuPhysAddrRange, pGpu->busInfo.gpuPhysAddr,
+ pGpu->busInfo.gpuPhysAddr + pGpu->deviceMappings[0].gpuNvLength -1);
+
+ if (NV_IS_OVERLAPPING_RANGE(gpuPhysAddrRange, addrRange))
+ {
+ NV_PRINTF(LEVEL_ERROR,
+ "%s(): phys range 0x%016llx-0x%016llx overlaps with GPU BAR0\n",
+ __FUNCTION__, addrRange.min, addrRange.max);
+ return NV_ERR_INVALID_ADDRESS;
+ }
+
+ if ((pGpu->pGpuArch->bGpuArchIsZeroFb) ||
+ (pGpu->getProperty(pGpu, PDB_PROP_GPU_TEGRA_SOC_NVDISPLAY)))
+ {
+ // No local FB or BAR2 for ZERO_FB and TEGRA_SOC_NVDISPLAY.
+ continue;
+ }
+
+ NV_INIT_RANGE(gpuPhysFbAddrRange, gpumgrGetGpuPhysFbAddr(pGpu),
+ gpumgrGetGpuPhysFbAddr(pGpu) + pGpu->fbLength -1);
+
+ NV_INIT_RANGE(gpuPhysInstAddrRange, pGpu->busInfo.gpuPhysInstAddr,
+ pGpu->busInfo.gpuPhysInstAddr + pGpu->instLength -1);
+
+ if (NV_IS_OVERLAPPING_RANGE(gpuPhysFbAddrRange, addrRange) ||
+ NV_IS_OVERLAPPING_RANGE(gpuPhysInstAddrRange, addrRange))
+ {
+ NV_PRINTF(LEVEL_ERROR,
+ "%s(): phys range 0x%016llx-0x%016llx overlaps with FB or GPU BAR2\n",
+ __FUNCTION__, addrRange.min, addrRange.max);
+ return NV_ERR_INVALID_ADDRESS;
+ }
+ }
+
+ return NV_OK;
+}
+
+static NvU64
+_doWarBug4040336
+(
+ OBJGPU *pGpu,
+ NvU64 addr
+)
+{
+ if (gpuIsWarBug4040336Enabled(pGpu))
+ {
+ if ((addr & 0xffffffff00000000ULL) == 0x7fff00000000ULL)
+ {
+ addr = addr & 0xffffffffULL;
+ }
+ }
+ return addr;
+}
+
+static NV_STATUS
+osCreateOsDescriptorFromIoMemory
+(
+ OBJGPU *pGpu,
+ NvP64 pDescriptor,
+ NvHandle hClient,
+ NvU32 flags,
+ NvU64 *pLimit,
+ MEMORY_DESCRIPTOR **ppMemDesc,
+ void **ppPrivate
+)
+{
+ NV_STATUS rmStatus;
+ NvU32 gpuCachedFlags;
+ MEMORY_DESCRIPTOR *pMemDesc;
+ NvU64 *pPteArray;
+ NvRangeU64 physAddrRange;
+ NvU64 *base = 0;
+ NvBool bAllowMmap;
+ NvU64 size;
+
+ //
+ // Unlike the page array path, this one deals exclusively
+ // with I/O memory, which is expected to be contiguous
+ // physically, and which may only be accessed with uncached
+ // transactions.
+ //
+ if (!FLD_TEST_DRF(OS02, _FLAGS, _COHERENCY, _UNCACHED, flags) ||
+ !FLD_TEST_DRF(OS02, _FLAGS, _PHYSICALITY, _CONTIGUOUS, flags))
+ {
+ return NV_ERR_INVALID_FLAGS;
+ }
+
+ //
+ // _PEER_MAP_OVERRIDE flag is controlled by the RM and not the client.
+ //
+ // RM will set the _PEER_MAP_OVERRIDE_REQUIRED flag itself for IO memory
+ // memory imported with RmVidHeapControl.
+ //
+ if (FLD_TEST_DRF(OS02, _FLAGS, _PEER_MAP_OVERRIDE, _REQUIRED, flags))
+ {
+ //
+ // Don't allow MMIO mappings for unprivileged users
+ // This is a temporary WAR for bug 1630288 "[PeerSync] threat related
+ // to GPU"
+ //
+ KernelBif *pKernelBif = GPU_GET_KERNEL_BIF(pGpu);
+ if (!pKernelBif->peerMappingOverride && !osIsAdministrator())
+ {
+ NV_PRINTF(LEVEL_ERROR,
+ "%s(): permission denied, allowPeermapping=%d\n",
+ __FUNCTION__, pKernelBif->peerMappingOverride);
+ return NV_ERR_INSUFFICIENT_PERMISSIONS;
+ }
+ }
+
+ bAllowMmap = !FLD_TEST_DRF(OS02, _FLAGS, _MAPPING, _NEVER_MAP, flags);
+
+ base = (void *)(NvUPtr)pDescriptor;
+
+ //
+ // There is an architectural deadlock scenario involved when full-duplex P2P
+ // enabled over BAR1. See #3 in the description of bug 1571948 which explains
+ // the classic deadlock. So, make sure to error out usermode's memory
+ // registration if a memory range falls within any of the available GPU's
+ // BAR window.
+ //
+ physAddrRange.min = *base;
+ physAddrRange.max = *base + *pLimit;
+
+ rmStatus = osCheckGpuBarsOverlapAddrRange(physAddrRange);
+ if (rmStatus != NV_OK)
+ {
+ return rmStatus;
+ }
+
+ //
+ // BF3's PCIe MMIO bus address at 0x800000000000(CPU PA 0x7fff00000000) is
+ // too high for Ampere to address. As a result, BF3's bus address is
+ // moved to < 4GB. Now, the CPU PA and the bus address are no longer 1:1
+ // and needs to be adjusted.
+ //
+ *base = _doWarBug4040336(pGpu, *base);
+
+ size = NV_ALIGN_UP64(*pLimit + 1, os_page_size);
+
+ rmStatus = memdescCreate(ppMemDesc, pGpu, size, 0,
+ NV_MEMORY_CONTIGUOUS, ADDR_SYSMEM,
+ NV_MEMORY_UNCACHED, MEMDESC_FLAGS_NONE);
+ if (rmStatus != NV_OK)
+ {
+ NV_PRINTF(LEVEL_ERROR,
+ "%s(): error %d while attempting to create the MMIO mapping\n",
+ __FUNCTION__, rmStatus);
+ return rmStatus;
+ }
+
+ pMemDesc = *ppMemDesc;
+
+ if (FLD_TEST_DRF(OS02, _FLAGS, _GPU_CACHEABLE, _YES, flags))
+ gpuCachedFlags = NV_MEMORY_CACHED;
+ else
+ gpuCachedFlags = NV_MEMORY_UNCACHED;
+
+ memdescSetGpuCacheAttrib(pMemDesc, gpuCachedFlags);
+ memdescSetMemData(pMemDesc, NULL, NULL);
+ memdescSetFlag(pMemDesc, MEMDESC_FLAGS_KERNEL_MODE, NV_FALSE);
+ memdescSetFlag(pMemDesc, MEMDESC_FLAGS_PEER_IO_MEM, NV_TRUE);
+
+ pPteArray = memdescGetPteArray(pMemDesc, AT_CPU);
+ pPteArray[0] = *base;
+
+ *ppPrivate = NULL;
+
+ if (!NV_IS_ALIGNED64(pPteArray[0], os_page_size))
+ {
+ rmStatus = NV_ERR_INVALID_ARGUMENT;
+ NV_ASSERT_OR_GOTO(0, cleanup);
+ }
+ NvU64 osPageCount;
+ if (IS_DISCONTIG_AND_DYNGRAN_ENABLED(pMemDesc))
+ {
+ NV_ASSERT_OK_OR_GOTO(rmStatus, memdescSetAllocSizeFields(pMemDesc, size, os_page_size), cleanup);
+ osPageCount = pMemDesc->PageCount;
+ }
+ else
+ {
+ NV_ASSERT_OK_OR_GOTO(rmStatus, memdescSetAllocSizeFields(pMemDesc, size, NV_RM_PAGE_SIZE), cleanup);
+ osPageCount = NV_RM_PAGES_TO_OS_PAGES(pMemDesc->PageCount);
+ }
+
+ if (bAllowMmap)
+ {
+ rmStatus = nv_register_peer_io_mem(NV_GET_NV_STATE(pGpu), pPteArray,
+ osPageCount,
+ ppPrivate);
+ if (rmStatus != NV_OK)
+ {
+ memdescDestroy(pMemDesc);
+ return rmStatus;
+ }
+ }
+
+ memdescSetMemData(pMemDesc, *ppPrivate, NULL);
+
+ //
+ // memdescMapIommu() requires the OS-private data to be set on the memory
+ // descriptor, but we don't want to wire up the teardown callback just yet:
+ // that callback needs to unpin the pages, but that will already be done
+ // as part of failure handling further up the stack if memdescMapIommu()
+ // fails. So we only set up the priv-data cleanup callback once we're sure
+ // this call will succeed.
+ //
+ rmStatus = memdescMapIommu(pMemDesc, pGpu->busInfo.iovaspaceId);
+cleanup:
+ if (rmStatus != NV_OK)
+ {
+ if (*ppPrivate != NULL)
+ {
+ nv_unregister_peer_io_mem(NV_GET_NV_STATE(pGpu), *ppPrivate);
+ }
+ memdescDestroy(pMemDesc);
+ return rmStatus;
+ }
+
+ // All is well - wire up the cleanup callback now
+ memdescSetMemData(pMemDesc, memdescGetMemData(pMemDesc),
+ osDestroyOsDescriptorFromIoMemory);
+
+ return NV_OK;
+}
+
+static NV_STATUS
+osCreateOsDescriptorFromPhysAddr
+(
+ OBJGPU *pGpu,
+ NvP64 pDescriptor,
+ NvHandle hClient,
+ NvU32 flags,
+ NvU64 *pLimit,
+ MEMORY_DESCRIPTOR **ppMemDesc,
+ void **ppPrivate
+)
+{
+ NV_STATUS rmStatus;
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ MEMORY_DESCRIPTOR *pMemDesc;
+ NvU64 *pPteArray;
+ NvU64 base = 0;
+ NvU32 cache_type = NV_MEMORY_CACHED;
+ NvU64 memdescFlags = MEMDESC_FLAGS_NONE;
+ NvU64 *pPhys_addrs;
+ NvU64 num_os_pages;
+ NvU32 idx;
+ NvU64 size;
+
+ // Currently only work with contiguous sysmem allocations
+ if (!FLD_TEST_DRF(OS02, _FLAGS, _PHYSICALITY, _CONTIGUOUS, flags))
+ {
+ return NV_ERR_INVALID_FLAGS;
+ }
+
+ if (FLD_TEST_DRF(OS02, _FLAGS, _ALLOC_TYPE_SYNCPOINT, _APERTURE, flags))
+ {
+ // Syncpoint memory is uncached, DMA mapping needs to skip CPU sync.
+ cache_type = NV_MEMORY_UNCACHED;
+
+ //
+ // Syncpoint memory is NISO. Don't attempt to IOMMU map if the NISO
+ // IOMMU isn't enabled.
+ //
+ if (!NV_SOC_IS_NISO_IOMMU_PRESENT(nv))
+ {
+ memdescFlags |= MEMDESC_FLAGS_SKIP_IOMMU_MAPPING;
+ }
+ }
+
+ if (FLD_TEST_DRF(OS02, _FLAGS, _ALLOC_NISO_DISPLAY, _YES, flags))
+ {
+ memdescFlags |= MEMDESC_FLAGS_MEMORY_TYPE_DISPLAY_NISO;
+ }
+
+ base = (NvU64)pDescriptor;
+ size = NV_ALIGN_UP64((*pLimit + 1), os_page_size);
+
+ NV_ASSERT_OR_RETURN(NV_IS_ALIGNED64(base, os_page_size), NV_ERR_INVALID_ARGUMENT);
+
+ rmStatus = memdescCreate(ppMemDesc, pGpu, size, 0,
+ NV_MEMORY_CONTIGUOUS, ADDR_SYSMEM,
+ cache_type, memdescFlags);
+ if (rmStatus != NV_OK)
+ {
+ NV_PRINTF(LEVEL_ERROR,
+ "%s(): error %d while creating memdesc for kernel memory\n",
+ __FUNCTION__, rmStatus);
+ return rmStatus;
+ }
+
+ pMemDesc = *ppMemDesc;
+
+ memdescSetMemData(pMemDesc, NULL, NULL);
+ memdescSetFlag(pMemDesc, MEMDESC_FLAGS_EXT_PAGE_ARRAY_MEM, NV_TRUE);
+
+ pPteArray = memdescGetPteArray(pMemDesc, AT_CPU);
+ pPteArray[0] = base;
+
+ num_os_pages = size >> os_page_shift;
+ pPhys_addrs = portMemAllocNonPaged(sizeof(NvU64) * num_os_pages);
+ if (pPhys_addrs == NULL)
+ goto cleanup_memdesc;
+
+ for (idx = 0; idx < num_os_pages; idx++)
+ {
+ pPhys_addrs[idx] = base + (idx * os_page_size);
+ }
+
+ *ppPrivate = NULL;
+ rmStatus = nv_register_phys_pages(nv, pPhys_addrs, num_os_pages,
+ memdescGetCpuCacheAttrib(pMemDesc),
+ ppPrivate);
+ if (rmStatus != NV_OK)
+ goto cleanup_memdesc;
+
+ if (IS_DISCONTIG_AND_DYNGRAN_ENABLED(pMemDesc))
+ {
+ NV_ASSERT_OK_OR_RETURN(memdescSetAllocSizeFields(pMemDesc, size, os_page_size));
+ }
+ else
+ {
+ NV_ASSERT_OK_OR_RETURN(memdescSetAllocSizeFields(pMemDesc, size, NV_RM_PAGE_SIZE));
+ }
+
+ // If IOMMU skip flag wasn't set earlier, create IOVA mapping.
+ if (!memdescGetFlag(pMemDesc, MEMDESC_FLAGS_SKIP_IOMMU_MAPPING))
+ {
+ //
+ // memdescMapIommu() requires the OS-private data to be set on the memory
+ // descriptor, but we don't want to wire up the teardown callback just yet:
+ // that callback needs to unpin the pages, but that will already be done
+ // as part of failure handling further up the stack if memdescMapIommu()
+ // fails. So we only set up the priv-data cleanup callback once we're sure
+ // this call will succeed.
+ //
+ memdescSetMemData(pMemDesc, *ppPrivate, NULL);
+
+ rmStatus = memdescMapIommu(pMemDesc, pGpu->busInfo.iovaspaceId);
+ if (rmStatus != NV_OK)
+ goto cleanup_pages;
+ }
+
+ // All is well - wire up the cleanup callback now
+ memdescSetMemData(pMemDesc, *ppPrivate,
+ osDestroyOsDescriptorFromPhysAddr);
+
+ portMemFree(pPhys_addrs);
+
+ return NV_OK;
+
+cleanup_pages:
+ if (*ppPrivate != NULL)
+ {
+ nv_unregister_phys_pages(NV_GET_NV_STATE(pGpu), *ppPrivate);
+ }
+
+cleanup_memdesc:
+ memdescDestroy(pMemDesc);
+
+ portMemFree(pPhys_addrs);
+
+ return rmStatus;
+}
+
+static NV_STATUS
+_createMemdescFromDmaBufSgtHelper
+(
+ OBJGPU *pGpu,
+ NvU32 flags,
+ void *pImportPriv,
+ struct sg_table *pImportSgt,
+ NvU32 size,
+ MEMORY_DESCRIPTOR **ppMemDesc,
+ void **ppPrivate,
+ MEM_DATA_RELEASE_CALL_BACK *pMemDataReleaseCallback
+)
+{
+ NV_STATUS rmStatus = NV_OK;
+ NvU32 cacheType = NV_MEMORY_UNCACHED;
+ MEMORY_DESCRIPTOR *pMemDesc;
+ NvU64 memdescFlags = MEMDESC_FLAGS_NONE;
+ NvU32 gpuCachedFlags;
+ NvBool isPeerMmio = NV_FALSE;
+ NvU64 osPageCount;
+
+ //
+ // Align size up to os page size. This is important in
+ // order to support submemdesc mappings at native page size.
+ // Once dynamic tracking is enabled this will not be needed
+ // as all submemor
+ //
+ size = NV_ALIGN_UP64(size, os_page_size);
+
+ osPageCount = size >> os_page_shift;
+
+ NV_ASSERT((pMemDataReleaseCallback == osDestroyOsDescriptorFromDmaBuf) ||
+ (pMemDataReleaseCallback == osDestroyOsDescriptorFromSgt));
+
+ if (FLD_TEST_DRF(OS02, _FLAGS, _COHERENCY, _WRITE_COMBINE, flags))
+ {
+ cacheType = NV_MEMORY_WRITECOMBINED;
+ }
+ else if (!FLD_TEST_DRF(OS02, _FLAGS, _COHERENCY, _UNCACHED, flags))
+ {
+ cacheType = NV_MEMORY_CACHED;
+ }
+
+ if (FLD_TEST_DRF(OS02, _FLAGS, _GPU_CACHEABLE, _YES, flags))
+ {
+ gpuCachedFlags = NV_MEMORY_CACHED;
+ }
+ else
+ {
+ gpuCachedFlags = NV_MEMORY_UNCACHED;
+ }
+
+ if (FLD_TEST_DRF(OS02, _FLAGS, _ALLOC_TYPE_SYNCPOINT, _APERTURE, flags))
+ {
+ // Syncpoint memory is uncached.
+ if ((cacheType != NV_MEMORY_UNCACHED) ||
+ (gpuCachedFlags != NV_MEMORY_UNCACHED))
+ {
+ NV_PRINTF(LEVEL_ERROR,
+ "%s(): Error: Syncpoint memory region should be uncached!!!\n",
+ __FUNCTION__);
+ return NV_ERR_INVALID_FLAGS;
+ }
+
+ isPeerMmio = NV_TRUE;
+
+ NV_PRINTF(LEVEL_INFO,
+ "%s(): Syncpoint type sgt!\n", __FUNCTION__);
+ }
+
+ if (FLD_TEST_DRF(OS02, _FLAGS, _ALLOC_NISO_DISPLAY, _YES, flags))
+ {
+ memdescFlags |= MEMDESC_FLAGS_MEMORY_TYPE_DISPLAY_NISO;
+ }
+
+ if (FLD_TEST_DRF(OS02, _FLAGS, _ALLOC_USER_READ_ONLY, _YES, flags))
+ {
+ memdescFlags |= MEMDESC_FLAGS_USER_READ_ONLY;
+ }
+
+ if (FLD_TEST_DRF(OS02, _FLAGS, _ALLOC_DEVICE_READ_ONLY, _YES, flags))
+ {
+ memdescFlags |= MEMDESC_FLAGS_DEVICE_READ_ONLY;
+ }
+
+ rmStatus = memdescCreate(ppMemDesc, pGpu, size, 0,
+ NV_MEMORY_NONCONTIGUOUS, ADDR_SYSMEM,
+ cacheType, memdescFlags);
+ if (rmStatus != NV_OK)
+ {
+ return rmStatus;
+ }
+
+ pMemDesc = *ppMemDesc;
+
+ memdescSetGpuCacheAttrib(pMemDesc, gpuCachedFlags);
+ memdescSetMemData(pMemDesc, NULL, NULL);
+ memdescSetFlag(pMemDesc, MEMDESC_FLAGS_KERNEL_MODE, NV_FALSE);
+ memdescSetFlag(pMemDesc, MEMDESC_FLAGS_EXT_PAGE_ARRAY_MEM, NV_TRUE);
+
+ *ppPrivate = NULL;
+ rmStatus = nv_register_sgt(NV_GET_NV_STATE(pGpu),
+ memdescGetPteArray(pMemDesc, AT_CPU),
+ osPageCount,
+ memdescGetCpuCacheAttrib(pMemDesc),
+ ppPrivate,
+ pImportSgt,
+ pImportPriv,
+ isPeerMmio);
+ if (rmStatus != NV_OK)
+ {
+ memdescDestroy(pMemDesc);
+ return rmStatus;
+ }
+
+ if (IS_DISCONTIG_AND_DYNGRAN_ENABLED(pMemDesc))
+ {
+ NV_ASSERT_OK_OR_GOTO(rmStatus, memdescSetAllocSizeFields(pMemDesc, size, os_page_size), cleanup);
+ }
+ else
+ {
+ NV_ASSERT_OK_OR_GOTO(rmStatus, memdescSetAllocSizeFields(pMemDesc, size, NV_RM_PAGE_SIZE), cleanup);
+ }
+
+ if (!NV_IS_ALIGNED64(memdescGetPhysAddr(pMemDesc, AT_CPU, 0), os_page_size))
+ {
+ rmStatus = NV_ERR_INVALID_ARGUMENT;
+ NV_ASSERT_OR_GOTO(0, cleanup);
+ }
+
+ //
+ // If the OS layer doesn't think in RM page size, we need to inflate the
+ // PTE array into RM pages.
+ //
+ if (IS_DISCONTIG_AND_DYNGRAN_ENABLED(pMemDesc))
+ {
+ // Because os_page_size == pMemDesc->pageArrayGranularity, we don't need to do any page array conversion.
+ NV_ASSERT_OR_ELSE(os_page_size == pMemDesc->pageArrayGranularity, rmStatus = NV_ERR_INVALID_ARGUMENT; goto cleanup);
+ }
+ else if ((NV_RM_PAGE_SIZE < os_page_size) &&
+ !memdescGetContiguity(pMemDesc, AT_CPU))
+ {
+ RmInflateOsToRmPageArray(memdescGetPteArray(pMemDesc, AT_CPU), pMemDesc->PageCount);
+ }
+
+ memdescSetMemData(*ppMemDesc, *ppPrivate, NULL);
+
+ //
+ // memdescMapIommu() requires the OS-private data to be set on the memory
+ // descriptor, but we don't want to wire up the teardown callback just yet:
+ // that callback does teardown that will already be done as part of failure
+ // handling further up the stack if memdescMapIommu() fails. So we only
+ // setup the priv-data cleanup callback once we're sure this call will
+ // succeed.
+ //
+ rmStatus = memdescMapIommu(*ppMemDesc, pGpu->busInfo.iovaspaceId);
+cleanup:
+ if (rmStatus != NV_OK)
+ {
+ if (IS_DISCONTIG_AND_DYNGRAN_ENABLED(pMemDesc))
+ {
+ // Because os_page_size == pMemDesc->pageArrayGranularity, we don't need to do any page array conversion.
+ NV_ASSERT(os_page_size == pMemDesc->pageArrayGranularity);
+ }
+ else if ((NV_RM_PAGE_SIZE < os_page_size) &&
+ !memdescGetContiguity(pMemDesc, AT_CPU))
+ {
+ RmDeflateRmToOsPageArray(memdescGetPteArray(pMemDesc, AT_CPU),
+ pMemDesc->PageCount);
+ }
+ if (*ppPrivate != NULL)
+ {
+ nv_unregister_sgt(NV_GET_NV_STATE(pGpu), &pImportSgt,
+ (void **) &pImportPriv, *ppPrivate);
+ }
+ memdescDestroy(pMemDesc);
+ return rmStatus;
+ }
+
+ // All is well - wire up the cleanup callback now
+ memdescSetMemData(*ppMemDesc, *ppPrivate, pMemDataReleaseCallback);
+
+ return rmStatus;
+}
+
+static NV_STATUS
+_createMemdescFromDmaBuf
+(
+ OBJGPU *pGpu,
+ NvU32 flags,
+ nv_dma_buf_t *pImportPriv,
+ struct sg_table *pImportSgt,
+ NvU32 size,
+ MEMORY_DESCRIPTOR **ppMemDesc,
+ void **ppPrivate
+)
+{
+ NV_STATUS rmStatus =
+ _createMemdescFromDmaBufSgtHelper(pGpu, flags, pImportPriv, pImportSgt,
+ size, ppMemDesc, ppPrivate,
+ osDestroyOsDescriptorFromDmaBuf);
+ if (rmStatus != NV_OK)
+ {
+ nv_dma_release_dma_buf(pImportPriv);
+ }
+
+ return rmStatus;
+}
+
+static NV_STATUS
+_createMemdescFromSgt
+(
+ OBJGPU *pGpu,
+ NvU32 flags,
+ struct drm_gem_object *pImportPrivGem,
+ struct sg_table *pImportSgt,
+ NvU32 size,
+ MEMORY_DESCRIPTOR **ppMemDesc,
+ void **ppPrivate
+)
+{
+ NV_STATUS rmStatus =
+ _createMemdescFromDmaBufSgtHelper(pGpu, flags, pImportPrivGem,
+ pImportSgt, size, ppMemDesc,
+ ppPrivate,
+ osDestroyOsDescriptorFromSgt);
+ if (rmStatus != NV_OK)
+ {
+ nv_dma_release_sgt(pImportSgt, pImportPrivGem);
+ }
+
+ return rmStatus;
+}
+
+static nv_dma_device_t *GetDmaDeviceForImport
+(
+ nv_state_t *nv,
+ NvU32 flags
+)
+{
+ if (FLD_TEST_DRF(OS02, _FLAGS, _ALLOC_NISO_DISPLAY, _YES, flags) &&
+ (nv->niso_dma_dev != NULL))
+ {
+ return nv->niso_dma_dev;
+ }
+ else
+ {
+ return nv->dma_dev;
+ }
+}
+
+static NV_STATUS
+osCreateOsDescriptorFromFileHandle
+(
+ OBJGPU *pGpu,
+ NvP64 pDescriptor,
+ NvHandle hClient,
+ NvU32 flags,
+ NvU64 *pLimit,
+ MEMORY_DESCRIPTOR **ppMemDesc,
+ void **ppPrivate
+)
+{
+ NV_STATUS rmStatus = NV_OK;
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ nv_dma_device_t *dma_dev = NULL;
+ NvU32 size = 0;
+ nv_dma_buf_t *pImportPriv = NULL;
+ struct sg_table *pImportSgt = NULL;
+ NvBool bRoDeviceMap = NV_FALSE;
+ NvS32 fd;
+
+ fd = (NvS32)((NvU64)pDescriptor);
+ if ((NvU64)fd != (NvU64)pDescriptor)
+ {
+ NV_PRINTF(LEVEL_ERROR,
+ "%s(): fd must fit within a signed 32-bit integer!\n",
+ __FUNCTION__);
+ return NV_ERR_INVALID_ARGUMENT;
+ }
+
+ dma_dev = GetDmaDeviceForImport(nv, flags);
+
+ if (FLD_TEST_DRF(OS02, _FLAGS, _ALLOC_DEVICE_READ_ONLY, _YES, flags))
+ {
+ bRoDeviceMap = NV_TRUE;
+ NV_PRINTF(LEVEL_INFO,
+ "%s(): RO DMA Mapping - flags [%x]!\n",
+ __FUNCTION__, flags);
+ }
+
+ rmStatus = nv_dma_import_from_fd(dma_dev, fd, bRoDeviceMap, &size,
+ &pImportSgt, &pImportPriv);
+ if (rmStatus != NV_OK)
+ {
+ NV_PRINTF(LEVEL_ERROR,
+ "%s(): Error (%d) while trying to import fd!\n",
+ __FUNCTION__, rmStatus);
+ return rmStatus;
+ }
+
+ return _createMemdescFromDmaBuf(pGpu, flags, pImportPriv,
+ pImportSgt,
+ size, ppMemDesc, ppPrivate);
+}
+
+static NV_STATUS
+osCreateOsDescriptorFromSgtPtr
+(
+ OBJGPU *pGpu,
+ NvP64 pDescriptor,
+ NvHandle hClient,
+ NvU32 flags,
+ NvU64 *pLimit,
+ MEMORY_DESCRIPTOR **ppMemDesc,
+ void **ppPrivate
+)
+{
+ NV_STATUS rmStatus = NV_OK;
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ NVOS32_DESCRIPTOR_TYPE_OS_SGT_PTR_PARAMETERS *params =
+ (NVOS32_DESCRIPTOR_TYPE_OS_SGT_PTR_PARAMETERS*)((NvUPtr) pDescriptor);
+
+ struct sg_table *sgt = params->sgt;
+ struct drm_gem_object *gem = params->gem;
+
+ rmStatus = nv_dma_import_sgt(nv->dma_dev, sgt, gem);
+ if (rmStatus != NV_OK)
+ {
+ NV_PRINTF(LEVEL_ERROR,
+ "%s(): Error (%d) while trying to import sgt!\n",
+ __FUNCTION__, rmStatus);
+ return rmStatus;
+ }
+
+ return _createMemdescFromSgt(pGpu, flags, gem, sgt,
+ (*pLimit + 1), ppMemDesc, ppPrivate);
+}
+
+static NV_STATUS
+osCreateOsDescriptorFromDmaBufPtr
+(
+ OBJGPU *pGpu,
+ NvP64 pDescriptor,
+ NvHandle hClient,
+ NvU32 flags,
+ NvU64 *pLimit,
+ MEMORY_DESCRIPTOR **ppMemDesc,
+ void **ppPrivate
+)
+{
+ NV_STATUS rmStatus = NV_OK;
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ nv_dma_device_t *dma_dev = NULL;
+ NvU32 size = 0;
+ nv_dma_buf_t *pImportPriv = NULL;
+ struct sg_table *pImportSgt = NULL;
+ void *dmaBuf = (void*)((NvUPtr)pDescriptor);
+ NvBool bRoDeviceMap = NV_FALSE;
+
+ dma_dev = GetDmaDeviceForImport(nv, flags);
+
+ if (FLD_TEST_DRF(OS02, _FLAGS, _ALLOC_DEVICE_READ_ONLY, _YES, flags))
+ {
+ bRoDeviceMap = NV_TRUE;
+ NV_PRINTF(LEVEL_INFO,
+ "%s(): RO DMA Mapping - flags [%x]!\n",
+ __FUNCTION__, flags);
+ }
+
+ rmStatus = nv_dma_import_dma_buf(dma_dev, dmaBuf, bRoDeviceMap, &size,
+ &pImportSgt, &pImportPriv);
+ if (rmStatus != NV_OK)
+ {
+ NV_PRINTF_COND(rmStatus == NV_ERR_NOT_SUPPORTED, LEVEL_INFO, LEVEL_ERROR,
+ "Error (%d) while trying to import dma_buf!\n", rmStatus);
+ return rmStatus;
+ }
+
+ return _createMemdescFromDmaBuf(pGpu, flags, pImportPriv,
+ pImportSgt,
+ size, ppMemDesc, ppPrivate);
+}
+
+static void
+osDestroyOsDescriptorFromPhysAddr
+(
+ PMEMORY_DESCRIPTOR pMemDesc
+)
+{
+ OBJGPU *pGpu = pMemDesc->pGpu;
+ void *pPrivate;
+
+ pPrivate = memdescGetMemData(pMemDesc);
+ NV_ASSERT(pPrivate != NULL);
+
+ if (!memdescGetFlag(pMemDesc, MEMDESC_FLAGS_SKIP_IOMMU_MAPPING))
+ memdescUnmapIommu(pMemDesc, pGpu->busInfo.iovaspaceId);
+
+ nv_unregister_phys_pages(NV_GET_NV_STATE(pGpu), pPrivate);
+}
+
+static void
+osDestroyOsDescriptorFromIoMemory
+(
+ PMEMORY_DESCRIPTOR pMemDesc
+)
+{
+ OBJGPU *pGpu = pMemDesc->pGpu;
+ void *pPrivate = memdescGetMemData(pMemDesc);
+
+ if (pPrivate == NULL)
+ {
+ return;
+ }
+
+ nv_unregister_peer_io_mem(NV_GET_NV_STATE(pGpu), pPrivate);
+}
+
+static void
+osDestroyOsDescriptorPageArray
+(
+ MEMORY_DESCRIPTOR *pMemDesc
+)
+{
+ OBJGPU *pGpu = pMemDesc->pGpu;
+ NvU64 osPageCount;
+ NV_STATUS status;
+ void *pPrivate;
+
+ pPrivate = memdescGetMemData(pMemDesc);
+
+ NV_ASSERT(pPrivate != NULL);
+
+ //
+ // TODO: Bug 1811006: Notably skip any IOMMU mapping management as the
+ // pMemDesc->pGpu might have been torn down already and the pGpu passed in
+ // doesn't necessarily have IOMMU mappings. For now just allow memdescDestroy()
+ // to clean up whatever is there (this may not work correctly either if any
+ // of the IOMMU mappings have outlasted their VASPACEs). This should
+ // be cleaned up once the fix for bug 1811006 is known.
+ //
+
+ if (IS_DISCONTIG_AND_DYNGRAN_ENABLED(pMemDesc))
+ {
+ // Because os_page_size == pMemDesc->pageArrayGranularity, we don't need to do any page array conversion.
+ NV_ASSERT_OR_RETURN_VOID(os_page_size == pMemDesc->pageArrayGranularity);
+ osPageCount = pMemDesc->PageCount;
+ }
+ else
+ {
+ osPageCount = NV_RM_PAGES_TO_OS_PAGES(pMemDesc->PageCount);
+ if ((NV_RM_PAGE_SIZE < os_page_size) &&
+ !memdescGetContiguity(pMemDesc, AT_CPU))
+ {
+ RmDeflateRmToOsPageArray(memdescGetPteArray(pMemDesc, AT_CPU),
+ pMemDesc->PageCount);
+ }
+ }
+
+ nv_unregister_user_pages(NV_GET_NV_STATE(pGpu), osPageCount,
+ NULL /* import_priv */, &pPrivate);
+
+ if (memdescGetFlag(pMemDesc, MEMDESC_FLAGS_FOREIGN_PAGE))
+ {
+ os_free_mem(pPrivate);
+ }
+ else
+ {
+ //
+ // We use MEMDESC_FLAGS_USER_READ_ONLY because this reflects the
+ // NVOS02_FLAGS_ALLOC_USER_READ_ONLY flag value passed into
+ // os_lock_user_pages(). That flag also results in
+ // MEMDESC_FLAGS_DEVICE_READ_ONLY being set.
+ //
+ NvBool writable = !memdescGetFlag(pMemDesc, MEMDESC_FLAGS_USER_READ_ONLY);
+ NvU32 flags = DRF_NUM(_LOCK_USER_PAGES, _FLAGS, _WRITE, writable);
+ status = os_unlock_user_pages(osPageCount, pPrivate, flags);
+ NV_ASSERT(status == NV_OK);
+ }
+}
+
+static void
+osDestroyOsDescriptorFromDmaBuf
+(
+ PMEMORY_DESCRIPTOR pMemDesc
+)
+{
+ OBJGPU *pGpu = pMemDesc->pGpu;
+ void *pPrivate = memdescGetMemData(pMemDesc);
+
+ struct sg_table *pImportSgt;
+ void *pImportPriv;
+
+ /*
+ * Unmap IOMMU now or we will get a kernel crash when it is unmapped after
+ * pImportSgt is freed.
+ */
+ memdescUnmapIommu(pMemDesc, pGpu->busInfo.iovaspaceId);
+
+ if (IS_DISCONTIG_AND_DYNGRAN_ENABLED(pMemDesc))
+ {
+ // Because os_page_size == pMemDesc->pageArrayGranularity, we don't need to do any page array conversion.
+ NV_ASSERT_OR_RETURN_VOID(os_page_size == pMemDesc->pageArrayGranularity);
+ }
+ else if ((NV_RM_PAGE_SIZE < os_page_size) &&
+ !memdescGetContiguity(pMemDesc, AT_CPU))
+ {
+ RmDeflateRmToOsPageArray(memdescGetPteArray(pMemDesc, AT_CPU),
+ pMemDesc->PageCount);
+ }
+
+ nv_unregister_sgt(NV_GET_NV_STATE(pGpu), &pImportSgt,
+ &pImportPriv, pPrivate);
+
+ /*
+ * pImportSgt doesn't need to be passed to nv_dma_release_dma_buf() because
+ * the DMA-BUF associated with pImportPriv already has a reference to the
+ * SGT.
+ */
+
+ nv_dma_release_dma_buf(pImportPriv);
+}
+
+static void
+osDestroyOsDescriptorFromSgt
+(
+ PMEMORY_DESCRIPTOR pMemDesc
+)
+{
+ OBJGPU *pGpu = pMemDesc->pGpu;
+ void *pPrivate = memdescGetMemData(pMemDesc);
+
+ struct sg_table *pImportSgt;
+ struct drm_gem_object *pImportPrivGem;
+
+ NV_ASSERT(pPrivate != NULL);
+
+ /*
+ * Unmap IOMMU now or we will get a kernel crash when it is unmapped after
+ * pImportSgt is freed.
+ */
+ memdescUnmapIommu(pMemDesc, pGpu->busInfo.iovaspaceId);
+
+ if (IS_DISCONTIG_AND_DYNGRAN_ENABLED(pMemDesc))
+ {
+ // Because os_page_size == pMemDesc->pageArrayGranularity, we don't need to do any page array conversion.
+ NV_ASSERT_OR_RETURN_VOID(os_page_size == pMemDesc->pageArrayGranularity);
+ }
+ else if ((NV_RM_PAGE_SIZE < os_page_size) &&
+ !memdescGetContiguity(pMemDesc, AT_CPU))
+ {
+ RmDeflateRmToOsPageArray(memdescGetPteArray(pMemDesc, AT_CPU),
+ pMemDesc->PageCount);
+ }
+
+ nv_unregister_sgt(NV_GET_NV_STATE(pGpu), &pImportSgt,
+ (void **) &pImportPrivGem, pPrivate);
+
+ nv_dma_release_sgt(pImportSgt, pImportPrivGem);
+}
diff --git a/userspace/sdks/nv570/nvalloc/unix/src/osnvlink.c b/userspace/sdks/nv570/nvalloc/unix/src/osnvlink.c
new file mode 100644
index 0000000..af65f9e
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/src/osnvlink.c
@@ -0,0 +1,783 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2015-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <nv.h>
+#include "kernel/gpu/nvlink/kernel_nvlink.h"
+#include "osapi.h"
+
+#if defined(INCLUDE_NVLINK_LIB)
+#include "nvlink.h"
+//
+// The functions in this file are a workaround for a significant design flaw
+// where RM callbacks for the nvlink library are built with the altstack
+// enabled, but the nvlink library is not built with altstack support. Whenever
+// the library calls a callback, the stack switching needs to be accounted for
+// or else we will observe corruption of data structures in the nvlink library
+// as data is pushed onto what the callback thinks is the stack. See bug
+// 1710300.
+//
+// This bug has also exposed other problems, such as the complete lack of
+// locking awareness by these callbacks (e.g., assumption that the RMAPI and
+// GPU locks are always held on entry, which is not a legitimate assumption).
+// For now, we ignore that just to unblock testing.
+//
+extern NvlStatus knvlinkCoreAddLinkCallback(struct nvlink_link *);
+extern NvlStatus knvlinkCoreRemoveLinkCallback(struct nvlink_link *);
+extern NvlStatus knvlinkCoreLockLinkCallback(struct nvlink_link *);
+extern void knvlinkCoreUnlockLinkCallback(struct nvlink_link *);
+extern NvlStatus knvlinkCoreQueueLinkChangeCallback(struct nvlink_link_change *);
+extern NvlStatus knvlinkCoreSetDlLinkModeCallback(struct nvlink_link *, NvU64, NvU32);
+extern NvlStatus knvlinkCoreGetDlLinkModeCallback(struct nvlink_link *, NvU64 *);
+extern NvlStatus knvlinkCoreSetTlLinkModeCallback(struct nvlink_link *, NvU64, NvU32);
+extern NvlStatus knvlinkCoreGetTlLinkModeCallback(struct nvlink_link *, NvU64 *);
+extern NvlStatus knvlinkCoreGetTxSublinkModeCallback(struct nvlink_link *, NvU64 *, NvU32 *);
+extern NvlStatus knvlinkCoreSetTxSublinkModeCallback(struct nvlink_link *, NvU64, NvU32);
+extern NvlStatus knvlinkCoreGetRxSublinkModeCallback(struct nvlink_link *, NvU64 *, NvU32 *);
+extern NvlStatus knvlinkCoreSetRxSublinkModeCallback(struct nvlink_link *, NvU64, NvU32);
+extern NvlStatus knvlinkCoreReadDiscoveryTokenCallback(struct nvlink_link *, NvU64 *);
+extern NvlStatus knvlinkCoreWriteDiscoveryTokenCallback(struct nvlink_link *, NvU64);
+extern void knvlinkCoreTrainingCompleteCallback(struct nvlink_link *);
+extern void knvlinkCoreGetUphyLoadCallback(struct nvlink_link *, NvBool*);
+extern NvlStatus knvlinkCoreGetCciLinkModeCallback(struct nvlink_link *, NvU64 *);
+
+/*!
+ * @brief Helper to allocate an alternate stack from within core RM.
+ *
+ * This needs to be an NV_API_CALL (built to use the original stack instead
+ * of the altstack) since it is called before we switch to using the altstack.
+ */
+static NV_STATUS NV_API_CALL osNvlinkAllocAltStack(nvidia_stack_t **pSp)
+{
+ NV_STATUS status = NV_OK;
+ nvidia_stack_t *sp = NULL;
+#if defined(NVCPU_X86_64) && defined(__use_altstack__)
+ status = os_alloc_mem((void **)&sp, sizeof(nvidia_stack_t));
+ if (status == NV_OK)
+ {
+ sp->size = sizeof(sp->stack);
+ sp->top = sp->stack + sp->size;
+ }
+#endif
+ *pSp = sp;
+ return status;
+}
+
+/*!
+ * @brief Helper to free an alternate stack from within core RM.
+ *
+ * This needs to be an NV_API_CALL (built to use the original stack instead
+ * of the altstack) since it is called after we've switched back to using the
+ * original stack.
+ */
+static void NV_API_CALL osNvlinkFreeAltStack(nvidia_stack_t *sp)
+{
+#if defined(NVCPU_X86_64) && defined(__use_altstack__)
+ os_free_mem(sp);
+#endif
+}
+
+static NV_STATUS NV_API_CALL osNvlinkGetAltStack(nvidia_stack_t **sp)
+{
+ return osNvlinkAllocAltStack(sp);
+}
+static void NV_API_CALL osNvlinkPutAltStack(nvidia_stack_t *sp)
+{
+ osNvlinkFreeAltStack(sp);
+}
+
+static NvlStatus NV_API_CALL rm_nvlink_ops_add_link
+(
+ struct nvlink_link *link
+)
+{
+ void *fp;
+ NvlStatus status;
+ nvidia_stack_t *sp;
+
+ if (osNvlinkGetAltStack(&sp) != NV_OK)
+ {
+ return NVL_ERR_GENERIC;
+ }
+
+ NV_ENTER_RM_RUNTIME(sp, fp);
+
+ status = knvlinkCoreAddLinkCallback(link);
+
+ NV_EXIT_RM_RUNTIME(sp, fp);
+
+ osNvlinkPutAltStack(sp);
+
+ return status;
+}
+
+static NvlStatus NV_API_CALL rm_nvlink_ops_remove_link
+(
+ struct nvlink_link *link
+)
+{
+ void *fp;
+ NvlStatus status;
+ nvidia_stack_t *sp;
+
+ if (osNvlinkGetAltStack(&sp) != NV_OK)
+ {
+ return NVL_ERR_GENERIC;
+ }
+
+ NV_ENTER_RM_RUNTIME(sp, fp);
+
+ status = knvlinkCoreRemoveLinkCallback(link);
+
+ NV_EXIT_RM_RUNTIME(sp, fp);
+
+ osNvlinkPutAltStack(sp);
+
+ return status;
+}
+
+static NvlStatus NV_API_CALL rm_nvlink_ops_lock_link
+(
+ struct nvlink_link *link
+)
+{
+ void *fp;
+ NvlStatus status;
+ THREAD_STATE_NODE threadState = {0};
+ nvidia_stack_t *sp;
+
+ if (osNvlinkGetAltStack(&sp) != NV_OK)
+ {
+ return NVL_ERR_GENERIC;
+ }
+
+ NV_ENTER_RM_RUNTIME(sp, fp);
+
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+ status = knvlinkCoreLockLinkCallback(link);
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ NV_EXIT_RM_RUNTIME(sp, fp);
+
+ osNvlinkPutAltStack(sp);
+
+ return status;
+}
+
+static void NV_API_CALL rm_nvlink_ops_unlock_link
+(
+ struct nvlink_link *link
+)
+{
+ void *fp;
+ THREAD_STATE_NODE threadState = {0};
+ nvidia_stack_t *sp;
+
+ if (osNvlinkGetAltStack(&sp) != NV_OK)
+ {
+ return;
+ }
+
+ NV_ENTER_RM_RUNTIME(sp, fp);
+
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+ knvlinkCoreUnlockLinkCallback(link);
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ NV_EXIT_RM_RUNTIME(sp, fp);
+
+ osNvlinkPutAltStack(sp);
+}
+
+static NvlStatus NV_API_CALL rm_nvlink_ops_queue_link_change
+(
+ struct nvlink_link_change *link_change
+)
+{
+ void *fp;
+ NvlStatus status;
+ THREAD_STATE_NODE threadState = {0};
+ nvidia_stack_t *sp;
+
+ if (osNvlinkGetAltStack(&sp) != NV_OK)
+ {
+ return NVL_ERR_GENERIC;
+ }
+
+ NV_ENTER_RM_RUNTIME(sp, fp);
+
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+ status = knvlinkCoreQueueLinkChangeCallback(link_change);
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ NV_EXIT_RM_RUNTIME(sp, fp);
+
+ osNvlinkPutAltStack(sp);
+
+ return status;
+}
+
+static NvlStatus NV_API_CALL rm_nvlink_ops_set_dl_link_mode
+(
+ struct nvlink_link *link,
+ NvU64 mode,
+ NvU32 flags
+)
+{
+ void *fp;
+ NvlStatus status;
+ THREAD_STATE_NODE threadState = {0};
+ nvidia_stack_t *sp;
+
+ if (osNvlinkGetAltStack(&sp) != NV_OK)
+ {
+ return NVL_ERR_GENERIC;
+ }
+
+ NV_ENTER_RM_RUNTIME(sp, fp);
+
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+ status = knvlinkCoreSetDlLinkModeCallback(link, mode, flags);
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ NV_EXIT_RM_RUNTIME(sp, fp);
+
+ osNvlinkPutAltStack(sp);
+
+ return status;
+}
+
+static NvlStatus NV_API_CALL rm_nvlink_ops_get_dl_link_mode
+(
+ struct nvlink_link *link,
+ NvU64 *mode
+)
+{
+ void *fp;
+ NvlStatus status;
+ THREAD_STATE_NODE threadState = {0};
+ nvidia_stack_t *sp;
+
+ if (osNvlinkGetAltStack(&sp) != NV_OK)
+ {
+ return NVL_ERR_GENERIC;
+ }
+
+ NV_ENTER_RM_RUNTIME(sp, fp);
+
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+ status = knvlinkCoreGetDlLinkModeCallback(link, mode);
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ NV_EXIT_RM_RUNTIME(sp, fp);
+
+ osNvlinkPutAltStack(sp);
+
+ return status;
+}
+
+static NvlStatus NV_API_CALL rm_nvlink_ops_set_tl_link_mode
+(
+ struct nvlink_link *link,
+ NvU64 mode,
+ NvU32 flags
+)
+{
+ void *fp;
+ NvlStatus status;
+ THREAD_STATE_NODE threadState = {0};
+ nvidia_stack_t *sp;
+
+ if (osNvlinkGetAltStack(&sp) != NV_OK)
+ {
+ return NVL_ERR_GENERIC;
+ }
+
+ NV_ENTER_RM_RUNTIME(sp, fp);
+
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+ status = knvlinkCoreSetTlLinkModeCallback(link, mode, flags);
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ NV_EXIT_RM_RUNTIME(sp, fp);
+ osNvlinkPutAltStack(sp);
+
+ return status;
+}
+
+static NvlStatus NV_API_CALL rm_nvlink_ops_get_tl_link_mode
+(
+ struct nvlink_link *link,
+ NvU64 *mode
+)
+{
+ void *fp;
+ NvlStatus status;
+ THREAD_STATE_NODE threadState = {0};
+ nvidia_stack_t *sp;
+
+ if (osNvlinkGetAltStack(&sp) != NV_OK)
+ {
+ return NVL_ERR_GENERIC;
+ }
+
+ NV_ENTER_RM_RUNTIME(sp, fp);
+
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+ status = knvlinkCoreGetTlLinkModeCallback(link, mode);
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ NV_EXIT_RM_RUNTIME(sp, fp);
+
+ osNvlinkPutAltStack(sp);
+
+ return status;
+}
+
+static NvlStatus NV_API_CALL rm_nvlink_ops_set_link_tx_mode
+(
+ struct nvlink_link *link,
+ NvU64 mode,
+ NvU32 flags
+)
+{
+ void *fp;
+ NvlStatus status;
+ THREAD_STATE_NODE threadState = {0};
+ nvidia_stack_t *sp;
+
+ if (osNvlinkGetAltStack(&sp) != NV_OK)
+ {
+ return NVL_ERR_GENERIC;
+ }
+
+ NV_ENTER_RM_RUNTIME(sp, fp);
+
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+ status = knvlinkCoreSetTxSublinkModeCallback(link, mode, flags);
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ NV_EXIT_RM_RUNTIME(sp, fp);
+
+ osNvlinkPutAltStack(sp);
+
+ return status;
+}
+
+static NvlStatus NV_API_CALL rm_nvlink_ops_get_link_tx_mode
+(
+ struct nvlink_link *link,
+ NvU64 *mode,
+ NvU32 *subMode
+)
+{
+ void *fp;
+ NvlStatus status;
+ THREAD_STATE_NODE threadState = {0};
+ nvidia_stack_t *sp;
+
+ if (osNvlinkGetAltStack(&sp) != NV_OK)
+ {
+ return NVL_ERR_GENERIC;
+ }
+
+ NV_ENTER_RM_RUNTIME(sp, fp);
+
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+ status = knvlinkCoreGetTxSublinkModeCallback(link, mode, subMode);
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ NV_EXIT_RM_RUNTIME(sp, fp);
+
+ osNvlinkPutAltStack(sp);
+
+ return status;
+}
+
+static NvlStatus NV_API_CALL rm_nvlink_ops_set_link_rx_mode
+(
+ struct nvlink_link *link,
+ NvU64 mode,
+ NvU32 flags
+)
+{
+ void *fp;
+ NvlStatus status;
+ THREAD_STATE_NODE threadState = {0};
+ nvidia_stack_t *sp;
+
+ if (osNvlinkGetAltStack(&sp) != NV_OK)
+ {
+ return NVL_ERR_GENERIC;
+ }
+
+ NV_ENTER_RM_RUNTIME(sp, fp);
+
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+ status = knvlinkCoreSetRxSublinkModeCallback(link, mode, flags);
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ NV_EXIT_RM_RUNTIME(sp, fp);
+
+ osNvlinkPutAltStack(sp);
+
+ return status;
+}
+
+static NvlStatus NV_API_CALL rm_nvlink_ops_get_link_rx_mode
+(
+ struct nvlink_link *link,
+ NvU64 *mode,
+ NvU32 *subMode
+)
+{
+ void *fp;
+ NvlStatus status;
+ THREAD_STATE_NODE threadState = {0};
+ nvidia_stack_t *sp;
+
+ if (osNvlinkGetAltStack(&sp) != NV_OK)
+ {
+ return NVL_ERR_GENERIC;
+ }
+
+ NV_ENTER_RM_RUNTIME(sp, fp);
+
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+ status = knvlinkCoreGetRxSublinkModeCallback(link, mode, subMode);
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ NV_EXIT_RM_RUNTIME(sp, fp);
+
+ osNvlinkPutAltStack(sp);
+
+ return status;
+}
+
+static NvlStatus NV_API_CALL rm_nvlink_ops_set_link_rx_detect
+(
+ struct nvlink_link *link,
+ NvU32 flags
+)
+{
+ void *fp;
+ NvlStatus status;
+ THREAD_STATE_NODE threadState = {0};
+ nvidia_stack_t *sp;
+
+ if (osNvlinkGetAltStack(&sp) != NV_OK)
+ {
+ return NVL_ERR_GENERIC;
+ }
+
+ NV_ENTER_RM_RUNTIME(sp, fp);
+
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+ status = knvlinkCoreSetRxSublinkDetectCallback(link, flags);
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ NV_EXIT_RM_RUNTIME(sp, fp);
+
+ osNvlinkPutAltStack(sp);
+
+ return status;
+}
+
+static NvlStatus NV_API_CALL rm_nvlink_ops_get_link_rx_detect
+(
+ struct nvlink_link *link
+)
+{
+ void *fp;
+ NvlStatus status;
+ THREAD_STATE_NODE threadState = {0};
+ nvidia_stack_t *sp;
+
+ if (osNvlinkGetAltStack(&sp) != NV_OK)
+ {
+ return NVL_ERR_GENERIC;
+ }
+
+ NV_ENTER_RM_RUNTIME(sp, fp);
+
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+ status = knvlinkCoreGetRxSublinkDetectCallback(link);
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ NV_EXIT_RM_RUNTIME(sp, fp);
+
+ osNvlinkPutAltStack(sp);
+
+ return status;
+}
+
+static void NV_API_CALL rm_nvlink_get_uphy_load
+(
+ struct nvlink_link *link,
+ NvBool *bUnlocked
+)
+{
+ void *fp;
+ THREAD_STATE_NODE threadState = {0};
+ nvidia_stack_t *sp;
+
+ if (osNvlinkGetAltStack(&sp) != NV_OK)
+ {
+ return;
+ }
+
+ NV_ENTER_RM_RUNTIME(sp, fp);
+
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+ knvlinkCoreGetUphyLoadCallback(link, bUnlocked);
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ NV_EXIT_RM_RUNTIME(sp, fp);
+
+ osNvlinkPutAltStack(sp);
+}
+
+static NvlStatus NV_API_CALL rm_nvlink_ops_read_link_discovery_token
+(
+ struct nvlink_link *link,
+ NvU64 *token
+)
+{
+ void *fp;
+ NvlStatus status;
+ THREAD_STATE_NODE threadState = {0};
+ nvidia_stack_t *sp;
+
+ if (osNvlinkGetAltStack(&sp) != NV_OK)
+ {
+ return NVL_ERR_GENERIC;
+ }
+
+ NV_ENTER_RM_RUNTIME(sp, fp);
+
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+ status = knvlinkCoreReadDiscoveryTokenCallback(link, token);
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ NV_EXIT_RM_RUNTIME(sp, fp);
+
+ osNvlinkPutAltStack(sp);
+
+ return status;
+}
+
+static NvlStatus NV_API_CALL rm_nvlink_ops_write_link_discovery_token
+(
+ struct nvlink_link *link,
+ NvU64 token
+)
+{
+ void *fp;
+ NvlStatus status;
+ THREAD_STATE_NODE threadState = {0};
+ nvidia_stack_t *sp;
+
+ if (osNvlinkGetAltStack(&sp) != NV_OK)
+ {
+ return NVL_ERR_GENERIC;
+ }
+
+ NV_ENTER_RM_RUNTIME(sp, fp);
+
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+ status = knvlinkCoreWriteDiscoveryTokenCallback(link, token);
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ NV_EXIT_RM_RUNTIME(sp, fp);
+
+ osNvlinkPutAltStack(sp);
+
+ return status;
+}
+
+static void NV_API_CALL rm_nvlink_ops_training_complete
+(
+ struct nvlink_link *link
+)
+{
+ void *fp;
+ THREAD_STATE_NODE threadState = {0};
+ nvidia_stack_t *sp;
+
+ if (osNvlinkGetAltStack(&sp) != NV_OK)
+ {
+ return;
+ }
+
+ NV_ENTER_RM_RUNTIME(sp, fp);
+
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+ knvlinkCoreTrainingCompleteCallback(link);
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ NV_EXIT_RM_RUNTIME(sp, fp);
+
+ osNvlinkPutAltStack(sp);
+}
+
+static NvlStatus NV_API_CALL rm_nvlink_ops_ali_training
+(
+ struct nvlink_link *link
+)
+{
+ void *fp;
+ NvlStatus status;
+ THREAD_STATE_NODE threadState = {0};
+ nvidia_stack_t * sp;
+
+ if (osNvlinkGetAltStack(&sp) != NV_OK)
+ {
+ return NVL_ERR_GENERIC;
+ }
+
+ NV_ENTER_RM_RUNTIME(sp, fp);
+
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+ status = knvlinkCoreAliTrainingCallback(link);
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ NV_EXIT_RM_RUNTIME(sp, fp);
+
+ osNvlinkPutAltStack(sp);
+ return status;
+}
+
+static NvlStatus NV_API_CALL rm_nvlink_ops_get_cci_link_mode
+(
+ struct nvlink_link *link,
+ NvU64 *mode
+)
+{
+ return NVL_SUCCESS;
+}
+
+#endif /* defined(INCLUDE_NVLINK_LIB) */
+
+const struct nvlink_link_handlers* osGetNvlinkLinkCallbacks(void)
+{
+#if defined(INCLUDE_NVLINK_LIB)
+ static const struct nvlink_link_handlers rm_nvlink_link_ops =
+ {
+ .add = rm_nvlink_ops_add_link,
+ .remove = rm_nvlink_ops_remove_link,
+ .lock = rm_nvlink_ops_lock_link,
+ .unlock = rm_nvlink_ops_unlock_link,
+ .queue_link_change = rm_nvlink_ops_queue_link_change,
+ .set_dl_link_mode = rm_nvlink_ops_set_dl_link_mode,
+ .get_dl_link_mode = rm_nvlink_ops_get_dl_link_mode,
+ .set_tl_link_mode = rm_nvlink_ops_set_tl_link_mode,
+ .get_tl_link_mode = rm_nvlink_ops_get_tl_link_mode,
+ .set_tx_mode = rm_nvlink_ops_set_link_tx_mode,
+ .get_tx_mode = rm_nvlink_ops_get_link_tx_mode,
+ .set_rx_mode = rm_nvlink_ops_set_link_rx_mode,
+ .get_rx_mode = rm_nvlink_ops_get_link_rx_mode,
+ .set_rx_detect = rm_nvlink_ops_set_link_rx_detect,
+ .get_rx_detect = rm_nvlink_ops_get_link_rx_detect,
+ .write_discovery_token = rm_nvlink_ops_write_link_discovery_token,
+ .read_discovery_token = rm_nvlink_ops_read_link_discovery_token,
+ .training_complete = rm_nvlink_ops_training_complete,
+ .get_uphy_load = rm_nvlink_get_uphy_load,
+ .get_cci_link_mode = rm_nvlink_ops_get_cci_link_mode,
+ .ali_training = rm_nvlink_ops_ali_training,
+ };
+
+ return &rm_nvlink_link_ops;
+#else
+ return NULL;
+#endif
+}
+
+/*
+ * @brief Verif only function to get the chiplib overrides for link connection
+ * state for all NVLINKs.
+ *
+ * If chiplib overrides exist, each link can either be enabled (1) or disabled (0)
+ *
+ * @param[in] pGpu GPU object pointer
+ * @param[in] maxLinks Size of pLinkConnection array
+ * @param[out] pLinkConnection array of pLinkConnection values to be populated by MODS
+ *
+ * @return NV_OK or NV_ERR_NOT_SUPPORTED (no overrides available)
+ */
+NV_STATUS
+osGetForcedNVLinkConnection
+(
+ OBJGPU *pGpu,
+ NvU32 maxLinks,
+ NvU32 *pLinkConnection
+)
+{
+ int i, ret;
+ NV_STATUS status;
+ char path[64];
+
+ NV_ASSERT_OR_RETURN((pLinkConnection != NULL), NV_ERR_INVALID_POINTER);
+ NV_ASSERT_OR_RETURN((maxLinks > 0), NV_ERR_NOT_SUPPORTED);
+ NV_ASSERT_OR_RETURN((pGpu != NULL), NV_ERR_INVALID_ARGUMENT);
+
+ for (i = 0; i < maxLinks; i++)
+ {
+ ret = os_snprintf(path, sizeof(path), "CPU_MODEL|CM_ATS_ADDRESS|NVLink%u", i);
+ NV_ASSERT((ret > 0) && (ret < (sizeof(path) - 1)));
+
+ status = gpuSimEscapeRead(pGpu, path, 0, 4, &pLinkConnection[i]);
+ if (status == NV_OK)
+ {
+ NV_PRINTF(LEVEL_INFO, "%s: %s=0x%X\n", __FUNCTION__,
+ path, pLinkConnection[i]);
+ }
+ else
+ {
+ NV_PRINTF(LEVEL_INFO, "%s: gpuSimEscapeRead for '%s' failed (%u)\n",
+ __FUNCTION__, path, status);
+ return NV_ERR_NOT_SUPPORTED;
+ }
+ }
+ return NV_OK;
+}
+
+/*
+ * @brief Get Platform suggested NVLink linerate
+ *
+ * NVLink will use this function to get the platform suggested linerate
+ * if available in FRU or device tree.
+ *
+ * @param[in] pGpu GPU object pointer
+ * @param[out] NvU32 * Suggested datarate
+ *
+ * @return NV_OK or NV_ERR_NOT_SUPPORTED (platform linerate data not available)
+ */
+NV_STATUS
+osGetPlatformNvlinkLinerate
+(
+ OBJGPU *pGpu,
+ NvU32 *lineRate
+)
+{
+ // TODO: Remove this function
+ return NV_ERR_NOT_SUPPORTED;
+}
diff --git a/userspace/sdks/nv570/nvalloc/unix/src/osunix.c b/userspace/sdks/nv570/nvalloc/unix/src/osunix.c
new file mode 100644
index 0000000..635bf86
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/src/osunix.c
@@ -0,0 +1,42 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 1993-2021 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+
+/***************************** HW State Routines ***************************\
+* *
+* Fills in os specific function pointers for the Unix OS object. *
+* *
+\***************************************************************************/
+
+#include <os/os.h>
+#include <core/system.h>
+
+void
+osInitObjOS(OBJOS *pOS)
+{
+ OBJSYS *pSys = SYS_GET_INSTANCE();
+
+ pSys->setProperty(pSys, PDB_PROP_SYS_ONDEMAND_VBLANK_CONTROL_ENABLE_DEFAULT, NV_TRUE);
+ pOS->setProperty(pOS, PDB_PROP_OS_CACHED_MEMORY_MAPPINGS_FOR_ACPI_TABLE, NV_TRUE);
+ pOS->setProperty(pOS, PDB_PROP_OS_LIMIT_GPU_RESET, NV_TRUE);
+}
diff --git a/userspace/sdks/nv570/nvalloc/unix/src/power-management-tegra.c b/userspace/sdks/nv570/nvalloc/unix/src/power-management-tegra.c
new file mode 100644
index 0000000..38c91d0
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/src/power-management-tegra.c
@@ -0,0 +1,100 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2022-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <nv.h>
+
+#include <nv-priv.h>
+#include <osapi.h>
+#include <core/locks.h>
+
+NV_STATUS
+RmPowerManagementTegra(
+ OBJGPU *pGpu,
+ nv_pm_action_t pmAction
+)
+{
+ //
+ // Default to NV_OK. there may cases where resman is loaded, but
+ // no devices are allocated (we're still at the console). in these
+ // cases, it's fine to let the system do whatever it wants.
+ //
+ NV_STATUS rmStatus = NV_OK;
+
+ if (pGpu)
+ {
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+
+ switch (pmAction)
+ {
+ case NV_PM_ACTION_HIBERNATE:
+ nvp->pm_state.InHibernate = NV_TRUE;
+ pGpu->setProperty(pGpu, PDB_PROP_GPU_IN_PM_CODEPATH, NV_TRUE);
+ rmStatus = gpuStateUnload(pGpu, GPU_STATE_FLAGS_PM_HIBERNATE |
+ GPU_STATE_FLAGS_PRESERVING |
+ GPU_STATE_FLAGS_PM_TRANSITION);
+ pGpu->setProperty(pGpu, PDB_PROP_GPU_IN_HIBERNATE, NV_TRUE);
+ break;
+
+ case NV_PM_ACTION_STANDBY:
+ nvp->pm_state.InHibernate = NV_FALSE;
+ pGpu->setProperty(pGpu, PDB_PROP_GPU_IN_PM_CODEPATH, NV_TRUE);
+ rmStatus = gpuStateUnload(pGpu, GPU_STATE_FLAGS_PM_SUSPEND |
+ GPU_STATE_FLAGS_PRESERVING |
+ GPU_STATE_FLAGS_PM_TRANSITION);;
+ pGpu->setProperty(pGpu, PDB_PROP_GPU_IN_STANDBY, NV_TRUE);
+ pGpu->bInD3Cold = NV_TRUE;
+ break;
+
+ case NV_PM_ACTION_RESUME:
+ pGpu->setProperty(pGpu, PDB_PROP_GPU_IN_PM_RESUME_CODEPATH, NV_TRUE);
+
+ if (nvp->pm_state.InHibernate)
+ {
+ rmStatus = gpuStateLoad(pGpu, GPU_STATE_FLAGS_PM_HIBERNATE |
+ GPU_STATE_FLAGS_PRESERVING |
+ GPU_STATE_FLAGS_PM_TRANSITION);;
+ pGpu->setProperty(pGpu, PDB_PROP_GPU_IN_HIBERNATE, NV_FALSE);
+ }
+ else
+ {
+ rmStatus = gpuStateLoad(pGpu, GPU_STATE_FLAGS_PM_SUSPEND |
+ GPU_STATE_FLAGS_PRESERVING |
+ GPU_STATE_FLAGS_PM_TRANSITION);;
+ pGpu->setProperty(pGpu, PDB_PROP_GPU_IN_STANDBY, NV_FALSE);
+ pGpu->bInD3Cold = NV_FALSE;
+ }
+
+ pGpu->setProperty(pGpu, PDB_PROP_GPU_IN_PM_CODEPATH, NV_FALSE);
+ pGpu->setProperty(pGpu, PDB_PROP_GPU_IN_PM_RESUME_CODEPATH, NV_FALSE);
+ break;
+
+ default:
+ rmStatus = NV_ERR_INVALID_ARGUMENT;
+ break;
+ }
+ }
+
+ return rmStatus;
+}
+
diff --git a/userspace/sdks/nv570/nvalloc/unix/src/registry.c b/userspace/sdks/nv570/nvalloc/unix/src/registry.c
new file mode 100644
index 0000000..70bbcc5
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/src/registry.c
@@ -0,0 +1,712 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 1999-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <nv.h>
+#include <nv-priv.h>
+#include <nvos.h>
+
+#if defined(DEBUG_REGISTRY)
+#define DBG_REG_PRINTF(a, ...) \
+ NV_PRINTF(LEVEL_INFO, a, ##__VA_ARGS__)
+#else
+#define DBG_REG_PRINTF(a, ...)
+#endif
+
+static NvS32 stringCaseCompare(
+ const char *string1,
+ const char *string2
+)
+{
+ NvU8 c1, c2;
+
+ do
+ {
+ c1 = *string1, c2 = *string2;
+ if (c1 >= 'A' && c1 <= 'Z')
+ c1 += ('a' - 'A');
+ if (c2 >= 'A' && c2 <= 'Z')
+ c2 += ('a' - 'A');
+ string1++, string2++;
+ }
+ while ((c1 == c2) && (c1 != '\0'));
+
+ return (c1 - c2);
+}
+
+static nv_reg_entry_t *the_registry = NULL;
+
+static nv_reg_entry_t* regCreateNewRegistryKey(
+ nv_state_t *nv,
+ const char *regParmStr
+)
+{
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+ nv_reg_entry_t *new_reg = NULL;
+ char *new_ParmStr = NULL;
+ NvU32 parm_size;
+
+ if (regParmStr == NULL)
+ {
+ DBG_BREAKPOINT();
+ return NULL;
+ }
+
+ new_reg = portMemAllocNonPaged(sizeof(nv_reg_entry_t));
+ if (NULL == new_reg)
+ {
+ NV_PRINTF(LEVEL_ERROR, "failed to grow registry\n");
+ return NULL;
+ }
+
+ portMemSet(new_reg, 0, sizeof(nv_reg_entry_t));
+
+ if (regParmStr != NULL)
+ {
+ parm_size = (portStringLength(regParmStr) + 1);
+ new_ParmStr = portMemAllocNonPaged(parm_size);
+ if (NULL == new_ParmStr)
+ {
+ NV_PRINTF(LEVEL_ERROR, "failed to allocate registry param string\n");
+ portMemFree(new_reg);
+ return NULL;
+ }
+
+ NV_ASSERT(parm_size <= NVOS38_MAX_REGISTRY_STRING_LENGTH);
+
+ if (portMemCopy(new_ParmStr, parm_size, regParmStr, parm_size) == NULL)
+ {
+ NV_PRINTF(LEVEL_ERROR, "failed to copy registry param string\n");
+ portMemFree(new_ParmStr);
+ portMemFree(new_reg);
+ return NULL;
+ }
+ }
+
+ new_reg->regParmStr = new_ParmStr;
+ new_reg->type = NV_REGISTRY_ENTRY_TYPE_UNKNOWN;
+
+ if (nvp != NULL)
+ {
+ new_reg->next = nvp->pRegistry;
+ nvp->pRegistry = new_reg;
+ DBG_REG_PRINTF("local registry now at 0x%p\n", nvp->pRegistry);
+ }
+ else
+ {
+ new_reg->next = the_registry;
+ the_registry = new_reg;
+ DBG_REG_PRINTF("global registry now at 0x%p\n", the_registry);
+ }
+
+ return new_reg;
+}
+
+static NV_STATUS regFreeEntry(nv_reg_entry_t *tmp)
+{
+ portMemFree(tmp->regParmStr);
+ tmp->regParmStr = NULL;
+ {
+ portMemFree(tmp->pdata);
+ tmp->pdata = NULL;
+ tmp->len = 0;
+ }
+ portMemFree(tmp);
+
+ return NV_OK;
+}
+
+static nv_reg_entry_t* regFindRegistryEntry(
+ nv_state_t *nv,
+ const char *regParmStr,
+ NvU32 type,
+ NvBool *bGlobalEntry
+)
+{
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+ nv_reg_entry_t *tmp;
+
+ DBG_REG_PRINTF("%s: %s\n", __FUNCTION__, regParmStr);
+
+ if (nvp != NULL)
+ {
+ tmp = nvp->pRegistry;
+ DBG_REG_PRINTF(" local registry at 0x%p\n", tmp);
+
+ while ((tmp != NULL) && (tmp->regParmStr != NULL))
+ {
+ DBG_REG_PRINTF(" Testing against %s\n",
+ tmp->regParmStr);
+ if ((stringCaseCompare(tmp->regParmStr, regParmStr) == 0) &&
+ (type == tmp->type))
+ {
+ DBG_REG_PRINTF(" found a match!\n");
+ if (bGlobalEntry)
+ *bGlobalEntry = NV_FALSE;
+ return tmp;
+ }
+ tmp = tmp->next;
+ }
+ }
+
+ tmp = the_registry;
+ DBG_REG_PRINTF(" global registry at 0x%p\n", tmp);
+
+ while ((tmp != NULL) && (tmp->regParmStr != NULL))
+ {
+ DBG_REG_PRINTF(" Testing against %s\n",
+ tmp->regParmStr);
+ if ((stringCaseCompare(tmp->regParmStr, regParmStr) == 0) &&
+ (type == tmp->type))
+ {
+ DBG_REG_PRINTF(" found a match!\n");
+ if (bGlobalEntry)
+ *bGlobalEntry = NV_TRUE;
+ return tmp;
+ }
+ tmp = tmp->next;
+ }
+
+ DBG_REG_PRINTF(" no match\n");
+ return NULL;
+}
+
+NV_STATUS RmWriteRegistryDword(
+ nv_state_t *nv,
+ const char *regParmStr,
+ NvU32 Data
+)
+{
+ nv_reg_entry_t *tmp;
+ NvBool bGlobalEntry;
+
+ if (regParmStr == NULL)
+ {
+ return NV_ERR_INVALID_ARGUMENT;
+ }
+
+ DBG_REG_PRINTF("%s: %s -> 0x%x\n", __FUNCTION__, regParmStr, Data);
+
+ tmp = regFindRegistryEntry(nv, regParmStr,
+ NV_REGISTRY_ENTRY_TYPE_DWORD, &bGlobalEntry);
+
+ // If we found an entry and we were looking for a global entry and
+ // found a global, or we were looking for a per-GPU entry and found a
+ // per-GPU entry
+ if (tmp != NULL &&
+ ((nv == NULL && bGlobalEntry) ||
+ (nv != NULL && !bGlobalEntry)))
+ {
+ tmp->data = Data;
+
+ if (stringCaseCompare(regParmStr, "ResmanDebugLevel") == 0)
+ {
+ os_dbg_set_level(Data);
+ }
+
+ return NV_OK;
+ }
+
+ tmp = regCreateNewRegistryKey(nv, regParmStr);
+ if (tmp == NULL)
+ return NV_ERR_GENERIC;
+
+ tmp->type = NV_REGISTRY_ENTRY_TYPE_DWORD;
+ tmp->data = Data;
+
+ return NV_OK;
+}
+
+NV_STATUS RmReadRegistryDword(
+ nv_state_t *nv,
+ const char *regParmStr,
+ NvU32 *Data
+)
+{
+ nv_reg_entry_t *tmp;
+
+ if ((regParmStr == NULL) || (Data == NULL))
+ {
+ return NV_ERR_INVALID_ARGUMENT;
+ }
+
+ DBG_REG_PRINTF("%s: %s\n", __FUNCTION__, regParmStr);
+
+ tmp = regFindRegistryEntry(nv, regParmStr,
+ NV_REGISTRY_ENTRY_TYPE_DWORD, NULL);
+ if (tmp == NULL)
+ {
+ tmp = regFindRegistryEntry(nv, regParmStr,
+ NV_REGISTRY_ENTRY_TYPE_BINARY, NULL);
+ if ((tmp != NULL) && (tmp->len >= sizeof(NvU32)))
+ {
+ *Data = *(NvU32 *)tmp->pdata;
+ }
+ else
+ {
+ DBG_REG_PRINTF(" not found\n");
+ return NV_ERR_GENERIC;
+ }
+ }
+ else
+ {
+ *Data = tmp->data;
+ }
+
+ DBG_REG_PRINTF(" found in the_registry: 0x%x\n", *Data);
+
+ return NV_OK;
+}
+
+NV_STATUS RmReadRegistryBinary(
+ nv_state_t *nv,
+ const char *regParmStr,
+ NvU8 *Data,
+ NvU32 *cbLen
+)
+{
+ nv_reg_entry_t *tmp;
+ NV_STATUS status;
+
+ if ((regParmStr == NULL) || (Data == NULL) || (cbLen == NULL))
+ {
+ return NV_ERR_INVALID_ARGUMENT;
+ }
+
+ DBG_REG_PRINTF("%s: %s\n", __FUNCTION__, regParmStr);
+
+ tmp = regFindRegistryEntry(nv, regParmStr,
+ NV_REGISTRY_ENTRY_TYPE_BINARY, NULL);
+ if (tmp == NULL)
+ {
+ DBG_REG_PRINTF(" not found\n");
+ return NV_ERR_GENERIC;
+ }
+
+ DBG_REG_PRINTF(" found\n");
+
+ if (*cbLen >= tmp->len)
+ {
+ portMemCopy((NvU8 *)Data, *cbLen, (NvU8 *)tmp->pdata, tmp->len);
+ *cbLen = tmp->len;
+ status = NV_OK;
+ }
+ else
+ {
+ NV_PRINTF(LEVEL_ERROR,
+ "buffer (length: %u) is too small (data length: %u)\n",
+ *cbLen, tmp->len);
+ status = NV_ERR_GENERIC;
+ }
+
+ return status;
+}
+
+NV_STATUS RmWriteRegistryBinary(
+ nv_state_t *nv,
+ const char *regParmStr,
+ NvU8 *Data,
+ NvU32 cbLen
+)
+{
+ nv_reg_entry_t *tmp;
+ NvBool bGlobalEntry;
+
+ if ((regParmStr == NULL) || (Data == NULL))
+ {
+ return NV_ERR_INVALID_ARGUMENT;
+ }
+
+ DBG_REG_PRINTF("%s: %s\n", __FUNCTION__, regParmStr);
+
+ tmp = regFindRegistryEntry(nv, regParmStr,
+ NV_REGISTRY_ENTRY_TYPE_BINARY, &bGlobalEntry);
+
+ // If we found an entry and we were looking for a global entry and
+ // found a global, or we were looking for a per-GPU entry and found a
+ // per-GPU entry
+ if (tmp != NULL &&
+ ((nv == NULL && bGlobalEntry) ||
+ (nv != NULL && !bGlobalEntry)))
+ {
+ if (tmp->pdata != NULL)
+ {
+ portMemFree(tmp->pdata);
+ tmp->pdata = NULL;
+ tmp->len = 0;
+ }
+ }
+ else
+ {
+ tmp = regCreateNewRegistryKey(nv, regParmStr);
+ if (tmp == NULL)
+ {
+ NV_PRINTF(LEVEL_ERROR, "failed to create binary registry entry\n");
+ return NV_ERR_GENERIC;
+ }
+ }
+
+ tmp->pdata = portMemAllocNonPaged(cbLen);
+ if (NULL == tmp->pdata)
+ {
+ NV_PRINTF(LEVEL_ERROR, "failed to write binary registry entry\n");
+ return NV_ERR_GENERIC;
+ }
+
+ tmp->type = NV_REGISTRY_ENTRY_TYPE_BINARY;
+ tmp->len = cbLen;
+ portMemCopy((NvU8 *)tmp->pdata, tmp->len, (NvU8 *)Data, cbLen);
+
+ return NV_OK;
+}
+
+NV_STATUS RmWriteRegistryString(
+ nv_state_t *nv,
+ const char *regParmStr,
+ const char *buffer,
+ NvU32 bufferLength
+)
+{
+ nv_reg_entry_t *tmp;
+ NvBool bGlobalEntry;
+
+ if ((regParmStr == NULL) || (buffer == NULL))
+ {
+ return NV_ERR_INVALID_ARGUMENT;
+ }
+
+ DBG_REG_PRINTF("%s: %s\n", __FUNCTION__, regParmStr);
+
+ tmp = regFindRegistryEntry(nv, regParmStr,
+ NV_REGISTRY_ENTRY_TYPE_STRING, &bGlobalEntry);
+
+ // If we found an entry and we were looking for a global entry and
+ // found a global, or we were looking for a per-GPU entry and found a
+ // per-GPU entry
+ if (tmp != NULL &&
+ ((nv == NULL && bGlobalEntry) ||
+ (nv != NULL && !bGlobalEntry)))
+ {
+ if (tmp->pdata != NULL)
+ {
+ portMemFree(tmp->pdata);
+ tmp->len = 0;
+ tmp->pdata = NULL;
+ }
+ }
+ else
+ {
+ tmp = regCreateNewRegistryKey(nv, regParmStr);
+ if (tmp == NULL)
+ {
+ NV_PRINTF(LEVEL_ERROR,
+ "failed to allocate a string registry entry!\n");
+ return NV_ERR_INSUFFICIENT_RESOURCES;
+ }
+ }
+
+ tmp->pdata = portMemAllocNonPaged(bufferLength);
+ if (tmp->pdata == NULL)
+ {
+ NV_PRINTF(LEVEL_ERROR, "failed to write a string registry entry!\n");
+ return NV_ERR_NO_MEMORY;
+ }
+
+ tmp->type = NV_REGISTRY_ENTRY_TYPE_STRING;
+ tmp->len = bufferLength;
+ portMemCopy((void *)tmp->pdata, tmp->len, buffer, (bufferLength - 1));
+ tmp->pdata[bufferLength-1] = '\0';
+
+ return NV_OK;
+}
+
+NV_STATUS RmReadRegistryString(
+ nv_state_t *nv,
+ const char *regParmStr,
+ NvU8 *buffer,
+ NvU32 *pBufferLength
+)
+{
+ NvU32 bufferLength;
+ nv_reg_entry_t *tmp;
+
+ if ((regParmStr == NULL) || (buffer == NULL) || (pBufferLength == NULL))
+ {
+ return NV_ERR_INVALID_ARGUMENT;
+ }
+
+ DBG_REG_PRINTF("%s: %s\n", __FUNCTION__, regParmStr);
+
+ bufferLength = *pBufferLength;
+ *pBufferLength = 0;
+ *buffer = '\0';
+
+ tmp = regFindRegistryEntry(nv, regParmStr,
+ NV_REGISTRY_ENTRY_TYPE_STRING, NULL);
+ if (tmp == NULL)
+ {
+ return NV_ERR_GENERIC;
+ }
+
+ if (bufferLength >= tmp->len)
+ {
+ portMemCopy((void *)buffer, bufferLength, (void *)tmp->pdata, tmp->len);
+ *pBufferLength = tmp->len;
+ }
+ else
+ {
+ NV_PRINTF(LEVEL_ERROR,
+ "buffer (length: %u) is too small (data length: %u)\n",
+ bufferLength, tmp->len);
+ return NV_ERR_BUFFER_TOO_SMALL;
+ }
+
+ return NV_OK;
+}
+
+
+NV_STATUS RmInitRegistry(void)
+{
+ NV_STATUS rmStatus;
+
+ rmStatus = os_registry_init();
+ if (rmStatus != NV_OK)
+ {
+ NV_PRINTF(LEVEL_ERROR, "failed to initialize the OS registry!\n");
+ }
+
+ return rmStatus;
+}
+
+NV_STATUS RmDestroyRegistry(nv_state_t *nv)
+{
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+ nv_reg_entry_t *tmp;
+
+ if (nvp != NULL)
+ {
+ tmp = nvp->pRegistry;
+ nvp->pRegistry = NULL;
+ }
+ else
+ {
+ tmp = the_registry;
+ the_registry = NULL;
+ }
+
+ while (tmp != NULL)
+ {
+ nv_reg_entry_t *entry = tmp;
+ tmp = tmp->next;
+ regFreeEntry(entry);
+ }
+
+ return NV_OK;
+}
+
+static void regCountEntriesAndSize(
+ NvU32 *pNumEntries, // Pointer to number of entries
+ NvU32 *pSize, // Pointer to total size
+ nv_reg_entry_t *pRegEntry // Pointer local or global registry
+)
+{
+ //
+ // Note that *pNumEntries and *pSize are not initialized here. This is so
+ // we can accumulate totals of both global and local registries.
+ //
+ NvU32 numEntries = *pNumEntries;
+ NvU32 size = *pSize;
+
+ while ((pRegEntry != NULL) && (pRegEntry->regParmStr != NULL))
+ {
+ size += portStringLength(pRegEntry->regParmStr) + 1 + pRegEntry->len;
+ numEntries++;
+ pRegEntry = pRegEntry->next;
+ }
+
+ *pNumEntries = numEntries;
+ *pSize = size;
+}
+
+static NV_STATUS regCopyEntriesToPackedBuffer(
+ PACKED_REGISTRY_TABLE *pRegTable, // Pointer to packed record
+ nv_reg_entry_t *pRegEntry, // Pointer local or global registry
+ NvU32 *pEntryIndex, // Pointer to next index
+ NvU32 *pDataOffset // Pointer to offset of next data byte.
+)
+{
+ NvU8 *pByte = (NvU8 *)pRegTable; // Byte version of record pointer.
+ NV_STATUS nvStatus = NV_OK;
+ NvU32 entryIndex = *pEntryIndex;
+ NvU32 dataOffset = *pDataOffset;
+
+ // Walk the records and copy the data.
+ while ((pRegEntry != NULL) && (pRegEntry->regParmStr != NULL))
+ {
+ PACKED_REGISTRY_ENTRY *pEntry = &pRegTable->entries[entryIndex];
+ NvU32 slen = portStringLength(pRegEntry->regParmStr) + 1;
+
+ // Sanity check the data offset and index against counted totals.
+ if ((dataOffset + slen + pRegEntry->len > pRegTable->size) ||
+ (entryIndex >= pRegTable->numEntries))
+ {
+ // Something has changed since we counted them?
+ NV_PRINTF(LEVEL_ERROR, "Registry entry record is full\n");
+ nvStatus = NV_ERR_INVALID_STATE;
+ break;
+ }
+
+ // Copy registry entry name to data blob.
+ pEntry->nameOffset = dataOffset;
+ portMemCopy(&pByte[dataOffset], slen, pRegEntry->regParmStr, slen);
+ dataOffset += slen;
+
+ switch (pRegEntry->type)
+ {
+ case NV_REGISTRY_ENTRY_TYPE_DWORD:
+ pEntry->type = REGISTRY_TABLE_ENTRY_TYPE_DWORD;
+ pEntry->length = sizeof(NvU32);
+ pEntry->data = pRegEntry->data;
+ break;
+
+ case NV_REGISTRY_ENTRY_TYPE_BINARY:
+ case NV_REGISTRY_ENTRY_TYPE_STRING:
+ pEntry->type = REGISTRY_TABLE_ENTRY_TYPE_STRING;
+ if (pRegEntry->type == NV_REGISTRY_ENTRY_TYPE_BINARY)
+ pEntry->type = REGISTRY_TABLE_ENTRY_TYPE_BINARY;
+
+ if (pRegEntry->len == 0)
+ {
+ NV_PRINTF(LEVEL_WARNING,
+ "Registry Key not sent to GSP-RM because it has 0 DataLength\n");
+ break;
+ }
+ pEntry->length = pRegEntry->len;
+ pEntry->data = dataOffset;
+ portMemCopy(&pByte[dataOffset], pEntry->length,
+ pRegEntry->pdata, pRegEntry->len);
+ dataOffset += pRegEntry->len;
+ break;
+
+ default:
+ // We should never get here.
+ pEntry->type = REGISTRY_TABLE_ENTRY_TYPE_UNKNOWN;
+ pEntry->length = 0;
+ pEntry->data = 0;
+ DBG_BREAKPOINT();
+ break;
+ }
+
+ pRegEntry = pRegEntry->next;
+ entryIndex++;
+ }
+
+ *pEntryIndex = entryIndex;
+ *pDataOffset = dataOffset;
+ return nvStatus;
+}
+
+// Package registry entries
+NV_STATUS RmPackageRegistry(
+ nv_state_t *nv,
+ PACKED_REGISTRY_TABLE *pRegTable,
+ NvU32 *pSize
+)
+{
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+ nv_reg_entry_t *pLocalRegistry = NULL;
+ NV_STATUS nvStatus = NV_OK;
+ NvU32 totalSize;
+ NvU32 numEntries;
+
+ if (pSize == NULL)
+ return NV_ERR_INVALID_ARGUMENT;
+
+ // Use the local (per-device) registry if we have one.
+ if (nvp != NULL)
+ pLocalRegistry = nvp->pRegistry;
+
+ numEntries = 0;
+ totalSize = NV_OFFSETOF(PACKED_REGISTRY_TABLE, entries);
+
+ // Count the number of global entries and total size.
+ regCountEntriesAndSize(&numEntries, &totalSize, the_registry);
+
+ // Count the number of local entries and total size.
+ regCountEntriesAndSize(&numEntries, &totalSize, pLocalRegistry);
+
+ // Add table record size into total size.
+ totalSize += sizeof(PACKED_REGISTRY_ENTRY) * numEntries;
+
+ //
+ // If this function is called to only compute total size of registry table,
+ // then we are done here.
+ //
+ if (pRegTable == NULL)
+ {
+ *pSize = totalSize;
+ return NV_OK;
+ }
+
+ // Return warning if there are no registry entries.
+ if (numEntries == 0)
+ return NV_WARN_NOTHING_TO_DO;
+
+ if (totalSize > *pSize)
+ {
+ NV_PRINTF(LEVEL_ERROR, "Registry entries overflow RPC record\n");
+ return NV_ERR_BUFFER_TOO_SMALL;
+ }
+
+ // Fill in our new structure with the first pass (counting) values.
+ pRegTable->size = totalSize;
+ *pSize = totalSize;
+ pRegTable->numEntries = numEntries;
+
+ // Offset of first byte after the registry entry table.
+ totalSize = NV_OFFSETOF(PACKED_REGISTRY_TABLE, entries) +
+ (sizeof(PACKED_REGISTRY_ENTRY) * numEntries);
+
+ // Starting index in the registry entry table.
+ numEntries = 0;
+
+ // Walk the global registry and copy the data.
+ nvStatus = regCopyEntriesToPackedBuffer(pRegTable,
+ the_registry, &numEntries, &totalSize);
+
+ // Walk the local registry and copy the data.
+ if (nvStatus == NV_OK)
+ {
+ nvStatus = regCopyEntriesToPackedBuffer(pRegTable,
+ pLocalRegistry, &numEntries, &totalSize);
+ }
+
+ // Sanity check second pass against first pass.
+ if ((numEntries != pRegTable->numEntries) || (totalSize != pRegTable->size))
+ {
+ NV_PRINTF(LEVEL_ERROR, "First/second pass mismatch\n");
+ nvStatus = NV_ERR_INVALID_STATE;
+ }
+
+ return nvStatus;
+}
+
diff --git a/userspace/sdks/nv570/nvalloc/unix/src/rm-gpu-ops.c b/userspace/sdks/nv570/nvalloc/unix/src/rm-gpu-ops.c
new file mode 100644
index 0000000..688b4c5
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/src/rm-gpu-ops.c
@@ -0,0 +1,1079 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2020-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <nv.h>
+#include <os/os.h>
+#include <osapi.h>
+#include <core/thread_state.h>
+#include "rmapi/nv_gpu_ops.h"
+#include "gpu/mem_mgr/phys_mem_allocator/phys_mem_allocator.h"
+
+NV_STATUS NV_API_CALL rm_gpu_ops_create_session(
+ nvidia_stack_t *sp,
+ struct gpuSession **session)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsCreateSession(session);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_destroy_session (
+ nvidia_stack_t *sp, gpuSessionHandle session)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsDestroySession(session);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_device_create (
+ nvidia_stack_t *sp,
+ nvgpuSessionHandle_t session,
+ const gpuInfo *pGpuInfo,
+ const NvProcessorUuid *gpuUuid,
+ nvgpuDeviceHandle_t *device,
+ NvBool bCreateSmcPartition)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsDeviceCreate(session, pGpuInfo, gpuUuid, device, bCreateSmcPartition);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_device_destroy (
+ nvidia_stack_t *sp,
+ gpuDeviceHandle device)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsDeviceDestroy(device);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_address_space_create (
+ nvidia_stack_t *sp,
+ gpuDeviceHandle device,
+ NvU64 vaBase,
+ NvU64 vaSize,
+ NvU32 enableAts,
+ gpuAddressSpaceHandle *vaSpace,
+ gpuAddressSpaceInfo *vaSpaceInfo)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsAddressSpaceCreate(device, vaBase, vaSize, enableAts,
+ vaSpace, vaSpaceInfo);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_dup_address_space(
+ nvidia_stack_t *sp,
+ gpuDeviceHandle device,
+ NvHandle hUserClient,
+ NvHandle hUserVASpace,
+ gpuAddressSpaceHandle *dupedVaspace,
+ gpuAddressSpaceInfo *vaSpaceInfo)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsDupAddressSpace(device, hUserClient, hUserVASpace,
+ dupedVaspace, vaSpaceInfo);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_address_space_destroy(nvidia_stack_t *sp,
+ gpuAddressSpaceHandle vaspace)
+{
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ nvGpuOpsAddressSpaceDestroy(vaspace);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return NV_OK;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_memory_alloc_fb(
+ nvidia_stack_t *sp, gpuAddressSpaceHandle vaspace,
+ NvLength size, NvU64 *gpuOffset, gpuAllocInfo *allocInfo)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsMemoryAllocFb(vaspace, size, gpuOffset, allocInfo);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_get_p2p_caps(nvidia_stack_t *sp,
+ gpuDeviceHandle device1,
+ gpuDeviceHandle device2,
+ getP2PCapsParams *pP2pCapsParams)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsGetP2PCaps(device1, device2, pP2pCapsParams);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_memory_alloc_sys(
+ nvidia_stack_t *sp, gpuAddressSpaceHandle vaspace,
+ NvLength size, NvU64 *gpuOffset, gpuAllocInfo *allocInfo)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsMemoryAllocSys(vaspace, size, gpuOffset, allocInfo);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_pma_register_callbacks(
+ nvidia_stack_t *sp,
+ void *pPma,
+ pmaEvictPagesCb_t evictPages,
+ pmaEvictRangeCb_t evictRange,
+ void *callbackData)
+{
+ THREAD_STATE_NODE threadState;
+ NV_STATUS rmStatus;
+ void *fp;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ rmStatus = pmaRegisterEvictionCb(pPma, evictPages, evictRange, callbackData);
+
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+void NV_API_CALL rm_gpu_ops_pma_unregister_callbacks(
+ nvidia_stack_t *sp,
+ void *pPma)
+{
+ THREAD_STATE_NODE threadState;
+ void *fp;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ pmaUnregisterEvictionCb(pPma);
+
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_get_pma_object(
+ nvidia_stack_t *sp,
+ gpuDeviceHandle device,
+ void **pPma,
+ const nvgpuPmaStatistics_t *pPmaPubStats)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsGetPmaObject(device, pPma,
+ (const UvmPmaStatistics **)pPmaPubStats);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_pma_alloc_pages(
+ nvidia_stack_t *sp, void *pPma,
+ NvLength pageCount, NvU64 pageSize,
+ nvgpuPmaAllocationOptions_t pPmaAllocOptions,
+ NvU64 *pPages)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsPmaAllocPages(pPma, pageCount, pageSize,
+ pPmaAllocOptions, pPages);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_pma_pin_pages(
+ nvidia_stack_t *sp, void *pPma,
+ NvU64 *pPages, NvLength pageCount, NvU64 pageSize, NvU32 flags)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsPmaPinPages(pPma, pPages, pageCount, pageSize, flags);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_memory_cpu_map(
+ nvidia_stack_t *sp, gpuAddressSpaceHandle vaspace,
+ NvU64 gpuOffset, NvLength length, void **cpuPtr, NvU64 pageSize)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsMemoryCpuMap(vaspace, gpuOffset, length, cpuPtr,
+ pageSize);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_memory_cpu_ummap(
+ nvidia_stack_t *sp, gpuAddressSpaceHandle vaspace, void* cpuPtr)
+{
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ nvGpuOpsMemoryCpuUnMap(vaspace, cpuPtr);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return NV_OK;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_tsg_allocate(nvidia_stack_t *sp,
+ gpuAddressSpaceHandle vaspace,
+ const gpuTsgAllocParams *allocParams,
+ gpuTsgHandle *tsg)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsTsgAllocate(vaspace, allocParams, tsg);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_tsg_destroy(nvidia_stack_t * sp,
+ nvgpuTsgHandle_t tsg)
+{
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ nvGpuOpsTsgDestroy(tsg);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return NV_OK;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_channel_allocate(nvidia_stack_t *sp,
+ const gpuTsgHandle tsg,
+ const gpuChannelAllocParams *allocParams,
+ gpuChannelHandle *channel,
+ gpuChannelInfo *channelInfo)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsChannelAllocate(tsg, allocParams, channel,
+ channelInfo);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_channel_destroy(nvidia_stack_t * sp,
+ nvgpuChannelHandle_t channel)
+{
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ nvGpuOpsChannelDestroy(channel);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return NV_OK;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_pma_free_pages(nvidia_stack_t *sp,
+ void *pPma, NvU64 *pPages, NvLength pageCount, NvU64 pageSize, NvU32 flags)
+{
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ nvGpuOpsPmaFreePages(pPma, pPages, pageCount, pageSize, flags);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return NV_OK;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_memory_free(
+ nvidia_stack_t *sp, gpuAddressSpaceHandle vaspace, NvU64 gpuOffset)
+{
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ nvGpuOpsMemoryFree(vaspace, gpuOffset);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return NV_OK;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_query_caps(nvidia_stack_t *sp,
+ gpuDeviceHandle device,
+ gpuCaps * caps)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsQueryCaps(device, caps);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_query_ces_caps(nvidia_stack_t *sp,
+ gpuDeviceHandle device,
+ gpuCesCaps *caps)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsQueryCesCaps(device, caps);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_get_gpu_info(nvidia_stack_t *sp,
+ const NvProcessorUuid *pUuid,
+ const gpuClientInfo *pGpuClientInfo,
+ gpuInfo *pGpuInfo)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsGetGpuInfo(pUuid, pGpuClientInfo, pGpuInfo);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_service_device_interrupts_rm(nvidia_stack_t *sp,
+ gpuDeviceHandle device)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsServiceDeviceInterruptsRM(device);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_set_page_directory (nvidia_stack_t *sp,
+ gpuAddressSpaceHandle vaSpace,
+ NvU64 physAddress, unsigned numEntries,
+ NvBool bVidMemAperture, NvU32 pasid,
+ NvU64 *dmaAddress)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsSetPageDirectory(vaSpace, physAddress, numEntries,
+ bVidMemAperture, pasid, dmaAddress);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_unset_page_directory (nvidia_stack_t *sp,
+ gpuAddressSpaceHandle vaSpace)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsUnsetPageDirectory(vaSpace);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_dup_allocation(nvidia_stack_t *sp,
+ gpuAddressSpaceHandle srcVaSpace,
+ NvU64 srcAddress,
+ gpuAddressSpaceHandle dstVaSpace,
+ NvU64 dstVaAlignment,
+ NvU64 *dstAddress)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsDupAllocation(srcVaSpace, srcAddress, dstVaSpace, dstVaAlignment, dstAddress);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_dup_memory (nvidia_stack_t *sp,
+ gpuDeviceHandle device,
+ NvHandle hClient,
+ NvHandle hPhysMemory,
+ NvHandle *hDupMemory,
+ nvgpuMemoryInfo_t gpuMemoryInfo)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsDupMemory(device, hClient, hPhysMemory, hDupMemory, gpuMemoryInfo);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_free_duped_handle (nvidia_stack_t *sp,
+ gpuDeviceHandle device,
+ NvHandle hPhysHandle)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsFreeDupedHandle(device, hPhysHandle);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_get_fb_info (nvidia_stack_t *sp,
+ gpuDeviceHandle device,
+ gpuFbInfo * fbInfo)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsGetFbInfo(device, fbInfo);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_get_ecc_info (nvidia_stack_t *sp,
+ gpuDeviceHandle device,
+ gpuEccInfo * eccInfo)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsGetEccInfo(device, eccInfo);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+//
+// Please see the comments for nvUvmInterfaceOwnPageFaultIntr(), in
+// nv_uvm_interface.h, for the recommended way to use this routine.
+//
+// How it works:
+//
+// The rmGpuLocksAcquire call generally saves the current GPU interrupt
+// state, then disables interrupt generation for one (or all) GPUs.
+// Likewise, the rmGpuLocksRelease call restores (re-enables) those
+// interrupts to their previous state. However, the rmGpuLocksRelease
+// call does NOT restore interrupts that RM does not own.
+//
+// This is rather hard to find in the code, so: very approximately, the
+// following sequence happens: rmGpuLocksRelease, osEnableInterrupts,
+// intrRestoreNonStall_HAL, intrEncodeIntrEn_HAL, and that last one skips
+// over any interrupts that RM does not own.
+//
+// This means that things are a bit asymmetric, because this routine
+// actually changes that ownership in between the rmGpuLocksAcquire and
+// rmGpuLocksRelease calls. So:
+//
+// -- If you call this routine with bOwnInterrupts == NV_TRUE (UVM is
+// taking ownership from the RM), then rmGpuLocksAcquire disables all
+// GPU interrupts. Then the ownership is taken away from RM, so the
+// rmGpuLocksRelease call leaves the replayable page fault interrupts
+// disabled. It is then up to UVM (the caller) to enable replayable
+// page fault interrupts when it is ready.
+//
+// -- If you call this routine with bOwnInterrupts == NV_FALSE (UVM is
+// returning ownership to the RM), then rmGpuLocksAcquire disables
+// all GPU interrupts that RM owns. Then the ownership is returned to
+// RM, so the rmGpuLocksRelease call re-enables replayable page fault
+// interrupts. So, that implies that you need to disable replayable page
+// fault interrupts before calling this routine, in order to hand
+// over a GPU to RM that is not generating interrupts, until RM is
+// ready to handle the interrupts.
+//
+NV_STATUS NV_API_CALL rm_gpu_ops_own_page_fault_intr(nvidia_stack_t *sp,
+ struct gpuDevice *device,
+ NvBool bOwnInterrupts)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsOwnPageFaultIntr(device, bOwnInterrupts);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_init_fault_info (nvidia_stack_t *sp,
+ gpuDeviceHandle device,
+ gpuFaultInfo *pFaultInfo)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsInitFaultInfo(device, pFaultInfo);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_destroy_fault_info (nvidia_stack_t *sp,
+ gpuDeviceHandle device,
+ gpuFaultInfo *pFaultInfo)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsDestroyFaultInfo(device, pFaultInfo);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+// Functions
+//
+// - rm_gpu_ops_has_pending_non_replayable_faults
+// - rm_gpu_ops_get_non_replayable_faults
+//
+// Cannot take the GPU/RM lock because it is called during fault servicing.
+// This could produce deadlocks if the UVM bottom half gets stuck behind a
+// stalling interrupt that cannot be serviced if UVM is holding the lock.
+//
+// However, these functions can be safely called with no locks because it is
+// just accessing the given client shadow fault buffer, which is implemented
+// using a lock-free queue. There is a different client shadow fault buffer
+// per GPU: RM top-half producer, UVM top/bottom-half consumer.
+
+NV_STATUS NV_API_CALL rm_gpu_ops_has_pending_non_replayable_faults(nvidia_stack_t *sp,
+ gpuFaultInfo *pFaultInfo,
+ NvBool *hasPendingFaults)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsHasPendingNonReplayableFaults(pFaultInfo, hasPendingFaults);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_get_non_replayable_faults(nvidia_stack_t *sp,
+ gpuFaultInfo *pFaultInfo,
+ void *faultBuffer,
+ NvU32 *numFaults)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsGetNonReplayableFaults(pFaultInfo, faultBuffer, numFaults);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_flush_replayable_fault_buffer(nvidia_stack_t *sp,
+ gpuFaultInfo *pFaultInfo,
+ NvBool bCopyAndFlush)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsFlushReplayableFaultBuffer(pFaultInfo, bCopyAndFlush);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_toggle_prefetch_faults(nvidia_stack_t *sp,
+ gpuFaultInfo *pFaultInfo,
+ NvBool bEnable)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsTogglePrefetchFaults(pFaultInfo, bEnable);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_access_bits_buffer_alloc(nvidia_stack_t *sp,
+ gpuDeviceHandle device,
+ gpuAccessBitsBufferAlloc *accessBitsInfo)
+{
+ NV_STATUS rmStatus;
+ void* fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsAccessBitsBufAlloc(device, accessBitsInfo);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_access_bits_buffer_free(nvidia_stack_t *sp,
+ gpuDeviceHandle device,
+ gpuAccessBitsBufferAlloc *accessBitsInfo)
+{
+ NV_STATUS rmStatus;
+ void* fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsAccessBitsBufFree(device, accessBitsInfo);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_access_bits_dump(nvidia_stack_t *sp,
+ gpuDeviceHandle device,
+ gpuAccessBitsBufferAlloc *accessBitsInfo,
+ UVM_ACCESS_BITS_DUMP_MODE mode)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsAccessBitsDump(device, accessBitsInfo, mode);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_init_access_cntr_info(nvidia_stack_t *sp,
+ gpuDeviceHandle device,
+ gpuAccessCntrInfo *accessCntrInfo,
+ NvU32 accessCntrIndex)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsInitAccessCntrInfo(device, accessCntrInfo, accessCntrIndex);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_destroy_access_cntr_info(nvidia_stack_t *sp,
+ gpuDeviceHandle device,
+ gpuAccessCntrInfo *accessCntrInfo)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsDestroyAccessCntrInfo(device, accessCntrInfo);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_enable_access_cntr(nvidia_stack_t *sp,
+ gpuDeviceHandle device,
+ gpuAccessCntrInfo *accessCntrInfo,
+ gpuAccessCntrConfig *accessCntrConfig)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsEnableAccessCntr(device, accessCntrInfo, accessCntrConfig);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_disable_access_cntr(nvidia_stack_t *sp,
+ gpuDeviceHandle device,
+ gpuAccessCntrInfo *accessCntrInfo)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsDisableAccessCntr(device, accessCntrInfo);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_get_nvlink_info (nvidia_stack_t *sp,
+ gpuDeviceHandle device,
+ gpuNvlinkInfo *nvlinkInfo)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsGetNvlinkInfo(device, nvlinkInfo);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL
+rm_gpu_ops_p2p_object_create(nvidia_stack_t *sp,
+ gpuDeviceHandle device1,
+ gpuDeviceHandle device2,
+ NvHandle *hP2pObject)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp, fp);
+ rmStatus = nvGpuOpsP2pObjectCreate(device1, device2, hP2pObject);
+ NV_EXIT_RM_RUNTIME(sp, fp);
+ return rmStatus;
+}
+
+void NV_API_CALL
+rm_gpu_ops_p2p_object_destroy(nvidia_stack_t *sp,
+ nvgpuSessionHandle_t session,
+ NvHandle hP2pObject)
+{
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp, fp);
+ nvGpuOpsP2pObjectDestroy(session, hP2pObject);
+ NV_EXIT_RM_RUNTIME(sp, fp);
+}
+
+NV_STATUS NV_API_CALL
+rm_gpu_ops_get_external_alloc_ptes(nvidia_stack_t* sp,
+ nvgpuAddressSpaceHandle_t vaSpace,
+ NvHandle hDupedMemory,
+ NvU64 offset,
+ NvU64 size,
+ nvgpuExternalMappingInfo_t gpuExternalMappingInfo)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp, fp);
+ rmStatus = nvGpuOpsGetExternalAllocPtes(vaSpace, hDupedMemory, offset, size,
+ gpuExternalMappingInfo);
+ NV_EXIT_RM_RUNTIME(sp, fp);
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL
+rm_gpu_ops_get_external_alloc_phys_addrs(nvidia_stack_t* sp,
+ nvgpuAddressSpaceHandle_t vaSpace,
+ NvHandle hDupedMemory,
+ NvU64 offset,
+ NvU64 size,
+ nvgpuExternalPhysAddrInfo_t gpuExternalPhysAddrsInfo)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp, fp);
+ rmStatus = nvGpuOpsGetExternalAllocPhysAddrs(vaSpace, hDupedMemory, offset, size,
+ gpuExternalPhysAddrsInfo);
+ NV_EXIT_RM_RUNTIME(sp, fp);
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL
+rm_gpu_ops_retain_channel(nvidia_stack_t* sp,
+ nvgpuAddressSpaceHandle_t vaSpace,
+ NvHandle hClient,
+ NvHandle hChannel,
+ void **retainedChannel,
+ nvgpuChannelInstanceInfo_t channelInstanceInfo)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp, fp);
+ rmStatus = nvGpuOpsRetainChannel(vaSpace, hClient, hChannel,
+ (gpuRetainedChannel **)retainedChannel,
+ channelInstanceInfo);
+ NV_EXIT_RM_RUNTIME(sp, fp);
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL
+rm_gpu_ops_bind_channel_resources(nvidia_stack_t* sp,
+ void *retainedChannel,
+ nvgpuChannelResourceBindParams_t channelResourceBindParams)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp, fp);
+ rmStatus = nvGpuOpsBindChannelResources(retainedChannel,
+ channelResourceBindParams);
+ NV_EXIT_RM_RUNTIME(sp, fp);
+ return rmStatus;
+}
+
+void NV_API_CALL
+rm_gpu_ops_release_channel(nvidia_stack_t *sp, void *retainedChannel)
+{
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp, fp);
+ nvGpuOpsReleaseChannel(retainedChannel);
+ NV_EXIT_RM_RUNTIME(sp, fp);
+}
+
+void NV_API_CALL
+rm_gpu_ops_stop_channel(nvidia_stack_t * sp,
+ void *retainedChannel,
+ NvBool bImmediate)
+{
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ nvGpuOpsStopChannel(retainedChannel, bImmediate);
+ NV_EXIT_RM_RUNTIME(sp, fp);
+}
+
+NV_STATUS NV_API_CALL
+rm_gpu_ops_get_channel_resource_ptes(nvidia_stack_t* sp,
+ nvgpuAddressSpaceHandle_t vaSpace,
+ NvP64 resourceDescriptor,
+ NvU64 offset,
+ NvU64 size,
+ nvgpuExternalMappingInfo_t gpuExternalMappingInfo)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp, fp);
+ rmStatus = nvGpuOpsGetChannelResourcePtes(vaSpace, resourceDescriptor,
+ offset, size,
+ gpuExternalMappingInfo);
+ NV_EXIT_RM_RUNTIME(sp, fp);
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL
+rm_gpu_ops_report_non_replayable_fault(nvidia_stack_t *sp,
+ nvgpuDeviceHandle_t device,
+ const void *pFaultPacket)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsReportNonReplayableFault(device, pFaultPacket);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL
+rm_gpu_ops_paging_channel_allocate(nvidia_stack_t *sp,
+ gpuDeviceHandle device,
+ const gpuPagingChannelAllocParams *allocParams,
+ gpuPagingChannelHandle *channel,
+ gpuPagingChannelInfo *channelInfo)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsPagingChannelAllocate(device, allocParams, channel,
+ channelInfo);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+void NV_API_CALL
+rm_gpu_ops_paging_channel_destroy(nvidia_stack_t *sp,
+ gpuPagingChannelHandle channel)
+{
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ nvGpuOpsPagingChannelDestroy(channel);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+}
+
+NV_STATUS NV_API_CALL
+rm_gpu_ops_paging_channels_map(nvidia_stack_t *sp,
+ gpuAddressSpaceHandle srcVaSpace,
+ NvU64 srcAddress,
+ gpuDeviceHandle device,
+ NvU64 *dstAddress)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsPagingChannelsMap(srcVaSpace, srcAddress, device, dstAddress);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+void NV_API_CALL
+rm_gpu_ops_paging_channels_unmap(nvidia_stack_t *sp,
+ gpuAddressSpaceHandle srcVaSpace,
+ NvU64 srcAddress,
+ gpuDeviceHandle device)
+{
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ nvGpuOpsPagingChannelsUnmap(srcVaSpace, srcAddress, device);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+}
+
+NV_STATUS NV_API_CALL
+rm_gpu_ops_paging_channel_push_stream(nvidia_stack_t *sp,
+ gpuPagingChannelHandle channel,
+ char *methodStream,
+ NvU32 methodStreamSize)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsPagingChannelPushStream(channel, methodStream, methodStreamSize);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+void NV_API_CALL
+rm_gpu_ops_report_fatal_error(nvidia_stack_t *sp,
+ NV_STATUS error)
+{
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ nvGpuOpsReportFatalError(error);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_ccsl_context_init(nvidia_stack_t *sp,
+ struct ccslContext_t **ctx,
+ gpuChannelHandle channel)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsCcslContextInit(ctx, channel);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_ccsl_context_clear(nvidia_stack_t *sp,
+ struct ccslContext_t *ctx)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsCcslContextClear(ctx);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_ccsl_rotate_key(nvidia_stack_t *sp,
+ UvmCslContext *contextList[],
+ NvU32 contextListCount)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsCcslRotateKey(contextList, contextListCount);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_ccsl_rotate_iv(nvidia_stack_t *sp,
+ struct ccslContext_t *ctx,
+ NvU8 direction)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsCcslRotateIv(ctx, direction);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_ccsl_encrypt_with_iv(nvidia_stack_t *sp,
+ struct ccslContext_t *ctx,
+ NvU32 bufferSize,
+ NvU8 const *inputBuffer,
+ NvU8 *encryptIv,
+ NvU8 *outputBuffer,
+ NvU8 *authTagData)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsCcslEncryptWithIv(ctx, bufferSize, inputBuffer, encryptIv, outputBuffer, authTagData);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_ccsl_encrypt(nvidia_stack_t *sp,
+ struct ccslContext_t *ctx,
+ NvU32 bufferSize,
+ NvU8 const *inputBuffer,
+ NvU8 *outputBuffer,
+ NvU8 *authTagData)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsCcslEncrypt(ctx, bufferSize, inputBuffer, outputBuffer, authTagData);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_ccsl_decrypt(nvidia_stack_t *sp,
+ struct ccslContext_t *ctx,
+ NvU32 bufferSize,
+ NvU8 const *inputBuffer,
+ NvU8 const *decryptIv,
+ NvU32 keyRotationId,
+ NvU8 *outputBuffer,
+ NvU8 const *addAuthData,
+ NvU32 addAuthDataSize,
+ NvU8 const *authTagData)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsCcslDecrypt(ctx, bufferSize, inputBuffer, decryptIv, keyRotationId, outputBuffer,
+ addAuthData, addAuthDataSize, authTagData);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_ccsl_sign(nvidia_stack_t *sp,
+ struct ccslContext_t *ctx,
+ NvU32 bufferSize,
+ NvU8 const *inputBuffer,
+ NvU8 *authTagData)
+
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsCcslSign(ctx, bufferSize, inputBuffer, authTagData);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_ccsl_query_message_pool(nvidia_stack_t *sp,
+ struct ccslContext_t *ctx,
+ NvU8 direction,
+ NvU64 *messageNum)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsQueryMessagePool(ctx, direction, messageNum);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_ccsl_increment_iv(nvidia_stack_t *sp,
+ struct ccslContext_t *ctx,
+ NvU8 direction,
+ NvU64 increment,
+ NvU8 *iv)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsIncrementIv(ctx, direction, increment, iv);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
+
+NV_STATUS NV_API_CALL rm_gpu_ops_ccsl_log_encryption(nvidia_stack_t *sp,
+ struct ccslContext_t *ctx,
+ NvU8 direction,
+ NvU32 bufferSize)
+{
+ NV_STATUS rmStatus;
+ void *fp;
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ rmStatus = nvGpuOpsLogEncryption(ctx, direction, bufferSize);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return rmStatus;
+}
diff --git a/userspace/sdks/nv570/nvalloc/unix/src/rmobjexportimport.c b/userspace/sdks/nv570/nvalloc/unix/src/rmobjexportimport.c
new file mode 100644
index 0000000..558f5fd
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/src/rmobjexportimport.c
@@ -0,0 +1,650 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2016-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/*!
+ * @file
+ *
+ * @brief Provides RmExportObject, RmImportObject, RmFreeObjExportHandle and
+ * RmGetExportObjectInfo interfaces :
+ *
+ * These interfaces allow rm clients to export their objects into
+ * a unique RmObjExportHandle which another rm client could
+ * import, even if the source rm client gets destroyed.
+ *
+ * RM's device instance may get destroyed asynchronously, in which
+ * case exported objects residing on that device instance also get
+ * destroyed. This means it is not possible to import it back, but the
+ * RmObjExportHandle into which the object had been exported still
+ * remains valid but no other object could get it.
+ *
+ * There are not init/fini routines, it is the responsibility of the
+ * rest of RM's eco-system to make sure that all RmObjExportHandles get
+ * freed during driver unload.
+ *
+ * The api lock is expected to be held before calling into
+ * rmobjexportimport.c; do not hold gpu or any other lock.
+ */
+
+#include "rmobjexportimport.h"
+#include "nvlimits.h"
+#include "gpu/device/device.h"
+#include "gpu/mig_mgr/kernel_mig_manager.h"
+#include "gpu/mig_mgr/gpu_instance_subscription.h"
+
+#include "containers/map.h"
+#include "rmapi/rmapi.h"
+#include "rmapi/rs_utils.h"
+
+#include "class/cl0080.h"
+#include "class/cl2080.h"
+#include <ctrl/ctrl0000/ctrl0000unix.h>
+#include <ctrl/ctrl0000/ctrl0000client.h>
+
+//
+// A reference to an RmObjExportHandle
+// generated by function RmGenerateObjExportHandle().
+//
+MAKE_MAP(RmObjExportHandleMap, NvU8);
+
+//
+// Memory allocator
+//
+PORT_MEM_ALLOCATOR *pMemAllocator;
+
+//
+// Map RmObjExportHandle -> RmObjExportHandleRef
+//
+RmObjExportHandleMap objExportHandleMap;
+
+//
+// Rm client to use to dup an object exported to RmObjExportHandle. The minimal
+// requirement for duping is to have a device object allocated. This rm client
+// is simply like any other external rm client and has no any special handling.
+//
+// We keep this rm client just like any other external rm client: if
+// gpu(s)/device gets powered-down/uninitialized, rm objects allocated by
+// external rm clients and located on that gpu(s)/device gets freed (the
+// os-layer does that). In that way, code in this file doesn't need to worry
+// about freeing exported objects located on that gpu(s)/device.
+//
+NvHandle hObjExportRmClient;
+
+//
+// Tracker for device and subdevice handles. For now only one subdevice
+// (instance 0) is supported per device.
+//
+typedef struct
+{
+ NvHandle hRmDevice;
+ NvHandle hRmSubDevice;
+ NvHandle hGpuInstSub;
+} RmObjExportDevice;
+MAKE_MAP(RmObjExportDeviceMap, RmObjExportDevice);
+
+RmObjExportDeviceMap objExportDeviceMap;
+
+//
+// Usage reference counter for static object in this file like rm client used to
+// dup an exported object, memory allocator, map etc.
+//
+NvU64 objExportImportRefCount;
+
+//
+// Static functions for internal use to code in this file.
+//
+static NV_STATUS RmRefObjExportImport (void);
+static void RmUnrefObjExportImport (void);
+
+static RmObjExportHandle RmGenerateObjExportHandle (void);
+static NV_STATUS RmUnrefObjExportHandle (RmObjExportHandle hObject);
+
+//
+// Free the RmObjExportHandle.
+//
+static NV_STATUS RmUnrefObjExportHandle(RmObjExportHandle hObject)
+{
+ RM_API *pRmApi = rmapiGetInterface(RMAPI_API_LOCK_INTERNAL);
+
+ void *pHandleRef = mapFind(&objExportHandleMap, hObject);
+ if (pHandleRef == NULL)
+ {
+ return NV_ERR_OBJECT_NOT_FOUND;
+ }
+
+ if (pRmApi->Free(pRmApi,
+ hObjExportRmClient,
+ (NvHandle)mapKey(&objExportHandleMap, pHandleRef)) != NV_OK)
+ {
+ NV_PRINTF(LEVEL_WARNING,
+ "Exported object trying to free was zombie in %s\n",
+ __FUNCTION__);
+ }
+
+ mapRemove(&objExportHandleMap, pHandleRef);
+
+ return NV_OK;
+}
+
+//
+// Generate unique RmObjExportHandle.
+//
+static RmObjExportHandle RmGenerateObjExportHandle(void)
+{
+ //
+ // The object export handle belongs to range of 0 to
+ // (MAX_OBJ_EXPORT_HANDLES - 1).
+ //
+ // Handle 0 is considered as invalid object handle, this function generates
+ // handle from range of 1 to (MAX_OBJ_EXPORT_HANDLES - 1).
+ //
+ #define MAX_OBJ_EXPORT_HANDLES 0x80000
+
+ static NvHandle hObjExportHandleNext = 1;
+
+ RmObjExportHandle hStartHandle = hObjExportHandleNext;
+ RmObjExportHandle hObject = 0;
+
+ do
+ {
+ void *pHandleRef;
+
+ hObject = hObjExportHandleNext++;
+ /* Reset hObjExportHandleNext to next valid handle */
+ if (hObjExportHandleNext == MAX_OBJ_EXPORT_HANDLES) {
+ hObjExportHandleNext = 1;
+ }
+
+ pHandleRef = mapFind(&objExportHandleMap, hObject);
+
+ if (hObject != hObjExportRmClient && pHandleRef == NULL)
+ {
+ break;
+ }
+ else
+ {
+ hObject = 0;
+ }
+
+ } while(hObjExportHandleNext != hStartHandle);
+
+ if (hObject != 0)
+ {
+ void *pHandleRef = mapInsertNew(&objExportHandleMap, hObject);
+
+ if (pHandleRef == NULL)
+ {
+ hObject = 0;
+ }
+ }
+
+ return hObject;
+}
+
+//
+// Validate that the given hObject is not one of our internally used handles.
+//
+// Note that mapFind(&objExportHandleMap, hObject) could still fail; that is the
+// caller's responsibility.
+//
+static NvBool RmValidateHandleAgainstInternalHandles(RmObjExportHandle hObject)
+{
+ RmObjExportDeviceMapIter iter;
+
+ //
+ // No external RmObjExportHandle could be valid if hObjExportRmClient has
+ // not been allocated yet, or if it is equal to any of the handles used
+ // internally by code in this file.
+ //
+ if (objExportImportRefCount == 0 || hObjExportRmClient == 0 ||
+ hObject == hObjExportRmClient)
+ {
+ return NV_FALSE;
+ }
+
+ iter = mapIterAll(&objExportDeviceMap);
+ while (mapIterNext(&iter))
+ {
+ RmObjExportDevice *pRmObjExportDevice = iter.pValue;
+
+ if (pRmObjExportDevice->hRmDevice != 0 &&
+ (hObject == pRmObjExportDevice->hRmDevice ||
+ hObject == pRmObjExportDevice->hRmSubDevice ||
+ hObject == pRmObjExportDevice->hGpuInstSub))
+ {
+ return NV_FALSE;
+ }
+ }
+
+ return NV_TRUE;
+}
+
+//
+// Increment reference count of static objects internally
+// used by code in this file.
+//
+static NV_STATUS RmRefObjExportImport(void)
+{
+ NV_STATUS rmStatus = NV_OK;
+ RM_API *pRmApi = rmapiGetInterface(RMAPI_API_LOCK_INTERNAL);
+
+ if ((objExportImportRefCount++) != 0)
+ {
+ NV_ASSERT(hObjExportRmClient != 0);
+ NV_ASSERT(pMemAllocator != NULL);
+ return NV_OK;
+ }
+
+ rmStatus = pRmApi->AllocWithHandle(pRmApi,
+ NV01_NULL_OBJECT,
+ NV01_NULL_OBJECT,
+ NV01_NULL_OBJECT,
+ NV01_ROOT,
+ &hObjExportRmClient,
+ sizeof(hObjExportRmClient));
+ if (rmStatus != NV_OK)
+ {
+ NV_PRINTF(LEVEL_ERROR, "Unable to alloc root in %s\n", __FUNCTION__);
+ goto failed;
+ }
+
+ pMemAllocator = portMemAllocatorCreateNonPaged();
+
+ if (pMemAllocator == NULL)
+ {
+ NV_PRINTF(LEVEL_ERROR, "Failed to alloc memory allocator in %s\n",
+ __FUNCTION__);
+ goto failed;
+ }
+
+ mapInit(&objExportHandleMap, pMemAllocator);
+ mapInit(&objExportDeviceMap, pMemAllocator);
+
+ return NV_OK;
+
+failed:
+
+ RmUnrefObjExportImport();
+
+ return rmStatus;
+}
+
+//
+// Decrement reference count of static objects internally used by code in this
+// file, and free them if reference count reaches to zero.
+//
+static void RmUnrefObjExportImport(void)
+{
+ RM_API *pRmApi = rmapiGetInterface(RMAPI_API_LOCK_INTERNAL);
+
+ if ((--objExportImportRefCount) != 0)
+ {
+ return;
+ }
+
+ if (pMemAllocator != NULL)
+ {
+ mapDestroy(&objExportDeviceMap);
+ mapDestroy(&objExportHandleMap);
+
+ portMemAllocatorRelease(pMemAllocator);
+ pMemAllocator = NULL;
+ }
+
+ if (hObjExportRmClient != 0)
+ {
+ NV_STATUS rmStatus = pRmApi->Free(pRmApi,
+ hObjExportRmClient,
+ hObjExportRmClient);
+
+ NV_ASSERT(rmStatus == NV_OK);
+ hObjExportRmClient = 0;
+ }
+}
+
+NV_STATUS RmExportObject(NvHandle hSrcClient, NvHandle hSrcObject,
+ RmObjExportHandle *pDstObject, NvU32 *pDeviceInstance)
+{
+ RmObjExportHandle hDstObject;
+ NvU32 deviceInstance = NV_MAX_DEVICES;
+ NvBool bClientAsDstParent = NV_FALSE;
+ NV_STATUS status;
+ RM_API *pRmApi = rmapiGetInterface(RMAPI_API_LOCK_INTERNAL);
+ MIG_INSTANCE_REF ref = kmigmgrMakeNoMIGReference();
+ NvU64 deviceMapIdx = 0;
+ RmObjExportDevice *pObjExportDevice = NULL;
+ RsResourceRef *pSrcResourceRef;
+ RsResourceRef *pDeviceRef;
+
+ if (pDstObject == NULL)
+ {
+ return NV_ERR_INVALID_ARGUMENT;
+ }
+
+ //
+ // Find the device instance on which the rm object exists.
+ //
+ NV_CHECK_OK_OR_RETURN(LEVEL_ERROR,
+ serverutilGetResourceRef(hSrcClient, hSrcObject, &pSrcResourceRef));
+
+ status = refFindAncestorOfType(pSrcResourceRef, classId(Device), &pDeviceRef);
+ if (status == NV_OK)
+ {
+ Device *pDevice = dynamicCast(pDeviceRef->pResource, Device);
+ OBJGPU *pGpu = GPU_RES_GET_GPU(pDevice);
+ NvU64 swizzId = KMIGMGR_MAX_GPU_SWIZZID;
+
+ if (IS_MIG_IN_USE(pGpu))
+ {
+ KernelMIGManager *pKernelMIGManager = GPU_GET_KERNEL_MIG_MANAGER(pGpu);
+
+ status = kmigmgrGetInstanceRefFromDevice(pGpu, pKernelMIGManager,
+ pDevice, &ref);
+ if (status == NV_OK)
+ {
+ swizzId = ref.pKernelMIGGpuInstance->swizzId;
+ }
+ }
+
+ deviceMapIdx = pDevice->deviceInst | (swizzId << 32);
+ deviceInstance = pDevice->deviceInst;
+ pObjExportDevice = mapFind(&objExportDeviceMap, deviceMapIdx);
+ }
+ else
+ {
+ bClientAsDstParent = NV_TRUE;
+ }
+
+ status = RmRefObjExportImport();
+
+ if (status != NV_OK)
+ {
+ return status;
+ }
+
+ if (!bClientAsDstParent &&
+ ((pObjExportDevice == NULL) ||
+ serverutilValidateNewResourceHandle(hObjExportRmClient,
+ pObjExportDevice->hRmDevice)))
+ {
+ //
+ // Device object has not been created or it got destroyed in the
+ // teardown path of device instance destruction; allocate a fresh device
+ // object.
+ //
+ NV0080_ALLOC_PARAMETERS params;
+ NV2080_ALLOC_PARAMETERS subdevParams;
+
+ if (pObjExportDevice == NULL)
+ {
+ pObjExportDevice = mapInsertNew(&objExportDeviceMap, deviceMapIdx);
+
+ pObjExportDevice->hRmDevice = RmGenerateObjExportHandle();
+ pObjExportDevice->hRmSubDevice = RmGenerateObjExportHandle();
+ pObjExportDevice->hGpuInstSub = NV01_NULL_OBJECT;
+
+ if (pObjExportDevice->hRmDevice == 0 ||
+ pObjExportDevice->hRmSubDevice == 0)
+ {
+ NV_PRINTF(LEVEL_ERROR, "Failed to allocate object handles in %s\n",
+ __FUNCTION__);
+
+ mapRemove(&objExportDeviceMap, pObjExportDevice);
+
+ status = NV_ERR_NO_MEMORY;
+ goto done;
+ }
+ }
+
+ portMemSet(&params, 0, sizeof(NV0080_ALLOC_PARAMETERS));
+
+ params.deviceId = deviceInstance;
+ params.hClientShare = hObjExportRmClient;
+
+ status = pRmApi->AllocWithHandle(pRmApi,
+ hObjExportRmClient,
+ hObjExportRmClient,
+ pObjExportDevice->hRmDevice,
+ NV01_DEVICE_0,
+ &params,
+ sizeof(params));
+ if (status != NV_OK)
+ {
+ NV_PRINTF(LEVEL_ERROR, "Unable to alloc device in %s\n",
+ __FUNCTION__);
+ goto done;
+ }
+
+ portMemSet(&subdevParams, 0, sizeof(NV2080_ALLOC_PARAMETERS));
+
+ subdevParams.subDeviceId = 0;
+
+ status = pRmApi->AllocWithHandle(pRmApi,
+ hObjExportRmClient,
+ pObjExportDevice->hRmDevice,
+ pObjExportDevice->hRmSubDevice,
+ NV20_SUBDEVICE_0,
+ &subdevParams,
+ sizeof(subdevParams));
+ if (status != NV_OK)
+ {
+ NV_PRINTF(LEVEL_ERROR, "Unable to alloc subdevice in %s\n",
+ __FUNCTION__);
+
+ (void) pRmApi->Free(pRmApi, hObjExportRmClient,
+ pObjExportDevice->hRmDevice);
+ goto done;
+ }
+
+ // Allocate MIG subscription, if needed
+ if ((ref.pKernelMIGGpuInstance != NULL) &&
+ (ref.pKernelMIGGpuInstance->swizzId < KMIGMGR_MAX_GPU_SWIZZID))
+ {
+ NVC637_ALLOCATION_PARAMETERS giSubAllocParams;
+
+ portMemSet(&giSubAllocParams, 0, sizeof(giSubAllocParams));
+ giSubAllocParams.swizzId = ref.pKernelMIGGpuInstance->swizzId;
+
+ pObjExportDevice->hGpuInstSub = RmGenerateObjExportHandle();
+
+ status = pRmApi->AllocWithHandle(pRmApi,
+ hObjExportRmClient,
+ pObjExportDevice->hRmSubDevice,
+ pObjExportDevice->hGpuInstSub,
+ AMPERE_SMC_PARTITION_REF,
+ &giSubAllocParams,
+ sizeof(giSubAllocParams));
+ if (status != NV_OK)
+ {
+ NV_PRINTF(LEVEL_ERROR, "Unable to alloc gpu instance subscription in %s\n",
+ __FUNCTION__);
+
+ (void) pRmApi->Free(pRmApi, hObjExportRmClient,
+ pObjExportDevice->hRmDevice);
+ goto done;
+ }
+ }
+ }
+
+ hDstObject = RmGenerateObjExportHandle();
+
+ if (hDstObject == 0)
+ {
+ NV_PRINTF(LEVEL_ERROR, "Failed to allocate object handle in %s\n",
+ __FUNCTION__);
+ status = NV_ERR_NO_MEMORY;
+ goto done;
+ }
+
+ // If duping under device handle fails, try subdevice handle.
+ status = pRmApi->DupObject(pRmApi,
+ hObjExportRmClient,
+ bClientAsDstParent ? hObjExportRmClient :
+ pObjExportDevice->hRmDevice,
+ &hDstObject,
+ hSrcClient,
+ hSrcObject,
+ 0 /* flags */);
+ if (status != NV_OK)
+ {
+ if (!bClientAsDstParent && (status == NV_ERR_INVALID_OBJECT_PARENT))
+ {
+ NV_PRINTF(LEVEL_INFO,
+ "pRmApi->DupObject(Dev, failed due to invalid parent in %s."
+ " Now attempting DupObject with Subdev handle.\n",
+ __FUNCTION__);
+
+ status = pRmApi->DupObject(pRmApi,
+ hObjExportRmClient,
+ pObjExportDevice->hRmSubDevice,
+ &hDstObject,
+ hSrcClient,
+ hSrcObject,
+ 0 /* flags */);
+ if (status != NV_OK)
+ {
+ RmUnrefObjExportHandle(hDstObject);
+
+ NV_PRINTF(LEVEL_ERROR,
+ "pRmApi->DupObject(Subdev, failed with error code 0x%x in %s\n",
+ status, __FUNCTION__);
+ goto done;
+ }
+ }
+ else
+ {
+ RmUnrefObjExportHandle(hDstObject);
+
+ NV_PRINTF(LEVEL_ERROR,
+ "pRmApi->DupObject(Dev, failed with error code 0x%x in %s\n",
+ status, __FUNCTION__);
+ goto done;
+ }
+ }
+
+ if (pDeviceInstance != NULL)
+ {
+ *pDeviceInstance = deviceInstance;
+ }
+
+ *pDstObject = hDstObject;
+
+done:
+ if (status != NV_OK)
+ {
+ RmUnrefObjExportImport();
+ }
+
+ return status;
+}
+
+void RmFreeObjExportHandle(RmObjExportHandle hObject)
+{
+ if (!RmValidateHandleAgainstInternalHandles(hObject))
+ {
+ NV_PRINTF(LEVEL_ERROR, "Invalid handle to exported object in %s\n",
+ __FUNCTION__);
+ return;
+ }
+
+ RmUnrefObjExportHandle(hObject);
+
+ RmUnrefObjExportImport();
+}
+
+NV_STATUS RmImportObject(NvHandle hDstClient, NvHandle hDstParent,
+ NvHandle *phDstObject, RmObjExportHandle hSrcObject,
+ NvU8 *pObjectType)
+{
+ NV_STATUS status;
+ NV0000_CTRL_CLIENT_GET_ADDR_SPACE_TYPE_PARAMS params;
+ RM_API *pRmApi = rmapiGetInterface(RMAPI_API_LOCK_INTERNAL);
+
+ if (!RmValidateHandleAgainstInternalHandles(hSrcObject))
+ {
+ return NV_ERR_INVALID_ARGUMENT;
+ }
+
+ if (mapFind(&objExportHandleMap, hSrcObject) == NULL)
+ {
+ return NV_ERR_INVALID_ARGUMENT;
+ }
+
+ if (pObjectType != NULL)
+ {
+ params.hObject = hSrcObject;
+ //
+ // rmApiGetEffectiveAddrSpace expect mapping flags to be set as DIRECT for
+ // GPU cacheable Sysmem for Pre-Ampere chips. We are not doing any mapping
+ // here, so passing this as workaround to get the expected address space.
+ //
+ params.mapFlags = FLD_SET_DRF(OS33, _FLAGS, _MAPPING, _DIRECT, 0);
+ params.addrSpaceType = \
+ NV0000_CTRL_CMD_CLIENT_GET_ADDR_SPACE_TYPE_INVALID;
+
+ status = pRmApi->Control(pRmApi, hObjExportRmClient, hObjExportRmClient,
+ NV0000_CTRL_CMD_CLIENT_GET_ADDR_SPACE_TYPE,
+ &params, sizeof(params));
+ if (status != NV_OK)
+ {
+ NV_PRINTF(LEVEL_ERROR,
+ "GET_ADDR_SPACE_TYPE failed with error code 0x%x in %s\n",
+ status, __FUNCTION__);
+ return status;
+ }
+
+ switch (params.addrSpaceType)
+ {
+ case NV0000_CTRL_CMD_CLIENT_GET_ADDR_SPACE_TYPE_SYSMEM:
+ *pObjectType = NV0000_CTRL_CMD_OS_UNIX_IMPORT_OBJECT_TYPE_SYSMEM;
+ break;
+ case NV0000_CTRL_CMD_CLIENT_GET_ADDR_SPACE_TYPE_VIDMEM:
+ *pObjectType = NV0000_CTRL_CMD_OS_UNIX_IMPORT_OBJECT_TYPE_VIDMEM;
+ break;
+ case NV0000_CTRL_CMD_CLIENT_GET_ADDR_SPACE_TYPE_FABRIC:
+ *pObjectType = NV0000_CTRL_CMD_OS_UNIX_IMPORT_OBJECT_TYPE_FABRIC;
+ break;
+#if defined(NV0000_CTRL_CMD_CLIENT_GET_ADDR_SPACE_TYPE_FABRIC_MC) && \
+ defined(NV0000_CTRL_CMD_OS_UNIX_IMPORT_OBJECT_TYPE_FABRIC_MC)
+ case NV0000_CTRL_CMD_CLIENT_GET_ADDR_SPACE_TYPE_FABRIC_MC:
+ *pObjectType = NV0000_CTRL_CMD_OS_UNIX_IMPORT_OBJECT_TYPE_FABRIC_MC;
+ break;
+#endif
+ default:
+ NV_ASSERT_OK_OR_RETURN(NV_ERR_INVALID_ARGUMENT);
+ }
+ }
+
+ status = pRmApi->DupObject(pRmApi, hDstClient, hDstParent, phDstObject,
+ hObjExportRmClient, hSrcObject,
+ 0 /* flags */);
+
+ if (status != NV_OK)
+ {
+ NV_PRINTF(LEVEL_ERROR,
+ "pRmApi->DupObject(pRmApi, failed with error code 0x%x in %s\n",
+ status, __FUNCTION__);
+ return status;
+ }
+
+ return NV_OK;
+}
diff --git a/userspace/sdks/nv570/nvalloc/unix/src/subdevice_ctrl_os_unix.c b/userspace/sdks/nv570/nvalloc/unix/src/subdevice_ctrl_os_unix.c
new file mode 100644
index 0000000..fdbdb6b
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/src/subdevice_ctrl_os_unix.c
@@ -0,0 +1,97 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2021-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <nv.h> // NV device driver interface
+#include <nv-priv.h>
+#include <os/os.h>
+#include <nvos.h>
+#include <osapi.h>
+#include "gpu/gpu.h"
+#include "gpu/gpu_resource.h"
+#include "gpu/subdevice/subdevice.h"
+#include <diagnostics/journal.h>
+#include "gpu/mem_mgr/mem_desc.h"
+#include "mem_mgr/mem.h"
+#include <nvpcie.h>
+#include <core/locks.h>
+#include "rmapi/rs_utils.h"
+#include "rmapi/client_resource.h"
+#include <class/cl0000.h>
+#include <class/cl90cd.h>
+#include <class/cl0005.h> // NV01_EVENT
+#include <class/cl003e.h> // NV01_MEMORY_SYSTEM
+#include <class/cl844c.h> // G84_PERFBUFFER
+#include <ctrl/ctrl0000/ctrl0000gpu.h>
+#include <ctrl/ctrl0000/ctrl0000unix.h>
+#include <ctrl/ctrl2080/ctrl2080gpu.h>
+#include <ctrl/ctrl2080/ctrl2080unix.h>
+
+/*!
+ * @brief Implements the NV2080_CTRL_CMD_OS_UNIX_VIDMEM_PERSISTENCE_STATUS
+ * RmControl request. It will check if the GPU video memory will be
+ * persistent during system suspend/resume cycle.
+ *
+ * @param[in] pSubdevice
+ * @param[in,out] pParams
+ *
+ * @return
+ * NV_OK Success
+ */
+NV_STATUS
+subdeviceCtrlCmdOsUnixVidmemPersistenceStatus_IMPL
+(
+ Subdevice *pSubdevice,
+ NV2080_CTRL_OS_UNIX_VIDMEM_PERSISTENCE_STATUS_PARAMS *pParams
+)
+{
+ OBJGPU *pGpu = GPU_RES_GET_GPU(pSubdevice);
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+
+ pParams->bVidmemPersistent = (nv->preserve_vidmem_allocations || nvp->s0ix_pm_enabled);
+
+ return NV_OK;
+}
+
+/*!
+ * @brief Implements the NV2080_CTRL_CMD_OS_UNIX_UPDATE_TGP_STATUS
+ * RmControl request. It sets restore TGP flag which is used
+ * to restore TGP limits when client is killed.
+ *
+ * @param[in] pSubdevice
+ * @param[in] pParams
+ *
+ * @return
+ * NV_OK Success
+ */
+NV_STATUS
+subdeviceCtrlCmdOsUnixUpdateTgpStatus_IMPL
+(
+ Subdevice *pSubdevice,
+ NV2080_CTRL_OS_UNIX_UPDATE_TGP_STATUS_PARAMS *pParams
+)
+{
+ pSubdevice->bUpdateTGP = pParams->bUpdateTGP;
+
+ return NV_OK;
+}
diff --git a/userspace/sdks/nv570/nvalloc/unix/src/unix_console.c b/userspace/sdks/nv570/nvalloc/unix/src/unix_console.c
new file mode 100644
index 0000000..28b597b
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/src/unix_console.c
@@ -0,0 +1,412 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2021-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <core/locks.h>
+#include <ctrl/ctrl0080/ctrl0080unix.h>
+#include <gpu/device/device.h>
+#include <gpu/gpu.h>
+#include <nv-priv.h>
+#include <nv.h>
+#include <osapi.h>
+#include <gpu/mem_mgr/mem_mgr.h>
+#include <platform/sli/sli.h>
+
+#include <vgpu/rpc.h>
+#include "vgpu/vgpu_events.h"
+
+static NV_STATUS
+unixCallVideoBIOS
+(
+ OBJGPU *pGpu,
+ NvU32 *eax,
+ NvU32 *ebx
+)
+{
+ NV_STATUS status = NV_ERR_NOT_SUPPORTED;
+
+ if (NVCPU_IS_X86_64)
+ {
+ NvU32 eax_in = *eax;
+ NvU32 ebx_in = *ebx;
+
+ if (pGpu->getProperty(pGpu, PDB_PROP_GPU_IS_UEFI))
+ {
+ return NV_ERR_NOT_SUPPORTED;
+ }
+
+ NV_PRINTF(LEVEL_INFO, "unixCallVideoBIOS: 0x%x 0x%x, vga_satus = %d\n", *eax, *ebx, NV_PRIMARY_VGA(NV_GET_NV_STATE(pGpu)));
+
+ status = nv_vbios_call(pGpu, eax, ebx);
+
+ // this was originally changed for nt in changelist 644223
+ if (*eax != 0x4f)
+ {
+ NV_PRINTF(LEVEL_ERROR,
+ "int10h(%04x, %04x) vesa call failed! (%04x, %04x)\n",
+ eax_in, ebx_in, *eax, *ebx);
+ status = NV_ERR_GENERIC;
+ }
+ }
+
+ return status;
+}
+
+static void
+RmSaveDisplayState
+(
+ OBJGPU *pGpu
+)
+{
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+ RM_API *pRmApi = rmapiGetInterface(RMAPI_GPU_LOCK_INTERNAL);
+ KernelDisplay *pKernelDisplay = GPU_GET_KERNEL_DISPLAY(pGpu);
+ NvBool use_vbios = NV_PRIMARY_VGA(nv) && RmGpuHasIOSpaceEnabled(nv);
+ NvU32 eax, ebx;
+ NV_STATUS status;
+ NV2080_CTRL_CMD_INTERNAL_DISPLAY_PRE_UNIX_CONSOLE_PARAMS preUnixConsoleParams = {0};
+ NV2080_CTRL_CMD_INTERNAL_DISPLAY_POST_UNIX_CONSOLE_PARAMS postUnixConsoleParams = {0};
+
+ if (IS_VIRTUAL(pGpu) || (pKernelDisplay == NULL) || nv->client_managed_console)
+ {
+ return;
+ }
+
+ if (pGpu->getProperty(pGpu, PDB_PROP_GPU_IS_UEFI))
+ {
+ NV_PRINTF(LEVEL_INFO, "RM fallback doesn't support saving of efifb console\n");
+ return;
+ }
+
+ preUnixConsoleParams.bSave = NV_TRUE;
+ preUnixConsoleParams.bUseVbios = use_vbios;
+
+ NV_CHECK_OK_OR_ELSE(status, LEVEL_ERROR, pRmApi->Control(pRmApi, nv->rmapi.hClient, nv->rmapi.hSubDevice,
+ NV2080_CTRL_CMD_INTERNAL_DISPLAY_PRE_UNIX_CONSOLE,
+ &preUnixConsoleParams, sizeof(preUnixConsoleParams)), return);
+
+ if (preUnixConsoleParams.bReturnEarly)
+ {
+ return;
+ }
+
+ if (use_vbios)
+ {
+ //
+ // Attempt to identify the currently set VESA mode; assume
+ // vanilla VGA text if the VBIOS call fails.
+ //
+ eax = 0x4f03;
+ ebx = 0;
+ if (NV_OK == unixCallVideoBIOS(pGpu, &eax, &ebx))
+ {
+ nvp->vga.vesaMode = (ebx & 0x3fff);
+ }
+ else
+ {
+ nvp->vga.vesaMode = 3;
+ }
+ }
+
+ postUnixConsoleParams.bSave = NV_TRUE;
+ postUnixConsoleParams.bUseVbios = use_vbios;
+
+ NV_CHECK_OK(status, LEVEL_ERROR,
+ pRmApi->Control(pRmApi, nv->rmapi.hClient,nv->rmapi.hSubDevice,
+ NV2080_CTRL_CMD_INTERNAL_DISPLAY_POST_UNIX_CONSOLE,
+ &postUnixConsoleParams, sizeof(postUnixConsoleParams)));
+}
+
+static void RmRestoreDisplayState
+(
+ OBJGPU *pGpu
+)
+{
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+ RM_API *pRmApi = rmapiGetInterface(RMAPI_GPU_LOCK_INTERNAL);
+ NvBool use_vbios = NV_PRIMARY_VGA(nv) && RmGpuHasIOSpaceEnabled(nv);;
+ KernelDisplay *pKernelDisplay = GPU_GET_KERNEL_DISPLAY(pGpu);
+ NV_STATUS status;
+ NvU32 eax, ebx;
+ NV2080_CTRL_CMD_INTERNAL_DISPLAY_PRE_UNIX_CONSOLE_PARAMS preUnixConsoleParams = {0};
+ NV2080_CTRL_CMD_INTERNAL_DISPLAY_POST_UNIX_CONSOLE_PARAMS postUnixConsoleParams = {0};
+
+ //
+ // Since vGPU does all real hardware management in the host,
+ // there is nothing to do at this point in the guest OS.
+ //
+ if (IS_VIRTUAL(pGpu) || (pKernelDisplay == NULL) || nv->client_managed_console)
+ {
+ return;
+ }
+
+ //
+ // Fix up DCB index VBIOS scratch registers.
+ // The strategies employed are:
+ //
+ // SBIOS/VBIOS:
+ // Clear the DCB index, and set the previous DCB index to the original
+ // value. This allows the VBIOS (during the int10h mode-set) to
+ // determine which display to enable, and to set the head-enabled bit
+ // as needed (see bugs #264873 and #944398).
+ //
+ if (pGpu->getProperty(pGpu, PDB_PROP_GPU_IS_UEFI))
+ {
+ NV_PRINTF(LEVEL_INFO, "RM fallback doesn't support efifb console restore\n");
+ return;
+ }
+
+ preUnixConsoleParams.bUseVbios = use_vbios;
+ preUnixConsoleParams.bSave = NV_FALSE;
+
+ NV_CHECK_OK_OR_ELSE(status, LEVEL_ERROR, pRmApi->Control(pRmApi, nv->rmapi.hClient,
+ nv->rmapi.hSubDevice,
+ NV2080_CTRL_CMD_INTERNAL_DISPLAY_PRE_UNIX_CONSOLE,
+ &preUnixConsoleParams, sizeof(preUnixConsoleParams)), return);
+
+ if (preUnixConsoleParams.bReturnEarly)
+ {
+ return;
+ }
+
+ if (use_vbios)
+ {
+ eax = 0x4f02;
+ ebx = nvp->vga.vesaMode;
+
+ if (NV_OK == unixCallVideoBIOS(pGpu, &eax, &ebx))
+ {
+ postUnixConsoleParams.bVbiosCallSuccessful = NV_TRUE;
+ }
+ }
+
+ postUnixConsoleParams.bSave = NV_FALSE;
+ postUnixConsoleParams.bUseVbios = use_vbios;
+
+ NV_CHECK_OK(status, LEVEL_ERROR,
+ pRmApi->Control(pRmApi, nv->rmapi.hClient, nv->rmapi.hSubDevice,
+ NV2080_CTRL_CMD_INTERNAL_DISPLAY_POST_UNIX_CONSOLE,
+ &postUnixConsoleParams, sizeof(postUnixConsoleParams)));
+}
+
+static void
+RmChangeResMode
+(
+ OBJGPU *pGpu,
+ NvBool hires
+)
+{
+ if (hires)
+ {
+ SLI_LOOP_START(SLI_LOOP_FLAGS_NONE)
+
+ RmSaveDisplayState(pGpu);
+
+ SLI_LOOP_END
+ }
+ else
+ {
+ SLI_LOOP_START(SLI_LOOP_FLAGS_NONE)
+
+ RmRestoreDisplayState(pGpu);
+ //
+ // vGPU:
+ //
+ // Since vGPU does all real hardware management in the host, if we
+ // are in guest OS (where IS_VIRTUAL(pGpu) is true), do an RPC to
+ // the host to trigger switch from HIRES to (LORES)VGA.
+ //
+ if (IS_VIRTUAL(pGpu))
+ {
+ NV_STATUS status = NV_OK;
+ NV_RM_RPC_SWITCH_TO_VGA(pGpu, status);
+ }
+
+ SLI_LOOP_END
+ }
+}
+
+NV_STATUS NV_API_CALL
+rm_save_low_res_mode
+(
+ nvidia_stack_t *sp,
+ nv_state_t *pNv
+)
+{
+ THREAD_STATE_NODE threadState;
+ OBJGPU *pGpu = NV_GET_NV_PRIV_PGPU(pNv);
+ void *fp;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ RmSaveDisplayState(pGpu);
+
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return NV_OK;
+}
+
+NV_STATUS
+deviceCtrlCmdOsUnixVTSwitch_IMPL
+(
+ Device *pDevice,
+ NV0080_CTRL_OS_UNIX_VT_SWITCH_PARAMS *pParams
+)
+{
+ OBJGPU *pGpu = GPU_RES_GET_GPU(pDevice);
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ NvBool hires;
+ NvBool bChangeResMode = NV_TRUE;
+
+ switch (pParams->cmd)
+ {
+ case NV0080_CTRL_OS_UNIX_VT_SWITCH_CMD_SAVE_VT_STATE:
+ hires = NV_TRUE;
+ break;
+
+ case NV0080_CTRL_OS_UNIX_VT_SWITCH_CMD_RESTORE_VT_STATE:
+ hires = NV_FALSE;
+ break;
+
+ case NV0080_CTRL_OS_UNIX_VT_SWITCH_CMD_CONSOLE_RESTORED:
+ bChangeResMode = NV_FALSE;
+ break;
+
+ default:
+ return NV_ERR_INVALID_ARGUMENT;
+ }
+
+ RmUpdateGc6ConsoleRefCount(nv,
+ pParams->cmd != NV0080_CTRL_OS_UNIX_VT_SWITCH_CMD_SAVE_VT_STATE);
+
+ if (!bChangeResMode)
+ {
+ return NV_OK;
+ }
+
+ if (rmGpuLocksAcquire(GPUS_LOCK_FLAGS_NONE, RM_LOCK_MODULES_FB) == NV_OK)
+ {
+ RmChangeResMode(pGpu, hires);
+ rmGpuLocksRelease(GPUS_LOCK_FLAGS_NONE, NULL);
+ }
+ else
+ {
+ NV_PRINTF(LEVEL_INFO,"%s: Failed to acquire GPU lock", __FUNCTION__);
+ }
+ return NV_OK;
+}
+
+NV_STATUS deviceCtrlCmdOsUnixVTGetFBInfo_IMPL
+(
+ Device *pDevice,
+ NV0080_CTRL_OS_UNIX_VT_GET_FB_INFO_PARAMS *pParams
+)
+{
+ OBJGPU *pGpu = GPU_RES_GET_GPU(pDevice);
+ NvBool bContinue = NV_TRUE;
+
+ if (rmGpuLocksAcquire(GPUS_LOCK_FLAGS_NONE, RM_LOCK_MODULES_FB) == NV_OK)
+ {
+ // See if the console is on one of the subdevices of this device.
+ portMemSet(pParams, 0, sizeof(*pParams));
+
+ SLI_LOOP_START(SLI_LOOP_FLAGS_NONE)
+
+ MemoryManager *pMemoryManager = GPU_GET_MEMORY_MANAGER(pGpu);
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+
+ if ((memmgrGetReservedConsoleMemDesc(pGpu, pMemoryManager) != NULL) && bContinue)
+ {
+ NvU64 baseAddr, size;
+ NvU32 width, height, depth, pitch;
+
+ // There should only be one.
+ NV_ASSERT(pParams->width == 0);
+
+ pParams->subDeviceInstance = gpumgrGetSubDeviceInstanceFromGpu(pGpu);
+
+ // Console is either mapped to BAR1 or BAR2 + 16 MB
+ nv_get_screen_info(nv, &baseAddr, &width, &height, &depth,
+ &pitch, &size);
+
+ pParams->baseAddress = baseAddr;
+ pParams->size = size;
+ pParams->width = (NvU16)width;
+ pParams->height = (NvU16)height;
+ pParams->depth = (NvU16)depth;
+ pParams->pitch = (NvU16)pitch;
+
+ if (baseAddr != 0)
+ {
+ bContinue = NV_FALSE;
+ }
+ }
+
+ SLI_LOOP_END
+
+ rmGpuLocksRelease(GPUS_LOCK_FLAGS_NONE, NULL);
+ }
+ else
+ {
+ NV_PRINTF(LEVEL_INFO,"%s: Failed to acquire GPU lock", __FUNCTION__);
+ }
+
+ return NV_OK;
+}
+
+
+void
+dispdeviceFillVgaSavedDisplayState
+(
+ OBJGPU *pGpu,
+ NvU64 vgaAddr,
+ NvU8 vgaMemType,
+ NvBool vgaValid,
+ NvU64 workspaceAddr,
+ NvU8 workspaceMemType,
+ NvBool workspaceValid,
+ NvBool baseValid,
+ NvBool workspaceBaseValid
+)
+{
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+ NvBool use_vbios = NV_PRIMARY_VGA(nv) && RmGpuHasIOSpaceEnabled(nv);
+
+ if (use_vbios)
+ {
+ nvp->vga.base.addr = vgaAddr;
+ nvp->vga.base.memTarget = vgaMemType;
+ nvp->vga.base.valid = vgaValid;
+ nvp->vga.baseValid = baseValid;
+
+ nvp->vga.workspaceBase.addr = workspaceAddr;
+ nvp->vga.workspaceBase.memTarget = workspaceMemType;
+ nvp->vga.workspaceBase.valid = workspaceValid;
+ nvp->vga.workspaceBaseValid = workspaceBaseValid;
+ }
+}
+
diff --git a/userspace/sdks/nv570/nvalloc/unix/src/unix_intr.c b/userspace/sdks/nv570/nvalloc/unix/src/unix_intr.c
new file mode 100644
index 0000000..aef36ab
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/src/unix_intr.c
@@ -0,0 +1,1050 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2021-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <nv.h>
+#include <nv-priv.h>
+#include <osapi.h>
+#include <core/thread_state.h>
+#include <core/locks.h>
+#include <gpu_mgr/gpu_mgr.h>
+#include <gpu/gpu.h>
+#include "kernel/gpu/intr/intr.h"
+#include "gpu/bif/kernel_bif.h"
+#include "gpu/mmu/kern_gmmu.h"
+#include "gpu/disp/kern_disp.h"
+#include "gpu/disp/head/kernel_head.h"
+#include <nv_sriov_defines.h>
+
+#include "platform/sli/sli.h"
+
+//
+// Service Interrupts that are not Masked when using
+// INTR_USE_INTR_MASK_FOR_LOCKING
+// Note that everything done here is without holding the GPUs Lock.
+// Returning NV_OK means an interrupt has been serviced
+//
+static NV_STATUS _osIsrIntrMask_GpusUnlocked(OBJGPU *pGpu, THREAD_STATE_NODE *pThreadState)
+{
+ NV_STATUS rmStatus = NV_ERR_NO_INTR_PENDING;
+ Intr *pIntr = GPU_GET_INTR(pGpu);
+ MC_ENGINE_BITVECTOR intrPending, intrEngMask;
+ NvU32 vblankIntrServicedHeadMask = 0;
+ KernelDisplay *pKernelDisplay = GPU_GET_KERNEL_DISPLAY(pGpu);
+ NvBool bFailedLockAcquire = NV_FALSE;
+
+ if (gpuIsGpuFullPower(pGpu) == NV_FALSE)
+ {
+ return rmStatus;
+ }
+
+ intrGetPendingLowLatencyHwDisplayIntr_HAL(pGpu, pIntr, &intrPending, pThreadState);
+
+ // Only disp interrupt remains in INTR_MASK
+ if ((pKernelDisplay != NULL) &&
+ (( pKernelDisplay->getProperty(pKernelDisplay, PDB_PROP_KDISP_HAS_SEPARATE_LOW_LATENCY_LINE) && bitVectorTest(&intrPending, MC_ENGINE_IDX_DISP_LOW)) ||
+ (!pKernelDisplay->getProperty(pKernelDisplay, PDB_PROP_KDISP_HAS_SEPARATE_LOW_LATENCY_LINE) && bitVectorTest(&intrPending, MC_ENGINE_IDX_DISP))))
+ {
+ if (kdispAcquireLowLatencyLockConditional(&pKernelDisplay->lowLatencyLock))
+ {
+
+ if (pKernelDisplay->getProperty(pKernelDisplay, PDB_PROP_KDISP_AGGRESSIVE_VBLANK_HANDLING))
+ {
+ NV_ASSERT_OK(
+ kdispOptimizePerFrameOsCallbacks(pGpu, pKernelDisplay, NV_TRUE,
+ pThreadState,
+ &vblankIntrServicedHeadMask,
+ &intrPending));
+
+ //
+ // Need to setup deferred vblank handling for once the
+ // GPUs Lock is released since we cleared vblank intrs.
+ //
+ if (vblankIntrServicedHeadMask)
+ {
+ vblankIntrServicedHeadMask |= kdispGetDeferredVblankHeadMask(pKernelDisplay);
+ kdispSetDeferredVblankHeadMask(pKernelDisplay, vblankIntrServicedHeadMask);
+ }
+ }
+ else
+ {
+ kdispServiceLowLatencyIntrs_HAL(pGpu, pKernelDisplay, 0,
+ (VBLANK_STATE_PROCESS_LOW_LATENCY |
+ VBLANK_STATE_PROCESS_CALLED_FROM_ISR),
+ pThreadState,
+ &vblankIntrServicedHeadMask,
+ &intrPending);
+ }
+
+ kdispReleaseLowLatencyLock(&pKernelDisplay->lowLatencyLock);
+ }
+ else
+ {
+ //
+ // If we lose this, then another thread is already servicing the low latency interrupts.
+ // Claim the interrupt, but go through the below disable code so that we don't immediately
+ // cause another interrupt indefinitely which could starve the other thread that already
+ // has the lock
+ //
+ rmStatus = NV_OK;
+ bFailedLockAcquire = NV_TRUE;
+ }
+
+ //
+ // Bug 4512542: The check for INTR_MASK is currently redundant since it's
+ // already checked outside this function, but we would like to unconditionally
+ // call this function if we can service the vblank first.
+ //
+ if (pIntr->getProperty(pIntr, PDB_PROP_INTR_USE_INTR_MASK_FOR_LOCKING))
+ {
+ //
+ // If an unmasked intr is still pending after the above, that means a
+ // intr other than the vblank, so we'll MSK this off
+ // for now and handle once the GPUs Lock is released.
+ //
+ intrGetPendingLowLatencyHwDisplayIntr_HAL(pGpu, pIntr, &intrPending, pThreadState);
+
+ //
+ // Only disp interrupt remains in INTR_MASK
+ // Don't re-mask it if we have an entirely separate interrupt line, unless we have lost the race above.
+ //
+ if (( pKernelDisplay->getProperty(pKernelDisplay, PDB_PROP_KDISP_HAS_SEPARATE_LOW_LATENCY_LINE) && bitVectorTest(&intrPending, MC_ENGINE_IDX_DISP_LOW) && bFailedLockAcquire) ||
+ (!pKernelDisplay->getProperty(pKernelDisplay, PDB_PROP_KDISP_HAS_SEPARATE_LOW_LATENCY_LINE) && bitVectorTest(&intrPending, MC_ENGINE_IDX_DISP)))
+ {
+ NvU32 intrMaskFlags;
+ NvU64 oldIrql;
+
+ oldIrql = rmIntrMaskLockAcquire(pGpu);
+
+ // Skip the IntrMask update if told to by another thread.
+ intrMaskFlags = intrGetIntrMaskFlags(pIntr);
+ if ((intrMaskFlags & INTR_MASK_FLAGS_ISR_SKIP_MASK_UPDATE) == 0)
+ {
+ if (pIntr->getProperty(pIntr, PDB_PROP_INTR_USE_INTR_MASK_FOR_LOCKING))
+ {
+ intrGetIntrMask_HAL(pGpu, pIntr, &intrEngMask, pThreadState);
+
+ // Only disp interrupt remains in INTR_MASK
+ bitVectorClr(&intrEngMask, MC_ENGINE_IDX_DISP);
+
+ if (pIntr->getProperty(pIntr, PDB_PROP_INTR_USE_TOP_EN_FOR_VBLANK_HANDLING))
+ {
+ intrSetDisplayInterruptEnable_HAL(pGpu, pIntr, NV_FALSE, pThreadState);
+ }
+ else
+ {
+ intrSetIntrMask_HAL(pGpu, pIntr, &intrEngMask, pThreadState);
+ }
+ }
+ }
+
+ rmIntrMaskLockRelease(pGpu, oldIrql);
+ }
+ }
+
+ if (vblankIntrServicedHeadMask)
+ {
+ rmStatus = NV_OK;
+ }
+ }
+
+ return rmStatus;
+}
+
+static NvBool osInterruptPending(
+ OBJGPU *pGpu,
+ NvBool *serviced,
+ THREAD_STATE_NODE *pThreadState
+)
+{
+ KernelDisplay *pKernelDisplay;
+ NvBool pending, sema_release;
+ THREAD_STATE_NODE threadState;
+ Intr *pIntr = NULL;
+ MC_ENGINE_BITVECTOR intr0Pending;
+ MC_ENGINE_BITVECTOR intr1Pending;
+
+ *serviced = NV_FALSE;
+ pending = NV_FALSE;
+ sema_release = NV_TRUE;
+ NvU8 stackAllocator[TLS_ISR_ALLOCATOR_SIZE]; // ISR allocations come from this buffer
+ PORT_MEM_ALLOCATOR *pIsrAllocator;
+
+ //
+ // GPU interrupt servicing ("top half")
+ //
+ // Top-level processing of GPU interrupts is performed using the
+ // steps below; although the code is straight forward, there
+ // are a few points to be aware of:
+ //
+ // 1) The GPUs lock is acquired for two reasons: to allow
+ // looping over GPUs atomically in SLI and to sanity
+ // check the PCI configuration space of any initialized
+ // GPUs. If the acquisition fails, the early return
+ // is acceptable since GPU interrupts are disabled while
+ // the lock is held; note that returning success
+ // in this case could interfere with the processing
+ // of third-party device interrupts if the IRQ is shared.
+ // Due to the above, some interrupts may be reported as
+ // unhandled if invocations of the ISR registered with
+ // the kernel are not serialized. This is bad, but
+ // ignored by currently supported kernels, provided most
+ // interrupts are handled.
+ //
+ // 2) Since acquisition of the lock disables interrupts
+ // on all initialized GPUs, NV_PMC_INTR_EN_0 can not be
+ // relied up on to determine whether interrupts are
+ // expected from a given GPU. The code below is therefore
+ // forced to rely on software state. NV_PMC_INTR_EN_0
+ // is read only as a sanity check to guard against
+ // invalid GPU state (lack of PCI memory access, etc.).
+ //
+ // 3) High priority interrupts (VBLANK, etc.), are serviced in
+ // this function, service of all other interrupts is
+ // deferred until a bottom half. If a bottom half needs
+ // to be scheduled, release of the GPUs lock is
+ // likewise deferred until completion of the bottom half.
+ //
+ // 4) To reduce the risk of starvation, an effort is made to
+ // consolidate processing of interrupts pending on
+ // all GPUs sharing a given IRQ.
+ //
+ // 5) Care is taken to ensure that the consolidated interrupt
+ // processing is performed in the context of a GPU
+ // that has interrupts pending. Else if additional ISR
+ // processing via a bottom-half is required, this
+ // bottom-half ISR might race against the GPU's shut-down
+ // path.
+ //
+
+ pIsrAllocator = portMemAllocatorCreateOnExistingBlock(stackAllocator, sizeof(stackAllocator));
+ tlsIsrInit(pIsrAllocator);
+
+ //
+ // Also check if we need to acquire the GPU lock at all and get critical interrupts
+ // This should not violate (1) from above since we are not servicing the GPUs in SLI,
+ // only checking their state.
+ //
+ // To do so, two steps are required:
+ // Step 1: Check if we can service nonstall interrupts outside the GPUs lock. Otherwise
+ // we have to acquire the GPUs lock to service the nonstall interrupts anyway, and we
+ // can't get around acquiring the GPUs lock.
+ //
+ // Step 2 is inline below
+ //
+ NvBool bIsAnyStallIntrPending = NV_TRUE;
+ NvBool bIsAnyBottomHalfStallPending = NV_FALSE;
+ NvU32 isDispPendingPerGpu = 0, isDispLowLatencyPendingPerGpu = 0;
+ NvU32 isTmrPendingPerGpu = 0;
+
+ {
+ threadStateInitISRLockless(&threadState, pGpu, THREAD_STATE_FLAGS_IS_ISR_LOCKLESS);
+ bIsAnyStallIntrPending = NV_FALSE;
+
+ {
+ pIntr = GPU_GET_INTR(pGpu);
+ KernelDisplay *pKernelDisplay = GPU_GET_KERNEL_DISPLAY(pGpu);
+
+ if (pGpu->getProperty(pGpu, PDB_PROP_GPU_TEGRA_SOC_NVDISPLAY))
+ {
+ bIsAnyStallIntrPending = NV_TRUE;
+ }
+ else
+ if ((pIntr != NULL) && (INTERRUPT_TYPE_HARDWARE == intrGetIntrEn(pIntr)))
+ {
+ NvBool bCtxswLog = NV_FALSE;
+ intrGetPendingNonStall_HAL(pGpu, pIntr, &intr1Pending, &threadState);
+ intrCheckFecsEventbufferPending(pGpu, pIntr, &intr1Pending, &bCtxswLog);
+ if (!bitVectorTestAllCleared(&intr1Pending))
+ {
+ intrServiceNonStall_HAL(pGpu, pIntr, &intr1Pending, &threadState);
+ *serviced = NV_TRUE;
+ }
+
+ //
+ // Step 2: Service nonstall interrupts and check if there are any stall interrupts
+ // pending on any GPUs. If there are, then we will take the GPU lock.
+ //
+ // Bug 4223192: calling intrGetPendingStall_HAL is rather expensive,
+ // so save off the critical interrupts to be handled in the top half.
+ //
+
+ // vblank read leaf 4 + read the rest
+
+ NvU32 intrStaticReg;
+ intrGetPendingDispLowLatencyAndStaticReg_HAL(pGpu, pIntr, &intrStaticReg, &intr0Pending, &threadState);
+ intrGetRemainingPendingStall_HAL(pGpu, pIntr, intrStaticReg, &intr0Pending, &threadState);
+
+ if (!bitVectorTestAllCleared(&intr0Pending))
+ {
+ if ((pKernelDisplay != NULL) && pKernelDisplay->getProperty(pKernelDisplay, PDB_PROP_KDISP_HAS_SEPARATE_LOW_LATENCY_LINE))
+ {
+ if (bitVectorTest(&intr0Pending, MC_ENGINE_IDX_DISP_LOW))
+ {
+ isDispLowLatencyPendingPerGpu |= NVBIT32(gpuGetInstance(pGpu));
+
+ // We will attempt to handle this separately from the other stall interrupts
+ bitVectorClr(&intr0Pending, MC_ENGINE_IDX_DISP_LOW);
+ }
+ }
+ else
+ {
+ if (bitVectorTest(&intr0Pending, MC_ENGINE_IDX_DISP))
+ {
+ isDispPendingPerGpu |= NVBIT32(gpuGetInstance(pGpu));
+
+ // We will attempt to handle this separately from the other stall interrupts
+ bitVectorClr(&intr0Pending, MC_ENGINE_IDX_DISP);
+ }
+ }
+
+ if (IS_VGPU_GSP_PLUGIN_OFFLOAD_ENABLED(pGpu) &&
+ !IS_VIRTUAL(pGpu) && bitVectorTest(&intr0Pending, MC_ENGINE_IDX_TMR))
+ {
+ isTmrPendingPerGpu |= NVBIT32(gpuGetInstance(pGpu));
+
+ // We will clear this in the top half
+ bitVectorClr(&intr0Pending, MC_ENGINE_IDX_TMR);
+ }
+
+ if (!bitVectorTestAllCleared(&intr0Pending))
+ {
+ //
+ // If any other stall interrupts are pending,
+ // they will be handled in the bottom half.
+ //
+ bIsAnyBottomHalfStallPending = NV_TRUE;
+ }
+
+ bIsAnyStallIntrPending = NV_TRUE;
+ }
+ }
+ }
+ threadStateFreeISRLockless(&threadState, pGpu, THREAD_STATE_FLAGS_IS_ISR_LOCKLESS);
+ }
+
+ // LOCK: try to acquire GPUs lock
+ if (bIsAnyStallIntrPending &&
+ (rmDeviceGpuLocksAcquire(pGpu, GPU_LOCK_FLAGS_COND_ACQUIRE, RM_LOCK_MODULES_ISR) == NV_OK))
+ {
+ threadStateInitISRAndDeferredIntHandler(&threadState,
+ pGpu, THREAD_STATE_FLAGS_IS_ISR);
+
+ {
+ pIntr = GPU_GET_INTR(pGpu);
+ pKernelDisplay = GPU_GET_KERNEL_DISPLAY(pGpu);
+
+ if (pGpu->getProperty(pGpu, PDB_PROP_GPU_TEGRA_SOC_NVDISPLAY))
+ {
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ nv_soc_irq_type_t irq_type;
+
+ irq_type = nv_get_current_irq_type(nv);
+
+ if (irq_type == NV_SOC_IRQ_DISPLAY_TYPE)
+ {
+ NvU32 dispIntr0Pending = 0;
+
+ if (kdispAcquireLowLatencyLockConditional(&pKernelDisplay->lowLatencyLock))
+ {
+ kdispServiceLowLatencyIntrs_HAL(pGpu, pKernelDisplay, 0,
+ (VBLANK_STATE_PROCESS_LOW_LATENCY |
+ VBLANK_STATE_PROCESS_CALLED_FROM_ISR),
+ &threadState,
+ NULL,
+ NULL);
+
+ kdispReleaseLowLatencyLock(&pKernelDisplay->lowLatencyLock);
+
+ *serviced = NV_TRUE;
+ }
+
+ kdispGetPendingInterrupts_HAL(pGpu, pKernelDisplay, &dispIntr0Pending);
+
+ if (dispIntr0Pending != 0)
+ {
+ pending = NV_TRUE;
+ sema_release = NV_FALSE;
+ }
+ }
+ }
+ else if ((pIntr != NULL) && INTERRUPT_TYPE_HARDWARE == intrGetIntrEn(pIntr))
+ {
+ // If interrupt enable is garbage the GPU is probably in a bad state
+ if (!(intrGetIntrEnFromHw_HAL(pGpu, pIntr, &threadState) > INTERRUPT_TYPE_MAX))
+ {
+ //
+ // If lockless interrupt handling was enabled, we have already cached which critical
+ // interrupts are pending. We only set the appropriate bits in the intr0Pending bitvector
+ // for the subsequent code to service them in the same manner as the lockless nonstall
+ // interrupt handling disabled case. But we also clear them from intr0Pending and
+ // for disp, check if they're still pending afterwards. We already checked whether any
+ // other bottom half stall interrupts are pending in bIsAnyBottomHalfStallPending above.
+ //
+ // After all this, the combination of bIsAnyBottomHalfStallPending and intr0Pending
+ // contains whether any stall interrupts are still pending, so check both to determine if
+ // we need a bottom half.
+ //
+ bitVectorClrAll(&intr0Pending);
+
+ if ((pKernelDisplay != NULL) && pKernelDisplay->getProperty(pKernelDisplay, PDB_PROP_KDISP_HAS_SEPARATE_LOW_LATENCY_LINE))
+ {
+ if ((isDispLowLatencyPendingPerGpu & NVBIT32(gpuGetInstance(pGpu))) != 0)
+ {
+ bitVectorSet(&intr0Pending, MC_ENGINE_IDX_DISP_LOW);
+ }
+ }
+ else
+ {
+ if ((isDispPendingPerGpu & NVBIT32(gpuGetInstance(pGpu))) != 0)
+ {
+ bitVectorSet(&intr0Pending, MC_ENGINE_IDX_DISP);
+ }
+
+ }
+
+ if ((isTmrPendingPerGpu & NVBIT32(gpuGetInstance(pGpu))) != 0)
+ {
+ bitVectorSet(&intr0Pending, MC_ENGINE_IDX_TMR);
+ }
+ }
+
+ if ((pKernelDisplay != NULL) &&
+ (( pKernelDisplay->getProperty(pKernelDisplay, PDB_PROP_KDISP_HAS_SEPARATE_LOW_LATENCY_LINE) && bitVectorTest(&intr0Pending, MC_ENGINE_IDX_DISP_LOW)) ||
+ (!pKernelDisplay->getProperty(pKernelDisplay, PDB_PROP_KDISP_HAS_SEPARATE_LOW_LATENCY_LINE) && bitVectorTest(&intr0Pending, MC_ENGINE_IDX_DISP))))
+ {
+ MC_ENGINE_BITVECTOR intrDispPending;
+ NvBool bIsLowLatencyIntrPending;
+
+ // If this is true, then we're here because it is true
+ bIsLowLatencyIntrPending = pKernelDisplay->getProperty(pKernelDisplay, PDB_PROP_KDISP_HAS_SEPARATE_LOW_LATENCY_LINE);
+
+ if (kdispAcquireLowLatencyLockConditional(&pKernelDisplay->lowLatencyLock))
+ {
+ if (pKernelDisplay->getProperty(pKernelDisplay, PDB_PROP_KDISP_AGGRESSIVE_VBLANK_HANDLING))
+ {
+ // Need to queue a bottom half to service the interrupts since unix otherwise won't
+ kdispHandleAggressiveVblank(pGpu, pKernelDisplay, pThreadState, &intr0Pending);
+ }
+ else
+ {
+ kdispServiceLowLatencyIntrs_HAL(pGpu, pKernelDisplay, 0,
+ (VBLANK_STATE_PROCESS_LOW_LATENCY |
+ VBLANK_STATE_PROCESS_CALLED_FROM_ISR),
+ &threadState,
+ NULL,
+ &intr0Pending);
+
+ }
+
+ *serviced = NV_TRUE;
+
+ kdispReleaseLowLatencyLock(&pKernelDisplay->lowLatencyLock);
+ }
+
+ if (bIsLowLatencyIntrPending)
+ {
+ bitVectorClr(&intr0Pending, MC_ENGINE_IDX_DISP_LOW);
+ }
+ else
+ {
+ bitVectorClr(&intr0Pending, MC_ENGINE_IDX_DISP);
+ }
+
+ intrGetPendingLowLatencyHwDisplayIntr_HAL(pGpu, pIntr, &intrDispPending, &threadState);
+
+ //
+ // If deferred vblank is used (depends on PDB_PROP_KDISP_AGGRESSIVE_VBLANK_HANDLING)
+ // and pending, we need to queue a bottom half to service the rest of the interrupts,
+ // so signal that an interrupt is still pending
+ //
+ if (kdispGetDeferredVblankHeadMask(pKernelDisplay) != 0)
+ {
+ bitVectorSet(&intrDispPending, MC_ENGINE_IDX_DISP);
+ }
+
+ bitVectorOr(&intr0Pending, &intr0Pending, &intrDispPending);
+ }
+
+ if (IS_VGPU_GSP_PLUGIN_OFFLOAD_ENABLED(pGpu) &&
+ !IS_VIRTUAL(pGpu) && bitVectorTest(&intr0Pending, MC_ENGINE_IDX_TMR))
+ {
+ // We have to clear the top level interrupt bit here since otherwise
+ // the bottom half will attempt to service the interrupt on the CPU
+ // side before GSP receives the notification and services it
+ intrClearLeafVector_HAL(pGpu, pIntr, intrGetVectorFromEngineId(pGpu, pIntr, MC_ENGINE_IDX_TMR, NV_FALSE), &threadState);
+ bitVectorClr(&intr0Pending, MC_ENGINE_IDX_TMR);
+
+ NV_ASSERT_OK(intrTriggerPrivDoorbell_HAL(pGpu, pIntr, NV_DOORBELL_NOTIFY_LEAF_SERVICE_TMR_HANDLE));
+ }
+
+ {
+ bitVectorClrAll(&intr1Pending);
+ }
+
+ if (bIsAnyBottomHalfStallPending ||
+ !bitVectorTestAllCleared(&intr0Pending) ||
+ !bitVectorTestAllCleared(&intr1Pending))
+ {
+ pending = NV_TRUE;
+ sema_release = NV_FALSE;
+ }
+ }
+ }
+
+ if (sema_release)
+ {
+ NV_ASSERT(!pending);
+
+ // UNLOCK: release GPUs lock
+ rmDeviceGpuLocksRelease(pGpu, GPUS_LOCK_FLAGS_NONE, NULL);
+ }
+ else
+ {
+ rmDeviceGpuLockSetOwner(pGpu, GPUS_LOCK_OWNER_PENDING_DPC_REFRESH);
+ }
+
+ threadStateFreeISRAndDeferredIntHandler(&threadState,
+ pGpu, THREAD_STATE_FLAGS_IS_ISR);
+ }
+ else if (bIsAnyStallIntrPending)
+ {
+ threadStateInitISRLockless(&threadState, pGpu, THREAD_STATE_FLAGS_IS_ISR_LOCKLESS);
+
+ {
+ pIntr = GPU_GET_INTR(pGpu);
+
+ if ((pIntr != NULL) && (pIntr->getProperty(pIntr, PDB_PROP_INTR_USE_INTR_MASK_FOR_LOCKING)))
+ {
+ if (_osIsrIntrMask_GpusUnlocked(pGpu, &threadState) == NV_OK)
+ {
+ *serviced = NV_TRUE;
+ }
+ }
+ }
+
+ threadStateFreeISRLockless(&threadState, pGpu, THREAD_STATE_FLAGS_IS_ISR_LOCKLESS);
+ }
+
+ tlsIsrDestroy(pIsrAllocator);
+ portMemAllocatorRelease(pIsrAllocator);
+
+ return pending;
+}
+
+NV_STATUS osIsr(
+ OBJGPU *pGpu
+)
+{
+ NV_STATUS status = NV_OK;
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+ NvBool pending = NV_FALSE;
+ NvBool serviced = NV_FALSE;
+ Intr *pIntr;
+
+ if (nvp->flags & NV_INIT_FLAG_GPU_STATE_LOAD)
+ {
+ if (pGpu->getProperty(pGpu, PDB_PROP_GPU_TEGRA_SOC_NVDISPLAY))
+ {
+ pending = osInterruptPending(pGpu, &serviced, NULL /* threadstate */);
+ }
+ else
+ {
+ pIntr = GPU_GET_INTR(pGpu);
+ if (INTERRUPT_TYPE_HARDWARE == intrGetIntrEn(pIntr))
+ {
+ KernelBif *pKernelBif = GPU_GET_KERNEL_BIF(pGpu);
+ pending = osInterruptPending(pGpu, &serviced, NULL /* threadstate */);
+ kbifCheckAndRearmMSI(pGpu, pKernelBif);
+ }
+ }
+ }
+
+ if (!pending && (IS_VIRTUAL(pGpu) || !serviced))
+ status = NV_ERR_NO_INTR_PENDING;
+ else if (pending)
+ status = NV_WARN_MORE_PROCESSING_REQUIRED;
+
+ return status;
+}
+
+/*
+ * Helper function to determine when the RM SEMA/GPUS LOCK should toggle
+ * interrupts. Based on the state of the GPU - we must add cases here as we
+ * discover them.
+ *
+ * Noteworthy special cases:
+ *
+ * - Suspend/resume: the GPU could still be suspended and not accessible
+ * on the bus, while passive-level threads need to grab the GPUs
+ * lock, or other GPUs are being resumed and triggering interrupts.
+ *
+ * @param[in] pGpu OBJGPU pointer
+ *
+ * @return NV_TRUE if the RM SEMA/GPUS LOCK should toggle interrupts, NV_FALSE
+ * otherwise.
+ */
+NvBool osLockShouldToggleInterrupts(OBJGPU *pGpu)
+{
+ if (IS_DCE_CLIENT(pGpu))
+ {
+ return NV_TRUE;
+ }
+
+ return (!pGpu->getProperty(pGpu, PDB_PROP_GPU_IN_PM_CODEPATH) &&
+ gpuIsStateLoaded(pGpu));
+}
+
+void osEnableInterrupts(OBJGPU *pGpu)
+{
+ if (pGpu->getProperty(pGpu, PDB_PROP_GPU_TEGRA_SOC_NVDISPLAY))
+ {
+ // enable irq through os call
+ nv_control_soc_irqs(NV_GET_NV_STATE(pGpu), NV_TRUE);
+ return;
+ }
+ else
+ {
+ Intr *pIntr = GPU_GET_INTR(pGpu);
+ NvU32 intrEn;
+
+ if (!pIntr->getProperty(pIntr, PDB_PROP_INTR_USE_INTR_MASK_FOR_LOCKING))
+ NV_ASSERT(intrGetIntrEnFromHw_HAL(pGpu, pIntr, NULL) == INTERRUPT_TYPE_DISABLED);
+
+ intrEn = intrGetIntrEn(pIntr);
+ intrSetIntrEnInHw_HAL(pGpu, pIntr, intrEn, NULL);
+ intrSetStall_HAL(pGpu, pIntr, intrEn, NULL);
+
+ intrRestoreNonStall_HAL(pGpu, pIntr, intrGetIntrEn(pIntr), NULL);
+ }
+}
+
+void osDisableInterrupts(
+ OBJGPU *pGpu,
+ NvBool bIsr
+)
+{
+ if (pGpu->getProperty(pGpu, PDB_PROP_GPU_TEGRA_SOC_NVDISPLAY))
+ {
+ // disable irq through os call
+ nv_control_soc_irqs(NV_GET_NV_STATE(pGpu), NV_FALSE);
+ return;
+ }
+ else
+ {
+ Intr *pIntr = GPU_GET_INTR(pGpu);
+ NvU32 new_intr_en_0 = INTERRUPT_TYPE_DISABLED;
+
+ intrSetIntrEnInHw_HAL(pGpu, pIntr, new_intr_en_0, NULL);
+ intrSetStall_HAL(pGpu, pIntr, new_intr_en_0, NULL);
+
+ intrRestoreNonStall_HAL(pGpu, pIntr, intrGetIntrEn(pIntr), NULL);
+ }
+}
+
+static void RmIsrBottomHalf(
+ nv_state_t *pNv
+)
+{
+ OBJGPU *pGpu = NV_GET_NV_PRIV_PGPU(pNv);
+ OS_THREAD_HANDLE threadId;
+ Intr *pIntr = NULL;
+ NvU8 stackAllocator[TLS_ISR_ALLOCATOR_SIZE]; // ISR allocations come from this buffer
+ PORT_MEM_ALLOCATOR *pIsrAllocator;
+
+ pIsrAllocator = portMemAllocatorCreateOnExistingBlock(stackAllocator, sizeof(stackAllocator));
+ tlsIsrInit(pIsrAllocator);
+
+ //
+ // The owning thread changes as the ISR acquires the GPUs lock,
+ // but the bottom half releases it. Refresh the ThreadId owner to be
+ // correct here for the bottom half context.
+ //
+ osGetCurrentThread(&threadId);
+ rmDeviceGpuLockSetOwner(pGpu, threadId);
+
+ {
+ threadStateInitISRAndDeferredIntHandler(pGpu->pDpcThreadState, pGpu,
+ THREAD_STATE_FLAGS_IS_ISR_DEFERRED_INT_HANDLER);
+ }
+
+ {
+ nv_state_t *nv = NV_GET_NV_STATE(pGpu);
+
+ KernelDisplay *pKernelDisplay = GPU_GET_KERNEL_DISPLAY(pGpu);
+ gpumgrSetCurrentGpuInstance(pGpu->gpuInstance);
+
+ pIntr = GPU_GET_INTR(pGpu);
+
+ //
+ // Call disp service incase of SOC Display,
+ // TODO : with multi interrupt handling based on irq aux interrupts are serviced by dpAuxService
+ // See JIRA task TDS-4253.
+ //
+ if (pGpu->getProperty(pGpu, PDB_PROP_GPU_TEGRA_SOC_NVDISPLAY))
+ {
+ if (nv_get_current_irq_type(nv) == NV_SOC_IRQ_DISPLAY_TYPE)
+ {
+ if (IS_DCE_CLIENT(pGpu))
+ {
+ kdispAcquireLowLatencyLock(&pKernelDisplay->lowLatencyLock);
+
+ kdispServiceLowLatencyIntrs_HAL(pGpu, pKernelDisplay, 0,
+ VBLANK_STATE_PROCESS_LOW_LATENCY,
+ pGpu->pDpcThreadState,
+ NULL,
+ NULL);
+
+ kdispReleaseLowLatencyLock(&pKernelDisplay->lowLatencyLock);
+ }
+ else
+ {
+ }
+ }
+ }
+ else if ((pIntr != NULL) && (INTERRUPT_TYPE_HARDWARE == intrGetIntrEn(pIntr)))
+ {
+ intrServiceStall_HAL(pGpu, pIntr);
+ }
+
+ gpumgrSetCurrentGpuInstance(NV_U32_MAX);
+ }
+
+ // UNLOCK: release GPUs lock
+ rmDeviceGpuLocksReleaseAndThreadStateFreeDeferredIntHandlerOptimized(pGpu, GPUS_LOCK_FLAGS_NONE, NULL);
+
+ tlsIsrDestroy(pIsrAllocator);
+ portMemAllocatorRelease(pIsrAllocator);
+}
+
+static void RmIsrBottomHalfUnlocked(
+ nv_state_t *pNv
+)
+{
+ OBJGPU *pGpu = NV_GET_NV_PRIV_PGPU(pNv);
+ Intr *pIntr;
+ THREAD_STATE_NODE threadState;
+
+ // In the GSP client scenario, the fatal fault interrupt is not shared
+ // by UVM and CPU-RM. Instead, it is handled entirely by GSP-RM. We
+ // therefore do not expect this function to be called. But if it is, bail
+ // without attempting to service interrupts.
+ if (IS_GSP_CLIENT(pGpu))
+ {
+ return;
+ }
+
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ // Grab GPU lock here as this kthread-item was enqueued without grabbing GPU lock
+ if (rmDeviceGpuLocksAcquire(pGpu, GPUS_LOCK_FLAGS_NONE, RM_LOCK_MODULES_DPC) == NV_OK)
+ {
+ if (FULL_GPU_SANITY_CHECK(pGpu))
+ {
+ pIntr = GPU_GET_INTR(pGpu);
+
+ if (intrGetIntrEn(pIntr) != INTERRUPT_TYPE_DISABLED)
+ {
+ MC_ENGINE_BITVECTOR intrPending;
+ intrGetPendingStall_HAL(pGpu, pIntr, &intrPending, &threadState);
+ intrServiceNonStallBottomHalf(pGpu, pIntr, &intrPending, &threadState);
+ }
+ }
+
+ rmDeviceGpuLocksRelease(pGpu, GPUS_LOCK_FLAGS_NONE, NULL);
+ }
+
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+}
+
+NvBool NV_API_CALL rm_isr(
+ nvidia_stack_t *sp,
+ nv_state_t *nv,
+ NvU32 *NeedBottomHalf
+)
+{
+ NV_STATUS status;
+ nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
+ OBJGPU *pGpu;
+ NvBool retval;
+ void *fp;
+
+ if ((nvp->flags & NV_INIT_FLAG_GPU_STATE_LOAD) == 0)
+ {
+ return NV_FALSE;
+ }
+
+ pGpu = NV_GET_NV_PRIV_PGPU(nv);
+ if (pGpu == NULL)
+ {
+ return NV_FALSE;
+ }
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+
+ // call actual isr function here
+ status = isrWrapper(pGpu->testIntr, pGpu);
+
+ switch (status)
+ {
+ case NV_OK:
+ *NeedBottomHalf = NV_FALSE;
+ retval = NV_TRUE;
+ break;
+ case NV_WARN_MORE_PROCESSING_REQUIRED:
+ *NeedBottomHalf = NV_TRUE;
+ retval = NV_TRUE;
+ break;
+ case NV_ERR_NO_INTR_PENDING:
+ default:
+ *NeedBottomHalf = NV_FALSE;
+ retval = NV_FALSE;
+ break;
+ }
+
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return retval;
+}
+
+void NV_API_CALL rm_isr_bh(
+ nvidia_stack_t *sp,
+ nv_state_t *pNv
+)
+{
+ void *fp;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+
+ RmIsrBottomHalf(pNv);
+
+ NV_EXIT_RM_RUNTIME(sp,fp);
+}
+
+void NV_API_CALL rm_isr_bh_unlocked(
+ nvidia_stack_t *sp,
+ nv_state_t *pNv
+)
+{
+ void *fp;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+
+ RmIsrBottomHalfUnlocked(pNv);
+
+ NV_EXIT_RM_RUNTIME(sp,fp);
+}
+
+NV_STATUS NV_API_CALL rm_gpu_copy_mmu_faults(
+ nvidia_stack_t *sp,
+ nv_state_t *nv,
+ NvU32 *faultsCopied
+)
+{
+ NV_STATUS status = NV_OK;
+ OBJGPU *pGpu;
+ void *fp;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+
+ pGpu = NV_GET_NV_PRIV_PGPU(nv);
+ if (pGpu == NULL || faultsCopied == NULL)
+ {
+ status = NV_ERR_OBJECT_NOT_FOUND;
+ goto done;
+ }
+
+ if (IS_GSP_CLIENT(pGpu))
+ {
+ // Non-replayable faults are copied to the client shadow buffer by GSP-RM.
+ status = NV_OK;
+ goto done;
+ }
+ else
+ {
+ KernelGmmu *pKernelGmmu = GPU_GET_KERNEL_GMMU(pGpu);
+ PORT_MEM_ALLOCATOR *pIsrAllocator;
+ THREAD_STATE_NODE threadState;
+ NvU8 stackAllocator[TLS_ISR_ALLOCATOR_SIZE]; // ISR allocations come from this buffer
+
+ if (pKernelGmmu == NULL)
+ {
+ status = NV_ERR_OBJECT_NOT_FOUND;
+ goto done;
+ }
+
+ // If MMU fault buffer is not enabled, return early
+ if (!gpuIsVoltaHubIntrSupported(pGpu))
+ goto done;
+
+ pIsrAllocator = portMemAllocatorCreateOnExistingBlock(stackAllocator, sizeof(stackAllocator));
+ tlsIsrInit(pIsrAllocator);
+ threadStateInitISRAndDeferredIntHandler(&threadState, pGpu, THREAD_STATE_FLAGS_IS_ISR);
+
+ // Copies all valid packets in RM's and client's shadow buffer
+ status = kgmmuCopyMmuFaults_HAL(pGpu, pKernelGmmu, &threadState, faultsCopied,
+ NON_REPLAYABLE_FAULT_BUFFER, NV_FALSE);
+
+ threadStateFreeISRAndDeferredIntHandler(&threadState, pGpu, THREAD_STATE_FLAGS_IS_ISR);
+ tlsIsrDestroy(pIsrAllocator);
+ portMemAllocatorRelease(pIsrAllocator);
+
+ }
+
+done:
+ NV_EXIT_RM_RUNTIME(sp,fp);
+
+ return status;
+}
+
+//
+// Use this call when MMU faults needs to be copied
+// outisde of RM lock.
+//
+static NV_STATUS _rm_gpu_copy_mmu_faults_unlocked(
+ OBJGPU *pGpu,
+ NvU32 *pFaultsCopied,
+ THREAD_STATE_NODE *pThreadState
+)
+{
+ KernelGmmu *pKernelGmmu = GPU_GET_KERNEL_GMMU(pGpu);
+
+ if (pKernelGmmu == NULL)
+ {
+ return NV_ERR_OBJECT_NOT_FOUND;
+ }
+
+ // If MMU fault buffer is not enabled, return early
+ if (!gpuIsVoltaHubIntrSupported(pGpu))
+ return NV_OK;
+
+ // Copies all valid packets in RM's and client's shadow buffer
+ return kgmmuCopyMmuFaults_HAL(pGpu, pKernelGmmu, pThreadState, pFaultsCopied,
+ NON_REPLAYABLE_FAULT_BUFFER, NV_FALSE);
+
+ return NV_OK;
+}
+
+//
+// Wrapper to handle calls to copy mmu faults
+//
+NV_STATUS rm_gpu_handle_mmu_faults(
+ nvidia_stack_t *sp,
+ nv_state_t *nv,
+ NvU32 *faultsCopied
+)
+{
+ NvU32 status = NV_OK;
+ OBJGPU *pGpu;
+ void *fp;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+
+ *faultsCopied = 0;
+ pGpu = NV_GET_NV_PRIV_PGPU(nv);
+
+ if (pGpu == NULL)
+ {
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return NV_ERR_OBJECT_NOT_FOUND;
+ }
+
+ {
+ KernelGmmu *pKernelGmmu;
+ PORT_MEM_ALLOCATOR *pIsrAllocator;
+ THREAD_STATE_NODE threadState;
+ NvU8 stackAllocator[TLS_ISR_ALLOCATOR_SIZE]; // ISR allocations come from this buffer
+
+ pIsrAllocator = portMemAllocatorCreateOnExistingBlock(stackAllocator, sizeof(stackAllocator));
+ tlsIsrInit(pIsrAllocator);
+ threadStateInitISRLockless(&threadState, pGpu, THREAD_STATE_FLAGS_IS_ISR_LOCKLESS);
+
+ pKernelGmmu = GPU_GET_KERNEL_GMMU(pGpu);
+
+ if (IS_VGPU_GSP_PLUGIN_OFFLOAD_ENABLED(pGpu) && !IS_VIRTUAL(pGpu))
+ {
+ Intr *pIntr = GPU_GET_INTR(pGpu);
+
+ if (kgmmuIsNonReplayableFaultPending_HAL(pGpu, pKernelGmmu, &threadState))
+ {
+ // We have to clear the top level interrupt bit here since otherwise
+ // the bottom half will attempt to service the interrupt on the CPU
+ // side before GSP receives the notification and services it
+ kgmmuClearNonReplayableFaultIntr_HAL(pGpu, pKernelGmmu, &threadState);
+ status = intrTriggerPrivDoorbell_HAL(pGpu, pIntr, NV_DOORBELL_NOTIFY_LEAF_SERVICE_NON_REPLAYABLE_FAULT_HANDLE);
+
+ }
+ }
+ else if (IS_VIRTUAL_WITH_SRIOV(pGpu))
+ {
+ if (kgmmuIsNonReplayableFaultPending_HAL(pGpu, pKernelGmmu, &threadState))
+ {
+ status = _rm_gpu_copy_mmu_faults_unlocked(pGpu, faultsCopied, &threadState);
+ }
+ }
+ else
+ {
+ if (IS_GSP_CLIENT(pGpu))
+ {
+ // Non-replayable faults are copied to the client shadow buffer by GSP-RM.
+ status = NV_OK;
+ }
+ else
+ {
+ status = _rm_gpu_copy_mmu_faults_unlocked(pGpu, faultsCopied, &threadState);
+ }
+ }
+
+ threadStateFreeISRLockless(&threadState, pGpu, THREAD_STATE_FLAGS_IS_ISR_LOCKLESS);
+ tlsIsrDestroy(pIsrAllocator);
+ portMemAllocatorRelease(pIsrAllocator);
+ }
+
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return status;
+}
+
+NvBool NV_API_CALL rm_is_msix_allowed(
+ nvidia_stack_t *sp,
+ nv_state_t *nv
+)
+{
+ nv_priv_t *pNvp = NV_GET_NV_PRIV(nv);
+ THREAD_STATE_NODE threadState;
+ void *fp;
+ NvBool ret = NV_FALSE;
+
+ NV_ENTER_RM_RUNTIME(sp,fp);
+ threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE);
+
+ if (rmapiLockAcquire(API_LOCK_FLAGS_NONE, RM_LOCK_MODULES_INIT) == NV_OK)
+ {
+ ret = gpumgrIsDeviceMsixAllowed(nv->regs->cpu_address,
+ pNvp->pmc_boot_1, pNvp->pmc_boot_42);
+ rmapiLockRelease();
+ }
+
+ threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE);
+ NV_EXIT_RM_RUNTIME(sp,fp);
+ return ret;
+}
diff --git a/userspace/sdks/nv570/nvalloc/unix/src/vbioscall.c b/userspace/sdks/nv570/nvalloc/unix/src/vbioscall.c
new file mode 100644
index 0000000..8eeb85e
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/src/vbioscall.c
@@ -0,0 +1,457 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 1999-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+
+/******************************************************************************
+*
+* Description:
+* This file provides the glue layer between the RM's OS object
+* unixCallVideoBIOS() method and the x86 real mode emulator
+*
+******************************************************************************/
+
+
+#include <core/core.h>
+#include <nv.h>
+#include <nv-priv.h>
+#include <osapi.h>
+
+#include <os/os.h>
+
+#include <x86emu/x86emu.h>
+
+#define IO_LOG(port, val)
+
+#define NV_ROMLEY_VGA_PHYS_ADDR 0x9d000
+#define NV_VGA_PHYS_ADDR 0xa0000
+#define NV_VIDEO_ROM_PHYS_ADDR 0xc0000
+#define NV_EXPANSION_VIDEO_ROM_PHYS_ADDR 0xc8000
+#define NV_SYSTEM_ROM_PHYS_ADDR 0xf0000
+
+#define X86EMU_LOWMEM 0x600 // Interrupt vectors, BIOS data size
+#define X86EMU_STACK_ADDR 0x10000
+#define X86EMU_STACK_SIZE 0x1000
+#define X86EMU_BUF_ADDR 0x20000 // EDID buffer for VESA int10 0x4f15
+#define X86EMU_BUF_SIZE 128
+
+#define OP_HLT 0xf4 // HLT instruction - causes the emulator to return
+
+// This is where IRET from int10 will take us
+#define X86EMU_IRET_SEG (X86EMU_STACK_ADDR >> 4)
+#define X86EMU_IRET_OFF 0
+
+#define X86EMU_DFLT_FLAGS (F_IF)
+
+static NvBool x86emuReady;
+static void *x86emuStack;
+
+static struct x86emu_mem_seg {
+ NvU32 start;
+ NvU32 end;
+ void *vaddr;
+} x86emu_mem_map[] = {
+ {NV_ROMLEY_VGA_PHYS_ADDR, NV_VGA_PHYS_ADDR - 1},
+ {NV_VGA_PHYS_ADDR, NV_VIDEO_ROM_PHYS_ADDR - 1}, // vga
+ {NV_VIDEO_ROM_PHYS_ADDR, NV_EXPANSION_VIDEO_ROM_PHYS_ADDR -1}, // vbios, sbios
+ {NV_EXPANSION_VIDEO_ROM_PHYS_ADDR, NV_SYSTEM_ROM_PHYS_ADDR -1}, // vbios, sbios
+ {NV_SYSTEM_ROM_PHYS_ADDR, 0xFFFFF}, // Motherboard BIOS
+ {X86EMU_STACK_ADDR, X86EMU_STACK_ADDR + X86EMU_STACK_SIZE - 1}, // emulator stack
+ {0, X86EMU_LOWMEM - 1}, // Interrupt vectors, BIOS data
+ {X86EMU_BUF_ADDR, X86EMU_BUF_ADDR + X86EMU_BUF_SIZE - 1},
+};
+
+enum {
+ X86EMU_SEG_ROMLEY_VGA = 0,
+ X86EMU_SEG_VGA,
+ X86EMU_SEG_ROM,
+ X86EMU_SEG_ROM_EXPANSION,
+ X86EMU_SEG_ROM_MOTHERBOARD_BIOS,
+ X86EMU_SEG_EMULATOR_STACK,
+ X86EMU_SEG_BIOS_DATA,
+ X86EMU_SEG_EDID_BUFFER,
+ X86EMU_NUM_SEGS
+};
+
+ct_assert(X86EMU_NUM_SEGS == NV_ARRAY_ELEMENTS(x86emu_mem_map));
+
+static NvU8
+x_inb(NvU16 port)
+{
+ NvU8 val;
+
+ val = os_io_read_byte(port);
+ IO_LOG(port, val);
+ return val;
+}
+
+static void
+x_outb(NvU16 port, NvU8 val)
+{
+ IO_LOG(port, val);
+ os_io_write_byte(port, val);
+}
+
+static NvU16
+x_inw(NvU16 port)
+{
+ NvU16 val;
+
+ val = os_io_read_word(port);
+ IO_LOG(port, val);
+ return val;
+}
+
+static void
+x_outw(NvU16 port, NvU16 val)
+{
+ IO_LOG(port, val);
+ os_io_write_word(port, val);
+}
+
+static u32
+x_inl(X86EMU_pioAddr port)
+{
+ NvU32 val;
+
+ val = os_io_read_dword(port);
+ IO_LOG(port, val);
+ return val;
+}
+
+static void
+x_outl(X86EMU_pioAddr port, u32 val)
+{
+ IO_LOG(port, val);
+ os_io_write_dword(port, val);
+}
+
+static void *
+Mem_addr_xlat(NvU32 addr, NvU32 sz)
+{
+ int i;
+ struct x86emu_mem_seg *pseg;
+
+ for (i = 0; i < X86EMU_NUM_SEGS; ++i)
+ {
+ pseg = x86emu_mem_map + i;
+ if (pseg->vaddr != 0 && addr >= pseg->start && addr + sz - 1 <= pseg->end)
+ return (void *)((char *)pseg->vaddr + addr - pseg->start);
+ }
+
+ X86EMU_halt_sys();
+
+ return 0;
+}
+
+static NvU8
+Mem_rb(u32 addr)
+{
+ NvU8 *va = Mem_addr_xlat(addr, 1);
+
+ return va != 0 ? *va : 0;
+}
+
+static NvU16
+Mem_rw(u32 addr)
+{
+ NvU16 *va = Mem_addr_xlat(addr, 2);
+
+ return va != 0 ? *va : 0;
+}
+
+static u32
+Mem_rl(u32 addr)
+{
+ NvU32 *va = Mem_addr_xlat(addr, 4);
+
+ return va != 0 ? *va : 0;
+}
+
+static void
+Mem_wb(u32 addr, NvU8 val)
+{
+ NvU8 *va = Mem_addr_xlat(addr, 1);
+
+ if (va != 0)
+ *va = val;
+}
+
+static void
+Mem_ww(u32 addr, NvU16 val)
+{
+ NvU16 *va = Mem_addr_xlat(addr, 2);
+
+ if (va != 0)
+ *va = val;
+}
+
+static void
+Mem_wl(u32 addr, u32 val)
+{
+ NvU32 *va = Mem_addr_xlat(addr, 4);
+
+ if (va != 0)
+ *va = val;
+}
+
+static NvU16
+get_int_seg(int i)
+{
+ return Mem_rw(i * 4 + 2);
+}
+
+
+static NvU16
+get_int_off(int i)
+{
+ return Mem_rw(i * 4);
+}
+
+
+static void
+pushw(NvU16 i)
+{
+ M.x86.R_ESP -= 2;
+ Mem_ww((M.x86.R_SS << 4) + M.x86.R_ESP, i);
+}
+
+static void
+x86emu_do_int(int num)
+{
+#if 0
+ Int10Current->num = num;
+
+ if (!int_handler(Int10Current)) {
+ X86EMU_halt_sys();
+ }
+#else
+ if ((num == 0x15) && (M.x86.R_AX == 0x5f80))
+ {
+ //
+ // Handle the MXM_SYS_INFO_CALLBACK_NUM int 15h SBIOS
+ // callback: disclaim support by returning a value
+ // other than 005fh (MXM_SYS_INFO_CALLBACK_FUNC_SUPPORTED)
+ // to the caller.
+ //
+ M.x86.R_AX = 0;
+ }
+ else
+ {
+ NV_PRINTF(LEVEL_ERROR, "x86emu: int $%d (eax = %08x)\n",
+ num, M.x86.R_EAX);
+ DBG_BREAKPOINT();
+ X86EMU_halt_sys();
+ }
+#endif
+}
+
+NV_STATUS
+RmInitX86EmuState(OBJGPU *pGpu) {
+ int i;
+ struct x86emu_mem_seg *pseg;
+ X86EMU_intrFuncs *intFuncs;
+ X86EMU_pioFuncs pioFuncs = {
+ (&x_inb),
+ (&x_inw),
+ (&x_inl),
+ (&x_outb),
+ (&x_outw),
+ (&x_outl)
+ };
+
+ X86EMU_memFuncs memFuncs = {
+ (&Mem_rb),
+ (&Mem_rw),
+ (&Mem_rl),
+ (&Mem_wb),
+ (&Mem_ww),
+ (&Mem_wl)
+ };
+
+ if (!NV_PRIMARY_VGA(NV_GET_NV_STATE(pGpu))) // not the primary GPU
+ return NV_OK;
+
+ NV_ASSERT(!x86emuReady);
+
+ x86emuStack = portMemAllocNonPaged(
+ X86EMU_STACK_SIZE + sizeof(X86EMU_intrFuncs*) * 256);
+ if (x86emuStack == NULL)
+ return NV_ERR_NO_MEMORY;
+
+ // Interrupt dispatch table
+ intFuncs = (void *)((NvU8 *)x86emuStack + X86EMU_STACK_SIZE);
+
+ // Fill virtual addresses in the memory map
+ for (i = 0; i < X86EMU_NUM_SEGS; ++i)
+ {
+ pseg = x86emu_mem_map + i;
+ switch (i)
+ {
+ case X86EMU_SEG_ROM:
+ case X86EMU_SEG_ROM_EXPANSION:
+ case X86EMU_SEG_ROM_MOTHERBOARD_BIOS:
+ nv_get_updated_emu_seg(&pseg->start, &pseg->end);
+ /* fallthrough */
+ case X86EMU_SEG_VGA:
+ case X86EMU_SEG_BIOS_DATA:
+ pseg->vaddr = os_map_kernel_space(pseg->start,
+ pseg->end - pseg->start + 1,
+ NV_MEMORY_CACHED);
+ if (pseg->vaddr == 0)
+ {
+ NV_PRINTF(LEVEL_ERROR, "x86emu can't map phys addr 0x%05x\n",
+ pseg->start);
+ return NV_ERR_GENERIC;
+ }
+ break;
+ case X86EMU_SEG_EMULATOR_STACK:
+ pseg->vaddr = x86emuStack;
+ break;
+ default:
+ pseg->vaddr = 0;
+ break;
+ }
+ }
+ X86EMU_setupMemFuncs(&memFuncs);
+
+ M.mem_base = 0;
+ M.mem_size = 1024*1024;
+ X86EMU_setupPioFuncs(&pioFuncs);
+
+ for (i=0;i<256;i++)
+ intFuncs[i] = x86emu_do_int;
+ X86EMU_setupIntrFuncs(intFuncs);
+
+ x86emuReady = NV_TRUE;
+
+ return NV_OK;
+}
+
+void
+RmFreeX86EmuState(OBJGPU *pGpu)
+{
+ int i;
+ struct x86emu_mem_seg *pseg;
+
+ if (! x86emuReady || !NV_PRIMARY_VGA(NV_GET_NV_STATE(pGpu))) // not the primary GPU
+ return;
+
+ portMemFree(x86emuStack);
+ x86emuStack = 0;
+
+ for (i = 0; i < X86EMU_NUM_SEGS; ++i)
+ {
+ pseg = x86emu_mem_map + i;
+ switch (i)
+ {
+ case X86EMU_SEG_ROMLEY_VGA:
+ case X86EMU_SEG_VGA:
+ case X86EMU_SEG_ROM:
+ case X86EMU_SEG_ROM_EXPANSION:
+ case X86EMU_SEG_ROM_MOTHERBOARD_BIOS:
+ case X86EMU_SEG_BIOS_DATA:
+ if (pseg->vaddr != 0)
+ os_unmap_kernel_space(pseg->vaddr, pseg->end - pseg->start + 1);
+ }
+ pseg->vaddr = 0;
+ }
+
+ x86emuReady = NV_FALSE;
+}
+
+NV_STATUS
+nv_vbios_call(
+ OBJGPU *pGpu,
+ NvU32 *eax,
+ NvU32 *ebx)
+{
+ NvU16 seg;
+ NvU16 off;
+ struct x86emu_mem_seg *pseg;
+
+ if (!NV_PRIMARY_VGA(NV_GET_NV_STATE(pGpu)))
+ return NV_ERR_GENERIC;
+
+ seg = get_int_seg(0x10);
+ off = get_int_off(0x10);
+
+ pseg = &x86emu_mem_map[X86EMU_SEG_VGA];
+ if (seg < (pseg->start >> 4))
+ {
+ pseg = &x86emu_mem_map[X86EMU_SEG_ROMLEY_VGA];
+ if (seg < (pseg->start >> 4))
+ {
+ NV_PRINTF(LEVEL_ERROR,
+ "cannot call the VBIOS. INT10 vector not in ROM: %04x:%04x\n",
+ seg, off);
+ return NV_ERR_GENERIC;
+ }
+ else if (pseg->vaddr == NULL)
+ {
+ pseg->vaddr = os_map_kernel_space(pseg->start,
+ (pseg->end - pseg->start + 1),
+ NV_MEMORY_CACHED);
+ if (pseg->vaddr == NULL)
+ {
+ NV_PRINTF(LEVEL_ERROR, "x86emu can't map phys addr 0x%05x\n",
+ pseg->start);
+ return NV_ERR_GENERIC;
+ }
+ }
+ }
+
+ // Reset the CPU
+ portMemSet(&M, 0, sizeof(M));
+
+ M.x86.R_SS = X86EMU_STACK_ADDR >> 4;
+ M.x86.R_ESP = X86EMU_STACK_SIZE;
+ M.x86.R_CS = seg;
+ M.x86.R_EIP = off;
+ M.x86.R_EFLG = X86EMU_DFLT_FLAGS;
+ M.x86.R_EAX = *eax;
+ M.x86.R_EBX = *ebx;
+ M.x86.R_ECX = 0;
+ M.x86.R_EDX = 0;
+ M.x86.R_ES = X86EMU_BUF_ADDR >> 4;
+
+ X86EMU_trace_on();
+
+ // Map ES:EDI to buffer. Used by vesa intr 4f15 - read EDID
+ pseg = &x86emu_mem_map[X86EMU_SEG_EDID_BUFFER];
+ pseg->vaddr = NULL;
+
+ // Prepare the code for IRET to jump to
+ Mem_wb((X86EMU_IRET_SEG << 4) + X86EMU_IRET_OFF, OP_HLT);
+
+ pushw(X86EMU_DFLT_FLAGS);
+ pushw(X86EMU_IRET_SEG);
+ pushw(X86EMU_IRET_OFF);
+
+ // Run the emulator
+ X86EMU_exec();
+
+ *eax = M.x86.R_EAX;
+ *ebx = M.x86.R_EBX;
+
+ return NV_OK;
+}
diff --git a/userspace/sdks/nv570/nvalloc/unix/x86emu/debug.c b/userspace/sdks/nv570/nvalloc/unix/x86emu/debug.c
new file mode 100644
index 0000000..ccf8be7
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/x86emu/debug.c
@@ -0,0 +1,547 @@
+/****************************************************************************
+*
+* Realmode X86 Emulator Library
+*
+* Copyright (C) 1996-1999 SciTech Software, Inc.
+* Copyright (C) David Mosberger-Tang
+* Copyright (C) 1999 Egbert Eich
+*
+* ========================================================================
+*
+* Permission to use, copy, modify, distribute, and sell this software and
+* its documentation for any purpose is hereby granted without fee,
+* provided that the above copyright notice appear in all copies and that
+* both that copyright notice and this permission notice appear in
+* supporting documentation, and that the name of the authors not be used
+* in advertising or publicity pertaining to distribution of the software
+* without specific, written prior permission. The authors makes no
+* representations about the suitability of this software for any purpose.
+* It is provided "as is" without express or implied warranty.
+*
+* THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+* EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+* PERFORMANCE OF THIS SOFTWARE.
+*
+* ========================================================================
+*
+* Language: ANSI C
+* Environment: Any
+* Developer: Kendall Bennett
+*
+* Description: This file contains the code to handle debugging of the
+* emulator.
+*
+****************************************************************************/
+
+#include "x86emu/x86emui.h"
+#ifndef NO_SYS_HEADERS
+#include <stdarg.h>
+#include <stdlib.h>
+#endif
+
+/*----------------------------- Implementation ----------------------------*/
+
+#ifdef X86EMU_DEBUG
+
+static void print_encoded_bytes (u16 s, u16 o);
+static void print_decoded_instruction (void);
+static int parse_line (char *s, int *ps, int *n);
+
+/* should look something like debug's output. */
+void X86EMU_trace_regs (void)
+{
+ if (DEBUG_TRACE()) {
+ x86emu_dump_regs();
+ }
+ if (DEBUG_DECODE() && ! DEBUG_DECODE_NOPRINT()) {
+ NV_PRINTF(LEVEL_INFO, "%04x:%04x ", M.x86.saved_cs,
+ M.x86.saved_ip);
+ print_encoded_bytes( M.x86.saved_cs, M.x86.saved_ip);
+ print_decoded_instruction();
+ }
+}
+
+void X86EMU_trace_xregs (void)
+{
+ if (DEBUG_TRACE()) {
+ x86emu_dump_xregs();
+ }
+}
+
+void x86emu_just_disassemble (void)
+{
+ /*
+ * This routine called if the flag DEBUG_DISASSEMBLE is set kind
+ * of a hack!
+ */
+ NV_PRINTF(LEVEL_INFO, "%04x:%04x ", M.x86.saved_cs,
+ M.x86.saved_ip);
+ print_encoded_bytes( M.x86.saved_cs, M.x86.saved_ip);
+ print_decoded_instruction();
+}
+
+static void disassemble_forward (u16 seg, u16 off, int n)
+{
+ X86EMU_sysEnv tregs;
+ int i;
+ u8 op1;
+ /*
+ * hack, hack, hack. What we do is use the exact machinery set up
+ * for execution, except that now there is an additional state
+ * flag associated with the "execution", and we are using a copy
+ * of the register struct. All the major opcodes, once fully
+ * decoded, have the following two steps: TRACE_REGS(r,m);
+ * SINGLE_STEP(r,m); which disappear if DEBUG is not defined to
+ * the preprocessor. The TRACE_REGS macro expands to:
+ *
+ * if (debug&DEBUG_DISASSEMBLE)
+ * {just_disassemble(); goto EndOfInstruction;}
+ * if (debug&DEBUG_TRACE) trace_regs(r,m);
+ *
+ * ...... and at the last line of the routine.
+ *
+ * EndOfInstruction: end_instr();
+ *
+ * Up to the point where TRACE_REG is expanded, NO modifications
+ * are done to any register EXCEPT the IP register, for fetch and
+ * decoding purposes.
+ *
+ * This was done for an entirely different reason, but makes a
+ * nice way to get the system to help debug codes.
+ */
+ tregs = M;
+ tregs.x86.R_IP = off;
+ tregs.x86.R_CS = seg;
+
+ /* reset the decoding buffers */
+ tregs.x86.enc_str_pos = 0;
+ tregs.x86.enc_pos = 0;
+
+ /* turn on the "disassemble only, no execute" flag */
+ tregs.x86.debug |= DEBUG_DISASSEMBLE_F;
+
+ /* DUMP NEXT n instructions to screen in straight_line fashion */
+ /*
+ * This looks like the regular instruction fetch stream, except
+ * that when this occurs, each fetched opcode, upon seeing the
+ * DEBUG_DISASSEMBLE flag set, exits immediately after decoding
+ * the instruction. XXX --- CHECK THAT MEM IS NOT AFFECTED!!!
+ * Note the use of a copy of the register structure...
+ */
+ for (i=0; i<n; i++) {
+ op1 = (*sys_rdb)(((u32)M.x86.R_CS<<4) + (M.x86.R_IP++));
+ (x86emu_optab[op1])(op1);
+ }
+ /* end major hack mode. */
+}
+
+void x86emu_check_ip_access (void)
+{
+ /* NULL as of now */
+}
+
+void x86emu_check_sp_access (void)
+{
+}
+
+void x86emu_check_mem_access (u32 dummy)
+{
+ /* check bounds, etc */
+}
+
+void x86emu_check_data_access (uint dummy1, uint dummy2)
+{
+ /* check bounds, etc */
+}
+
+void x86emu_inc_decoded_inst_len (int x)
+{
+ M.x86.enc_pos += x;
+}
+
+void x86emu_decode_printf (const char *x)
+{
+ NvU32 max_size = sizeof(M.x86.decoded_buf) - M.x86.enc_str_pos;
+
+ nvDbgSnprintf(M.x86.decoded_buf + M.x86.enc_str_pos, max_size, "%s", x);
+ M.x86.enc_str_pos += portStringLength(x);
+}
+
+void x86emu_decode_printf2 (const char *x, int y)
+{
+ char temp[100];
+ nvDbgSnprintf(temp, sizeof(temp), x, y);
+ x86emu_decode_printf(temp);
+}
+
+void x86emu_end_instr (void)
+{
+ M.x86.enc_str_pos = 0;
+ M.x86.enc_pos = 0;
+}
+
+static void print_encoded_bytes (u16 s, u16 o)
+{
+ int i;
+ char buf1[64];
+ for (i=0; i< M.x86.enc_pos; i++) {
+ nvDbgSnprintf(buf1 + 2 * i, sizeof(buf1) - (2 * i),
+ "%02x", fetch_data_byte_abs(s, o + i));
+ }
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "%-20s", buf1);
+}
+
+static void print_decoded_instruction (void)
+{
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "%s", M.x86.decoded_buf);
+}
+
+void x86emu_print_int_vect (u16 iv)
+{
+ u16 seg,off;
+
+ if (iv > 256) return;
+ seg = fetch_data_word_abs(0,iv*4);
+ off = fetch_data_word_abs(0,iv*4+2);
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "%04x:%04x ", seg, off);
+}
+
+void X86EMU_dump_memory (u16 seg, u16 off, u32 amt)
+{
+ u32 start = off & 0xfffffff0;
+ u32 end = (off+16) & 0xfffffff0;
+ u32 i;
+
+ while (end <= off + amt) {
+ NV_PRINTF(LEVEL_INFO, "%04x:%04x ", seg, start);
+ for (i=start; i< off; i++)
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, " ");
+ for ( ; i< end; i++)
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "%02x ", fetch_data_byte_abs(seg, i));
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "\n");
+ start = end;
+ end = start + 16;
+ }
+}
+
+void x86emu_single_step (void)
+{
+ int ps[10];
+ int ntok;
+ int cmd;
+ int done;
+ int segment;
+ int offset;
+ static int breakpoint;
+ static int noDecode = 1;
+
+ if (DEBUG_BREAK()) {
+ if (M.x86.saved_ip != breakpoint) {
+ return;
+ } else {
+ M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F;
+ M.x86.debug |= DEBUG_TRACE_F;
+ M.x86.debug &= ~DEBUG_BREAK_F;
+ print_decoded_instruction ();
+ X86EMU_trace_regs();
+ }
+ }
+ done=0;
+ offset = M.x86.saved_ip;
+ while (!done) {
+ NV_PRINTF(LEVEL_INFO, "-");
+
+ /*
+ * Set _X86EMU_env.x86.debug_cmd from a kernel debugger to a command to
+ * control the emulator debugger
+ */
+ if (M.x86.debug_cmd[0] == '\0')
+ {
+ DBG_BREAKPOINT();
+ }
+
+ cmd = parse_line(M.x86.debug_cmd, ps, &ntok);
+ switch(cmd) {
+ case 'u':
+ disassemble_forward(M.x86.saved_cs,(u16)offset,10);
+ break;
+ case 'd':
+ if (ntok == 2) {
+ segment = M.x86.saved_cs;
+ offset = ps[1];
+ X86EMU_dump_memory(segment,(u16)offset,16);
+ offset += 16;
+ } else if (ntok == 3) {
+ segment = ps[1];
+ offset = ps[2];
+ X86EMU_dump_memory(segment,(u16)offset,16);
+ offset += 16;
+ } else {
+ segment = M.x86.saved_cs;
+ X86EMU_dump_memory(segment,(u16)offset,16);
+ offset += 16;
+ }
+ break;
+ case 'c':
+ M.x86.debug ^= DEBUG_TRACECALL_F;
+ break;
+ case 's':
+ M.x86.debug ^= DEBUG_SVC_F | DEBUG_SYS_F | DEBUG_SYSINT_F;
+ break;
+ case 'r':
+ X86EMU_trace_regs();
+ break;
+ case 'x':
+ X86EMU_trace_xregs();
+ break;
+ case 'g':
+ if (ntok == 2) {
+ breakpoint = ps[1];
+ if (noDecode) {
+ M.x86.debug |= DEBUG_DECODE_NOPRINT_F;
+ } else {
+ M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F;
+ }
+ M.x86.debug &= ~DEBUG_TRACE_F;
+ M.x86.debug |= DEBUG_BREAK_F;
+ done = 1;
+ }
+ break;
+ case 'q':
+ M.x86.debug |= DEBUG_EXIT;
+ return;
+ case 'P':
+ noDecode = (noDecode)?0:1;
+ NV_PRINTF(LEVEL_INFO, "Toggled decoding to %s\n",
+ (noDecode) ? "FALSE" : "TRUE");
+ break;
+ case 'a':
+ X86EMU_trace_off();
+ /* fall thru */
+ case 't':
+ case 0:
+ done = 1;
+ break;
+ }
+ portMemSet(&M.x86.debug_cmd, 0, sizeof(M.x86.debug_cmd));
+ }
+}
+
+int X86EMU_trace_on(void)
+{
+ return M.x86.debug |= DEBUG_STEP_F | DEBUG_DECODE_F | DEBUG_TRACE_F;
+}
+
+int X86EMU_trace_off(void)
+{
+ return M.x86.debug &= ~(DEBUG_STEP_F | DEBUG_DECODE_F | DEBUG_TRACE_F);
+}
+
+static void parse_hex (char *s, int *pval)
+{
+ unsigned int val = 0;
+ unsigned char c;
+
+ if (s[0] == '0' && s[1] == 'x')
+ s += 2;
+
+ while ((c = *(s++)))
+ {
+ if (c >= '0' && c <= '9')
+ {
+ val <<= 4;
+ val |= c - '0';
+ continue;
+ }
+ else if (c >= 'a' && c <= 'f')
+ {
+ val <<= 4;
+ val |= c - 'a';
+ continue;
+ }
+ else if (c >= 'A' && c <= 'F')
+ {
+ val <<= 4;
+ val |= c - 'A';
+ continue;
+ }
+ break;
+ }
+
+ *pval = val;
+}
+
+static int parse_line (char *s, int *ps, int *n)
+{
+ int cmd;
+
+ *n = 0;
+ while(*s == ' ' || *s == '\t') s++;
+ ps[*n] = *s;
+ switch (*s) {
+ case '\n':
+ *n += 1;
+ return 0;
+ default:
+ cmd = *s;
+ *n += 1;
+ }
+
+ while (1)
+ {
+ while (*s != ' ' && *s != '\t' && *s != '\n' && *s != '\0')
+ s++;
+
+ if (*s == '\n' || *s == '\0')
+ return cmd;
+
+ while(*s == ' ' || *s == '\t')
+ s++;
+
+ parse_hex(s, &ps[*n]);
+ *n += 1;
+ }
+}
+
+void x86emu_dump_regs (void)
+{
+ NV_PRINTF(LEVEL_INFO, "\tAX=%04x ", M.x86.R_AX);
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "BX=%04x ", M.x86.R_BX);
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "CX=%04x ", M.x86.R_CX);
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "DX=%04x ", M.x86.R_DX);
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "SP=%04x ", M.x86.R_SP);
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "BP=%04x ", M.x86.R_BP);
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "SI=%04x ", M.x86.R_SI);
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "DI=%04x\n", M.x86.R_DI);
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "\tDS=%04x ", M.x86.R_DS);
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "ES=%04x ", M.x86.R_ES);
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "SS=%04x ", M.x86.R_SS);
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "CS=%04x ", M.x86.R_CS);
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "IP=%04x ", M.x86.R_IP);
+ if (ACCESS_FLAG(F_OF)) {
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "OV ");
+ } else {
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "NV ");
+ }
+ if (ACCESS_FLAG(F_DF)) {
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "DN ");
+ } else {
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "UP ");
+ }
+ if (ACCESS_FLAG(F_IF)) {
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "EI ");
+ } else {
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "DI ");
+ }
+ if (ACCESS_FLAG(F_SF)) {
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "NG ");
+ } else {
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "PL ");
+ }
+ if (ACCESS_FLAG(F_ZF)) {
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "ZR ");
+ } else {
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "NZ ");
+ }
+ if (ACCESS_FLAG(F_AF)) {
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "AC ");
+ } else {
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "NA ");
+ }
+ if (ACCESS_FLAG(F_PF)) {
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "PE ");
+ } else {
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "PO ");
+ }
+ if (ACCESS_FLAG(F_CF)) {
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "CY ");
+ } else {
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "NC ");
+ }
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "\n");
+}
+
+void x86emu_dump_xregs (void)
+{
+ NV_PRINTF(LEVEL_INFO, "\tEAX=%08x ", M.x86.R_EAX);
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "EBX=%08x ", M.x86.R_EBX);
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "ECX=%08x ", M.x86.R_ECX);
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "EDX=%08x \n", M.x86.R_EDX);
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "\tESP=%08x ", M.x86.R_ESP);
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "EBP=%08x ", M.x86.R_EBP);
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "ESI=%08x ", M.x86.R_ESI);
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "EDI=%08x\n", M.x86.R_EDI);
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "\tDS=%04x ", M.x86.R_DS);
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "ES=%04x ", M.x86.R_ES);
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "SS=%04x ", M.x86.R_SS);
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "CS=%04x ", M.x86.R_CS);
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "EIP=%08x\n\t", M.x86.R_EIP);
+ if (ACCESS_FLAG(F_OF)) {
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "OV ");
+ } else {
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "NV ");
+ }
+ if (ACCESS_FLAG(F_DF)) {
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "DN ");
+ } else {
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "UP ");
+ }
+ if (ACCESS_FLAG(F_IF)) {
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "EI ");
+ } else {
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "DI ");
+ }
+ if (ACCESS_FLAG(F_SF)) {
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "NG ");
+ } else {
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "PL ");
+ }
+ if (ACCESS_FLAG(F_ZF)) {
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "ZR ");
+ } else {
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "NZ ");
+ }
+ if (ACCESS_FLAG(F_AF)) {
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "AC ");
+ } else {
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "NA ");
+ }
+ if (ACCESS_FLAG(F_PF)) {
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "PE ");
+ } else {
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "PO ");
+ }
+ if (ACCESS_FLAG(F_CF)) {
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "CY ");
+ } else {
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "NC ");
+ }
+ NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "\n");
+}
+
+#else
+
+void x86emu_dump_regs (void)
+{
+}
+
+void x86emu_dump_xregs (void)
+{
+}
+
+int X86EMU_trace_on(void)
+{
+ return 0;
+}
+
+int X86EMU_trace_off(void)
+{
+ return 0;
+}
+
+#endif /* X86EMU_DEBUG */
+
diff --git a/userspace/sdks/nv570/nvalloc/unix/x86emu/decode.c b/userspace/sdks/nv570/nvalloc/unix/x86emu/decode.c
new file mode 100644
index 0000000..a683ce4
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/x86emu/decode.c
@@ -0,0 +1,1094 @@
+/****************************************************************************
+*
+* Realmode X86 Emulator Library
+*
+* Copyright (C) 1996-1999 SciTech Software, Inc.
+* Copyright (C) David Mosberger-Tang
+* Copyright (C) 1999 Egbert Eich
+*
+* ========================================================================
+*
+* Permission to use, copy, modify, distribute, and sell this software and
+* its documentation for any purpose is hereby granted without fee,
+* provided that the above copyright notice appear in all copies and that
+* both that copyright notice and this permission notice appear in
+* supporting documentation, and that the name of the authors not be used
+* in advertising or publicity pertaining to distribution of the software
+* without specific, written prior permission. The authors makes no
+* representations about the suitability of this software for any purpose.
+* It is provided "as is" without express or implied warranty.
+*
+* THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+* EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+* PERFORMANCE OF THIS SOFTWARE.
+*
+* ========================================================================
+*
+* Language: ANSI C
+* Environment: Any
+* Developer: Kendall Bennett
+*
+* Description: This file includes subroutines which are related to
+* instruction decoding and accessess of immediate data via IP. etc.
+*
+****************************************************************************/
+
+
+#include "x86emu/x86emui.h"
+
+/*----------------------------- Implementation ----------------------------*/
+
+/****************************************************************************
+REMARKS:
+Handles any pending asychronous interrupts.
+****************************************************************************/
+static void x86emu_intr_handle(void)
+{
+ u8 intno;
+
+ if (M.x86.intr & INTR_SYNCH) {
+ intno = M.x86.intno;
+ if (_X86EMU_intrTab[intno]) {
+ (*_X86EMU_intrTab[intno])(intno);
+ } else {
+ push_word((u16)M.x86.R_FLG);
+ CLEAR_FLAG(F_IF);
+ CLEAR_FLAG(F_TF);
+ push_word(M.x86.R_CS);
+ M.x86.R_CS = mem_access_word(intno * 4 + 2);
+ push_word(M.x86.R_IP);
+ M.x86.R_IP = mem_access_word(intno * 4);
+ M.x86.intr = 0;
+ }
+ }
+}
+
+/****************************************************************************
+PARAMETERS:
+intrnum - Interrupt number to raise
+
+REMARKS:
+Raise the specified interrupt to be handled before the execution of the
+next instruction.
+****************************************************************************/
+void x86emu_intr_raise(
+ u8 intrnum)
+{
+ M.x86.intno = intrnum;
+ M.x86.intr |= INTR_SYNCH;
+}
+
+/****************************************************************************
+REMARKS:
+Main execution loop for the emulator. We return from here when the system
+halts, which is normally caused by a stack fault when we return from the
+original real mode call.
+****************************************************************************/
+void X86EMU_exec(void)
+{
+ u8 op1;
+
+ M.x86.intr = 0;
+ DB(x86emu_end_instr();)
+
+ for (;;) {
+DB( if (CHECK_IP_FETCH())
+ x86emu_check_ip_access();)
+ /* If debugging, save the IP and CS values. */
+ SAVE_IP_CS(M.x86.R_CS, M.x86.R_IP);
+ INC_DECODED_INST_LEN(1);
+ if (M.x86.intr) {
+ if (M.x86.intr & INTR_HALTED) {
+DB( if (M.x86.R_SP != 0) {
+ NV_PRINTF(LEVEL_INFO, "halted\n");
+ X86EMU_trace_regs();
+ }
+ else {
+ if (M.x86.debug)
+ NV_PRINTF(LEVEL_INFO,
+ "Service completed successfully\n");
+ })
+ return;
+ }
+ if (((M.x86.intr & INTR_SYNCH) && (M.x86.intno == 0 || M.x86.intno == 2)) ||
+ !ACCESS_FLAG(F_IF)) {
+ x86emu_intr_handle();
+ }
+ }
+ op1 = (*sys_rdb)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP++));
+ (*x86emu_optab[op1])(op1);
+ if (M.x86.debug & DEBUG_EXIT) {
+ M.x86.debug &= ~DEBUG_EXIT;
+ return;
+ }
+ }
+}
+
+/****************************************************************************
+REMARKS:
+Halts the system by setting the halted system flag.
+****************************************************************************/
+void X86EMU_halt_sys(void)
+{
+ M.x86.intr |= INTR_HALTED;
+}
+
+/****************************************************************************
+PARAMETERS:
+mod - Mod value from decoded byte
+regh - Reg h value from decoded byte
+regl - Reg l value from decoded byte
+
+REMARKS:
+Raise the specified interrupt to be handled before the execution of the
+next instruction.
+
+NOTE: Do not inline this function, as (*sys_rdb) is already inline!
+****************************************************************************/
+void fetch_decode_modrm(
+ int *mod,
+ int *regh,
+ int *regl)
+{
+ int fetched;
+
+DB( if (CHECK_IP_FETCH())
+ x86emu_check_ip_access();)
+ fetched = (*sys_rdb)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP++));
+ INC_DECODED_INST_LEN(1);
+ *mod = (fetched >> 6) & 0x03;
+ *regh = (fetched >> 3) & 0x07;
+ *regl = (fetched >> 0) & 0x07;
+}
+
+/****************************************************************************
+RETURNS:
+Immediate byte value read from instruction queue
+
+REMARKS:
+This function returns the immediate byte from the instruction queue, and
+moves the instruction pointer to the next value.
+
+NOTE: Do not inline this function, as (*sys_rdb) is already inline!
+****************************************************************************/
+u8 fetch_byte_imm(void)
+{
+ u8 fetched;
+
+DB( if (CHECK_IP_FETCH())
+ x86emu_check_ip_access();)
+ fetched = (*sys_rdb)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP++));
+ INC_DECODED_INST_LEN(1);
+ return fetched;
+}
+
+/****************************************************************************
+RETURNS:
+Immediate word value read from instruction queue
+
+REMARKS:
+This function returns the immediate byte from the instruction queue, and
+moves the instruction pointer to the next value.
+
+NOTE: Do not inline this function, as (*sys_rdw) is already inline!
+****************************************************************************/
+u16 fetch_word_imm(void)
+{
+ u16 fetched;
+
+DB( if (CHECK_IP_FETCH())
+ x86emu_check_ip_access();)
+ fetched = (*sys_rdw)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP));
+ M.x86.R_IP += 2;
+ INC_DECODED_INST_LEN(2);
+ return fetched;
+}
+
+/****************************************************************************
+RETURNS:
+Immediate lone value read from instruction queue
+
+REMARKS:
+This function returns the immediate byte from the instruction queue, and
+moves the instruction pointer to the next value.
+
+NOTE: Do not inline this function, as (*sys_rdw) is already inline!
+****************************************************************************/
+u32 fetch_long_imm(void)
+{
+ u32 fetched;
+
+DB( if (CHECK_IP_FETCH())
+ x86emu_check_ip_access();)
+ fetched = (*sys_rdl)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP));
+ M.x86.R_IP += 4;
+ INC_DECODED_INST_LEN(4);
+ return fetched;
+}
+
+/****************************************************************************
+RETURNS:
+Value of the default data segment
+
+REMARKS:
+Inline function that returns the default data segment for the current
+instruction.
+
+On the x86 processor, the default segment is not always DS if there is
+no segment override. Address modes such as -3[BP] or 10[BP+SI] all refer to
+addresses relative to SS (ie: on the stack). So, at the minimum, all
+decodings of addressing modes would have to set/clear a bit describing
+whether the access is relative to DS or SS. That is the function of the
+cpu-state-varible M.x86.mode. There are several potential states:
+
+ repe prefix seen (handled elsewhere)
+ repne prefix seen (ditto)
+
+ cs segment override
+ ds segment override
+ es segment override
+ fs segment override
+ gs segment override
+ ss segment override
+
+ ds/ss select (in absense of override)
+
+Each of the above 7 items are handled with a bit in the mode field.
+****************************************************************************/
+_INLINE u32 get_data_segment(void)
+{
+#define GET_SEGMENT(segment)
+ switch (M.x86.mode & SYSMODE_SEGMASK) {
+ case 0: /* default case: use ds register */
+ case SYSMODE_SEGOVR_DS:
+ case SYSMODE_SEGOVR_DS | SYSMODE_SEG_DS_SS:
+ return M.x86.R_DS;
+ case SYSMODE_SEG_DS_SS: /* non-overridden, use ss register */
+ return M.x86.R_SS;
+ case SYSMODE_SEGOVR_CS:
+ case SYSMODE_SEGOVR_CS | SYSMODE_SEG_DS_SS:
+ return M.x86.R_CS;
+ case SYSMODE_SEGOVR_ES:
+ case SYSMODE_SEGOVR_ES | SYSMODE_SEG_DS_SS:
+ return M.x86.R_ES;
+ case SYSMODE_SEGOVR_FS:
+ case SYSMODE_SEGOVR_FS | SYSMODE_SEG_DS_SS:
+ return M.x86.R_FS;
+ case SYSMODE_SEGOVR_GS:
+ case SYSMODE_SEGOVR_GS | SYSMODE_SEG_DS_SS:
+ return M.x86.R_GS;
+ case SYSMODE_SEGOVR_SS:
+ case SYSMODE_SEGOVR_SS | SYSMODE_SEG_DS_SS:
+ return M.x86.R_SS;
+ default:
+#ifdef X86EMU_DEBUG
+ NV_PRINTF(LEVEL_INFO,
+ "error: should not happen: multiple overrides.\n");
+#endif
+ HALT_SYS();
+ return 0;
+ }
+}
+
+/****************************************************************************
+PARAMETERS:
+offset - Offset to load data from
+
+RETURNS:
+Byte value read from the absolute memory location.
+
+NOTE: Do not inline this function as (*sys_rdX) is already inline!
+****************************************************************************/
+u8 fetch_data_byte(
+ uint offset)
+{
+#ifdef X86EMU_DEBUG
+ if (CHECK_DATA_ACCESS())
+ x86emu_check_data_access((u16)get_data_segment(), offset);
+#endif
+ return (*sys_rdb)((get_data_segment() << 4) + offset);
+}
+
+/****************************************************************************
+PARAMETERS:
+offset - Offset to load data from
+
+RETURNS:
+Word value read from the absolute memory location.
+
+NOTE: Do not inline this function as (*sys_rdX) is already inline!
+****************************************************************************/
+u16 fetch_data_word(
+ uint offset)
+{
+#ifdef X86EMU_DEBUG
+ if (CHECK_DATA_ACCESS())
+ x86emu_check_data_access((u16)get_data_segment(), offset);
+#endif
+ return (*sys_rdw)((get_data_segment() << 4) + offset);
+}
+
+/****************************************************************************
+PARAMETERS:
+offset - Offset to load data from
+
+RETURNS:
+Long value read from the absolute memory location.
+
+NOTE: Do not inline this function as (*sys_rdX) is already inline!
+****************************************************************************/
+u32 fetch_data_long(
+ uint offset)
+{
+#ifdef X86EMU_DEBUG
+ if (CHECK_DATA_ACCESS())
+ x86emu_check_data_access((u16)get_data_segment(), offset);
+#endif
+ return (*sys_rdl)((get_data_segment() << 4) + offset);
+}
+
+/****************************************************************************
+PARAMETERS:
+segment - Segment to load data from
+offset - Offset to load data from
+
+RETURNS:
+Byte value read from the absolute memory location.
+
+NOTE: Do not inline this function as (*sys_rdX) is already inline!
+****************************************************************************/
+u8 fetch_data_byte_abs(
+ uint segment,
+ uint offset)
+{
+#ifdef X86EMU_DEBUG
+ if (CHECK_DATA_ACCESS())
+ x86emu_check_data_access(segment, offset);
+#endif
+ return (*sys_rdb)(((u32)segment << 4) + offset);
+}
+
+/****************************************************************************
+PARAMETERS:
+segment - Segment to load data from
+offset - Offset to load data from
+
+RETURNS:
+Word value read from the absolute memory location.
+
+NOTE: Do not inline this function as (*sys_rdX) is already inline!
+****************************************************************************/
+u16 fetch_data_word_abs(
+ uint segment,
+ uint offset)
+{
+#ifdef X86EMU_DEBUG
+ if (CHECK_DATA_ACCESS())
+ x86emu_check_data_access(segment, offset);
+#endif
+ return (*sys_rdw)(((u32)segment << 4) + offset);
+}
+
+/****************************************************************************
+PARAMETERS:
+segment - Segment to load data from
+offset - Offset to load data from
+
+RETURNS:
+Long value read from the absolute memory location.
+
+NOTE: Do not inline this function as (*sys_rdX) is already inline!
+****************************************************************************/
+u32 fetch_data_long_abs(
+ uint segment,
+ uint offset)
+{
+#ifdef X86EMU_DEBUG
+ if (CHECK_DATA_ACCESS())
+ x86emu_check_data_access(segment, offset);
+#endif
+ return (*sys_rdl)(((u32)segment << 4) + offset);
+}
+
+/****************************************************************************
+PARAMETERS:
+offset - Offset to store data at
+val - Value to store
+
+REMARKS:
+Writes a word value to an segmented memory location. The segment used is
+the current 'default' segment, which may have been overridden.
+
+NOTE: Do not inline this function as (*sys_wrX) is already inline!
+****************************************************************************/
+void store_data_byte(
+ uint offset,
+ u8 val)
+{
+#ifdef X86EMU_DEBUG
+ if (CHECK_DATA_ACCESS())
+ x86emu_check_data_access((u16)get_data_segment(), offset);
+#endif
+ (*sys_wrb)((get_data_segment() << 4) + offset, val);
+}
+
+/****************************************************************************
+PARAMETERS:
+offset - Offset to store data at
+val - Value to store
+
+REMARKS:
+Writes a word value to an segmented memory location. The segment used is
+the current 'default' segment, which may have been overridden.
+
+NOTE: Do not inline this function as (*sys_wrX) is already inline!
+****************************************************************************/
+void store_data_word(
+ uint offset,
+ u16 val)
+{
+#ifdef X86EMU_DEBUG
+ if (CHECK_DATA_ACCESS())
+ x86emu_check_data_access((u16)get_data_segment(), offset);
+#endif
+ (*sys_wrw)((get_data_segment() << 4) + offset, val);
+}
+
+/****************************************************************************
+PARAMETERS:
+offset - Offset to store data at
+val - Value to store
+
+REMARKS:
+Writes a long value to an segmented memory location. The segment used is
+the current 'default' segment, which may have been overridden.
+
+NOTE: Do not inline this function as (*sys_wrX) is already inline!
+****************************************************************************/
+void store_data_long(
+ uint offset,
+ u32 val)
+{
+#ifdef X86EMU_DEBUG
+ if (CHECK_DATA_ACCESS())
+ x86emu_check_data_access((u16)get_data_segment(), offset);
+#endif
+ (*sys_wrl)((get_data_segment() << 4) + offset, val);
+}
+
+/****************************************************************************
+PARAMETERS:
+segment - Segment to store data at
+offset - Offset to store data at
+val - Value to store
+
+REMARKS:
+Writes a byte value to an absolute memory location.
+
+NOTE: Do not inline this function as (*sys_wrX) is already inline!
+****************************************************************************/
+void store_data_byte_abs(
+ uint segment,
+ uint offset,
+ u8 val)
+{
+#ifdef X86EMU_DEBUG
+ if (CHECK_DATA_ACCESS())
+ x86emu_check_data_access(segment, offset);
+#endif
+ (*sys_wrb)(((u32)segment << 4) + offset, val);
+}
+
+/****************************************************************************
+PARAMETERS:
+segment - Segment to store data at
+offset - Offset to store data at
+val - Value to store
+
+REMARKS:
+Writes a word value to an absolute memory location.
+
+NOTE: Do not inline this function as (*sys_wrX) is already inline!
+****************************************************************************/
+void store_data_word_abs(
+ uint segment,
+ uint offset,
+ u16 val)
+{
+#ifdef X86EMU_DEBUG
+ if (CHECK_DATA_ACCESS())
+ x86emu_check_data_access(segment, offset);
+#endif
+ (*sys_wrw)(((u32)segment << 4) + offset, val);
+}
+
+/****************************************************************************
+PARAMETERS:
+segment - Segment to store data at
+offset - Offset to store data at
+val - Value to store
+
+REMARKS:
+Writes a long value to an absolute memory location.
+
+NOTE: Do not inline this function as (*sys_wrX) is already inline!
+****************************************************************************/
+void store_data_long_abs(
+ uint segment,
+ uint offset,
+ u32 val)
+{
+#ifdef X86EMU_DEBUG
+ if (CHECK_DATA_ACCESS())
+ x86emu_check_data_access(segment, offset);
+#endif
+ (*sys_wrl)(((u32)segment << 4) + offset, val);
+}
+
+/****************************************************************************
+PARAMETERS:
+reg - Register to decode
+
+RETURNS:
+Pointer to the appropriate register
+
+REMARKS:
+Return a pointer to the register given by the R/RM field of the
+modrm byte, for byte operands. Also enables the decoding of instructions.
+****************************************************************************/
+u8* decode_rm_byte_register(
+ int reg)
+{
+ switch (reg) {
+ case 0:
+ DECODE_PRINTF("AL");
+ return &M.x86.R_AL;
+ case 1:
+ DECODE_PRINTF("CL");
+ return &M.x86.R_CL;
+ case 2:
+ DECODE_PRINTF("DL");
+ return &M.x86.R_DL;
+ case 3:
+ DECODE_PRINTF("BL");
+ return &M.x86.R_BL;
+ case 4:
+ DECODE_PRINTF("AH");
+ return &M.x86.R_AH;
+ case 5:
+ DECODE_PRINTF("CH");
+ return &M.x86.R_CH;
+ case 6:
+ DECODE_PRINTF("DH");
+ return &M.x86.R_DH;
+ case 7:
+ DECODE_PRINTF("BH");
+ return &M.x86.R_BH;
+ }
+ HALT_SYS();
+ return NULL; /* NOT REACHED OR REACHED ON ERROR */
+}
+
+/****************************************************************************
+PARAMETERS:
+reg - Register to decode
+
+RETURNS:
+Pointer to the appropriate register
+
+REMARKS:
+Return a pointer to the register given by the R/RM field of the
+modrm byte, for word operands. Also enables the decoding of instructions.
+****************************************************************************/
+u16* decode_rm_word_register(
+ int reg)
+{
+ switch (reg) {
+ case 0:
+ DECODE_PRINTF("AX");
+ return &M.x86.R_AX;
+ case 1:
+ DECODE_PRINTF("CX");
+ return &M.x86.R_CX;
+ case 2:
+ DECODE_PRINTF("DX");
+ return &M.x86.R_DX;
+ case 3:
+ DECODE_PRINTF("BX");
+ return &M.x86.R_BX;
+ case 4:
+ DECODE_PRINTF("SP");
+ return &M.x86.R_SP;
+ case 5:
+ DECODE_PRINTF("BP");
+ return &M.x86.R_BP;
+ case 6:
+ DECODE_PRINTF("SI");
+ return &M.x86.R_SI;
+ case 7:
+ DECODE_PRINTF("DI");
+ return &M.x86.R_DI;
+ }
+ HALT_SYS();
+ return NULL; /* NOTREACHED OR REACHED ON ERROR */
+}
+
+/****************************************************************************
+PARAMETERS:
+reg - Register to decode
+
+RETURNS:
+Pointer to the appropriate register
+
+REMARKS:
+Return a pointer to the register given by the R/RM field of the
+modrm byte, for dword operands. Also enables the decoding of instructions.
+****************************************************************************/
+u32* decode_rm_long_register(
+ int reg)
+{
+ switch (reg) {
+ case 0:
+ DECODE_PRINTF("EAX");
+ return &M.x86.R_EAX;
+ case 1:
+ DECODE_PRINTF("ECX");
+ return &M.x86.R_ECX;
+ case 2:
+ DECODE_PRINTF("EDX");
+ return &M.x86.R_EDX;
+ case 3:
+ DECODE_PRINTF("EBX");
+ return &M.x86.R_EBX;
+ case 4:
+ DECODE_PRINTF("ESP");
+ return &M.x86.R_ESP;
+ case 5:
+ DECODE_PRINTF("EBP");
+ return &M.x86.R_EBP;
+ case 6:
+ DECODE_PRINTF("ESI");
+ return &M.x86.R_ESI;
+ case 7:
+ DECODE_PRINTF("EDI");
+ return &M.x86.R_EDI;
+ }
+ HALT_SYS();
+ return NULL; /* NOTREACHED OR REACHED ON ERROR */
+}
+
+/****************************************************************************
+PARAMETERS:
+reg - Register to decode
+
+RETURNS:
+Pointer to the appropriate register
+
+REMARKS:
+Return a pointer to the register given by the R/RM field of the
+modrm byte, for word operands, modified from above for the weirdo
+special case of segreg operands. Also enables the decoding of instructions.
+****************************************************************************/
+u16* decode_rm_seg_register(
+ int reg)
+{
+ switch (reg) {
+ case 0:
+ DECODE_PRINTF("ES");
+ return &M.x86.R_ES;
+ case 1:
+ DECODE_PRINTF("CS");
+ return &M.x86.R_CS;
+ case 2:
+ DECODE_PRINTF("SS");
+ return &M.x86.R_SS;
+ case 3:
+ DECODE_PRINTF("DS");
+ return &M.x86.R_DS;
+ case 4:
+ DECODE_PRINTF("FS");
+ return &M.x86.R_FS;
+ case 5:
+ DECODE_PRINTF("GS");
+ return &M.x86.R_GS;
+ case 6:
+ case 7:
+ DECODE_PRINTF("ILLEGAL SEGREG");
+ break;
+ }
+ HALT_SYS();
+ return NULL; /* NOT REACHED OR REACHED ON ERROR */
+}
+
+/*
+ *
+ * return offset from the SIB Byte
+ */
+u32 decode_sib_address(int sib, int mod)
+{
+ u32 base = 0, i = 0, scale = 1;
+
+ switch(sib & 0x07) {
+ case 0:
+ DECODE_PRINTF("[EAX]");
+ base = M.x86.R_EAX;
+ break;
+ case 1:
+ DECODE_PRINTF("[ECX]");
+ base = M.x86.R_ECX;
+ break;
+ case 2:
+ DECODE_PRINTF("[EDX]");
+ base = M.x86.R_EDX;
+ break;
+ case 3:
+ DECODE_PRINTF("[EBX]");
+ base = M.x86.R_EBX;
+ break;
+ case 4:
+ DECODE_PRINTF("[ESP]");
+ base = M.x86.R_ESP;
+ M.x86.mode |= SYSMODE_SEG_DS_SS;
+ break;
+ case 5:
+ if (mod == 0) {
+ base = fetch_long_imm();
+ DECODE_PRINTF2("%08x", base);
+ } else {
+ DECODE_PRINTF("[EBP]");
+ base = M.x86.R_ESP;
+ M.x86.mode |= SYSMODE_SEG_DS_SS;
+ }
+ break;
+ case 6:
+ DECODE_PRINTF("[ESI]");
+ base = M.x86.R_ESI;
+ break;
+ case 7:
+ DECODE_PRINTF("[EDI]");
+ base = M.x86.R_EDI;
+ break;
+ }
+ switch ((sib >> 3) & 0x07) {
+ case 0:
+ DECODE_PRINTF("[EAX");
+ i = M.x86.R_EAX;
+ break;
+ case 1:
+ DECODE_PRINTF("[ECX");
+ i = M.x86.R_ECX;
+ break;
+ case 2:
+ DECODE_PRINTF("[EDX");
+ i = M.x86.R_EDX;
+ break;
+ case 3:
+ DECODE_PRINTF("[EBX");
+ i = M.x86.R_EBX;
+ break;
+ case 4:
+ i = 0;
+ break;
+ case 5:
+ DECODE_PRINTF("[EBP");
+ i = M.x86.R_EBP;
+ break;
+ case 6:
+ DECODE_PRINTF("[ESI");
+ i = M.x86.R_ESI;
+ break;
+ case 7:
+ DECODE_PRINTF("[EDI");
+ i = M.x86.R_EDI;
+ break;
+ }
+ scale = 1 << ((sib >> 6) & 0x03);
+ if (((sib >> 3) & 0x07) != 4) {
+ if (scale == 1) {
+ DECODE_PRINTF("]");
+ } else {
+ DECODE_PRINTF2("*%d]", scale);
+ }
+ }
+ return base + (i * scale);
+}
+
+/****************************************************************************
+PARAMETERS:
+rm - RM value to decode
+
+RETURNS:
+Offset in memory for the address decoding
+
+REMARKS:
+Return the offset given by mod=00 addressing. Also enables the
+decoding of instructions.
+
+NOTE: The code which specifies the corresponding segment (ds vs ss)
+ below in the case of [BP+..]. The assumption here is that at the
+ point that this subroutine is called, the bit corresponding to
+ SYSMODE_SEG_DS_SS will be zero. After every instruction
+ except the segment override instructions, this bit (as well
+ as any bits indicating segment overrides) will be clear. So
+ if a SS access is needed, set this bit. Otherwise, DS access
+ occurs (unless any of the segment override bits are set).
+****************************************************************************/
+u32 decode_rm00_address(
+ int rm)
+{
+ u32 offset;
+ int sib;
+
+ if (M.x86.mode & SYSMODE_PREFIX_ADDR) {
+ /* 32-bit addressing */
+ switch (rm) {
+ case 0:
+ DECODE_PRINTF("[EAX]");
+ return M.x86.R_EAX;
+ case 1:
+ DECODE_PRINTF("[ECX]");
+ return M.x86.R_ECX;
+ case 2:
+ DECODE_PRINTF("[EDX]");
+ return M.x86.R_EDX;
+ case 3:
+ DECODE_PRINTF("[EBX]");
+ return M.x86.R_EBX;
+ case 4:
+ sib = fetch_byte_imm();
+ return decode_sib_address(sib, 0);
+ case 5:
+ offset = fetch_long_imm();
+ DECODE_PRINTF2("[%08x]", offset);
+ return offset;
+ case 6:
+ DECODE_PRINTF("[ESI]");
+ return M.x86.R_ESI;
+ case 7:
+ DECODE_PRINTF("[EDI]");
+ return M.x86.R_EDI;
+ }
+ HALT_SYS();
+ } else {
+ /* 16-bit addressing */
+ switch (rm) {
+ case 0:
+ DECODE_PRINTF("[BX+SI]");
+ return (M.x86.R_BX + M.x86.R_SI) & 0xffff;
+ case 1:
+ DECODE_PRINTF("[BX+DI]");
+ return (M.x86.R_BX + M.x86.R_DI) & 0xffff;
+ case 2:
+ DECODE_PRINTF("[BP+SI]");
+ M.x86.mode |= SYSMODE_SEG_DS_SS;
+ return (M.x86.R_BP + M.x86.R_SI) & 0xffff;
+ case 3:
+ DECODE_PRINTF("[BP+DI]");
+ M.x86.mode |= SYSMODE_SEG_DS_SS;
+ return (M.x86.R_BP + M.x86.R_DI) & 0xffff;
+ case 4:
+ DECODE_PRINTF("[SI]");
+ return M.x86.R_SI;
+ case 5:
+ DECODE_PRINTF("[DI]");
+ return M.x86.R_DI;
+ case 6:
+ offset = fetch_word_imm();
+ DECODE_PRINTF2("[%04x]", offset);
+ return offset;
+ case 7:
+ DECODE_PRINTF("[BX]");
+ return M.x86.R_BX;
+ }
+ HALT_SYS();
+ }
+ return 0;
+}
+
+/****************************************************************************
+PARAMETERS:
+rm - RM value to decode
+
+RETURNS:
+Offset in memory for the address decoding
+
+REMARKS:
+Return the offset given by mod=01 addressing. Also enables the
+decoding of instructions.
+****************************************************************************/
+u32 decode_rm01_address(
+ int rm)
+{
+ int displacement = 0;
+ int sib;
+
+ /* Fetch disp8 if no SIB byte */
+ if (!((M.x86.mode & SYSMODE_PREFIX_ADDR) && (rm == 4)))
+ displacement = (s8)fetch_byte_imm();
+
+ if (M.x86.mode & SYSMODE_PREFIX_ADDR) {
+ /* 32-bit addressing */
+ switch (rm) {
+ case 0:
+ DECODE_PRINTF2("%d[EAX]", displacement);
+ return M.x86.R_EAX + displacement;
+ case 1:
+ DECODE_PRINTF2("%d[ECX]", displacement);
+ return M.x86.R_ECX + displacement;
+ case 2:
+ DECODE_PRINTF2("%d[EDX]", displacement);
+ return M.x86.R_EDX + displacement;
+ case 3:
+ DECODE_PRINTF2("%d[EBX]", displacement);
+ return M.x86.R_EBX + displacement;
+ case 4:
+ sib = fetch_byte_imm();
+ displacement = (s8)fetch_byte_imm();
+ DECODE_PRINTF2("%d", displacement);
+ return decode_sib_address(sib, 1) + displacement;
+ case 5:
+ DECODE_PRINTF2("%d[EBP]", displacement);
+ return M.x86.R_EBP + displacement;
+ case 6:
+ DECODE_PRINTF2("%d[ESI]", displacement);
+ return M.x86.R_ESI + displacement;
+ case 7:
+ DECODE_PRINTF2("%d[EDI]", displacement);
+ return M.x86.R_EDI + displacement;
+ }
+ HALT_SYS();
+ } else {
+ /* 16-bit addressing */
+ switch (rm) {
+ case 0:
+ DECODE_PRINTF2("%d[BX+SI]", displacement);
+ return (M.x86.R_BX + M.x86.R_SI + displacement) & 0xffff;
+ case 1:
+ DECODE_PRINTF2("%d[BX+DI]", displacement);
+ return (M.x86.R_BX + M.x86.R_DI + displacement) & 0xffff;
+ case 2:
+ DECODE_PRINTF2("%d[BP+SI]", displacement);
+ M.x86.mode |= SYSMODE_SEG_DS_SS;
+ return (M.x86.R_BP + M.x86.R_SI + displacement) & 0xffff;
+ case 3:
+ DECODE_PRINTF2("%d[BP+DI]", displacement);
+ M.x86.mode |= SYSMODE_SEG_DS_SS;
+ return (M.x86.R_BP + M.x86.R_DI + displacement) & 0xffff;
+ case 4:
+ DECODE_PRINTF2("%d[SI]", displacement);
+ return (M.x86.R_SI + displacement) & 0xffff;
+ case 5:
+ DECODE_PRINTF2("%d[DI]", displacement);
+ return (M.x86.R_DI + displacement) & 0xffff;
+ case 6:
+ DECODE_PRINTF2("%d[BP]", displacement);
+ M.x86.mode |= SYSMODE_SEG_DS_SS;
+ return (M.x86.R_BP + displacement) & 0xffff;
+ case 7:
+ DECODE_PRINTF2("%d[BX]", displacement);
+ return (M.x86.R_BX + displacement) & 0xffff;
+ }
+ HALT_SYS();
+ }
+ return 0; /* SHOULD NOT HAPPEN */
+}
+
+/****************************************************************************
+PARAMETERS:
+rm - RM value to decode
+
+RETURNS:
+Offset in memory for the address decoding
+
+REMARKS:
+Return the offset given by mod=10 addressing. Also enables the
+decoding of instructions.
+****************************************************************************/
+u32 decode_rm10_address(
+ int rm)
+{
+ u32 displacement = 0;
+ int sib;
+
+ /* Fetch disp16 if 16-bit addr mode */
+ if (!(M.x86.mode & SYSMODE_PREFIX_ADDR))
+ displacement = (u16)fetch_word_imm();
+ else {
+ /* Fetch disp32 if no SIB byte */
+ if (rm != 4)
+ displacement = (u32)fetch_long_imm();
+ }
+
+ if (M.x86.mode & SYSMODE_PREFIX_ADDR) {
+ /* 32-bit addressing */
+ switch (rm) {
+ case 0:
+ DECODE_PRINTF2("%08x[EAX]", displacement);
+ return M.x86.R_EAX + displacement;
+ case 1:
+ DECODE_PRINTF2("%08x[ECX]", displacement);
+ return M.x86.R_ECX + displacement;
+ case 2:
+ DECODE_PRINTF2("%08x[EDX]", displacement);
+ M.x86.mode |= SYSMODE_SEG_DS_SS;
+ return M.x86.R_EDX + displacement;
+ case 3:
+ DECODE_PRINTF2("%08x[EBX]", displacement);
+ return M.x86.R_EBX + displacement;
+ case 4:
+ sib = fetch_byte_imm();
+ displacement = (u32)fetch_long_imm();
+ DECODE_PRINTF2("%08x", displacement);
+ return decode_sib_address(sib, 2) + displacement;
+ break;
+ case 5:
+ DECODE_PRINTF2("%08x[EBP]", displacement);
+ return M.x86.R_EBP + displacement;
+ case 6:
+ DECODE_PRINTF2("%08x[ESI]", displacement);
+ return M.x86.R_ESI + displacement;
+ case 7:
+ DECODE_PRINTF2("%08x[EDI]", displacement);
+ return M.x86.R_EDI + displacement;
+ }
+ HALT_SYS();
+ } else {
+ /* 16-bit addressing */
+ switch (rm) {
+ case 0:
+ DECODE_PRINTF2("%04x[BX+SI]", displacement);
+ return (M.x86.R_BX + M.x86.R_SI + displacement) & 0xffff;
+ case 1:
+ DECODE_PRINTF2("%04x[BX+DI]", displacement);
+ return (M.x86.R_BX + M.x86.R_DI + displacement) & 0xffff;
+ case 2:
+ DECODE_PRINTF2("%04x[BP+SI]", displacement);
+ M.x86.mode |= SYSMODE_SEG_DS_SS;
+ return (M.x86.R_BP + M.x86.R_SI + displacement) & 0xffff;
+ case 3:
+ DECODE_PRINTF2("%04x[BP+DI]", displacement);
+ M.x86.mode |= SYSMODE_SEG_DS_SS;
+ return (M.x86.R_BP + M.x86.R_DI + displacement) & 0xffff;
+ case 4:
+ DECODE_PRINTF2("%04x[SI]", displacement);
+ return (M.x86.R_SI + displacement) & 0xffff;
+ case 5:
+ DECODE_PRINTF2("%04x[DI]", displacement);
+ return (M.x86.R_DI + displacement) & 0xffff;
+ case 6:
+ DECODE_PRINTF2("%04x[BP]", displacement);
+ M.x86.mode |= SYSMODE_SEG_DS_SS;
+ return (M.x86.R_BP + displacement) & 0xffff;
+ case 7:
+ DECODE_PRINTF2("%04x[BX]", displacement);
+ return (M.x86.R_BX + displacement) & 0xffff;
+ }
+ HALT_SYS();
+ }
+ return 0;
+ /*NOTREACHED */
+}
diff --git a/userspace/sdks/nv570/nvalloc/unix/x86emu/fpu.c b/userspace/sdks/nv570/nvalloc/unix/x86emu/fpu.c
new file mode 100644
index 0000000..0a21c99
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/x86emu/fpu.c
@@ -0,0 +1,965 @@
+/****************************************************************************
+*
+* Realmode X86 Emulator Library
+*
+* Copyright (C) 1996-1999 SciTech Software, Inc.
+* Copyright (C) David Mosberger-Tang
+* Copyright (C) 1999 Egbert Eich
+*
+* ========================================================================
+*
+* Permission to use, copy, modify, distribute, and sell this software and
+* its documentation for any purpose is hereby granted without fee,
+* provided that the above copyright notice appear in all copies and that
+* both that copyright notice and this permission notice appear in
+* supporting documentation, and that the name of the authors not be used
+* in advertising or publicity pertaining to distribution of the software
+* without specific, written prior permission. The authors makes no
+* representations about the suitability of this software for any purpose.
+* It is provided "as is" without express or implied warranty.
+*
+* THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+* EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+* PERFORMANCE OF THIS SOFTWARE.
+*
+* ========================================================================
+*
+* Language: ANSI C
+* Environment: Any
+* Developer: Kendall Bennett
+*
+* Description: This file contains the code to implement the decoding and
+* emulation of the FPU instructions.
+*
+****************************************************************************/
+
+#include "x86emu/x86emui.h"
+
+/*----------------------------- Implementation ----------------------------*/
+
+/* opcode=0xd8 */
+void x86emuOp_esc_coprocess_d8(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ DECODE_PRINTF("ESC D8\n");
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR_NO_TRACE();
+}
+
+#ifdef X86EMU_DEBUG
+
+static char *x86emu_fpu_op_d9_tab[] = {
+ "FLD\tDWORD PTR ", "ESC_D9\t", "FST\tDWORD PTR ", "FSTP\tDWORD PTR ",
+ "FLDENV\t", "FLDCW\t", "FSTENV\t", "FSTCW\t",
+
+ "FLD\tDWORD PTR ", "ESC_D9\t", "FST\tDWORD PTR ", "FSTP\tDWORD PTR ",
+ "FLDENV\t", "FLDCW\t", "FSTENV\t", "FSTCW\t",
+
+ "FLD\tDWORD PTR ", "ESC_D9\t", "FST\tDWORD PTR ", "FSTP\tDWORD PTR ",
+ "FLDENV\t", "FLDCW\t", "FSTENV\t", "FSTCW\t",
+};
+
+static char *x86emu_fpu_op_d9_tab1[] = {
+ "FLD\t", "FLD\t", "FLD\t", "FLD\t",
+ "FLD\t", "FLD\t", "FLD\t", "FLD\t",
+
+ "FXCH\t", "FXCH\t", "FXCH\t", "FXCH\t",
+ "FXCH\t", "FXCH\t", "FXCH\t", "FXCH\t",
+
+ "FNOP", "ESC_D9", "ESC_D9", "ESC_D9",
+ "ESC_D9", "ESC_D9", "ESC_D9", "ESC_D9",
+
+ "FSTP\t", "FSTP\t", "FSTP\t", "FSTP\t",
+ "FSTP\t", "FSTP\t", "FSTP\t", "FSTP\t",
+
+ "FCHS", "FABS", "ESC_D9", "ESC_D9",
+ "FTST", "FXAM", "ESC_D9", "ESC_D9",
+
+ "FLD1", "FLDL2T", "FLDL2E", "FLDPI",
+ "FLDLG2", "FLDLN2", "FLDZ", "ESC_D9",
+
+ "F2XM1", "FYL2X", "FPTAN", "FPATAN",
+ "FXTRACT", "ESC_D9", "FDECSTP", "FINCSTP",
+
+ "FPREM", "FYL2XP1", "FSQRT", "ESC_D9",
+ "FRNDINT", "FSCALE", "ESC_D9", "ESC_D9",
+};
+
+#endif /* X86EMU_DEBUG */
+
+/* opcode=0xd9 */
+void x86emuOp_esc_coprocess_d9(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ uint destoffset = 0;
+ u8 stkelem = 0;
+
+ START_OF_INSTR();
+ FETCH_DECODE_MODRM(mod, rh, rl);
+#ifdef X86EMU_DEBUG
+ if (mod != 3) {
+ DECODE_PRINTINSTR32(x86emu_fpu_op_d9_tab, mod, rh, rl);
+ } else {
+ DECODE_PRINTF(x86emu_fpu_op_d9_tab1[(rh << 3) + rl]);
+ }
+#endif
+ switch (mod) {
+ case 0:
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF("\n");
+ break;
+ case 1:
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF("\n");
+ break;
+ case 2:
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF("\n");
+ break;
+ case 3: /* register to register */
+ stkelem = (u8)rl;
+ if (rh < 4) {
+ DECODE_PRINTF2("ST(%d)\n", stkelem);
+ } else {
+ DECODE_PRINTF("\n");
+ }
+ break;
+ }
+#ifdef X86EMU_FPU_PRESENT
+ /* execute */
+ switch (mod) {
+ case 3:
+ switch (rh) {
+ case 0:
+ x86emu_fpu_R_fld(X86EMU_FPU_STKTOP, stkelem);
+ break;
+ case 1:
+ x86emu_fpu_R_fxch(X86EMU_FPU_STKTOP, stkelem);
+ break;
+ case 2:
+ switch (rl) {
+ case 0:
+ x86emu_fpu_R_nop();
+ break;
+ default:
+ x86emu_fpu_illegal();
+ break;
+ }
+ case 3:
+ x86emu_fpu_R_fstp(X86EMU_FPU_STKTOP, stkelem);
+ break;
+ case 4:
+ switch (rl) {
+ case 0:
+ x86emu_fpu_R_fchs(X86EMU_FPU_STKTOP);
+ break;
+ case 1:
+ x86emu_fpu_R_fabs(X86EMU_FPU_STKTOP);
+ break;
+ case 4:
+ x86emu_fpu_R_ftst(X86EMU_FPU_STKTOP);
+ break;
+ case 5:
+ x86emu_fpu_R_fxam(X86EMU_FPU_STKTOP);
+ break;
+ default:
+ /* 2,3,6,7 */
+ x86emu_fpu_illegal();
+ break;
+ }
+ break;
+
+ case 5:
+ switch (rl) {
+ case 0:
+ x86emu_fpu_R_fld1(X86EMU_FPU_STKTOP);
+ break;
+ case 1:
+ x86emu_fpu_R_fldl2t(X86EMU_FPU_STKTOP);
+ break;
+ case 2:
+ x86emu_fpu_R_fldl2e(X86EMU_FPU_STKTOP);
+ break;
+ case 3:
+ x86emu_fpu_R_fldpi(X86EMU_FPU_STKTOP);
+ break;
+ case 4:
+ x86emu_fpu_R_fldlg2(X86EMU_FPU_STKTOP);
+ break;
+ case 5:
+ x86emu_fpu_R_fldln2(X86EMU_FPU_STKTOP);
+ break;
+ case 6:
+ x86emu_fpu_R_fldz(X86EMU_FPU_STKTOP);
+ break;
+ default:
+ /* 7 */
+ x86emu_fpu_illegal();
+ break;
+ }
+ break;
+
+ case 6:
+ switch (rl) {
+ case 0:
+ x86emu_fpu_R_f2xm1(X86EMU_FPU_STKTOP);
+ break;
+ case 1:
+ x86emu_fpu_R_fyl2x(X86EMU_FPU_STKTOP);
+ break;
+ case 2:
+ x86emu_fpu_R_fptan(X86EMU_FPU_STKTOP);
+ break;
+ case 3:
+ x86emu_fpu_R_fpatan(X86EMU_FPU_STKTOP);
+ break;
+ case 4:
+ x86emu_fpu_R_fxtract(X86EMU_FPU_STKTOP);
+ break;
+ case 5:
+ x86emu_fpu_illegal();
+ break;
+ case 6:
+ x86emu_fpu_R_decstp();
+ break;
+ case 7:
+ x86emu_fpu_R_incstp();
+ break;
+ }
+ break;
+
+ case 7:
+ switch (rl) {
+ case 0:
+ x86emu_fpu_R_fprem(X86EMU_FPU_STKTOP);
+ break;
+ case 1:
+ x86emu_fpu_R_fyl2xp1(X86EMU_FPU_STKTOP);
+ break;
+ case 2:
+ x86emu_fpu_R_fsqrt(X86EMU_FPU_STKTOP);
+ break;
+ case 3:
+ x86emu_fpu_illegal();
+ break;
+ case 4:
+ x86emu_fpu_R_frndint(X86EMU_FPU_STKTOP);
+ break;
+ case 5:
+ x86emu_fpu_R_fscale(X86EMU_FPU_STKTOP);
+ break;
+ case 6:
+ case 7:
+ default:
+ x86emu_fpu_illegal();
+ break;
+ }
+ break;
+
+ default:
+ switch (rh) {
+ case 0:
+ x86emu_fpu_M_fld(X86EMU_FPU_FLOAT, destoffset);
+ break;
+ case 1:
+ x86emu_fpu_illegal();
+ break;
+ case 2:
+ x86emu_fpu_M_fst(X86EMU_FPU_FLOAT, destoffset);
+ break;
+ case 3:
+ x86emu_fpu_M_fstp(X86EMU_FPU_FLOAT, destoffset);
+ break;
+ case 4:
+ x86emu_fpu_M_fldenv(X86EMU_FPU_WORD, destoffset);
+ break;
+ case 5:
+ x86emu_fpu_M_fldcw(X86EMU_FPU_WORD, destoffset);
+ break;
+ case 6:
+ x86emu_fpu_M_fstenv(X86EMU_FPU_WORD, destoffset);
+ break;
+ case 7:
+ x86emu_fpu_M_fstcw(X86EMU_FPU_WORD, destoffset);
+ break;
+ }
+ }
+ }
+#else
+ (void)destoffset;
+ (void)stkelem;
+#endif /* X86EMU_FPU_PRESENT */
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR_NO_TRACE();
+}
+
+#ifdef X86EMU_DEBUG
+
+char *x86emu_fpu_op_da_tab[] = {
+ "FIADD\tDWORD PTR ", "FIMUL\tDWORD PTR ", "FICOM\tDWORD PTR ",
+ "FICOMP\tDWORD PTR ",
+ "FISUB\tDWORD PTR ", "FISUBR\tDWORD PTR ", "FIDIV\tDWORD PTR ",
+ "FIDIVR\tDWORD PTR ",
+
+ "FIADD\tDWORD PTR ", "FIMUL\tDWORD PTR ", "FICOM\tDWORD PTR ",
+ "FICOMP\tDWORD PTR ",
+ "FISUB\tDWORD PTR ", "FISUBR\tDWORD PTR ", "FIDIV\tDWORD PTR ",
+ "FIDIVR\tDWORD PTR ",
+
+ "FIADD\tDWORD PTR ", "FIMUL\tDWORD PTR ", "FICOM\tDWORD PTR ",
+ "FICOMP\tDWORD PTR ",
+ "FISUB\tDWORD PTR ", "FISUBR\tDWORD PTR ", "FIDIV\tDWORD PTR ",
+ "FIDIVR\tDWORD PTR ",
+
+ "ESC_DA ", "ESC_DA ", "ESC_DA ", "ESC_DA ",
+ "ESC_DA ", "ESC_DA ", "ESC_DA ", "ESC_DA ",
+};
+
+#endif /* X86EMU_DEBUG */
+
+/* opcode=0xda */
+void x86emuOp_esc_coprocess_da(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ uint destoffset = 0;
+ u8 stkelem = 0;
+
+ START_OF_INSTR();
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ DECODE_PRINTINSTR32(x86emu_fpu_op_da_tab, mod, rh, rl);
+ switch (mod) {
+ case 0:
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF("\n");
+ break;
+ case 1:
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF("\n");
+ break;
+ case 2:
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF("\n");
+ break;
+ case 3: /* register to register */
+ stkelem = (u8)rl;
+ DECODE_PRINTF2("\tST(%d),ST\n", stkelem);
+ break;
+ }
+#ifdef X86EMU_FPU_PRESENT
+ switch (mod) {
+ case 3:
+ x86emu_fpu_illegal();
+ break;
+ default:
+ switch (rh) {
+ case 0:
+ x86emu_fpu_M_iadd(X86EMU_FPU_SHORT, destoffset);
+ break;
+ case 1:
+ x86emu_fpu_M_imul(X86EMU_FPU_SHORT, destoffset);
+ break;
+ case 2:
+ x86emu_fpu_M_icom(X86EMU_FPU_SHORT, destoffset);
+ break;
+ case 3:
+ x86emu_fpu_M_icomp(X86EMU_FPU_SHORT, destoffset);
+ break;
+ case 4:
+ x86emu_fpu_M_isub(X86EMU_FPU_SHORT, destoffset);
+ break;
+ case 5:
+ x86emu_fpu_M_isubr(X86EMU_FPU_SHORT, destoffset);
+ break;
+ case 6:
+ x86emu_fpu_M_idiv(X86EMU_FPU_SHORT, destoffset);
+ break;
+ case 7:
+ x86emu_fpu_M_idivr(X86EMU_FPU_SHORT, destoffset);
+ break;
+ }
+ }
+#else
+ (void)destoffset;
+ (void)stkelem;
+#endif
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR_NO_TRACE();
+}
+
+#ifdef X86EMU_DEBUG
+
+char *x86emu_fpu_op_db_tab[] = {
+ "FILD\tDWORD PTR ", "ESC_DB\t19", "FIST\tDWORD PTR ", "FISTP\tDWORD PTR ",
+ "ESC_DB\t1C", "FLD\tTBYTE PTR ", "ESC_DB\t1E", "FSTP\tTBYTE PTR ",
+
+ "FILD\tDWORD PTR ", "ESC_DB\t19", "FIST\tDWORD PTR ", "FISTP\tDWORD PTR ",
+ "ESC_DB\t1C", "FLD\tTBYTE PTR ", "ESC_DB\t1E", "FSTP\tTBYTE PTR ",
+
+ "FILD\tDWORD PTR ", "ESC_DB\t19", "FIST\tDWORD PTR ", "FISTP\tDWORD PTR ",
+ "ESC_DB\t1C", "FLD\tTBYTE PTR ", "ESC_DB\t1E", "FSTP\tTBYTE PTR ",
+};
+
+#endif /* X86EMU_DEBUG */
+
+/* opcode=0xdb */
+void x86emuOp_esc_coprocess_db(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ uint destoffset = 0;
+
+ START_OF_INSTR();
+ FETCH_DECODE_MODRM(mod, rh, rl);
+#ifdef X86EMU_DEBUG
+ if (mod != 3) {
+ DECODE_PRINTINSTR32(x86emu_fpu_op_db_tab, mod, rh, rl);
+ } else if (rh == 4) { /* === 11 10 0 nnn */
+ switch (rl) {
+ case 0:
+ DECODE_PRINTF("FENI\n");
+ break;
+ case 1:
+ DECODE_PRINTF("FDISI\n");
+ break;
+ case 2:
+ DECODE_PRINTF("FCLEX\n");
+ break;
+ case 3:
+ DECODE_PRINTF("FINIT\n");
+ break;
+ }
+ } else {
+ DECODE_PRINTF2("ESC_DB %0x\n", (mod << 6) + (rh << 3) + (rl));
+ }
+#endif /* X86EMU_DEBUG */
+ switch (mod) {
+ case 0:
+ destoffset = decode_rm00_address(rl);
+ break;
+ case 1:
+ destoffset = decode_rm01_address(rl);
+ break;
+ case 2:
+ destoffset = decode_rm10_address(rl);
+ break;
+ case 3: /* register to register */
+ break;
+ }
+#ifdef X86EMU_FPU_PRESENT
+ /* execute */
+ switch (mod) {
+ case 3:
+ switch (rh) {
+ case 4:
+ switch (rl) {
+ case 0:
+ x86emu_fpu_R_feni();
+ break;
+ case 1:
+ x86emu_fpu_R_fdisi();
+ break;
+ case 2:
+ x86emu_fpu_R_fclex();
+ break;
+ case 3:
+ x86emu_fpu_R_finit();
+ break;
+ default:
+ x86emu_fpu_illegal();
+ break;
+ }
+ break;
+ default:
+ x86emu_fpu_illegal();
+ break;
+ }
+ break;
+ default:
+ switch (rh) {
+ case 0:
+ x86emu_fpu_M_fild(X86EMU_FPU_SHORT, destoffset);
+ break;
+ case 1:
+ x86emu_fpu_illegal();
+ break;
+ case 2:
+ x86emu_fpu_M_fist(X86EMU_FPU_SHORT, destoffset);
+ break;
+ case 3:
+ x86emu_fpu_M_fistp(X86EMU_FPU_SHORT, destoffset);
+ break;
+ case 4:
+ x86emu_fpu_illegal();
+ break;
+ case 5:
+ x86emu_fpu_M_fld(X86EMU_FPU_LDBL, destoffset);
+ break;
+ case 6:
+ x86emu_fpu_illegal();
+ break;
+ case 7:
+ x86emu_fpu_M_fstp(X86EMU_FPU_LDBL, destoffset);
+ break;
+ }
+ }
+#else
+ (void)destoffset;
+#endif
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR_NO_TRACE();
+}
+
+#ifdef X86EMU_DEBUG
+char *x86emu_fpu_op_dc_tab[] = {
+ "FADD\tQWORD PTR ", "FMUL\tQWORD PTR ", "FCOM\tQWORD PTR ",
+ "FCOMP\tQWORD PTR ",
+ "FSUB\tQWORD PTR ", "FSUBR\tQWORD PTR ", "FDIV\tQWORD PTR ",
+ "FDIVR\tQWORD PTR ",
+
+ "FADD\tQWORD PTR ", "FMUL\tQWORD PTR ", "FCOM\tQWORD PTR ",
+ "FCOMP\tQWORD PTR ",
+ "FSUB\tQWORD PTR ", "FSUBR\tQWORD PTR ", "FDIV\tQWORD PTR ",
+ "FDIVR\tQWORD PTR ",
+
+ "FADD\tQWORD PTR ", "FMUL\tQWORD PTR ", "FCOM\tQWORD PTR ",
+ "FCOMP\tQWORD PTR ",
+ "FSUB\tQWORD PTR ", "FSUBR\tQWORD PTR ", "FDIV\tQWORD PTR ",
+ "FDIVR\tQWORD PTR ",
+
+ "FADD\t", "FMUL\t", "FCOM\t", "FCOMP\t",
+ "FSUBR\t", "FSUB\t", "FDIVR\t", "FDIV\t",
+};
+#endif /* X86EMU_DEBUG */
+
+/* opcode=0xdc */
+void x86emuOp_esc_coprocess_dc(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ uint destoffset = 0;
+ u8 stkelem = 0;
+
+ START_OF_INSTR();
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ DECODE_PRINTINSTR32(x86emu_fpu_op_dc_tab, mod, rh, rl);
+ switch (mod) {
+ case 0:
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF("\n");
+ break;
+ case 1:
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF("\n");
+ break;
+ case 2:
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF("\n");
+ break;
+ case 3: /* register to register */
+ stkelem = (u8)rl;
+ DECODE_PRINTF2("\tST(%d),ST\n", stkelem);
+ break;
+ }
+#ifdef X86EMU_FPU_PRESENT
+ /* execute */
+ switch (mod) {
+ case 3:
+ switch (rh) {
+ case 0:
+ x86emu_fpu_R_fadd(stkelem, X86EMU_FPU_STKTOP);
+ break;
+ case 1:
+ x86emu_fpu_R_fmul(stkelem, X86EMU_FPU_STKTOP);
+ break;
+ case 2:
+ x86emu_fpu_R_fcom(stkelem, X86EMU_FPU_STKTOP);
+ break;
+ case 3:
+ x86emu_fpu_R_fcomp(stkelem, X86EMU_FPU_STKTOP);
+ break;
+ case 4:
+ x86emu_fpu_R_fsubr(stkelem, X86EMU_FPU_STKTOP);
+ break;
+ case 5:
+ x86emu_fpu_R_fsub(stkelem, X86EMU_FPU_STKTOP);
+ break;
+ case 6:
+ x86emu_fpu_R_fdivr(stkelem, X86EMU_FPU_STKTOP);
+ break;
+ case 7:
+ x86emu_fpu_R_fdiv(stkelem, X86EMU_FPU_STKTOP);
+ break;
+ }
+ break;
+ default:
+ switch (rh) {
+ case 0:
+ x86emu_fpu_M_fadd(X86EMU_FPU_DOUBLE, destoffset);
+ break;
+ case 1:
+ x86emu_fpu_M_fmul(X86EMU_FPU_DOUBLE, destoffset);
+ break;
+ case 2:
+ x86emu_fpu_M_fcom(X86EMU_FPU_DOUBLE, destoffset);
+ break;
+ case 3:
+ x86emu_fpu_M_fcomp(X86EMU_FPU_DOUBLE, destoffset);
+ break;
+ case 4:
+ x86emu_fpu_M_fsub(X86EMU_FPU_DOUBLE, destoffset);
+ break;
+ case 5:
+ x86emu_fpu_M_fsubr(X86EMU_FPU_DOUBLE, destoffset);
+ break;
+ case 6:
+ x86emu_fpu_M_fdiv(X86EMU_FPU_DOUBLE, destoffset);
+ break;
+ case 7:
+ x86emu_fpu_M_fdivr(X86EMU_FPU_DOUBLE, destoffset);
+ break;
+ }
+ }
+#else
+ (void)destoffset;
+ (void)stkelem;
+#endif
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR_NO_TRACE();
+}
+
+#ifdef X86EMU_DEBUG
+
+static char *x86emu_fpu_op_dd_tab[] = {
+ "FLD\tQWORD PTR ", "ESC_DD\t29,", "FST\tQWORD PTR ", "FSTP\tQWORD PTR ",
+ "FRSTOR\t", "ESC_DD\t2D,", "FSAVE\t", "FSTSW\t",
+
+ "FLD\tQWORD PTR ", "ESC_DD\t29,", "FST\tQWORD PTR ", "FSTP\tQWORD PTR ",
+ "FRSTOR\t", "ESC_DD\t2D,", "FSAVE\t", "FSTSW\t",
+
+ "FLD\tQWORD PTR ", "ESC_DD\t29,", "FST\tQWORD PTR ", "FSTP\tQWORD PTR ",
+ "FRSTOR\t", "ESC_DD\t2D,", "FSAVE\t", "FSTSW\t",
+
+ "FFREE\t", "FXCH\t", "FST\t", "FSTP\t",
+ "ESC_DD\t2C,", "ESC_DD\t2D,", "ESC_DD\t2E,", "ESC_DD\t2F,",
+};
+
+#endif /* X86EMU_DEBUG */
+
+/* opcode=0xdd */
+void x86emuOp_esc_coprocess_dd(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ uint destoffset = 0;
+ u8 stkelem = 0;
+
+ START_OF_INSTR();
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ DECODE_PRINTINSTR32(x86emu_fpu_op_dd_tab, mod, rh, rl);
+ switch (mod) {
+ case 0:
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF("\n");
+ break;
+ case 1:
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF("\n");
+ break;
+ case 2:
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF("\n");
+ break;
+ case 3: /* register to register */
+ stkelem = (u8)rl;
+ DECODE_PRINTF2("\tST(%d),ST\n", stkelem);
+ break;
+ }
+#ifdef X86EMU_FPU_PRESENT
+ switch (mod) {
+ case 3:
+ switch (rh) {
+ case 0:
+ x86emu_fpu_R_ffree(stkelem);
+ break;
+ case 1:
+ x86emu_fpu_R_fxch(stkelem);
+ break;
+ case 2:
+ x86emu_fpu_R_fst(stkelem); /* register version */
+ break;
+ case 3:
+ x86emu_fpu_R_fstp(stkelem); /* register version */
+ break;
+ default:
+ x86emu_fpu_illegal();
+ break;
+ }
+ break;
+ default:
+ switch (rh) {
+ case 0:
+ x86emu_fpu_M_fld(X86EMU_FPU_DOUBLE, destoffset);
+ break;
+ case 1:
+ x86emu_fpu_illegal();
+ break;
+ case 2:
+ x86emu_fpu_M_fst(X86EMU_FPU_DOUBLE, destoffset);
+ break;
+ case 3:
+ x86emu_fpu_M_fstp(X86EMU_FPU_DOUBLE, destoffset);
+ break;
+ case 4:
+ x86emu_fpu_M_frstor(X86EMU_FPU_WORD, destoffset);
+ break;
+ case 5:
+ x86emu_fpu_illegal();
+ break;
+ case 6:
+ x86emu_fpu_M_fsave(X86EMU_FPU_WORD, destoffset);
+ break;
+ case 7:
+ x86emu_fpu_M_fstsw(X86EMU_FPU_WORD, destoffset);
+ break;
+ }
+ }
+#else
+ (void)destoffset;
+ (void)stkelem;
+#endif
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR_NO_TRACE();
+}
+
+#ifdef X86EMU_DEBUG
+
+static char *x86emu_fpu_op_de_tab[] =
+{
+ "FIADD\tWORD PTR ", "FIMUL\tWORD PTR ", "FICOM\tWORD PTR ",
+ "FICOMP\tWORD PTR ",
+ "FISUB\tWORD PTR ", "FISUBR\tWORD PTR ", "FIDIV\tWORD PTR ",
+ "FIDIVR\tWORD PTR ",
+
+ "FIADD\tWORD PTR ", "FIMUL\tWORD PTR ", "FICOM\tWORD PTR ",
+ "FICOMP\tWORD PTR ",
+ "FISUB\tWORD PTR ", "FISUBR\tWORD PTR ", "FIDIV\tWORD PTR ",
+ "FIDIVR\tWORD PTR ",
+
+ "FIADD\tWORD PTR ", "FIMUL\tWORD PTR ", "FICOM\tWORD PTR ",
+ "FICOMP\tWORD PTR ",
+ "FISUB\tWORD PTR ", "FISUBR\tWORD PTR ", "FIDIV\tWORD PTR ",
+ "FIDIVR\tWORD PTR ",
+
+ "FADDP\t", "FMULP\t", "FCOMP\t", "FCOMPP\t",
+ "FSUBRP\t", "FSUBP\t", "FDIVRP\t", "FDIVP\t",
+};
+
+#endif /* X86EMU_DEBUG */
+
+/* opcode=0xde */
+void x86emuOp_esc_coprocess_de(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ uint destoffset = 0;
+ u8 stkelem = 0;
+
+ START_OF_INSTR();
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ DECODE_PRINTINSTR32(x86emu_fpu_op_de_tab, mod, rh, rl);
+ switch (mod) {
+ case 0:
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF("\n");
+ break;
+ case 1:
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF("\n");
+ break;
+ case 2:
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF("\n");
+ break;
+ case 3: /* register to register */
+ stkelem = (u8)rl;
+ DECODE_PRINTF2("\tST(%d),ST\n", stkelem);
+ break;
+ }
+#ifdef X86EMU_FPU_PRESENT
+ switch (mod) {
+ case 3:
+ switch (rh) {
+ case 0:
+ x86emu_fpu_R_faddp(stkelem, X86EMU_FPU_STKTOP);
+ break;
+ case 1:
+ x86emu_fpu_R_fmulp(stkelem, X86EMU_FPU_STKTOP);
+ break;
+ case 2:
+ x86emu_fpu_R_fcomp(stkelem, X86EMU_FPU_STKTOP);
+ break;
+ case 3:
+ if (stkelem == 1)
+ x86emu_fpu_R_fcompp(stkelem, X86EMU_FPU_STKTOP);
+ else
+ x86emu_fpu_illegal();
+ break;
+ case 4:
+ x86emu_fpu_R_fsubrp(stkelem, X86EMU_FPU_STKTOP);
+ break;
+ case 5:
+ x86emu_fpu_R_fsubp(stkelem, X86EMU_FPU_STKTOP);
+ break;
+ case 6:
+ x86emu_fpu_R_fdivrp(stkelem, X86EMU_FPU_STKTOP);
+ break;
+ case 7:
+ x86emu_fpu_R_fdivp(stkelem, X86EMU_FPU_STKTOP);
+ break;
+ }
+ break;
+ default:
+ switch (rh) {
+ case 0:
+ x86emu_fpu_M_fiadd(X86EMU_FPU_WORD, destoffset);
+ break;
+ case 1:
+ x86emu_fpu_M_fimul(X86EMU_FPU_WORD, destoffset);
+ break;
+ case 2:
+ x86emu_fpu_M_ficom(X86EMU_FPU_WORD, destoffset);
+ break;
+ case 3:
+ x86emu_fpu_M_ficomp(X86EMU_FPU_WORD, destoffset);
+ break;
+ case 4:
+ x86emu_fpu_M_fisub(X86EMU_FPU_WORD, destoffset);
+ break;
+ case 5:
+ x86emu_fpu_M_fisubr(X86EMU_FPU_WORD, destoffset);
+ break;
+ case 6:
+ x86emu_fpu_M_fidiv(X86EMU_FPU_WORD, destoffset);
+ break;
+ case 7:
+ x86emu_fpu_M_fidivr(X86EMU_FPU_WORD, destoffset);
+ break;
+ }
+ }
+#else
+ (void)destoffset;
+ (void)stkelem;
+#endif
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR_NO_TRACE();
+}
+
+#ifdef X86EMU_DEBUG
+
+static char *x86emu_fpu_op_df_tab[] = {
+ /* mod == 00 */
+ "FILD\tWORD PTR ", "ESC_DF\t39\n", "FIST\tWORD PTR ", "FISTP\tWORD PTR ",
+ "FBLD\tTBYTE PTR ", "FILD\tQWORD PTR ", "FBSTP\tTBYTE PTR ",
+ "FISTP\tQWORD PTR ",
+
+ /* mod == 01 */
+ "FILD\tWORD PTR ", "ESC_DF\t39 ", "FIST\tWORD PTR ", "FISTP\tWORD PTR ",
+ "FBLD\tTBYTE PTR ", "FILD\tQWORD PTR ", "FBSTP\tTBYTE PTR ",
+ "FISTP\tQWORD PTR ",
+
+ /* mod == 10 */
+ "FILD\tWORD PTR ", "ESC_DF\t39 ", "FIST\tWORD PTR ", "FISTP\tWORD PTR ",
+ "FBLD\tTBYTE PTR ", "FILD\tQWORD PTR ", "FBSTP\tTBYTE PTR ",
+ "FISTP\tQWORD PTR ",
+
+ /* mod == 11 */
+ "FFREE\t", "FXCH\t", "FST\t", "FSTP\t",
+ "ESC_DF\t3C,", "ESC_DF\t3D,", "ESC_DF\t3E,", "ESC_DF\t3F,"
+};
+
+#endif /* X86EMU_DEBUG */
+
+/* opcode=0xdf */
+void x86emuOp_esc_coprocess_df(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ uint destoffset = 0;
+ u8 stkelem = 0;
+
+ START_OF_INSTR();
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ DECODE_PRINTINSTR32(x86emu_fpu_op_df_tab, mod, rh, rl);
+ switch (mod) {
+ case 0:
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF("\n");
+ break;
+ case 1:
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF("\n");
+ break;
+ case 2:
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF("\n");
+ break;
+ case 3: /* register to register */
+ stkelem = (u8)rl;
+ DECODE_PRINTF2("\tST(%d)\n", stkelem);
+ break;
+ }
+#ifdef X86EMU_FPU_PRESENT
+ switch (mod) {
+ case 3:
+ switch (rh) {
+ case 0:
+ x86emu_fpu_R_ffree(stkelem);
+ break;
+ case 1:
+ x86emu_fpu_R_fxch(stkelem);
+ break;
+ case 2:
+ x86emu_fpu_R_fst(stkelem); /* register version */
+ break;
+ case 3:
+ x86emu_fpu_R_fstp(stkelem); /* register version */
+ break;
+ default:
+ x86emu_fpu_illegal();
+ break;
+ }
+ break;
+ default:
+ switch (rh) {
+ case 0:
+ x86emu_fpu_M_fild(X86EMU_FPU_WORD, destoffset);
+ break;
+ case 1:
+ x86emu_fpu_illegal();
+ break;
+ case 2:
+ x86emu_fpu_M_fist(X86EMU_FPU_WORD, destoffset);
+ break;
+ case 3:
+ x86emu_fpu_M_fistp(X86EMU_FPU_WORD, destoffset);
+ break;
+ case 4:
+ x86emu_fpu_M_fbld(X86EMU_FPU_BSD, destoffset);
+ break;
+ case 5:
+ x86emu_fpu_M_fild(X86EMU_FPU_LONG, destoffset);
+ break;
+ case 6:
+ x86emu_fpu_M_fbstp(X86EMU_FPU_BSD, destoffset);
+ break;
+ case 7:
+ x86emu_fpu_M_fistp(X86EMU_FPU_LONG, destoffset);
+ break;
+ }
+ }
+#else
+ (void)destoffset;
+ (void)stkelem;
+#endif
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR_NO_TRACE();
+}
diff --git a/userspace/sdks/nv570/nvalloc/unix/x86emu/ops.c b/userspace/sdks/nv570/nvalloc/unix/x86emu/ops.c
new file mode 100644
index 0000000..52b97b4
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/x86emu/ops.c
@@ -0,0 +1,11761 @@
+/****************************************************************************
+*
+* Realmode X86 Emulator Library
+*
+* Copyright (C) 1996-1999 SciTech Software, Inc.
+* Copyright (C) David Mosberger-Tang
+* Copyright (C) 1999 Egbert Eich
+*
+* ========================================================================
+*
+* Permission to use, copy, modify, distribute, and sell this software and
+* its documentation for any purpose is hereby granted without fee,
+* provided that the above copyright notice appear in all copies and that
+* both that copyright notice and this permission notice appear in
+* supporting documentation, and that the name of the authors not be used
+* in advertising or publicity pertaining to distribution of the software
+* without specific, written prior permission. The authors makes no
+* representations about the suitability of this software for any purpose.
+* It is provided "as is" without express or implied warranty.
+*
+* THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+* EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+* PERFORMANCE OF THIS SOFTWARE.
+*
+* ========================================================================
+*
+* Language: ANSI C
+* Environment: Any
+* Developer: Kendall Bennett
+*
+* Description: This file includes subroutines to implement the decoding
+* and emulation of all the x86 processor instructions.
+*
+* There are approximately 250 subroutines in here, which correspond
+* to the 256 byte-"opcodes" found on the 8086. The table which
+* dispatches this is found in the files optab.[ch].
+*
+* Each opcode proc has a comment preceeding it which gives it's table
+* address. Several opcodes are missing (undefined) in the table.
+*
+* Each proc includes information for decoding (DECODE_PRINTF and
+* DECODE_PRINTF2), debugging (TRACE_REGS, SINGLE_STEP), and misc
+* functions (START_OF_INSTR, END_OF_INSTR).
+*
+* Many of the procedures are *VERY* similar in coding. This has
+* allowed for a very large amount of code to be generated in a fairly
+* short amount of time (i.e. cut, paste, and modify). The result is
+* that much of the code below could have been folded into subroutines
+* for a large reduction in size of this file. The downside would be
+* that there would be a penalty in execution speed. The file could
+* also have been *MUCH* larger by inlining certain functions which
+* were called. This could have resulted even faster execution. The
+* prime directive I used to decide whether to inline the code or to
+* modularize it, was basically: 1) no unnecessary subroutine calls,
+* 2) no routines more than about 200 lines in size, and 3) modularize
+* any code that I might not get right the first time. The fetch_*
+* subroutines fall into the latter category. The The decode_* fall
+* into the second category. The coding of the "switch(mod){ .... }"
+* in many of the subroutines below falls into the first category.
+* Especially, the coding of {add,and,or,sub,...}_{byte,word}
+* subroutines are an especially glaring case of the third guideline.
+* Since so much of the code is cloned from other modules (compare
+* opcode #00 to opcode #01), making the basic operations subroutine
+* calls is especially important; otherwise mistakes in coding an
+* "add" would represent a nightmare in maintenance.
+*
+****************************************************************************/
+
+#include "x86emu/x86emui.h"
+
+/*----------------------------- Implementation ----------------------------*/
+
+/****************************************************************************
+PARAMETERS:
+op1 - Instruction op code
+
+REMARKS:
+Handles illegal opcodes.
+****************************************************************************/
+static void x86emuOp_illegal_op(
+ u8 op1)
+{
+ START_OF_INSTR();
+ if (M.x86.R_SP != 0) {
+ DECODE_PRINTF("ILLEGAL X86 OPCODE\n");
+ TRACE_REGS();
+ DB( NV_PRINTF(LEVEL_INFO, "%04x:%04x: %02X ILLEGAL X86 OPCODE!\n",
+ M.x86.R_CS, M.x86.R_IP - 1, op1);)
+ HALT_SYS();
+ }
+ else {
+ /* If we get here, it means the stack pointer is back to zero
+ * so we are just returning from an emulator service call
+ * so therte is no need to display an error message. We trap
+ * the emulator with an 0xF1 opcode to finish the service
+ * call.
+ */
+ X86EMU_halt_sys();
+ }
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x00
+****************************************************************************/
+static void x86emuOp_add_byte_RM_R(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ uint destoffset;
+ u8 *destreg, *srcreg;
+ u8 destval;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("ADD\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_byte(destoffset);
+ srcreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = add_byte(destval, *srcreg);
+ store_data_byte(destoffset, destval);
+ break;
+ case 1:
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_byte(destoffset);
+ srcreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = add_byte(destval, *srcreg);
+ store_data_byte(destoffset, destval);
+ break;
+ case 2:
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_byte(destoffset);
+ srcreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = add_byte(destval, *srcreg);
+ store_data_byte(destoffset, destval);
+ break;
+ case 3: /* register to register */
+ destreg = DECODE_RM_BYTE_REGISTER(rl);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = add_byte(*destreg, *srcreg);
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x01
+****************************************************************************/
+static void x86emuOp_add_word_RM_R(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ uint destoffset;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("ADD\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+ u32 *srcreg;
+
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_long(destoffset);
+ srcreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = add_long(destval, *srcreg);
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+ u16 *srcreg;
+
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_word(destoffset);
+ srcreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = add_word(destval, *srcreg);
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 1:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+ u32 *srcreg;
+
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_long(destoffset);
+ srcreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = add_long(destval, *srcreg);
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+ u16 *srcreg;
+
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_word(destoffset);
+ srcreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = add_word(destval, *srcreg);
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 2:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+ u32 *srcreg;
+
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_long(destoffset);
+ srcreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = add_long(destval, *srcreg);
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+ u16 *srcreg;
+
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_word(destoffset);
+ srcreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = add_word(destval, *srcreg);
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 3: /* register to register */
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg,*srcreg;
+
+ destreg = DECODE_RM_LONG_REGISTER(rl);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = add_long(*destreg, *srcreg);
+ } else {
+ u16 *destreg,*srcreg;
+
+ destreg = DECODE_RM_WORD_REGISTER(rl);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = add_word(*destreg, *srcreg);
+ }
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x02
+****************************************************************************/
+static void x86emuOp_add_byte_R_RM(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ u8 *destreg, *srcreg;
+ uint srcoffset;
+ u8 srcval;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("ADD\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ destreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm00_address(rl);
+ srcval = fetch_data_byte(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = add_byte(*destreg, srcval);
+ break;
+ case 1:
+ destreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm01_address(rl);
+ srcval = fetch_data_byte(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = add_byte(*destreg, srcval);
+ break;
+ case 2:
+ destreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm10_address(rl);
+ srcval = fetch_data_byte(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = add_byte(*destreg, srcval);
+ break;
+ case 3: /* register to register */
+ destreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_BYTE_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = add_byte(*destreg, *srcreg);
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x03
+****************************************************************************/
+static void x86emuOp_add_word_R_RM(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ uint srcoffset;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("ADD\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+ u32 srcval;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm00_address(rl);
+ srcval = fetch_data_long(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = add_long(*destreg, srcval);
+ } else {
+ u16 *destreg;
+ u16 srcval;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm00_address(rl);
+ srcval = fetch_data_word(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = add_word(*destreg, srcval);
+ }
+ break;
+ case 1:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+ u32 srcval;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm01_address(rl);
+ srcval = fetch_data_long(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = add_long(*destreg, srcval);
+ } else {
+ u16 *destreg;
+ u16 srcval;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm01_address(rl);
+ srcval = fetch_data_word(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = add_word(*destreg, srcval);
+ }
+ break;
+ case 2:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+ u32 srcval;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm10_address(rl);
+ srcval = fetch_data_long(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = add_long(*destreg, srcval);
+ } else {
+ u16 *destreg;
+ u16 srcval;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm10_address(rl);
+ srcval = fetch_data_word(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = add_word(*destreg, srcval);
+ }
+ break;
+ case 3: /* register to register */
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg,*srcreg;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_LONG_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = add_long(*destreg, *srcreg);
+ } else {
+ u16 *destreg,*srcreg;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_WORD_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = add_word(*destreg, *srcreg);
+ }
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x04
+****************************************************************************/
+static void x86emuOp_add_byte_AL_IMM(u8 X86EMU_UNUSED(op1))
+{
+ u8 srcval;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("ADD\tAL,");
+ srcval = fetch_byte_imm();
+ DECODE_PRINTF2("%x\n", srcval);
+ TRACE_AND_STEP();
+ M.x86.R_AL = add_byte(M.x86.R_AL, srcval);
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x05
+****************************************************************************/
+static void x86emuOp_add_word_AX_IMM(u8 X86EMU_UNUSED(op1))
+{
+ u32 srcval;
+
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("ADD\tEAX,");
+ srcval = fetch_long_imm();
+ } else {
+ DECODE_PRINTF("ADD\tAX,");
+ srcval = fetch_word_imm();
+ }
+ DECODE_PRINTF2("%x\n", srcval);
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ M.x86.R_EAX = add_long(M.x86.R_EAX, srcval);
+ } else {
+ M.x86.R_AX = add_word(M.x86.R_AX, (u16)srcval);
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x06
+****************************************************************************/
+static void x86emuOp_push_ES(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ DECODE_PRINTF("PUSH\tES\n");
+ TRACE_AND_STEP();
+ push_word(M.x86.R_ES);
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x07
+****************************************************************************/
+static void x86emuOp_pop_ES(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ DECODE_PRINTF("POP\tES\n");
+ TRACE_AND_STEP();
+ M.x86.R_ES = pop_word();
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x08
+****************************************************************************/
+static void x86emuOp_or_byte_RM_R(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ u8 *destreg, *srcreg;
+ uint destoffset;
+ u8 destval;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("OR\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_byte(destoffset);
+ srcreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = or_byte(destval, *srcreg);
+ store_data_byte(destoffset, destval);
+ break;
+ case 1:
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_byte(destoffset);
+ srcreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = or_byte(destval, *srcreg);
+ store_data_byte(destoffset, destval);
+ break;
+ case 2:
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_byte(destoffset);
+ srcreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = or_byte(destval, *srcreg);
+ store_data_byte(destoffset, destval);
+ break;
+ case 3: /* register to register */
+ destreg = DECODE_RM_BYTE_REGISTER(rl);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = or_byte(*destreg, *srcreg);
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x09
+****************************************************************************/
+static void x86emuOp_or_word_RM_R(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ uint destoffset;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("OR\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+ u32 *srcreg;
+
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_long(destoffset);
+ srcreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = or_long(destval, *srcreg);
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+ u16 *srcreg;
+
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_word(destoffset);
+ srcreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = or_word(destval, *srcreg);
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 1:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+ u32 *srcreg;
+
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_long(destoffset);
+ srcreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = or_long(destval, *srcreg);
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+ u16 *srcreg;
+
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_word(destoffset);
+ srcreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = or_word(destval, *srcreg);
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 2:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+ u32 *srcreg;
+
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_long(destoffset);
+ srcreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = or_long(destval, *srcreg);
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+ u16 *srcreg;
+
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_word(destoffset);
+ srcreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = or_word(destval, *srcreg);
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 3: /* register to register */
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg,*srcreg;
+
+ destreg = DECODE_RM_LONG_REGISTER(rl);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = or_long(*destreg, *srcreg);
+ } else {
+ u16 *destreg,*srcreg;
+
+ destreg = DECODE_RM_WORD_REGISTER(rl);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = or_word(*destreg, *srcreg);
+ }
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0a
+****************************************************************************/
+static void x86emuOp_or_byte_R_RM(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ u8 *destreg, *srcreg;
+ uint srcoffset;
+ u8 srcval;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("OR\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ destreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm00_address(rl);
+ srcval = fetch_data_byte(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = or_byte(*destreg, srcval);
+ break;
+ case 1:
+ destreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm01_address(rl);
+ srcval = fetch_data_byte(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = or_byte(*destreg, srcval);
+ break;
+ case 2:
+ destreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm10_address(rl);
+ srcval = fetch_data_byte(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = or_byte(*destreg, srcval);
+ break;
+ case 3: /* register to register */
+ destreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_BYTE_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = or_byte(*destreg, *srcreg);
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0b
+****************************************************************************/
+static void x86emuOp_or_word_R_RM(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ uint srcoffset;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("OR\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+ u32 srcval;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm00_address(rl);
+ srcval = fetch_data_long(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = or_long(*destreg, srcval);
+ } else {
+ u16 *destreg;
+ u16 srcval;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm00_address(rl);
+ srcval = fetch_data_word(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = or_word(*destreg, srcval);
+ }
+ break;
+ case 1:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+ u32 srcval;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm01_address(rl);
+ srcval = fetch_data_long(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = or_long(*destreg, srcval);
+ } else {
+ u16 *destreg;
+ u16 srcval;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm01_address(rl);
+ srcval = fetch_data_word(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = or_word(*destreg, srcval);
+ }
+ break;
+ case 2:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+ u32 srcval;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm10_address(rl);
+ srcval = fetch_data_long(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = or_long(*destreg, srcval);
+ } else {
+ u16 *destreg;
+ u16 srcval;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm10_address(rl);
+ srcval = fetch_data_word(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = or_word(*destreg, srcval);
+ }
+ break;
+ case 3: /* register to register */
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg,*srcreg;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_LONG_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = or_long(*destreg, *srcreg);
+ } else {
+ u16 *destreg,*srcreg;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_WORD_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = or_word(*destreg, *srcreg);
+ }
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0c
+****************************************************************************/
+static void x86emuOp_or_byte_AL_IMM(u8 X86EMU_UNUSED(op1))
+{
+ u8 srcval;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("OR\tAL,");
+ srcval = fetch_byte_imm();
+ DECODE_PRINTF2("%x\n", srcval);
+ TRACE_AND_STEP();
+ M.x86.R_AL = or_byte(M.x86.R_AL, srcval);
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0d
+****************************************************************************/
+static void x86emuOp_or_word_AX_IMM(u8 X86EMU_UNUSED(op1))
+{
+ u32 srcval;
+
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("OR\tEAX,");
+ srcval = fetch_long_imm();
+ } else {
+ DECODE_PRINTF("OR\tAX,");
+ srcval = fetch_word_imm();
+ }
+ DECODE_PRINTF2("%x\n", srcval);
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ M.x86.R_EAX = or_long(M.x86.R_EAX, srcval);
+ } else {
+ M.x86.R_AX = or_word(M.x86.R_AX, (u16)srcval);
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0e
+****************************************************************************/
+static void x86emuOp_push_CS(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ DECODE_PRINTF("PUSH\tCS\n");
+ TRACE_AND_STEP();
+ push_word(M.x86.R_CS);
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0f. Escape for two-byte opcode (286 or better)
+****************************************************************************/
+static void x86emuOp_two_byte(u8 X86EMU_UNUSED(op1))
+{
+ u8 op2 = (*sys_rdb)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP++));
+ INC_DECODED_INST_LEN(1);
+ (*x86emu_optab2[op2])(op2);
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x10
+****************************************************************************/
+static void x86emuOp_adc_byte_RM_R(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ u8 *destreg, *srcreg;
+ uint destoffset;
+ u8 destval;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("ADC\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_byte(destoffset);
+ srcreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = adc_byte(destval, *srcreg);
+ store_data_byte(destoffset, destval);
+ break;
+ case 1:
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_byte(destoffset);
+ srcreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = adc_byte(destval, *srcreg);
+ store_data_byte(destoffset, destval);
+ break;
+ case 2:
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_byte(destoffset);
+ srcreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = adc_byte(destval, *srcreg);
+ store_data_byte(destoffset, destval);
+ break;
+ case 3: /* register to register */
+ destreg = DECODE_RM_BYTE_REGISTER(rl);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = adc_byte(*destreg, *srcreg);
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x11
+****************************************************************************/
+static void x86emuOp_adc_word_RM_R(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ uint destoffset;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("ADC\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+ u32 *srcreg;
+
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_long(destoffset);
+ srcreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = adc_long(destval, *srcreg);
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+ u16 *srcreg;
+
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_word(destoffset);
+ srcreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = adc_word(destval, *srcreg);
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 1:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+ u32 *srcreg;
+
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_long(destoffset);
+ srcreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = adc_long(destval, *srcreg);
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+ u16 *srcreg;
+
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_word(destoffset);
+ srcreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = adc_word(destval, *srcreg);
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 2:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+ u32 *srcreg;
+
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_long(destoffset);
+ srcreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = adc_long(destval, *srcreg);
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+ u16 *srcreg;
+
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_word(destoffset);
+ srcreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = adc_word(destval, *srcreg);
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 3: /* register to register */
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg,*srcreg;
+
+ destreg = DECODE_RM_LONG_REGISTER(rl);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = adc_long(*destreg, *srcreg);
+ } else {
+ u16 *destreg,*srcreg;
+
+ destreg = DECODE_RM_WORD_REGISTER(rl);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = adc_word(*destreg, *srcreg);
+ }
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x12
+****************************************************************************/
+static void x86emuOp_adc_byte_R_RM(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ u8 *destreg, *srcreg;
+ uint srcoffset;
+ u8 srcval;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("ADC\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ destreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm00_address(rl);
+ srcval = fetch_data_byte(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = adc_byte(*destreg, srcval);
+ break;
+ case 1:
+ destreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm01_address(rl);
+ srcval = fetch_data_byte(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = adc_byte(*destreg, srcval);
+ break;
+ case 2:
+ destreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm10_address(rl);
+ srcval = fetch_data_byte(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = adc_byte(*destreg, srcval);
+ break;
+ case 3: /* register to register */
+ destreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_BYTE_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = adc_byte(*destreg, *srcreg);
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x13
+****************************************************************************/
+static void x86emuOp_adc_word_R_RM(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ uint srcoffset;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("ADC\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+ u32 srcval;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm00_address(rl);
+ srcval = fetch_data_long(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = adc_long(*destreg, srcval);
+ } else {
+ u16 *destreg;
+ u16 srcval;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm00_address(rl);
+ srcval = fetch_data_word(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = adc_word(*destreg, srcval);
+ }
+ break;
+ case 1:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+ u32 srcval;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm01_address(rl);
+ srcval = fetch_data_long(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = adc_long(*destreg, srcval);
+ } else {
+ u16 *destreg;
+ u16 srcval;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm01_address(rl);
+ srcval = fetch_data_word(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = adc_word(*destreg, srcval);
+ }
+ break;
+ case 2:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+ u32 srcval;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm10_address(rl);
+ srcval = fetch_data_long(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = adc_long(*destreg, srcval);
+ } else {
+ u16 *destreg;
+ u16 srcval;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm10_address(rl);
+ srcval = fetch_data_word(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = adc_word(*destreg, srcval);
+ }
+ break;
+ case 3: /* register to register */
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg,*srcreg;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_LONG_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = adc_long(*destreg, *srcreg);
+ } else {
+ u16 *destreg,*srcreg;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_WORD_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = adc_word(*destreg, *srcreg);
+ }
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x14
+****************************************************************************/
+static void x86emuOp_adc_byte_AL_IMM(u8 X86EMU_UNUSED(op1))
+{
+ u8 srcval;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("ADC\tAL,");
+ srcval = fetch_byte_imm();
+ DECODE_PRINTF2("%x\n", srcval);
+ TRACE_AND_STEP();
+ M.x86.R_AL = adc_byte(M.x86.R_AL, srcval);
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x15
+****************************************************************************/
+static void x86emuOp_adc_word_AX_IMM(u8 X86EMU_UNUSED(op1))
+{
+ u32 srcval;
+
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("ADC\tEAX,");
+ srcval = fetch_long_imm();
+ } else {
+ DECODE_PRINTF("ADC\tAX,");
+ srcval = fetch_word_imm();
+ }
+ DECODE_PRINTF2("%x\n", srcval);
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ M.x86.R_EAX = adc_long(M.x86.R_EAX, srcval);
+ } else {
+ M.x86.R_AX = adc_word(M.x86.R_AX, (u16)srcval);
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x16
+****************************************************************************/
+static void x86emuOp_push_SS(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ DECODE_PRINTF("PUSH\tSS\n");
+ TRACE_AND_STEP();
+ push_word(M.x86.R_SS);
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x17
+****************************************************************************/
+static void x86emuOp_pop_SS(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ DECODE_PRINTF("POP\tSS\n");
+ TRACE_AND_STEP();
+ M.x86.R_SS = pop_word();
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x18
+****************************************************************************/
+static void x86emuOp_sbb_byte_RM_R(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ u8 *destreg, *srcreg;
+ uint destoffset;
+ u8 destval;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("SBB\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_byte(destoffset);
+ srcreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = sbb_byte(destval, *srcreg);
+ store_data_byte(destoffset, destval);
+ break;
+ case 1:
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_byte(destoffset);
+ srcreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = sbb_byte(destval, *srcreg);
+ store_data_byte(destoffset, destval);
+ break;
+ case 2:
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_byte(destoffset);
+ srcreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = sbb_byte(destval, *srcreg);
+ store_data_byte(destoffset, destval);
+ break;
+ case 3: /* register to register */
+ destreg = DECODE_RM_BYTE_REGISTER(rl);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = sbb_byte(*destreg, *srcreg);
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x19
+****************************************************************************/
+static void x86emuOp_sbb_word_RM_R(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ uint destoffset;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("SBB\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+ u32 *srcreg;
+
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_long(destoffset);
+ srcreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = sbb_long(destval, *srcreg);
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+ u16 *srcreg;
+
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_word(destoffset);
+ srcreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = sbb_word(destval, *srcreg);
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 1:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+ u32 *srcreg;
+
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_long(destoffset);
+ srcreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = sbb_long(destval, *srcreg);
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+ u16 *srcreg;
+
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_word(destoffset);
+ srcreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = sbb_word(destval, *srcreg);
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 2:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+ u32 *srcreg;
+
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_long(destoffset);
+ srcreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = sbb_long(destval, *srcreg);
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+ u16 *srcreg;
+
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_word(destoffset);
+ srcreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = sbb_word(destval, *srcreg);
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 3: /* register to register */
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg,*srcreg;
+
+ destreg = DECODE_RM_LONG_REGISTER(rl);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = sbb_long(*destreg, *srcreg);
+ } else {
+ u16 *destreg,*srcreg;
+
+ destreg = DECODE_RM_WORD_REGISTER(rl);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = sbb_word(*destreg, *srcreg);
+ }
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x1a
+****************************************************************************/
+static void x86emuOp_sbb_byte_R_RM(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ u8 *destreg, *srcreg;
+ uint srcoffset;
+ u8 srcval;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("SBB\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ destreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm00_address(rl);
+ srcval = fetch_data_byte(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = sbb_byte(*destreg, srcval);
+ break;
+ case 1:
+ destreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm01_address(rl);
+ srcval = fetch_data_byte(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = sbb_byte(*destreg, srcval);
+ break;
+ case 2:
+ destreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm10_address(rl);
+ srcval = fetch_data_byte(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = sbb_byte(*destreg, srcval);
+ break;
+ case 3: /* register to register */
+ destreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_BYTE_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = sbb_byte(*destreg, *srcreg);
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x1b
+****************************************************************************/
+static void x86emuOp_sbb_word_R_RM(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ uint srcoffset;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("SBB\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+ u32 srcval;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm00_address(rl);
+ srcval = fetch_data_long(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = sbb_long(*destreg, srcval);
+ } else {
+ u16 *destreg;
+ u16 srcval;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm00_address(rl);
+ srcval = fetch_data_word(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = sbb_word(*destreg, srcval);
+ }
+ break;
+ case 1:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+ u32 srcval;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm01_address(rl);
+ srcval = fetch_data_long(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = sbb_long(*destreg, srcval);
+ } else {
+ u16 *destreg;
+ u16 srcval;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm01_address(rl);
+ srcval = fetch_data_word(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = sbb_word(*destreg, srcval);
+ }
+ break;
+ case 2:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+ u32 srcval;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm10_address(rl);
+ srcval = fetch_data_long(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = sbb_long(*destreg, srcval);
+ } else {
+ u16 *destreg;
+ u16 srcval;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm10_address(rl);
+ srcval = fetch_data_word(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = sbb_word(*destreg, srcval);
+ }
+ break;
+ case 3: /* register to register */
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg,*srcreg;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_LONG_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = sbb_long(*destreg, *srcreg);
+ } else {
+ u16 *destreg,*srcreg;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_WORD_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = sbb_word(*destreg, *srcreg);
+ }
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x1c
+****************************************************************************/
+static void x86emuOp_sbb_byte_AL_IMM(u8 X86EMU_UNUSED(op1))
+{
+ u8 srcval;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("SBB\tAL,");
+ srcval = fetch_byte_imm();
+ DECODE_PRINTF2("%x\n", srcval);
+ TRACE_AND_STEP();
+ M.x86.R_AL = sbb_byte(M.x86.R_AL, srcval);
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x1d
+****************************************************************************/
+static void x86emuOp_sbb_word_AX_IMM(u8 X86EMU_UNUSED(op1))
+{
+ u32 srcval;
+
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("SBB\tEAX,");
+ srcval = fetch_long_imm();
+ } else {
+ DECODE_PRINTF("SBB\tAX,");
+ srcval = fetch_word_imm();
+ }
+ DECODE_PRINTF2("%x\n", srcval);
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ M.x86.R_EAX = sbb_long(M.x86.R_EAX, srcval);
+ } else {
+ M.x86.R_AX = sbb_word(M.x86.R_AX, (u16)srcval);
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x1e
+****************************************************************************/
+static void x86emuOp_push_DS(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ DECODE_PRINTF("PUSH\tDS\n");
+ TRACE_AND_STEP();
+ push_word(M.x86.R_DS);
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x1f
+****************************************************************************/
+static void x86emuOp_pop_DS(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ DECODE_PRINTF("POP\tDS\n");
+ TRACE_AND_STEP();
+ M.x86.R_DS = pop_word();
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x20
+****************************************************************************/
+static void x86emuOp_and_byte_RM_R(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ u8 *destreg, *srcreg;
+ uint destoffset;
+ u8 destval;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("AND\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+
+ switch (mod) {
+ case 0:
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_byte(destoffset);
+ srcreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = and_byte(destval, *srcreg);
+ store_data_byte(destoffset, destval);
+ break;
+
+ case 1:
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_byte(destoffset);
+ srcreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = and_byte(destval, *srcreg);
+ store_data_byte(destoffset, destval);
+ break;
+
+ case 2:
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_byte(destoffset);
+ srcreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = and_byte(destval, *srcreg);
+ store_data_byte(destoffset, destval);
+ break;
+
+ case 3: /* register to register */
+ destreg = DECODE_RM_BYTE_REGISTER(rl);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = and_byte(*destreg, *srcreg);
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x21
+****************************************************************************/
+static void x86emuOp_and_word_RM_R(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ uint destoffset;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("AND\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+ u32 *srcreg;
+
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_long(destoffset);
+ srcreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = and_long(destval, *srcreg);
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+ u16 *srcreg;
+
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_word(destoffset);
+ srcreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = and_word(destval, *srcreg);
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 1:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+ u32 *srcreg;
+
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_long(destoffset);
+ srcreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = and_long(destval, *srcreg);
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+ u16 *srcreg;
+
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_word(destoffset);
+ srcreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = and_word(destval, *srcreg);
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 2:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+ u32 *srcreg;
+
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_long(destoffset);
+ srcreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = and_long(destval, *srcreg);
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+ u16 *srcreg;
+
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_word(destoffset);
+ srcreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = and_word(destval, *srcreg);
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 3: /* register to register */
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg,*srcreg;
+
+ destreg = DECODE_RM_LONG_REGISTER(rl);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = and_long(*destreg, *srcreg);
+ } else {
+ u16 *destreg,*srcreg;
+
+ destreg = DECODE_RM_WORD_REGISTER(rl);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = and_word(*destreg, *srcreg);
+ }
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x22
+****************************************************************************/
+static void x86emuOp_and_byte_R_RM(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ u8 *destreg, *srcreg;
+ uint srcoffset;
+ u8 srcval;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("AND\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ destreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm00_address(rl);
+ srcval = fetch_data_byte(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = and_byte(*destreg, srcval);
+ break;
+ case 1:
+ destreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm01_address(rl);
+ srcval = fetch_data_byte(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = and_byte(*destreg, srcval);
+ break;
+ case 2:
+ destreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm10_address(rl);
+ srcval = fetch_data_byte(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = and_byte(*destreg, srcval);
+ break;
+ case 3: /* register to register */
+ destreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_BYTE_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = and_byte(*destreg, *srcreg);
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x23
+****************************************************************************/
+static void x86emuOp_and_word_R_RM(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ uint srcoffset;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("AND\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+ u32 srcval;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm00_address(rl);
+ srcval = fetch_data_long(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = and_long(*destreg, srcval);
+ } else {
+ u16 *destreg;
+ u16 srcval;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm00_address(rl);
+ srcval = fetch_data_word(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = and_word(*destreg, srcval);
+ }
+ break;
+ case 1:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+ u32 srcval;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm01_address(rl);
+ srcval = fetch_data_long(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = and_long(*destreg, srcval);
+ break;
+ } else {
+ u16 *destreg;
+ u16 srcval;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm01_address(rl);
+ srcval = fetch_data_word(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = and_word(*destreg, srcval);
+ break;
+ }
+ case 2:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+ u32 srcval;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm10_address(rl);
+ srcval = fetch_data_long(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = and_long(*destreg, srcval);
+ } else {
+ u16 *destreg;
+ u16 srcval;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm10_address(rl);
+ srcval = fetch_data_word(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = and_word(*destreg, srcval);
+ }
+ break;
+ case 3: /* register to register */
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg,*srcreg;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_LONG_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = and_long(*destreg, *srcreg);
+ } else {
+ u16 *destreg,*srcreg;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_WORD_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = and_word(*destreg, *srcreg);
+ }
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x24
+****************************************************************************/
+static void x86emuOp_and_byte_AL_IMM(u8 X86EMU_UNUSED(op1))
+{
+ u8 srcval;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("AND\tAL,");
+ srcval = fetch_byte_imm();
+ DECODE_PRINTF2("%x\n", srcval);
+ TRACE_AND_STEP();
+ M.x86.R_AL = and_byte(M.x86.R_AL, srcval);
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x25
+****************************************************************************/
+static void x86emuOp_and_word_AX_IMM(u8 X86EMU_UNUSED(op1))
+{
+ u32 srcval;
+
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("AND\tEAX,");
+ srcval = fetch_long_imm();
+ } else {
+ DECODE_PRINTF("AND\tAX,");
+ srcval = fetch_word_imm();
+ }
+ DECODE_PRINTF2("%x\n", srcval);
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ M.x86.R_EAX = and_long(M.x86.R_EAX, srcval);
+ } else {
+ M.x86.R_AX = and_word(M.x86.R_AX, (u16)srcval);
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x26
+****************************************************************************/
+static void x86emuOp_segovr_ES(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ DECODE_PRINTF("ES:\n");
+ TRACE_AND_STEP();
+ M.x86.mode |= SYSMODE_SEGOVR_ES;
+ /*
+ * note the lack of DECODE_CLEAR_SEGOVR(r) since, here is one of 4
+ * opcode subroutines we do not want to do this.
+ */
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x27
+****************************************************************************/
+static void x86emuOp_daa(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ DECODE_PRINTF("DAA\n");
+ TRACE_AND_STEP();
+ M.x86.R_AL = daa_byte(M.x86.R_AL);
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x28
+****************************************************************************/
+static void x86emuOp_sub_byte_RM_R(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ u8 *destreg, *srcreg;
+ uint destoffset;
+ u8 destval;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("SUB\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_byte(destoffset);
+ srcreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = sub_byte(destval, *srcreg);
+ store_data_byte(destoffset, destval);
+ break;
+ case 1:
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_byte(destoffset);
+ srcreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = sub_byte(destval, *srcreg);
+ store_data_byte(destoffset, destval);
+ break;
+ case 2:
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_byte(destoffset);
+ srcreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = sub_byte(destval, *srcreg);
+ store_data_byte(destoffset, destval);
+ break;
+ case 3: /* register to register */
+ destreg = DECODE_RM_BYTE_REGISTER(rl);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = sub_byte(*destreg, *srcreg);
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x29
+****************************************************************************/
+static void x86emuOp_sub_word_RM_R(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ uint destoffset;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("SUB\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+ u32 *srcreg;
+
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_long(destoffset);
+ srcreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = sub_long(destval, *srcreg);
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+ u16 *srcreg;
+
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_word(destoffset);
+ srcreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = sub_word(destval, *srcreg);
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 1:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+ u32 *srcreg;
+
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_long(destoffset);
+ srcreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = sub_long(destval, *srcreg);
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+ u16 *srcreg;
+
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_word(destoffset);
+ srcreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = sub_word(destval, *srcreg);
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 2:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+ u32 *srcreg;
+
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_long(destoffset);
+ srcreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = sub_long(destval, *srcreg);
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+ u16 *srcreg;
+
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_word(destoffset);
+ srcreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = sub_word(destval, *srcreg);
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 3: /* register to register */
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg,*srcreg;
+
+ destreg = DECODE_RM_LONG_REGISTER(rl);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = sub_long(*destreg, *srcreg);
+ } else {
+ u16 *destreg,*srcreg;
+
+ destreg = DECODE_RM_WORD_REGISTER(rl);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = sub_word(*destreg, *srcreg);
+ }
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x2a
+****************************************************************************/
+static void x86emuOp_sub_byte_R_RM(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ u8 *destreg, *srcreg;
+ uint srcoffset;
+ u8 srcval;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("SUB\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ destreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm00_address(rl);
+ srcval = fetch_data_byte(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = sub_byte(*destreg, srcval);
+ break;
+ case 1:
+ destreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm01_address(rl);
+ srcval = fetch_data_byte(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = sub_byte(*destreg, srcval);
+ break;
+ case 2:
+ destreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm10_address(rl);
+ srcval = fetch_data_byte(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = sub_byte(*destreg, srcval);
+ break;
+ case 3: /* register to register */
+ destreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_BYTE_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = sub_byte(*destreg, *srcreg);
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x2b
+****************************************************************************/
+static void x86emuOp_sub_word_R_RM(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ uint srcoffset;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("SUB\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+ u32 srcval;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm00_address(rl);
+ srcval = fetch_data_long(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = sub_long(*destreg, srcval);
+ } else {
+ u16 *destreg;
+ u16 srcval;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm00_address(rl);
+ srcval = fetch_data_word(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = sub_word(*destreg, srcval);
+ }
+ break;
+ case 1:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+ u32 srcval;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm01_address(rl);
+ srcval = fetch_data_long(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = sub_long(*destreg, srcval);
+ } else {
+ u16 *destreg;
+ u16 srcval;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm01_address(rl);
+ srcval = fetch_data_word(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = sub_word(*destreg, srcval);
+ }
+ break;
+ case 2:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+ u32 srcval;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm10_address(rl);
+ srcval = fetch_data_long(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = sub_long(*destreg, srcval);
+ } else {
+ u16 *destreg;
+ u16 srcval;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm10_address(rl);
+ srcval = fetch_data_word(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = sub_word(*destreg, srcval);
+ }
+ break;
+ case 3: /* register to register */
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg,*srcreg;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_LONG_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = sub_long(*destreg, *srcreg);
+ } else {
+ u16 *destreg,*srcreg;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_WORD_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = sub_word(*destreg, *srcreg);
+ }
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x2c
+****************************************************************************/
+static void x86emuOp_sub_byte_AL_IMM(u8 X86EMU_UNUSED(op1))
+{
+ u8 srcval;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("SUB\tAL,");
+ srcval = fetch_byte_imm();
+ DECODE_PRINTF2("%x\n", srcval);
+ TRACE_AND_STEP();
+ M.x86.R_AL = sub_byte(M.x86.R_AL, srcval);
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x2d
+****************************************************************************/
+static void x86emuOp_sub_word_AX_IMM(u8 X86EMU_UNUSED(op1))
+{
+ u32 srcval;
+
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("SUB\tEAX,");
+ srcval = fetch_long_imm();
+ } else {
+ DECODE_PRINTF("SUB\tAX,");
+ srcval = fetch_word_imm();
+ }
+ DECODE_PRINTF2("%x\n", srcval);
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ M.x86.R_EAX = sub_long(M.x86.R_EAX, srcval);
+ } else {
+ M.x86.R_AX = sub_word(M.x86.R_AX, (u16)srcval);
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x2e
+****************************************************************************/
+static void x86emuOp_segovr_CS(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ DECODE_PRINTF("CS:\n");
+ TRACE_AND_STEP();
+ M.x86.mode |= SYSMODE_SEGOVR_CS;
+ /* note no DECODE_CLEAR_SEGOVR here. */
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x2f
+****************************************************************************/
+static void x86emuOp_das(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ DECODE_PRINTF("DAS\n");
+ TRACE_AND_STEP();
+ M.x86.R_AL = das_byte(M.x86.R_AL);
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x30
+****************************************************************************/
+static void x86emuOp_xor_byte_RM_R(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ u8 *destreg, *srcreg;
+ uint destoffset;
+ u8 destval;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("XOR\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_byte(destoffset);
+ srcreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = xor_byte(destval, *srcreg);
+ store_data_byte(destoffset, destval);
+ break;
+ case 1:
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_byte(destoffset);
+ srcreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = xor_byte(destval, *srcreg);
+ store_data_byte(destoffset, destval);
+ break;
+ case 2:
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_byte(destoffset);
+ srcreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = xor_byte(destval, *srcreg);
+ store_data_byte(destoffset, destval);
+ break;
+ case 3: /* register to register */
+ destreg = DECODE_RM_BYTE_REGISTER(rl);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = xor_byte(*destreg, *srcreg);
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x31
+****************************************************************************/
+static void x86emuOp_xor_word_RM_R(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ uint destoffset;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("XOR\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+ u32 *srcreg;
+
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_long(destoffset);
+ srcreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = xor_long(destval, *srcreg);
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+ u16 *srcreg;
+
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_word(destoffset);
+ srcreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = xor_word(destval, *srcreg);
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 1:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+ u32 *srcreg;
+
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_long(destoffset);
+ srcreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = xor_long(destval, *srcreg);
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+ u16 *srcreg;
+
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_word(destoffset);
+ srcreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = xor_word(destval, *srcreg);
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 2:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+ u32 *srcreg;
+
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_long(destoffset);
+ srcreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = xor_long(destval, *srcreg);
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+ u16 *srcreg;
+
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_word(destoffset);
+ srcreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = xor_word(destval, *srcreg);
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 3: /* register to register */
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg,*srcreg;
+
+ destreg = DECODE_RM_LONG_REGISTER(rl);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = xor_long(*destreg, *srcreg);
+ } else {
+ u16 *destreg,*srcreg;
+
+ destreg = DECODE_RM_WORD_REGISTER(rl);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = xor_word(*destreg, *srcreg);
+ }
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x32
+****************************************************************************/
+static void x86emuOp_xor_byte_R_RM(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ u8 *destreg, *srcreg;
+ uint srcoffset;
+ u8 srcval;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("XOR\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ destreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm00_address(rl);
+ srcval = fetch_data_byte(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = xor_byte(*destreg, srcval);
+ break;
+ case 1:
+ destreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm01_address(rl);
+ srcval = fetch_data_byte(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = xor_byte(*destreg, srcval);
+ break;
+ case 2:
+ destreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm10_address(rl);
+ srcval = fetch_data_byte(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = xor_byte(*destreg, srcval);
+ break;
+ case 3: /* register to register */
+ destreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_BYTE_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = xor_byte(*destreg, *srcreg);
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x33
+****************************************************************************/
+static void x86emuOp_xor_word_R_RM(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ uint srcoffset;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("XOR\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+ u32 srcval;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm00_address(rl);
+ srcval = fetch_data_long(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = xor_long(*destreg, srcval);
+ } else {
+ u16 *destreg;
+ u16 srcval;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm00_address(rl);
+ srcval = fetch_data_word(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = xor_word(*destreg, srcval);
+ }
+ break;
+ case 1:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+ u32 srcval;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm01_address(rl);
+ srcval = fetch_data_long(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = xor_long(*destreg, srcval);
+ } else {
+ u16 *destreg;
+ u16 srcval;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm01_address(rl);
+ srcval = fetch_data_word(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = xor_word(*destreg, srcval);
+ }
+ break;
+ case 2:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+ u32 srcval;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm10_address(rl);
+ srcval = fetch_data_long(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = xor_long(*destreg, srcval);
+ } else {
+ u16 *destreg;
+ u16 srcval;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm10_address(rl);
+ srcval = fetch_data_word(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = xor_word(*destreg, srcval);
+ }
+ break;
+ case 3: /* register to register */
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg,*srcreg;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_LONG_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = xor_long(*destreg, *srcreg);
+ } else {
+ u16 *destreg,*srcreg;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_WORD_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = xor_word(*destreg, *srcreg);
+ }
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x34
+****************************************************************************/
+static void x86emuOp_xor_byte_AL_IMM(u8 X86EMU_UNUSED(op1))
+{
+ u8 srcval;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("XOR\tAL,");
+ srcval = fetch_byte_imm();
+ DECODE_PRINTF2("%x\n", srcval);
+ TRACE_AND_STEP();
+ M.x86.R_AL = xor_byte(M.x86.R_AL, srcval);
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x35
+****************************************************************************/
+static void x86emuOp_xor_word_AX_IMM(u8 X86EMU_UNUSED(op1))
+{
+ u32 srcval;
+
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("XOR\tEAX,");
+ srcval = fetch_long_imm();
+ } else {
+ DECODE_PRINTF("XOR\tAX,");
+ srcval = fetch_word_imm();
+ }
+ DECODE_PRINTF2("%x\n", srcval);
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ M.x86.R_EAX = xor_long(M.x86.R_EAX, srcval);
+ } else {
+ M.x86.R_AX = xor_word(M.x86.R_AX, (u16)srcval);
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x36
+****************************************************************************/
+static void x86emuOp_segovr_SS(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ DECODE_PRINTF("SS:\n");
+ TRACE_AND_STEP();
+ M.x86.mode |= SYSMODE_SEGOVR_SS;
+ /* no DECODE_CLEAR_SEGOVR ! */
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x37
+****************************************************************************/
+static void x86emuOp_aaa(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ DECODE_PRINTF("AAA\n");
+ TRACE_AND_STEP();
+ M.x86.R_AX = aaa_word(M.x86.R_AX);
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x38
+****************************************************************************/
+static void x86emuOp_cmp_byte_RM_R(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ uint destoffset;
+ u8 *destreg, *srcreg;
+ u8 destval;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("CMP\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_byte(destoffset);
+ srcreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ cmp_byte(destval, *srcreg);
+ break;
+ case 1:
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_byte(destoffset);
+ srcreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ cmp_byte(destval, *srcreg);
+ break;
+ case 2:
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_byte(destoffset);
+ srcreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ cmp_byte(destval, *srcreg);
+ break;
+ case 3: /* register to register */
+ destreg = DECODE_RM_BYTE_REGISTER(rl);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ cmp_byte(*destreg, *srcreg);
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x39
+****************************************************************************/
+static void x86emuOp_cmp_word_RM_R(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ uint destoffset;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("CMP\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+ u32 *srcreg;
+
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_long(destoffset);
+ srcreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ cmp_long(destval, *srcreg);
+ } else {
+ u16 destval;
+ u16 *srcreg;
+
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_word(destoffset);
+ srcreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ cmp_word(destval, *srcreg);
+ }
+ break;
+ case 1:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+ u32 *srcreg;
+
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_long(destoffset);
+ srcreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ cmp_long(destval, *srcreg);
+ } else {
+ u16 destval;
+ u16 *srcreg;
+
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_word(destoffset);
+ srcreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ cmp_word(destval, *srcreg);
+ }
+ break;
+ case 2:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+ u32 *srcreg;
+
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_long(destoffset);
+ srcreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ cmp_long(destval, *srcreg);
+ } else {
+ u16 destval;
+ u16 *srcreg;
+
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_word(destoffset);
+ srcreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ cmp_word(destval, *srcreg);
+ }
+ break;
+ case 3: /* register to register */
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg,*srcreg;
+
+ destreg = DECODE_RM_LONG_REGISTER(rl);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ cmp_long(*destreg, *srcreg);
+ } else {
+ u16 *destreg,*srcreg;
+
+ destreg = DECODE_RM_WORD_REGISTER(rl);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ cmp_word(*destreg, *srcreg);
+ }
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x3a
+****************************************************************************/
+static void x86emuOp_cmp_byte_R_RM(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ u8 *destreg, *srcreg;
+ uint srcoffset;
+ u8 srcval;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("CMP\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ destreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm00_address(rl);
+ srcval = fetch_data_byte(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ cmp_byte(*destreg, srcval);
+ break;
+ case 1:
+ destreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm01_address(rl);
+ srcval = fetch_data_byte(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ cmp_byte(*destreg, srcval);
+ break;
+ case 2:
+ destreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm10_address(rl);
+ srcval = fetch_data_byte(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ cmp_byte(*destreg, srcval);
+ break;
+ case 3: /* register to register */
+ destreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_BYTE_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ cmp_byte(*destreg, *srcreg);
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x3b
+****************************************************************************/
+static void x86emuOp_cmp_word_R_RM(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ uint srcoffset;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("CMP\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+ u32 srcval;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm00_address(rl);
+ srcval = fetch_data_long(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ cmp_long(*destreg, srcval);
+ } else {
+ u16 *destreg;
+ u16 srcval;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm00_address(rl);
+ srcval = fetch_data_word(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ cmp_word(*destreg, srcval);
+ }
+ break;
+ case 1:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+ u32 srcval;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm01_address(rl);
+ srcval = fetch_data_long(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ cmp_long(*destreg, srcval);
+ } else {
+ u16 *destreg;
+ u16 srcval;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm01_address(rl);
+ srcval = fetch_data_word(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ cmp_word(*destreg, srcval);
+ }
+ break;
+ case 2:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+ u32 srcval;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm10_address(rl);
+ srcval = fetch_data_long(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ cmp_long(*destreg, srcval);
+ } else {
+ u16 *destreg;
+ u16 srcval;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm10_address(rl);
+ srcval = fetch_data_word(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ cmp_word(*destreg, srcval);
+ }
+ break;
+ case 3: /* register to register */
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg,*srcreg;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_LONG_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ cmp_long(*destreg, *srcreg);
+ } else {
+ u16 *destreg,*srcreg;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_WORD_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ cmp_word(*destreg, *srcreg);
+ }
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x3c
+****************************************************************************/
+static void x86emuOp_cmp_byte_AL_IMM(u8 X86EMU_UNUSED(op1))
+{
+ u8 srcval;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("CMP\tAL,");
+ srcval = fetch_byte_imm();
+ DECODE_PRINTF2("%x\n", srcval);
+ TRACE_AND_STEP();
+ cmp_byte(M.x86.R_AL, srcval);
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x3d
+****************************************************************************/
+static void x86emuOp_cmp_word_AX_IMM(u8 X86EMU_UNUSED(op1))
+{
+ u32 srcval;
+
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("CMP\tEAX,");
+ srcval = fetch_long_imm();
+ } else {
+ DECODE_PRINTF("CMP\tAX,");
+ srcval = fetch_word_imm();
+ }
+ DECODE_PRINTF2("%x\n", srcval);
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ cmp_long(M.x86.R_EAX, srcval);
+ } else {
+ cmp_word(M.x86.R_AX, (u16)srcval);
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x3e
+****************************************************************************/
+static void x86emuOp_segovr_DS(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ DECODE_PRINTF("DS:\n");
+ TRACE_AND_STEP();
+ M.x86.mode |= SYSMODE_SEGOVR_DS;
+ /* NO DECODE_CLEAR_SEGOVR! */
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x3f
+****************************************************************************/
+static void x86emuOp_aas(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ DECODE_PRINTF("AAS\n");
+ TRACE_AND_STEP();
+ M.x86.R_AX = aas_word(M.x86.R_AX);
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x40
+****************************************************************************/
+static void x86emuOp_inc_AX(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("INC\tEAX\n");
+ } else {
+ DECODE_PRINTF("INC\tAX\n");
+ }
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ M.x86.R_EAX = inc_long(M.x86.R_EAX);
+ } else {
+ M.x86.R_AX = inc_word(M.x86.R_AX);
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x41
+****************************************************************************/
+static void x86emuOp_inc_CX(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("INC\tECX\n");
+ } else {
+ DECODE_PRINTF("INC\tCX\n");
+ }
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ M.x86.R_ECX = inc_long(M.x86.R_ECX);
+ } else {
+ M.x86.R_CX = inc_word(M.x86.R_CX);
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x42
+****************************************************************************/
+static void x86emuOp_inc_DX(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("INC\tEDX\n");
+ } else {
+ DECODE_PRINTF("INC\tDX\n");
+ }
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ M.x86.R_EDX = inc_long(M.x86.R_EDX);
+ } else {
+ M.x86.R_DX = inc_word(M.x86.R_DX);
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x43
+****************************************************************************/
+static void x86emuOp_inc_BX(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("INC\tEBX\n");
+ } else {
+ DECODE_PRINTF("INC\tBX\n");
+ }
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ M.x86.R_EBX = inc_long(M.x86.R_EBX);
+ } else {
+ M.x86.R_BX = inc_word(M.x86.R_BX);
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x44
+****************************************************************************/
+static void x86emuOp_inc_SP(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("INC\tESP\n");
+ } else {
+ DECODE_PRINTF("INC\tSP\n");
+ }
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ M.x86.R_ESP = inc_long(M.x86.R_ESP);
+ } else {
+ M.x86.R_SP = inc_word(M.x86.R_SP);
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x45
+****************************************************************************/
+static void x86emuOp_inc_BP(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("INC\tEBP\n");
+ } else {
+ DECODE_PRINTF("INC\tBP\n");
+ }
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ M.x86.R_EBP = inc_long(M.x86.R_EBP);
+ } else {
+ M.x86.R_BP = inc_word(M.x86.R_BP);
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x46
+****************************************************************************/
+static void x86emuOp_inc_SI(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("INC\tESI\n");
+ } else {
+ DECODE_PRINTF("INC\tSI\n");
+ }
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ M.x86.R_ESI = inc_long(M.x86.R_ESI);
+ } else {
+ M.x86.R_SI = inc_word(M.x86.R_SI);
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x47
+****************************************************************************/
+static void x86emuOp_inc_DI(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("INC\tEDI\n");
+ } else {
+ DECODE_PRINTF("INC\tDI\n");
+ }
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ M.x86.R_EDI = inc_long(M.x86.R_EDI);
+ } else {
+ M.x86.R_DI = inc_word(M.x86.R_DI);
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x48
+****************************************************************************/
+static void x86emuOp_dec_AX(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("DEC\tEAX\n");
+ } else {
+ DECODE_PRINTF("DEC\tAX\n");
+ }
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ M.x86.R_EAX = dec_long(M.x86.R_EAX);
+ } else {
+ M.x86.R_AX = dec_word(M.x86.R_AX);
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x49
+****************************************************************************/
+static void x86emuOp_dec_CX(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("DEC\tECX\n");
+ } else {
+ DECODE_PRINTF("DEC\tCX\n");
+ }
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ M.x86.R_ECX = dec_long(M.x86.R_ECX);
+ } else {
+ M.x86.R_CX = dec_word(M.x86.R_CX);
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x4a
+****************************************************************************/
+static void x86emuOp_dec_DX(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("DEC\tEDX\n");
+ } else {
+ DECODE_PRINTF("DEC\tDX\n");
+ }
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ M.x86.R_EDX = dec_long(M.x86.R_EDX);
+ } else {
+ M.x86.R_DX = dec_word(M.x86.R_DX);
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x4b
+****************************************************************************/
+static void x86emuOp_dec_BX(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("DEC\tEBX\n");
+ } else {
+ DECODE_PRINTF("DEC\tBX\n");
+ }
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ M.x86.R_EBX = dec_long(M.x86.R_EBX);
+ } else {
+ M.x86.R_BX = dec_word(M.x86.R_BX);
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x4c
+****************************************************************************/
+static void x86emuOp_dec_SP(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("DEC\tESP\n");
+ } else {
+ DECODE_PRINTF("DEC\tSP\n");
+ }
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ M.x86.R_ESP = dec_long(M.x86.R_ESP);
+ } else {
+ M.x86.R_SP = dec_word(M.x86.R_SP);
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x4d
+****************************************************************************/
+static void x86emuOp_dec_BP(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("DEC\tEBP\n");
+ } else {
+ DECODE_PRINTF("DEC\tBP\n");
+ }
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ M.x86.R_EBP = dec_long(M.x86.R_EBP);
+ } else {
+ M.x86.R_BP = dec_word(M.x86.R_BP);
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x4e
+****************************************************************************/
+static void x86emuOp_dec_SI(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("DEC\tESI\n");
+ } else {
+ DECODE_PRINTF("DEC\tSI\n");
+ }
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ M.x86.R_ESI = dec_long(M.x86.R_ESI);
+ } else {
+ M.x86.R_SI = dec_word(M.x86.R_SI);
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x4f
+****************************************************************************/
+static void x86emuOp_dec_DI(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("DEC\tEDI\n");
+ } else {
+ DECODE_PRINTF("DEC\tDI\n");
+ }
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ M.x86.R_EDI = dec_long(M.x86.R_EDI);
+ } else {
+ M.x86.R_DI = dec_word(M.x86.R_DI);
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x50
+****************************************************************************/
+static void x86emuOp_push_AX(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("PUSH\tEAX\n");
+ } else {
+ DECODE_PRINTF("PUSH\tAX\n");
+ }
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ push_long(M.x86.R_EAX);
+ } else {
+ push_word(M.x86.R_AX);
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x51
+****************************************************************************/
+static void x86emuOp_push_CX(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("PUSH\tECX\n");
+ } else {
+ DECODE_PRINTF("PUSH\tCX\n");
+ }
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ push_long(M.x86.R_ECX);
+ } else {
+ push_word(M.x86.R_CX);
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x52
+****************************************************************************/
+static void x86emuOp_push_DX(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("PUSH\tEDX\n");
+ } else {
+ DECODE_PRINTF("PUSH\tDX\n");
+ }
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ push_long(M.x86.R_EDX);
+ } else {
+ push_word(M.x86.R_DX);
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x53
+****************************************************************************/
+static void x86emuOp_push_BX(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("PUSH\tEBX\n");
+ } else {
+ DECODE_PRINTF("PUSH\tBX\n");
+ }
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ push_long(M.x86.R_EBX);
+ } else {
+ push_word(M.x86.R_BX);
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x54
+****************************************************************************/
+static void x86emuOp_push_SP(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("PUSH\tESP\n");
+ } else {
+ DECODE_PRINTF("PUSH\tSP\n");
+ }
+ TRACE_AND_STEP();
+ /* Always push (E)SP, since we are emulating an i386 and above
+ * processor. This is necessary as some BIOS'es use this to check
+ * what type of processor is in the system.
+ */
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ push_long(M.x86.R_ESP);
+ } else {
+ push_word((u16)(M.x86.R_SP));
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x55
+****************************************************************************/
+static void x86emuOp_push_BP(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("PUSH\tEBP\n");
+ } else {
+ DECODE_PRINTF("PUSH\tBP\n");
+ }
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ push_long(M.x86.R_EBP);
+ } else {
+ push_word(M.x86.R_BP);
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x56
+****************************************************************************/
+static void x86emuOp_push_SI(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("PUSH\tESI\n");
+ } else {
+ DECODE_PRINTF("PUSH\tSI\n");
+ }
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ push_long(M.x86.R_ESI);
+ } else {
+ push_word(M.x86.R_SI);
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x57
+****************************************************************************/
+static void x86emuOp_push_DI(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("PUSH\tEDI\n");
+ } else {
+ DECODE_PRINTF("PUSH\tDI\n");
+ }
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ push_long(M.x86.R_EDI);
+ } else {
+ push_word(M.x86.R_DI);
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x58
+****************************************************************************/
+static void x86emuOp_pop_AX(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("POP\tEAX\n");
+ } else {
+ DECODE_PRINTF("POP\tAX\n");
+ }
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ M.x86.R_EAX = pop_long();
+ } else {
+ M.x86.R_AX = pop_word();
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x59
+****************************************************************************/
+static void x86emuOp_pop_CX(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("POP\tECX\n");
+ } else {
+ DECODE_PRINTF("POP\tCX\n");
+ }
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ M.x86.R_ECX = pop_long();
+ } else {
+ M.x86.R_CX = pop_word();
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x5a
+****************************************************************************/
+static void x86emuOp_pop_DX(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("POP\tEDX\n");
+ } else {
+ DECODE_PRINTF("POP\tDX\n");
+ }
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ M.x86.R_EDX = pop_long();
+ } else {
+ M.x86.R_DX = pop_word();
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x5b
+****************************************************************************/
+static void x86emuOp_pop_BX(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("POP\tEBX\n");
+ } else {
+ DECODE_PRINTF("POP\tBX\n");
+ }
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ M.x86.R_EBX = pop_long();
+ } else {
+ M.x86.R_BX = pop_word();
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x5c
+****************************************************************************/
+static void x86emuOp_pop_SP(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("POP\tESP\n");
+ } else {
+ DECODE_PRINTF("POP\tSP\n");
+ }
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ M.x86.R_ESP = pop_long();
+ } else {
+ M.x86.R_SP = pop_word();
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x5d
+****************************************************************************/
+static void x86emuOp_pop_BP(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("POP\tEBP\n");
+ } else {
+ DECODE_PRINTF("POP\tBP\n");
+ }
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ M.x86.R_EBP = pop_long();
+ } else {
+ M.x86.R_BP = pop_word();
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x5e
+****************************************************************************/
+static void x86emuOp_pop_SI(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("POP\tESI\n");
+ } else {
+ DECODE_PRINTF("POP\tSI\n");
+ }
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ M.x86.R_ESI = pop_long();
+ } else {
+ M.x86.R_SI = pop_word();
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x5f
+****************************************************************************/
+static void x86emuOp_pop_DI(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("POP\tEDI\n");
+ } else {
+ DECODE_PRINTF("POP\tDI\n");
+ }
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ M.x86.R_EDI = pop_long();
+ } else {
+ M.x86.R_DI = pop_word();
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x60
+****************************************************************************/
+static void x86emuOp_push_all(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("PUSHAD\n");
+ } else {
+ DECODE_PRINTF("PUSHA\n");
+ }
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 old_sp = M.x86.R_ESP;
+
+ push_long(M.x86.R_EAX);
+ push_long(M.x86.R_ECX);
+ push_long(M.x86.R_EDX);
+ push_long(M.x86.R_EBX);
+ push_long(old_sp);
+ push_long(M.x86.R_EBP);
+ push_long(M.x86.R_ESI);
+ push_long(M.x86.R_EDI);
+ } else {
+ u16 old_sp = M.x86.R_SP;
+
+ push_word(M.x86.R_AX);
+ push_word(M.x86.R_CX);
+ push_word(M.x86.R_DX);
+ push_word(M.x86.R_BX);
+ push_word(old_sp);
+ push_word(M.x86.R_BP);
+ push_word(M.x86.R_SI);
+ push_word(M.x86.R_DI);
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x61
+****************************************************************************/
+static void x86emuOp_pop_all(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("POPAD\n");
+ } else {
+ DECODE_PRINTF("POPA\n");
+ }
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ M.x86.R_EDI = pop_long();
+ M.x86.R_ESI = pop_long();
+ M.x86.R_EBP = pop_long();
+ M.x86.R_ESP += 4; /* skip ESP */
+ M.x86.R_EBX = pop_long();
+ M.x86.R_EDX = pop_long();
+ M.x86.R_ECX = pop_long();
+ M.x86.R_EAX = pop_long();
+ } else {
+ M.x86.R_DI = pop_word();
+ M.x86.R_SI = pop_word();
+ M.x86.R_BP = pop_word();
+ M.x86.R_SP += 2; /* skip SP */
+ M.x86.R_BX = pop_word();
+ M.x86.R_DX = pop_word();
+ M.x86.R_CX = pop_word();
+ M.x86.R_AX = pop_word();
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/*opcode 0x62 ILLEGAL OP, calls x86emuOp_illegal_op() */
+/*opcode 0x63 ILLEGAL OP, calls x86emuOp_illegal_op() */
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x64
+****************************************************************************/
+static void x86emuOp_segovr_FS(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ DECODE_PRINTF("FS:\n");
+ TRACE_AND_STEP();
+ M.x86.mode |= SYSMODE_SEGOVR_FS;
+ /*
+ * note the lack of DECODE_CLEAR_SEGOVR(r) since, here is one of 4
+ * opcode subroutines we do not want to do this.
+ */
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x65
+****************************************************************************/
+static void x86emuOp_segovr_GS(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ DECODE_PRINTF("GS:\n");
+ TRACE_AND_STEP();
+ M.x86.mode |= SYSMODE_SEGOVR_GS;
+ /*
+ * note the lack of DECODE_CLEAR_SEGOVR(r) since, here is one of 4
+ * opcode subroutines we do not want to do this.
+ */
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x66 - prefix for 32-bit register
+****************************************************************************/
+static void x86emuOp_prefix_data(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ DECODE_PRINTF("DATA:\n");
+ TRACE_AND_STEP();
+ M.x86.mode |= SYSMODE_PREFIX_DATA;
+ /* note no DECODE_CLEAR_SEGOVR here. */
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x67 - prefix for 32-bit address
+****************************************************************************/
+static void x86emuOp_prefix_addr(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ DECODE_PRINTF("ADDR:\n");
+ TRACE_AND_STEP();
+ M.x86.mode |= SYSMODE_PREFIX_ADDR;
+ /* note no DECODE_CLEAR_SEGOVR here. */
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x68
+****************************************************************************/
+static void x86emuOp_push_word_IMM(u8 X86EMU_UNUSED(op1))
+{
+ u32 imm;
+
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ imm = fetch_long_imm();
+ } else {
+ imm = fetch_word_imm();
+ }
+ DECODE_PRINTF2("PUSH\t%x\n", imm);
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ push_long(imm);
+ } else {
+ push_word((u16)imm);
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x69
+****************************************************************************/
+static void x86emuOp_imul_word_IMM(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ uint srcoffset;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("IMUL\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+ u32 srcval;
+ u32 res_lo,res_hi;
+ s32 imm;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm00_address(rl);
+ srcval = fetch_data_long(srcoffset);
+ imm = fetch_long_imm();
+ DECODE_PRINTF2(",%d\n", (s32)imm);
+ TRACE_AND_STEP();
+ imul_long_direct(&res_lo,&res_hi,(s32)srcval,(s32)imm);
+ if (res_hi != 0) {
+ SET_FLAG(F_CF);
+ SET_FLAG(F_OF);
+ } else {
+ CLEAR_FLAG(F_CF);
+ CLEAR_FLAG(F_OF);
+ }
+ *destreg = (u32)res_lo;
+ } else {
+ u16 *destreg;
+ u16 srcval;
+ u32 res;
+ s16 imm;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm00_address(rl);
+ srcval = fetch_data_word(srcoffset);
+ imm = fetch_word_imm();
+ DECODE_PRINTF2(",%d\n", (s32)imm);
+ TRACE_AND_STEP();
+ res = (s16)srcval * (s16)imm;
+ if (res > 0xFFFF) {
+ SET_FLAG(F_CF);
+ SET_FLAG(F_OF);
+ } else {
+ CLEAR_FLAG(F_CF);
+ CLEAR_FLAG(F_OF);
+ }
+ *destreg = (u16)res;
+ }
+ break;
+ case 1:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+ u32 srcval;
+ u32 res_lo,res_hi;
+ s32 imm;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm01_address(rl);
+ srcval = fetch_data_long(srcoffset);
+ imm = fetch_long_imm();
+ DECODE_PRINTF2(",%d\n", (s32)imm);
+ TRACE_AND_STEP();
+ imul_long_direct(&res_lo,&res_hi,(s32)srcval,(s32)imm);
+ if (res_hi != 0) {
+ SET_FLAG(F_CF);
+ SET_FLAG(F_OF);
+ } else {
+ CLEAR_FLAG(F_CF);
+ CLEAR_FLAG(F_OF);
+ }
+ *destreg = (u32)res_lo;
+ } else {
+ u16 *destreg;
+ u16 srcval;
+ u32 res;
+ s16 imm;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm01_address(rl);
+ srcval = fetch_data_word(srcoffset);
+ imm = fetch_word_imm();
+ DECODE_PRINTF2(",%d\n", (s32)imm);
+ TRACE_AND_STEP();
+ res = (s16)srcval * (s16)imm;
+ if (res > 0xFFFF) {
+ SET_FLAG(F_CF);
+ SET_FLAG(F_OF);
+ } else {
+ CLEAR_FLAG(F_CF);
+ CLEAR_FLAG(F_OF);
+ }
+ *destreg = (u16)res;
+ }
+ break;
+ case 2:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+ u32 srcval;
+ u32 res_lo,res_hi;
+ s32 imm;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm10_address(rl);
+ srcval = fetch_data_long(srcoffset);
+ imm = fetch_long_imm();
+ DECODE_PRINTF2(",%d\n", (s32)imm);
+ TRACE_AND_STEP();
+ imul_long_direct(&res_lo,&res_hi,(s32)srcval,(s32)imm);
+ if (res_hi != 0) {
+ SET_FLAG(F_CF);
+ SET_FLAG(F_OF);
+ } else {
+ CLEAR_FLAG(F_CF);
+ CLEAR_FLAG(F_OF);
+ }
+ *destreg = (u32)res_lo;
+ } else {
+ u16 *destreg;
+ u16 srcval;
+ u32 res;
+ s16 imm;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm10_address(rl);
+ srcval = fetch_data_word(srcoffset);
+ imm = fetch_word_imm();
+ DECODE_PRINTF2(",%d\n", (s32)imm);
+ TRACE_AND_STEP();
+ res = (s16)srcval * (s16)imm;
+ if (res > 0xFFFF) {
+ SET_FLAG(F_CF);
+ SET_FLAG(F_OF);
+ } else {
+ CLEAR_FLAG(F_CF);
+ CLEAR_FLAG(F_OF);
+ }
+ *destreg = (u16)res;
+ }
+ break;
+ case 3: /* register to register */
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg,*srcreg;
+ u32 res_lo,res_hi;
+ s32 imm;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_LONG_REGISTER(rl);
+ imm = fetch_long_imm();
+ DECODE_PRINTF2(",%d\n", (s32)imm);
+ TRACE_AND_STEP();
+ imul_long_direct(&res_lo,&res_hi,(s32)*srcreg,(s32)imm);
+ if (res_hi != 0) {
+ SET_FLAG(F_CF);
+ SET_FLAG(F_OF);
+ } else {
+ CLEAR_FLAG(F_CF);
+ CLEAR_FLAG(F_OF);
+ }
+ *destreg = (u32)res_lo;
+ } else {
+ u16 *destreg,*srcreg;
+ u32 res;
+ s16 imm;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_WORD_REGISTER(rl);
+ imm = fetch_word_imm();
+ DECODE_PRINTF2(",%d\n", (s32)imm);
+ res = (s16)*srcreg * (s16)imm;
+ if (res > 0xFFFF) {
+ SET_FLAG(F_CF);
+ SET_FLAG(F_OF);
+ } else {
+ CLEAR_FLAG(F_CF);
+ CLEAR_FLAG(F_OF);
+ }
+ *destreg = (u16)res;
+ }
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x6a
+****************************************************************************/
+static void x86emuOp_push_byte_IMM(u8 X86EMU_UNUSED(op1))
+{
+ s16 imm;
+
+ START_OF_INSTR();
+ imm = (s8)fetch_byte_imm();
+ DECODE_PRINTF2("PUSH\t%d\n", imm);
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ push_long((s32)imm);
+ } else {
+ push_word(imm);
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x6b
+****************************************************************************/
+static void x86emuOp_imul_byte_IMM(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ uint srcoffset;
+ s8 imm;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("IMUL\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+ u32 srcval;
+ u32 res_lo,res_hi;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm00_address(rl);
+ srcval = fetch_data_long(srcoffset);
+ imm = fetch_byte_imm();
+ DECODE_PRINTF2(",%d\n", (s32)imm);
+ TRACE_AND_STEP();
+ imul_long_direct(&res_lo,&res_hi,(s32)srcval,(s32)imm);
+ if (res_hi != 0) {
+ SET_FLAG(F_CF);
+ SET_FLAG(F_OF);
+ } else {
+ CLEAR_FLAG(F_CF);
+ CLEAR_FLAG(F_OF);
+ }
+ *destreg = (u32)res_lo;
+ } else {
+ u16 *destreg;
+ u16 srcval;
+ u32 res;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm00_address(rl);
+ srcval = fetch_data_word(srcoffset);
+ imm = fetch_byte_imm();
+ DECODE_PRINTF2(",%d\n", (s32)imm);
+ TRACE_AND_STEP();
+ res = (s16)srcval * (s16)imm;
+ if (res > 0xFFFF) {
+ SET_FLAG(F_CF);
+ SET_FLAG(F_OF);
+ } else {
+ CLEAR_FLAG(F_CF);
+ CLEAR_FLAG(F_OF);
+ }
+ *destreg = (u16)res;
+ }
+ break;
+ case 1:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+ u32 srcval;
+ u32 res_lo,res_hi;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm01_address(rl);
+ srcval = fetch_data_long(srcoffset);
+ imm = fetch_byte_imm();
+ DECODE_PRINTF2(",%d\n", (s32)imm);
+ TRACE_AND_STEP();
+ imul_long_direct(&res_lo,&res_hi,(s32)srcval,(s32)imm);
+ if (res_hi != 0) {
+ SET_FLAG(F_CF);
+ SET_FLAG(F_OF);
+ } else {
+ CLEAR_FLAG(F_CF);
+ CLEAR_FLAG(F_OF);
+ }
+ *destreg = (u32)res_lo;
+ } else {
+ u16 *destreg;
+ u16 srcval;
+ u32 res;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm01_address(rl);
+ srcval = fetch_data_word(srcoffset);
+ imm = fetch_byte_imm();
+ DECODE_PRINTF2(",%d\n", (s32)imm);
+ TRACE_AND_STEP();
+ res = (s16)srcval * (s16)imm;
+ if (res > 0xFFFF) {
+ SET_FLAG(F_CF);
+ SET_FLAG(F_OF);
+ } else {
+ CLEAR_FLAG(F_CF);
+ CLEAR_FLAG(F_OF);
+ }
+ *destreg = (u16)res;
+ }
+ break;
+ case 2:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+ u32 srcval;
+ u32 res_lo,res_hi;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm10_address(rl);
+ srcval = fetch_data_long(srcoffset);
+ imm = fetch_byte_imm();
+ DECODE_PRINTF2(",%d\n", (s32)imm);
+ TRACE_AND_STEP();
+ imul_long_direct(&res_lo,&res_hi,(s32)srcval,(s32)imm);
+ if (res_hi != 0) {
+ SET_FLAG(F_CF);
+ SET_FLAG(F_OF);
+ } else {
+ CLEAR_FLAG(F_CF);
+ CLEAR_FLAG(F_OF);
+ }
+ *destreg = (u32)res_lo;
+ } else {
+ u16 *destreg;
+ u16 srcval;
+ u32 res;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm10_address(rl);
+ srcval = fetch_data_word(srcoffset);
+ imm = fetch_byte_imm();
+ DECODE_PRINTF2(",%d\n", (s32)imm);
+ TRACE_AND_STEP();
+ res = (s16)srcval * (s16)imm;
+ if (res > 0xFFFF) {
+ SET_FLAG(F_CF);
+ SET_FLAG(F_OF);
+ } else {
+ CLEAR_FLAG(F_CF);
+ CLEAR_FLAG(F_OF);
+ }
+ *destreg = (u16)res;
+ }
+ break;
+ case 3: /* register to register */
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg,*srcreg;
+ u32 res_lo,res_hi;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_LONG_REGISTER(rl);
+ imm = fetch_byte_imm();
+ DECODE_PRINTF2(",%d\n", (s32)imm);
+ TRACE_AND_STEP();
+ imul_long_direct(&res_lo,&res_hi,(s32)*srcreg,(s32)imm);
+ if (res_hi != 0) {
+ SET_FLAG(F_CF);
+ SET_FLAG(F_OF);
+ } else {
+ CLEAR_FLAG(F_CF);
+ CLEAR_FLAG(F_OF);
+ }
+ *destreg = (u32)res_lo;
+ } else {
+ u16 *destreg,*srcreg;
+ u32 res;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_WORD_REGISTER(rl);
+ imm = fetch_byte_imm();
+ DECODE_PRINTF2(",%d\n", (s32)imm);
+ res = (s16)*srcreg * (s16)imm;
+ if (res > 0xFFFF) {
+ SET_FLAG(F_CF);
+ SET_FLAG(F_OF);
+ } else {
+ CLEAR_FLAG(F_CF);
+ CLEAR_FLAG(F_OF);
+ }
+ *destreg = (u16)res;
+ }
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x6c
+****************************************************************************/
+static void x86emuOp_ins_byte(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ DECODE_PRINTF("INSB\n");
+ ins(1);
+ TRACE_AND_STEP();
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x6d
+****************************************************************************/
+static void x86emuOp_ins_word(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("INSD\n");
+ ins(4);
+ } else {
+ DECODE_PRINTF("INSW\n");
+ ins(2);
+ }
+ TRACE_AND_STEP();
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x6e
+****************************************************************************/
+static void x86emuOp_outs_byte(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ DECODE_PRINTF("OUTSB\n");
+ outs(1);
+ TRACE_AND_STEP();
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x6f
+****************************************************************************/
+static void x86emuOp_outs_word(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("OUTSD\n");
+ outs(4);
+ } else {
+ DECODE_PRINTF("OUTSW\n");
+ outs(2);
+ }
+ TRACE_AND_STEP();
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x70
+****************************************************************************/
+static void x86emuOp_jump_near_O(u8 X86EMU_UNUSED(op1))
+{
+ s8 offset;
+ u16 target;
+
+ /* jump to byte offset if overflow flag is set */
+ START_OF_INSTR();
+ DECODE_PRINTF("JO\t");
+ offset = (s8)fetch_byte_imm();
+ target = (u16)(M.x86.R_IP + (s16)offset);
+ DECODE_PRINTF2("%x\n", target);
+ TRACE_AND_STEP();
+ if (ACCESS_FLAG(F_OF))
+ M.x86.R_IP = target;
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x71
+****************************************************************************/
+static void x86emuOp_jump_near_NO(u8 X86EMU_UNUSED(op1))
+{
+ s8 offset;
+ u16 target;
+
+ /* jump to byte offset if overflow is not set */
+ START_OF_INSTR();
+ DECODE_PRINTF("JNO\t");
+ offset = (s8)fetch_byte_imm();
+ target = (u16)(M.x86.R_IP + (s16)offset);
+ DECODE_PRINTF2("%x\n", target);
+ TRACE_AND_STEP();
+ if (!ACCESS_FLAG(F_OF))
+ M.x86.R_IP = target;
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x72
+****************************************************************************/
+static void x86emuOp_jump_near_B(u8 X86EMU_UNUSED(op1))
+{
+ s8 offset;
+ u16 target;
+
+ /* jump to byte offset if carry flag is set. */
+ START_OF_INSTR();
+ DECODE_PRINTF("JB\t");
+ offset = (s8)fetch_byte_imm();
+ target = (u16)(M.x86.R_IP + (s16)offset);
+ DECODE_PRINTF2("%x\n", target);
+ TRACE_AND_STEP();
+ if (ACCESS_FLAG(F_CF))
+ M.x86.R_IP = target;
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x73
+****************************************************************************/
+static void x86emuOp_jump_near_NB(u8 X86EMU_UNUSED(op1))
+{
+ s8 offset;
+ u16 target;
+
+ /* jump to byte offset if carry flag is clear. */
+ START_OF_INSTR();
+ DECODE_PRINTF("JNB\t");
+ offset = (s8)fetch_byte_imm();
+ target = (u16)(M.x86.R_IP + (s16)offset);
+ DECODE_PRINTF2("%x\n", target);
+ TRACE_AND_STEP();
+ if (!ACCESS_FLAG(F_CF))
+ M.x86.R_IP = target;
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x74
+****************************************************************************/
+static void x86emuOp_jump_near_Z(u8 X86EMU_UNUSED(op1))
+{
+ s8 offset;
+ u16 target;
+
+ /* jump to byte offset if zero flag is set. */
+ START_OF_INSTR();
+ DECODE_PRINTF("JZ\t");
+ offset = (s8)fetch_byte_imm();
+ target = (u16)(M.x86.R_IP + (s16)offset);
+ DECODE_PRINTF2("%x\n", target);
+ TRACE_AND_STEP();
+ if (ACCESS_FLAG(F_ZF))
+ M.x86.R_IP = target;
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x75
+****************************************************************************/
+static void x86emuOp_jump_near_NZ(u8 X86EMU_UNUSED(op1))
+{
+ s8 offset;
+ u16 target;
+
+ /* jump to byte offset if zero flag is clear. */
+ START_OF_INSTR();
+ DECODE_PRINTF("JNZ\t");
+ offset = (s8)fetch_byte_imm();
+ target = (u16)(M.x86.R_IP + (s16)offset);
+ DECODE_PRINTF2("%x\n", target);
+ TRACE_AND_STEP();
+ if (!ACCESS_FLAG(F_ZF))
+ M.x86.R_IP = target;
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x76
+****************************************************************************/
+static void x86emuOp_jump_near_BE(u8 X86EMU_UNUSED(op1))
+{
+ s8 offset;
+ u16 target;
+
+ /* jump to byte offset if carry flag is set or if the zero
+ flag is set. */
+ START_OF_INSTR();
+ DECODE_PRINTF("JBE\t");
+ offset = (s8)fetch_byte_imm();
+ target = (u16)(M.x86.R_IP + (s16)offset);
+ DECODE_PRINTF2("%x\n", target);
+ TRACE_AND_STEP();
+ if (ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF))
+ M.x86.R_IP = target;
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x77
+****************************************************************************/
+static void x86emuOp_jump_near_NBE(u8 X86EMU_UNUSED(op1))
+{
+ s8 offset;
+ u16 target;
+
+ /* jump to byte offset if carry flag is clear and if the zero
+ flag is clear */
+ START_OF_INSTR();
+ DECODE_PRINTF("JNBE\t");
+ offset = (s8)fetch_byte_imm();
+ target = (u16)(M.x86.R_IP + (s16)offset);
+ DECODE_PRINTF2("%x\n", target);
+ TRACE_AND_STEP();
+ if (!(ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF)))
+ M.x86.R_IP = target;
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x78
+****************************************************************************/
+static void x86emuOp_jump_near_S(u8 X86EMU_UNUSED(op1))
+{
+ s8 offset;
+ u16 target;
+
+ /* jump to byte offset if sign flag is set */
+ START_OF_INSTR();
+ DECODE_PRINTF("JS\t");
+ offset = (s8)fetch_byte_imm();
+ target = (u16)(M.x86.R_IP + (s16)offset);
+ DECODE_PRINTF2("%x\n", target);
+ TRACE_AND_STEP();
+ if (ACCESS_FLAG(F_SF))
+ M.x86.R_IP = target;
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x79
+****************************************************************************/
+static void x86emuOp_jump_near_NS(u8 X86EMU_UNUSED(op1))
+{
+ s8 offset;
+ u16 target;
+
+ /* jump to byte offset if sign flag is clear */
+ START_OF_INSTR();
+ DECODE_PRINTF("JNS\t");
+ offset = (s8)fetch_byte_imm();
+ target = (u16)(M.x86.R_IP + (s16)offset);
+ DECODE_PRINTF2("%x\n", target);
+ TRACE_AND_STEP();
+ if (!ACCESS_FLAG(F_SF))
+ M.x86.R_IP = target;
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x7a
+****************************************************************************/
+static void x86emuOp_jump_near_P(u8 X86EMU_UNUSED(op1))
+{
+ s8 offset;
+ u16 target;
+
+ /* jump to byte offset if parity flag is set (even parity) */
+ START_OF_INSTR();
+ DECODE_PRINTF("JP\t");
+ offset = (s8)fetch_byte_imm();
+ target = (u16)(M.x86.R_IP + (s16)offset);
+ DECODE_PRINTF2("%x\n", target);
+ TRACE_AND_STEP();
+ if (ACCESS_FLAG(F_PF))
+ M.x86.R_IP = target;
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x7b
+****************************************************************************/
+static void x86emuOp_jump_near_NP(u8 X86EMU_UNUSED(op1))
+{
+ s8 offset;
+ u16 target;
+
+ /* jump to byte offset if parity flag is clear (odd parity) */
+ START_OF_INSTR();
+ DECODE_PRINTF("JNP\t");
+ offset = (s8)fetch_byte_imm();
+ target = (u16)(M.x86.R_IP + (s16)offset);
+ DECODE_PRINTF2("%x\n", target);
+ TRACE_AND_STEP();
+ if (!ACCESS_FLAG(F_PF))
+ M.x86.R_IP = target;
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x7c
+****************************************************************************/
+static void x86emuOp_jump_near_L(u8 X86EMU_UNUSED(op1))
+{
+ s8 offset;
+ u16 target;
+ int sf, of;
+
+ /* jump to byte offset if sign flag not equal to overflow flag. */
+ START_OF_INSTR();
+ DECODE_PRINTF("JL\t");
+ offset = (s8)fetch_byte_imm();
+ target = (u16)(M.x86.R_IP + (s16)offset);
+ DECODE_PRINTF2("%x\n", target);
+ TRACE_AND_STEP();
+ sf = ACCESS_FLAG(F_SF) != 0;
+ of = ACCESS_FLAG(F_OF) != 0;
+ if (sf ^ of)
+ M.x86.R_IP = target;
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x7d
+****************************************************************************/
+static void x86emuOp_jump_near_NL(u8 X86EMU_UNUSED(op1))
+{
+ s8 offset;
+ u16 target;
+ int sf, of;
+
+ /* jump to byte offset if sign flag not equal to overflow flag. */
+ START_OF_INSTR();
+ DECODE_PRINTF("JNL\t");
+ offset = (s8)fetch_byte_imm();
+ target = (u16)(M.x86.R_IP + (s16)offset);
+ DECODE_PRINTF2("%x\n", target);
+ TRACE_AND_STEP();
+ sf = ACCESS_FLAG(F_SF) != 0;
+ of = ACCESS_FLAG(F_OF) != 0;
+ /* note: inverse of above, but using == instead of xor. */
+ if (sf == of)
+ M.x86.R_IP = target;
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x7e
+****************************************************************************/
+static void x86emuOp_jump_near_LE(u8 X86EMU_UNUSED(op1))
+{
+ s8 offset;
+ u16 target;
+ int sf, of;
+
+ /* jump to byte offset if sign flag not equal to overflow flag
+ or the zero flag is set */
+ START_OF_INSTR();
+ DECODE_PRINTF("JLE\t");
+ offset = (s8)fetch_byte_imm();
+ target = (u16)(M.x86.R_IP + (s16)offset);
+ DECODE_PRINTF2("%x\n", target);
+ TRACE_AND_STEP();
+ sf = ACCESS_FLAG(F_SF) != 0;
+ of = ACCESS_FLAG(F_OF) != 0;
+ if ((sf ^ of) || ACCESS_FLAG(F_ZF))
+ M.x86.R_IP = target;
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x7f
+****************************************************************************/
+static void x86emuOp_jump_near_NLE(u8 X86EMU_UNUSED(op1))
+{
+ s8 offset;
+ u16 target;
+ int sf, of;
+
+ /* jump to byte offset if sign flag equal to overflow flag.
+ and the zero flag is clear */
+ START_OF_INSTR();
+ DECODE_PRINTF("JNLE\t");
+ offset = (s8)fetch_byte_imm();
+ target = (u16)(M.x86.R_IP + (s16)offset);
+ DECODE_PRINTF2("%x\n", target);
+ TRACE_AND_STEP();
+ sf = ACCESS_FLAG(F_SF) != 0;
+ of = ACCESS_FLAG(F_OF) != 0;
+ if ((sf == of) && !ACCESS_FLAG(F_ZF))
+ M.x86.R_IP = target;
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+static u8 (*opc80_byte_operation[])(u8 d, u8 s) =
+{
+ add_byte, /* 00 */
+ or_byte, /* 01 */
+ adc_byte, /* 02 */
+ sbb_byte, /* 03 */
+ and_byte, /* 04 */
+ sub_byte, /* 05 */
+ xor_byte, /* 06 */
+ cmp_byte, /* 07 */
+};
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x80
+****************************************************************************/
+static void x86emuOp_opc80_byte_RM_IMM(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ u8 *destreg;
+ uint destoffset;
+ u8 imm;
+ u8 destval;
+
+ /*
+ * Weirdo special case instruction format. Part of the opcode
+ * held below in "RH". Doubly nested case would result, except
+ * that the decoded instruction
+ */
+ START_OF_INSTR();
+ FETCH_DECODE_MODRM(mod, rh, rl);
+#ifdef X86EMU_DEBUG
+ if (DEBUG_DECODE()) {
+ /* XXX DECODE_PRINTF may be changed to something more
+ general, so that it is important to leave the strings
+ in the same format, even though the result is that the
+ above test is done twice. */
+
+ switch (rh) {
+ case 0:
+ DECODE_PRINTF("ADD\t");
+ break;
+ case 1:
+ DECODE_PRINTF("OR\t");
+ break;
+ case 2:
+ DECODE_PRINTF("ADC\t");
+ break;
+ case 3:
+ DECODE_PRINTF("SBB\t");
+ break;
+ case 4:
+ DECODE_PRINTF("AND\t");
+ break;
+ case 5:
+ DECODE_PRINTF("SUB\t");
+ break;
+ case 6:
+ DECODE_PRINTF("XOR\t");
+ break;
+ case 7:
+ DECODE_PRINTF("CMP\t");
+ break;
+ }
+ }
+#endif
+ /* know operation, decode the mod byte to find the addressing
+ mode. */
+ switch (mod) {
+ case 0:
+ DECODE_PRINTF("BYTE PTR ");
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_byte(destoffset);
+ imm = fetch_byte_imm();
+ DECODE_PRINTF2("%x\n", imm);
+ TRACE_AND_STEP();
+ destval = (*opc80_byte_operation[rh]) (destval, imm);
+ if (rh != 7)
+ store_data_byte(destoffset, destval);
+ break;
+ case 1:
+ DECODE_PRINTF("BYTE PTR ");
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_byte(destoffset);
+ imm = fetch_byte_imm();
+ DECODE_PRINTF2("%x\n", imm);
+ TRACE_AND_STEP();
+ destval = (*opc80_byte_operation[rh]) (destval, imm);
+ if (rh != 7)
+ store_data_byte(destoffset, destval);
+ break;
+ case 2:
+ DECODE_PRINTF("BYTE PTR ");
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_byte(destoffset);
+ imm = fetch_byte_imm();
+ DECODE_PRINTF2("%x\n", imm);
+ TRACE_AND_STEP();
+ destval = (*opc80_byte_operation[rh]) (destval, imm);
+ if (rh != 7)
+ store_data_byte(destoffset, destval);
+ break;
+ case 3: /* register to register */
+ destreg = DECODE_RM_BYTE_REGISTER(rl);
+ DECODE_PRINTF(",");
+ imm = fetch_byte_imm();
+ DECODE_PRINTF2("%x\n", imm);
+ TRACE_AND_STEP();
+ destval = (*opc80_byte_operation[rh]) (*destreg, imm);
+ if (rh != 7)
+ *destreg = destval;
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+static u16 (*opc81_word_operation[])(u16 d, u16 s) =
+{
+ add_word, /*00 */
+ or_word, /*01 */
+ adc_word, /*02 */
+ sbb_word, /*03 */
+ and_word, /*04 */
+ sub_word, /*05 */
+ xor_word, /*06 */
+ cmp_word, /*07 */
+};
+
+static u32 (*opc81_long_operation[])(u32 d, u32 s) =
+{
+ add_long, /*00 */
+ or_long, /*01 */
+ adc_long, /*02 */
+ sbb_long, /*03 */
+ and_long, /*04 */
+ sub_long, /*05 */
+ xor_long, /*06 */
+ cmp_long, /*07 */
+};
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x81
+****************************************************************************/
+static void x86emuOp_opc81_word_RM_IMM(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ uint destoffset;
+
+ /*
+ * Weirdo special case instruction format. Part of the opcode
+ * held below in "RH". Doubly nested case would result, except
+ * that the decoded instruction
+ */
+ START_OF_INSTR();
+ FETCH_DECODE_MODRM(mod, rh, rl);
+#ifdef X86EMU_DEBUG
+ if (DEBUG_DECODE()) {
+ /* XXX DECODE_PRINTF may be changed to something more
+ general, so that it is important to leave the strings
+ in the same format, even though the result is that the
+ above test is done twice. */
+
+ switch (rh) {
+ case 0:
+ DECODE_PRINTF("ADD\t");
+ break;
+ case 1:
+ DECODE_PRINTF("OR\t");
+ break;
+ case 2:
+ DECODE_PRINTF("ADC\t");
+ break;
+ case 3:
+ DECODE_PRINTF("SBB\t");
+ break;
+ case 4:
+ DECODE_PRINTF("AND\t");
+ break;
+ case 5:
+ DECODE_PRINTF("SUB\t");
+ break;
+ case 6:
+ DECODE_PRINTF("XOR\t");
+ break;
+ case 7:
+ DECODE_PRINTF("CMP\t");
+ break;
+ }
+ }
+#endif
+ /*
+ * Know operation, decode the mod byte to find the addressing
+ * mode.
+ */
+ switch (mod) {
+ case 0:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval,imm;
+
+ DECODE_PRINTF("DWORD PTR ");
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_long(destoffset);
+ imm = fetch_long_imm();
+ DECODE_PRINTF2("%x\n", imm);
+ TRACE_AND_STEP();
+ destval = (*opc81_long_operation[rh]) (destval, imm);
+ if (rh != 7)
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval,imm;
+
+ DECODE_PRINTF("WORD PTR ");
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_word(destoffset);
+ imm = fetch_word_imm();
+ DECODE_PRINTF2("%x\n", imm);
+ TRACE_AND_STEP();
+ destval = (*opc81_word_operation[rh]) (destval, imm);
+ if (rh != 7)
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 1:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval,imm;
+
+ DECODE_PRINTF("DWORD PTR ");
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_long(destoffset);
+ imm = fetch_long_imm();
+ DECODE_PRINTF2("%x\n", imm);
+ TRACE_AND_STEP();
+ destval = (*opc81_long_operation[rh]) (destval, imm);
+ if (rh != 7)
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval,imm;
+
+ DECODE_PRINTF("WORD PTR ");
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_word(destoffset);
+ imm = fetch_word_imm();
+ DECODE_PRINTF2("%x\n", imm);
+ TRACE_AND_STEP();
+ destval = (*opc81_word_operation[rh]) (destval, imm);
+ if (rh != 7)
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 2:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval,imm;
+
+ DECODE_PRINTF("DWORD PTR ");
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_long(destoffset);
+ imm = fetch_long_imm();
+ DECODE_PRINTF2("%x\n", imm);
+ TRACE_AND_STEP();
+ destval = (*opc81_long_operation[rh]) (destval, imm);
+ if (rh != 7)
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval,imm;
+
+ DECODE_PRINTF("WORD PTR ");
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_word(destoffset);
+ imm = fetch_word_imm();
+ DECODE_PRINTF2("%x\n", imm);
+ TRACE_AND_STEP();
+ destval = (*opc81_word_operation[rh]) (destval, imm);
+ if (rh != 7)
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 3: /* register to register */
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+ u32 destval,imm;
+
+ destreg = DECODE_RM_LONG_REGISTER(rl);
+ DECODE_PRINTF(",");
+ imm = fetch_long_imm();
+ DECODE_PRINTF2("%x\n", imm);
+ TRACE_AND_STEP();
+ destval = (*opc81_long_operation[rh]) (*destreg, imm);
+ if (rh != 7)
+ *destreg = destval;
+ } else {
+ u16 *destreg;
+ u16 destval,imm;
+
+ destreg = DECODE_RM_WORD_REGISTER(rl);
+ DECODE_PRINTF(",");
+ imm = fetch_word_imm();
+ DECODE_PRINTF2("%x\n", imm);
+ TRACE_AND_STEP();
+ destval = (*opc81_word_operation[rh]) (*destreg, imm);
+ if (rh != 7)
+ *destreg = destval;
+ }
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+static u8 (*opc82_byte_operation[])(u8 s, u8 d) =
+{
+ add_byte, /*00 */
+ or_byte, /*01 *//*YYY UNUSED ???? */
+ adc_byte, /*02 */
+ sbb_byte, /*03 */
+ and_byte, /*04 *//*YYY UNUSED ???? */
+ sub_byte, /*05 */
+ xor_byte, /*06 *//*YYY UNUSED ???? */
+ cmp_byte, /*07 */
+};
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x82
+****************************************************************************/
+static void x86emuOp_opc82_byte_RM_IMM(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ u8 *destreg;
+ uint destoffset;
+ u8 imm;
+ u8 destval;
+
+ /*
+ * Weirdo special case instruction format. Part of the opcode
+ * held below in "RH". Doubly nested case would result, except
+ * that the decoded instruction Similar to opcode 81, except that
+ * the immediate byte is sign extended to a word length.
+ */
+ START_OF_INSTR();
+ FETCH_DECODE_MODRM(mod, rh, rl);
+#ifdef X86EMU_DEBUG
+ if (DEBUG_DECODE()) {
+ /* XXX DECODE_PRINTF may be changed to something more
+ general, so that it is important to leave the strings
+ in the same format, even though the result is that the
+ above test is done twice. */
+ switch (rh) {
+ case 0:
+ DECODE_PRINTF("ADD\t");
+ break;
+ case 1:
+ DECODE_PRINTF("OR\t");
+ break;
+ case 2:
+ DECODE_PRINTF("ADC\t");
+ break;
+ case 3:
+ DECODE_PRINTF("SBB\t");
+ break;
+ case 4:
+ DECODE_PRINTF("AND\t");
+ break;
+ case 5:
+ DECODE_PRINTF("SUB\t");
+ break;
+ case 6:
+ DECODE_PRINTF("XOR\t");
+ break;
+ case 7:
+ DECODE_PRINTF("CMP\t");
+ break;
+ }
+ }
+#endif
+ /* know operation, decode the mod byte to find the addressing
+ mode. */
+ switch (mod) {
+ case 0:
+ DECODE_PRINTF("BYTE PTR ");
+ destoffset = decode_rm00_address(rl);
+ destval = fetch_data_byte(destoffset);
+ imm = fetch_byte_imm();
+ DECODE_PRINTF2(",%x\n", imm);
+ TRACE_AND_STEP();
+ destval = (*opc82_byte_operation[rh]) (destval, imm);
+ if (rh != 7)
+ store_data_byte(destoffset, destval);
+ break;
+ case 1:
+ DECODE_PRINTF("BYTE PTR ");
+ destoffset = decode_rm01_address(rl);
+ destval = fetch_data_byte(destoffset);
+ imm = fetch_byte_imm();
+ DECODE_PRINTF2(",%x\n", imm);
+ TRACE_AND_STEP();
+ destval = (*opc82_byte_operation[rh]) (destval, imm);
+ if (rh != 7)
+ store_data_byte(destoffset, destval);
+ break;
+ case 2:
+ DECODE_PRINTF("BYTE PTR ");
+ destoffset = decode_rm10_address(rl);
+ destval = fetch_data_byte(destoffset);
+ imm = fetch_byte_imm();
+ DECODE_PRINTF2(",%x\n", imm);
+ TRACE_AND_STEP();
+ destval = (*opc82_byte_operation[rh]) (destval, imm);
+ if (rh != 7)
+ store_data_byte(destoffset, destval);
+ break;
+ case 3: /* register to register */
+ destreg = DECODE_RM_BYTE_REGISTER(rl);
+ imm = fetch_byte_imm();
+ DECODE_PRINTF2(",%x\n", imm);
+ TRACE_AND_STEP();
+ destval = (*opc82_byte_operation[rh]) (*destreg, imm);
+ if (rh != 7)
+ *destreg = destval;
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+static u16 (*opc83_word_operation[])(u16 s, u16 d) =
+{
+ add_word, /*00 */
+ or_word, /*01 *//*YYY UNUSED ???? */
+ adc_word, /*02 */
+ sbb_word, /*03 */
+ and_word, /*04 *//*YYY UNUSED ???? */
+ sub_word, /*05 */
+ xor_word, /*06 *//*YYY UNUSED ???? */
+ cmp_word, /*07 */
+};
+
+static u32 (*opc83_long_operation[])(u32 s, u32 d) =
+{
+ add_long, /*00 */
+ or_long, /*01 *//*YYY UNUSED ???? */
+ adc_long, /*02 */
+ sbb_long, /*03 */
+ and_long, /*04 *//*YYY UNUSED ???? */
+ sub_long, /*05 */
+ xor_long, /*06 *//*YYY UNUSED ???? */
+ cmp_long, /*07 */
+};
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x83
+****************************************************************************/
+static void x86emuOp_opc83_word_RM_IMM(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ uint destoffset;
+
+ /*
+ * Weirdo special case instruction format. Part of the opcode
+ * held below in "RH". Doubly nested case would result, except
+ * that the decoded instruction Similar to opcode 81, except that
+ * the immediate byte is sign extended to a word length.
+ */
+ START_OF_INSTR();
+ FETCH_DECODE_MODRM(mod, rh, rl);
+#ifdef X86EMU_DEBUG
+ if (DEBUG_DECODE()) {
+ /* XXX DECODE_PRINTF may be changed to something more
+ general, so that it is important to leave the strings
+ in the same format, even though the result is that the
+ above test is done twice. */
+ switch (rh) {
+ case 0:
+ DECODE_PRINTF("ADD\t");
+ break;
+ case 1:
+ DECODE_PRINTF("OR\t");
+ break;
+ case 2:
+ DECODE_PRINTF("ADC\t");
+ break;
+ case 3:
+ DECODE_PRINTF("SBB\t");
+ break;
+ case 4:
+ DECODE_PRINTF("AND\t");
+ break;
+ case 5:
+ DECODE_PRINTF("SUB\t");
+ break;
+ case 6:
+ DECODE_PRINTF("XOR\t");
+ break;
+ case 7:
+ DECODE_PRINTF("CMP\t");
+ break;
+ }
+ }
+#endif
+ /* know operation, decode the mod byte to find the addressing
+ mode. */
+ switch (mod) {
+ case 0:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval,imm;
+
+ DECODE_PRINTF("DWORD PTR ");
+ destoffset = decode_rm00_address(rl);
+ destval = fetch_data_long(destoffset);
+ imm = (s8) fetch_byte_imm();
+ DECODE_PRINTF2(",%x\n", imm);
+ TRACE_AND_STEP();
+ destval = (*opc83_long_operation[rh]) (destval, imm);
+ if (rh != 7)
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval,imm;
+
+ DECODE_PRINTF("WORD PTR ");
+ destoffset = decode_rm00_address(rl);
+ destval = fetch_data_word(destoffset);
+ imm = (s8) fetch_byte_imm();
+ DECODE_PRINTF2(",%x\n", imm);
+ TRACE_AND_STEP();
+ destval = (*opc83_word_operation[rh]) (destval, imm);
+ if (rh != 7)
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 1:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval,imm;
+
+ DECODE_PRINTF("DWORD PTR ");
+ destoffset = decode_rm01_address(rl);
+ destval = fetch_data_long(destoffset);
+ imm = (s8) fetch_byte_imm();
+ DECODE_PRINTF2(",%x\n", imm);
+ TRACE_AND_STEP();
+ destval = (*opc83_long_operation[rh]) (destval, imm);
+ if (rh != 7)
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval,imm;
+
+ DECODE_PRINTF("WORD PTR ");
+ destoffset = decode_rm01_address(rl);
+ destval = fetch_data_word(destoffset);
+ imm = (s8) fetch_byte_imm();
+ DECODE_PRINTF2(",%x\n", imm);
+ TRACE_AND_STEP();
+ destval = (*opc83_word_operation[rh]) (destval, imm);
+ if (rh != 7)
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 2:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval,imm;
+
+ DECODE_PRINTF("DWORD PTR ");
+ destoffset = decode_rm10_address(rl);
+ destval = fetch_data_long(destoffset);
+ imm = (s8) fetch_byte_imm();
+ DECODE_PRINTF2(",%x\n", imm);
+ TRACE_AND_STEP();
+ destval = (*opc83_long_operation[rh]) (destval, imm);
+ if (rh != 7)
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval,imm;
+
+ DECODE_PRINTF("WORD PTR ");
+ destoffset = decode_rm10_address(rl);
+ destval = fetch_data_word(destoffset);
+ imm = (s8) fetch_byte_imm();
+ DECODE_PRINTF2(",%x\n", imm);
+ TRACE_AND_STEP();
+ destval = (*opc83_word_operation[rh]) (destval, imm);
+ if (rh != 7)
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 3: /* register to register */
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+ u32 destval,imm;
+
+ destreg = DECODE_RM_LONG_REGISTER(rl);
+ imm = (s8) fetch_byte_imm();
+ DECODE_PRINTF2(",%x\n", imm);
+ TRACE_AND_STEP();
+ destval = (*opc83_long_operation[rh]) (*destreg, imm);
+ if (rh != 7)
+ *destreg = destval;
+ } else {
+ u16 *destreg;
+ u16 destval,imm;
+
+ destreg = DECODE_RM_WORD_REGISTER(rl);
+ imm = (s8) fetch_byte_imm();
+ DECODE_PRINTF2(",%x\n", imm);
+ TRACE_AND_STEP();
+ destval = (*opc83_word_operation[rh]) (*destreg, imm);
+ if (rh != 7)
+ *destreg = destval;
+ }
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x84
+****************************************************************************/
+static void x86emuOp_test_byte_RM_R(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ u8 *destreg, *srcreg;
+ uint destoffset;
+ u8 destval;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("TEST\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_byte(destoffset);
+ srcreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ test_byte(destval, *srcreg);
+ break;
+ case 1:
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_byte(destoffset);
+ srcreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ test_byte(destval, *srcreg);
+ break;
+ case 2:
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_byte(destoffset);
+ srcreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ test_byte(destval, *srcreg);
+ break;
+ case 3: /* register to register */
+ destreg = DECODE_RM_BYTE_REGISTER(rl);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ test_byte(*destreg, *srcreg);
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x85
+****************************************************************************/
+static void x86emuOp_test_word_RM_R(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ uint destoffset;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("TEST\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+ u32 *srcreg;
+
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_long(destoffset);
+ srcreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ test_long(destval, *srcreg);
+ } else {
+ u16 destval;
+ u16 *srcreg;
+
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_word(destoffset);
+ srcreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ test_word(destval, *srcreg);
+ }
+ break;
+ case 1:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+ u32 *srcreg;
+
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_long(destoffset);
+ srcreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ test_long(destval, *srcreg);
+ } else {
+ u16 destval;
+ u16 *srcreg;
+
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_word(destoffset);
+ srcreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ test_word(destval, *srcreg);
+ }
+ break;
+ case 2:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+ u32 *srcreg;
+
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_long(destoffset);
+ srcreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ test_long(destval, *srcreg);
+ } else {
+ u16 destval;
+ u16 *srcreg;
+
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_word(destoffset);
+ srcreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ test_word(destval, *srcreg);
+ }
+ break;
+ case 3: /* register to register */
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg,*srcreg;
+
+ destreg = DECODE_RM_LONG_REGISTER(rl);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ test_long(*destreg, *srcreg);
+ } else {
+ u16 *destreg,*srcreg;
+
+ destreg = DECODE_RM_WORD_REGISTER(rl);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ test_word(*destreg, *srcreg);
+ }
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x86
+****************************************************************************/
+static void x86emuOp_xchg_byte_RM_R(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ u8 *destreg, *srcreg;
+ uint destoffset;
+ u8 destval;
+ u8 tmp;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("XCHG\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_byte(destoffset);
+ srcreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ tmp = *srcreg;
+ *srcreg = destval;
+ destval = tmp;
+ store_data_byte(destoffset, destval);
+ break;
+ case 1:
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_byte(destoffset);
+ srcreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ tmp = *srcreg;
+ *srcreg = destval;
+ destval = tmp;
+ store_data_byte(destoffset, destval);
+ break;
+ case 2:
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_byte(destoffset);
+ srcreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ tmp = *srcreg;
+ *srcreg = destval;
+ destval = tmp;
+ store_data_byte(destoffset, destval);
+ break;
+ case 3: /* register to register */
+ destreg = DECODE_RM_BYTE_REGISTER(rl);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ tmp = *srcreg;
+ *srcreg = *destreg;
+ *destreg = tmp;
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x87
+****************************************************************************/
+static void x86emuOp_xchg_word_RM_R(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ uint destoffset;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("XCHG\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *srcreg;
+ u32 destval,tmp;
+
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_long(destoffset);
+ srcreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ tmp = *srcreg;
+ *srcreg = destval;
+ destval = tmp;
+ store_data_long(destoffset, destval);
+ } else {
+ u16 *srcreg;
+ u16 destval,tmp;
+
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_word(destoffset);
+ srcreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ tmp = *srcreg;
+ *srcreg = destval;
+ destval = tmp;
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 1:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *srcreg;
+ u32 destval,tmp;
+
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_long(destoffset);
+ srcreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ tmp = *srcreg;
+ *srcreg = destval;
+ destval = tmp;
+ store_data_long(destoffset, destval);
+ } else {
+ u16 *srcreg;
+ u16 destval,tmp;
+
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_word(destoffset);
+ srcreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ tmp = *srcreg;
+ *srcreg = destval;
+ destval = tmp;
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 2:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *srcreg;
+ u32 destval,tmp;
+
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_long(destoffset);
+ srcreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ tmp = *srcreg;
+ *srcreg = destval;
+ destval = tmp;
+ store_data_long(destoffset, destval);
+ } else {
+ u16 *srcreg;
+ u16 destval,tmp;
+
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ destval = fetch_data_word(destoffset);
+ srcreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ tmp = *srcreg;
+ *srcreg = destval;
+ destval = tmp;
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 3: /* register to register */
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg,*srcreg;
+ u32 tmp;
+
+ destreg = DECODE_RM_LONG_REGISTER(rl);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ tmp = *srcreg;
+ *srcreg = *destreg;
+ *destreg = tmp;
+ } else {
+ u16 *destreg,*srcreg;
+ u16 tmp;
+
+ destreg = DECODE_RM_WORD_REGISTER(rl);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ tmp = *srcreg;
+ *srcreg = *destreg;
+ *destreg = tmp;
+ }
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x88
+****************************************************************************/
+static void x86emuOp_mov_byte_RM_R(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ u8 *destreg, *srcreg;
+ uint destoffset;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("MOV\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ store_data_byte(destoffset, *srcreg);
+ break;
+ case 1:
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ store_data_byte(destoffset, *srcreg);
+ break;
+ case 2:
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ store_data_byte(destoffset, *srcreg);
+ break;
+ case 3: /* register to register */
+ destreg = DECODE_RM_BYTE_REGISTER(rl);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = *srcreg;
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x89
+****************************************************************************/
+static void x86emuOp_mov_word_RM_R(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ u32 destoffset;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("MOV\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *srcreg;
+
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ store_data_long(destoffset, *srcreg);
+ } else {
+ u16 *srcreg;
+
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ store_data_word(destoffset, *srcreg);
+ }
+ break;
+ case 1:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *srcreg;
+
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ store_data_long(destoffset, *srcreg);
+ } else {
+ u16 *srcreg;
+
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ store_data_word(destoffset, *srcreg);
+ }
+ break;
+ case 2:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *srcreg;
+
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ store_data_long(destoffset, *srcreg);
+ } else {
+ u16 *srcreg;
+
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ store_data_word(destoffset, *srcreg);
+ }
+ break;
+ case 3: /* register to register */
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg,*srcreg;
+
+ destreg = DECODE_RM_LONG_REGISTER(rl);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = *srcreg;
+ } else {
+ u16 *destreg,*srcreg;
+
+ destreg = DECODE_RM_WORD_REGISTER(rl);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = *srcreg;
+ }
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x8a
+****************************************************************************/
+static void x86emuOp_mov_byte_R_RM(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ u8 *destreg, *srcreg;
+ uint srcoffset;
+ u8 srcval;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("MOV\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ destreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm00_address(rl);
+ srcval = fetch_data_byte(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = srcval;
+ break;
+ case 1:
+ destreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm01_address(rl);
+ srcval = fetch_data_byte(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = srcval;
+ break;
+ case 2:
+ destreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm10_address(rl);
+ srcval = fetch_data_byte(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = srcval;
+ break;
+ case 3: /* register to register */
+ destreg = DECODE_RM_BYTE_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_BYTE_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = *srcreg;
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x8b
+****************************************************************************/
+static void x86emuOp_mov_word_R_RM(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ uint srcoffset;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("MOV\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+ u32 srcval;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm00_address(rl);
+ srcval = fetch_data_long(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = srcval;
+ } else {
+ u16 *destreg;
+ u16 srcval;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm00_address(rl);
+ srcval = fetch_data_word(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = srcval;
+ }
+ break;
+ case 1:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+ u32 srcval;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm01_address(rl);
+ srcval = fetch_data_long(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = srcval;
+ } else {
+ u16 *destreg;
+ u16 srcval;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm01_address(rl);
+ srcval = fetch_data_word(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = srcval;
+ }
+ break;
+ case 2:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+ u32 srcval;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm10_address(rl);
+ srcval = fetch_data_long(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = srcval;
+ } else {
+ u16 *destreg;
+ u16 srcval;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm10_address(rl);
+ srcval = fetch_data_word(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = srcval;
+ }
+ break;
+ case 3: /* register to register */
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg, *srcreg;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_LONG_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = *srcreg;
+ } else {
+ u16 *destreg, *srcreg;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_WORD_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = *srcreg;
+ }
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x8c
+****************************************************************************/
+static void x86emuOp_mov_word_RM_SR(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ u16 *destreg, *srcreg;
+ uint destoffset;
+ u16 destval;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("MOV\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ srcreg = decode_rm_seg_register(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = *srcreg;
+ store_data_word(destoffset, destval);
+ break;
+ case 1:
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ srcreg = decode_rm_seg_register(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = *srcreg;
+ store_data_word(destoffset, destval);
+ break;
+ case 2:
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ srcreg = decode_rm_seg_register(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = *srcreg;
+ store_data_word(destoffset, destval);
+ break;
+ case 3: /* register to register */
+ destreg = DECODE_RM_WORD_REGISTER(rl);
+ DECODE_PRINTF(",");
+ srcreg = decode_rm_seg_register(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = *srcreg;
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x8d
+****************************************************************************/
+static void x86emuOp_lea_word_R_M(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ uint destoffset;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("LEA\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ if (M.x86.mode & SYSMODE_PREFIX_ADDR) {
+ u32 *srcreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *srcreg = (u32)destoffset;
+ } else {
+ u16 *srcreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *srcreg = (u16)destoffset;
+ }
+ break;
+ case 1:
+ if (M.x86.mode & SYSMODE_PREFIX_ADDR) {
+ u32 *srcreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *srcreg = (u32)destoffset;
+ } else {
+ u16 *srcreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *srcreg = (u16)destoffset;
+ }
+ break;
+ case 2:
+ if (M.x86.mode & SYSMODE_PREFIX_ADDR) {
+ u32 *srcreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *srcreg = (u32)destoffset;
+ } else {
+ u16 *srcreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *srcreg = (u16)destoffset;
+ }
+ break;
+ case 3: /* register to register */
+ /* undefined. Do nothing. */
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x8e
+****************************************************************************/
+static void x86emuOp_mov_word_SR_RM(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ u16 *destreg, *srcreg;
+ uint srcoffset;
+ u16 srcval;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("MOV\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ destreg = decode_rm_seg_register(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm00_address(rl);
+ srcval = fetch_data_word(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = srcval;
+ break;
+ case 1:
+ destreg = decode_rm_seg_register(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm01_address(rl);
+ srcval = fetch_data_word(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = srcval;
+ break;
+ case 2:
+ destreg = decode_rm_seg_register(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm10_address(rl);
+ srcval = fetch_data_word(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = srcval;
+ break;
+ case 3: /* register to register */
+ destreg = decode_rm_seg_register(rh);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_WORD_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = *srcreg;
+ break;
+ }
+ /*
+ * Clean up, and reset all the R_xSP pointers to the correct
+ * locations. This is about 3x too much overhead (doing all the
+ * segreg ptrs when only one is needed, but this instruction
+ * *cannot* be that common, and this isn't too much work anyway.
+ */
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x8f
+****************************************************************************/
+static void x86emuOp_pop_RM(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ uint destoffset;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("POP\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ if (rh != 0) {
+ DECODE_PRINTF("ILLEGAL DECODE OF OPCODE 8F\n");
+ HALT_SYS();
+ }
+ switch (mod) {
+ case 0:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = pop_long();
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = pop_word();
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 1:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = pop_long();
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = pop_word();
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 2:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = pop_long();
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ destval = pop_word();
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 3: /* register to register */
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+
+ destreg = DECODE_RM_LONG_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = pop_long();
+ } else {
+ u16 *destreg;
+
+ destreg = DECODE_RM_WORD_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = pop_word();
+ }
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x90
+****************************************************************************/
+static void x86emuOp_nop(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ DECODE_PRINTF("NOP\n");
+ TRACE_AND_STEP();
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x91
+****************************************************************************/
+static void x86emuOp_xchg_word_AX_CX(u8 X86EMU_UNUSED(op1))
+{
+ u32 tmp;
+
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("XCHG\tEAX,ECX\n");
+ } else {
+ DECODE_PRINTF("XCHG\tAX,CX\n");
+ }
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ tmp = M.x86.R_EAX;
+ M.x86.R_EAX = M.x86.R_ECX;
+ M.x86.R_ECX = tmp;
+ } else {
+ tmp = M.x86.R_AX;
+ M.x86.R_AX = M.x86.R_CX;
+ M.x86.R_CX = (u16)tmp;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x92
+****************************************************************************/
+static void x86emuOp_xchg_word_AX_DX(u8 X86EMU_UNUSED(op1))
+{
+ u32 tmp;
+
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("XCHG\tEAX,EDX\n");
+ } else {
+ DECODE_PRINTF("XCHG\tAX,DX\n");
+ }
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ tmp = M.x86.R_EAX;
+ M.x86.R_EAX = M.x86.R_EDX;
+ M.x86.R_EDX = tmp;
+ } else {
+ tmp = M.x86.R_AX;
+ M.x86.R_AX = M.x86.R_DX;
+ M.x86.R_DX = (u16)tmp;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x93
+****************************************************************************/
+static void x86emuOp_xchg_word_AX_BX(u8 X86EMU_UNUSED(op1))
+{
+ u32 tmp;
+
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("XCHG\tEAX,EBX\n");
+ } else {
+ DECODE_PRINTF("XCHG\tAX,BX\n");
+ }
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ tmp = M.x86.R_EAX;
+ M.x86.R_EAX = M.x86.R_EBX;
+ M.x86.R_EBX = tmp;
+ } else {
+ tmp = M.x86.R_AX;
+ M.x86.R_AX = M.x86.R_BX;
+ M.x86.R_BX = (u16)tmp;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x94
+****************************************************************************/
+static void x86emuOp_xchg_word_AX_SP(u8 X86EMU_UNUSED(op1))
+{
+ u32 tmp;
+
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("XCHG\tEAX,ESP\n");
+ } else {
+ DECODE_PRINTF("XCHG\tAX,SP\n");
+ }
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ tmp = M.x86.R_EAX;
+ M.x86.R_EAX = M.x86.R_ESP;
+ M.x86.R_ESP = tmp;
+ } else {
+ tmp = M.x86.R_AX;
+ M.x86.R_AX = M.x86.R_SP;
+ M.x86.R_SP = (u16)tmp;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x95
+****************************************************************************/
+static void x86emuOp_xchg_word_AX_BP(u8 X86EMU_UNUSED(op1))
+{
+ u32 tmp;
+
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("XCHG\tEAX,EBP\n");
+ } else {
+ DECODE_PRINTF("XCHG\tAX,BP\n");
+ }
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ tmp = M.x86.R_EAX;
+ M.x86.R_EAX = M.x86.R_EBP;
+ M.x86.R_EBP = tmp;
+ } else {
+ tmp = M.x86.R_AX;
+ M.x86.R_AX = M.x86.R_BP;
+ M.x86.R_BP = (u16)tmp;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x96
+****************************************************************************/
+static void x86emuOp_xchg_word_AX_SI(u8 X86EMU_UNUSED(op1))
+{
+ u32 tmp;
+
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("XCHG\tEAX,ESI\n");
+ } else {
+ DECODE_PRINTF("XCHG\tAX,SI\n");
+ }
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ tmp = M.x86.R_EAX;
+ M.x86.R_EAX = M.x86.R_ESI;
+ M.x86.R_ESI = tmp;
+ } else {
+ tmp = M.x86.R_AX;
+ M.x86.R_AX = M.x86.R_SI;
+ M.x86.R_SI = (u16)tmp;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x97
+****************************************************************************/
+static void x86emuOp_xchg_word_AX_DI(u8 X86EMU_UNUSED(op1))
+{
+ u32 tmp;
+
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("XCHG\tEAX,EDI\n");
+ } else {
+ DECODE_PRINTF("XCHG\tAX,DI\n");
+ }
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ tmp = M.x86.R_EAX;
+ M.x86.R_EAX = M.x86.R_EDI;
+ M.x86.R_EDI = tmp;
+ } else {
+ tmp = M.x86.R_AX;
+ M.x86.R_AX = M.x86.R_DI;
+ M.x86.R_DI = (u16)tmp;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x98
+****************************************************************************/
+static void x86emuOp_cbw(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("CWDE\n");
+ } else {
+ DECODE_PRINTF("CBW\n");
+ }
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ if (M.x86.R_AX & 0x8000) {
+ M.x86.R_EAX |= 0xffff0000;
+ } else {
+ M.x86.R_EAX &= 0x0000ffff;
+ }
+ } else {
+ if (M.x86.R_AL & 0x80) {
+ M.x86.R_AH = 0xff;
+ } else {
+ M.x86.R_AH = 0x0;
+ }
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x99
+****************************************************************************/
+static void x86emuOp_cwd(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("CDQ\n");
+ } else {
+ DECODE_PRINTF("CWD\n");
+ }
+ DECODE_PRINTF("CWD\n");
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ if (M.x86.R_EAX & 0x80000000) {
+ M.x86.R_EDX = 0xffffffff;
+ } else {
+ M.x86.R_EDX = 0x0;
+ }
+ } else {
+ if (M.x86.R_AX & 0x8000) {
+ M.x86.R_DX = 0xffff;
+ } else {
+ M.x86.R_DX = 0x0;
+ }
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x9a
+****************************************************************************/
+static void x86emuOp_call_far_IMM(u8 X86EMU_UNUSED(op1))
+{
+ u32 farseg, faroff;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("CALL\t");
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ faroff = fetch_long_imm();
+ farseg = fetch_word_imm();
+ } else {
+ faroff = fetch_word_imm();
+ farseg = fetch_word_imm();
+ }
+ DECODE_PRINTF2("%04x:", farseg);
+ DECODE_PRINTF2("%04x\n", faroff);
+ CALL_TRACE(M.x86.saved_cs, M.x86.saved_ip, farseg, faroff, "FAR ");
+
+ /* XXX
+ *
+ * Hooked interrupt vectors calling into our "BIOS" will cause
+ * problems unless all intersegment stuff is checked for BIOS
+ * access. Check needed here. For moment, let it alone.
+ */
+ TRACE_AND_STEP();
+ push_word(M.x86.R_CS);
+ M.x86.R_CS = farseg;
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ push_long(M.x86.R_EIP);
+ } else {
+ push_word(M.x86.R_IP);
+ }
+ M.x86.R_EIP = faroff & 0xffff;
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x9b
+****************************************************************************/
+static void x86emuOp_wait(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ DECODE_PRINTF("WAIT");
+ TRACE_AND_STEP();
+ /* NADA. */
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x9c
+****************************************************************************/
+static void x86emuOp_pushf_word(u8 X86EMU_UNUSED(op1))
+{
+ u32 flags;
+
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("PUSHFD\n");
+ } else {
+ DECODE_PRINTF("PUSHF\n");
+ }
+ TRACE_AND_STEP();
+
+ /* clear out *all* bits not representing flags, and turn on real bits */
+ flags = (M.x86.R_EFLG & F_MSK) | F_ALWAYS_ON;
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ push_long(flags);
+ } else {
+ push_word((u16)flags);
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x9d
+****************************************************************************/
+static void x86emuOp_popf_word(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("POPFD\n");
+ } else {
+ DECODE_PRINTF("POPF\n");
+ }
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ M.x86.R_EFLG = pop_long();
+ } else {
+ M.x86.R_FLG = pop_word();
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x9e
+****************************************************************************/
+static void x86emuOp_sahf(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ DECODE_PRINTF("SAHF\n");
+ TRACE_AND_STEP();
+ /* clear the lower bits of the flag register */
+ M.x86.R_FLG &= 0xffffff00;
+ /* or in the AH register into the flags register */
+ M.x86.R_FLG |= M.x86.R_AH;
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x9f
+****************************************************************************/
+static void x86emuOp_lahf(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ DECODE_PRINTF("LAHF\n");
+ TRACE_AND_STEP();
+ M.x86.R_AH = (u8)(M.x86.R_FLG & 0xff);
+ /*undocumented TC++ behavior??? Nope. It's documented, but
+ you have too look real hard to notice it. */
+ M.x86.R_AH |= 0x2;
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xa0
+****************************************************************************/
+static void x86emuOp_mov_AL_M_IMM(u8 X86EMU_UNUSED(op1))
+{
+ u16 offset;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("MOV\tAL,");
+ offset = fetch_word_imm();
+ DECODE_PRINTF2("[%04x]\n", offset);
+ TRACE_AND_STEP();
+ M.x86.R_AL = fetch_data_byte(offset);
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xa1
+****************************************************************************/
+static void x86emuOp_mov_AX_M_IMM(u8 X86EMU_UNUSED(op1))
+{
+ u16 offset;
+
+ START_OF_INSTR();
+ offset = fetch_word_imm();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF2("MOV\tEAX,[%04x]\n", offset);
+ } else {
+ DECODE_PRINTF2("MOV\tAX,[%04x]\n", offset);
+ }
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ M.x86.R_EAX = fetch_data_long(offset);
+ } else {
+ M.x86.R_AX = fetch_data_word(offset);
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xa2
+****************************************************************************/
+static void x86emuOp_mov_M_AL_IMM(u8 X86EMU_UNUSED(op1))
+{
+ u16 offset;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("MOV\t");
+ offset = fetch_word_imm();
+ DECODE_PRINTF2("[%04x],AL\n", offset);
+ TRACE_AND_STEP();
+ store_data_byte(offset, M.x86.R_AL);
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xa3
+****************************************************************************/
+static void x86emuOp_mov_M_AX_IMM(u8 X86EMU_UNUSED(op1))
+{
+ u16 offset;
+
+ START_OF_INSTR();
+ offset = fetch_word_imm();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF2("MOV\t[%04x],EAX\n", offset);
+ } else {
+ DECODE_PRINTF2("MOV\t[%04x],AX\n", offset);
+ }
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ store_data_long(offset, M.x86.R_EAX);
+ } else {
+ store_data_word(offset, M.x86.R_AX);
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xa4
+****************************************************************************/
+static void x86emuOp_movs_byte(u8 X86EMU_UNUSED(op1))
+{
+ u8 val;
+ u32 count;
+ int inc;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("MOVS\tBYTE\n");
+ if (ACCESS_FLAG(F_DF)) /* down */
+ inc = -1;
+ else
+ inc = 1;
+ TRACE_AND_STEP();
+ count = 1;
+ if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
+ /* dont care whether REPE or REPNE */
+ /* move them until CX is ZERO. */
+ count = M.x86.R_CX;
+ M.x86.R_CX = 0;
+ M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
+ }
+ while (count--) {
+ val = fetch_data_byte(M.x86.R_SI);
+ store_data_byte_abs(M.x86.R_ES, M.x86.R_DI, val);
+ M.x86.R_SI += inc;
+ M.x86.R_DI += inc;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xa5
+****************************************************************************/
+static void x86emuOp_movs_word(u8 X86EMU_UNUSED(op1))
+{
+ u32 val;
+ int inc;
+ u32 count;
+
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("MOVS\tDWORD\n");
+ if (ACCESS_FLAG(F_DF)) /* down */
+ inc = -4;
+ else
+ inc = 4;
+ } else {
+ DECODE_PRINTF("MOVS\tWORD\n");
+ if (ACCESS_FLAG(F_DF)) /* down */
+ inc = -2;
+ else
+ inc = 2;
+ }
+ TRACE_AND_STEP();
+ count = 1;
+ if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
+ /* dont care whether REPE or REPNE */
+ /* move them until CX is ZERO. */
+ count = M.x86.R_CX;
+ M.x86.R_CX = 0;
+ M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
+ }
+ while (count--) {
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ val = fetch_data_long(M.x86.R_SI);
+ store_data_long_abs(M.x86.R_ES, M.x86.R_DI, val);
+ } else {
+ val = fetch_data_word(M.x86.R_SI);
+ store_data_word_abs(M.x86.R_ES, M.x86.R_DI, (u16)val);
+ }
+ M.x86.R_SI += inc;
+ M.x86.R_DI += inc;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xa6
+****************************************************************************/
+static void x86emuOp_cmps_byte(u8 X86EMU_UNUSED(op1))
+{
+ s8 val1, val2;
+ int inc;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("CMPS\tBYTE\n");
+ TRACE_AND_STEP();
+ if (ACCESS_FLAG(F_DF)) /* down */
+ inc = -1;
+ else
+ inc = 1;
+
+ if (M.x86.mode & SYSMODE_PREFIX_REPE) {
+ /* REPE */
+ /* move them until CX is ZERO. */
+ while (M.x86.R_CX != 0) {
+ val1 = fetch_data_byte(M.x86.R_SI);
+ val2 = fetch_data_byte_abs(M.x86.R_ES, M.x86.R_DI);
+ cmp_byte(val1, val2);
+ M.x86.R_CX -= 1;
+ M.x86.R_SI += inc;
+ M.x86.R_DI += inc;
+ if (ACCESS_FLAG(F_ZF) == 0)
+ break;
+ }
+ M.x86.mode &= ~SYSMODE_PREFIX_REPE;
+ } else if (M.x86.mode & SYSMODE_PREFIX_REPNE) {
+ /* REPNE */
+ /* move them until CX is ZERO. */
+ while (M.x86.R_CX != 0) {
+ val1 = fetch_data_byte(M.x86.R_SI);
+ val2 = fetch_data_byte_abs(M.x86.R_ES, M.x86.R_DI);
+ cmp_byte(val1, val2);
+ M.x86.R_CX -= 1;
+ M.x86.R_SI += inc;
+ M.x86.R_DI += inc;
+ if (ACCESS_FLAG(F_ZF))
+ break; /* zero flag set means equal */
+ }
+ M.x86.mode &= ~SYSMODE_PREFIX_REPNE;
+ } else {
+ val1 = fetch_data_byte(M.x86.R_SI);
+ val2 = fetch_data_byte_abs(M.x86.R_ES, M.x86.R_DI);
+ cmp_byte(val1, val2);
+ M.x86.R_SI += inc;
+ M.x86.R_DI += inc;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xa7
+****************************************************************************/
+static void x86emuOp_cmps_word(u8 X86EMU_UNUSED(op1))
+{
+ u32 val1,val2;
+ int inc;
+
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("CMPS\tDWORD\n");
+ if (ACCESS_FLAG(F_DF)) /* down */
+ inc = -4;
+ else
+ inc = 4;
+ } else {
+ DECODE_PRINTF("CMPS\tWORD\n");
+ if (ACCESS_FLAG(F_DF)) /* down */
+ inc = -2;
+ else
+ inc = 2;
+ }
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_REPE) {
+ /* REPE */
+ /* move them until CX is ZERO. */
+ while (M.x86.R_CX != 0) {
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ val1 = fetch_data_long(M.x86.R_SI);
+ val2 = fetch_data_long_abs(M.x86.R_ES, M.x86.R_DI);
+ cmp_long(val1, val2);
+ } else {
+ val1 = fetch_data_word(M.x86.R_SI);
+ val2 = fetch_data_word_abs(M.x86.R_ES, M.x86.R_DI);
+ cmp_word((u16)val1, (u16)val2);
+ }
+ M.x86.R_CX -= 1;
+ M.x86.R_SI += inc;
+ M.x86.R_DI += inc;
+ if (ACCESS_FLAG(F_ZF) == 0)
+ break;
+ }
+ M.x86.mode &= ~SYSMODE_PREFIX_REPE;
+ } else if (M.x86.mode & SYSMODE_PREFIX_REPNE) {
+ /* REPNE */
+ /* move them until CX is ZERO. */
+ while (M.x86.R_CX != 0) {
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ val1 = fetch_data_long(M.x86.R_SI);
+ val2 = fetch_data_long_abs(M.x86.R_ES, M.x86.R_DI);
+ cmp_long(val1, val2);
+ } else {
+ val1 = fetch_data_word(M.x86.R_SI);
+ val2 = fetch_data_word_abs(M.x86.R_ES, M.x86.R_DI);
+ cmp_word((u16)val1, (u16)val2);
+ }
+ M.x86.R_CX -= 1;
+ M.x86.R_SI += inc;
+ M.x86.R_DI += inc;
+ if (ACCESS_FLAG(F_ZF))
+ break; /* zero flag set means equal */
+ }
+ M.x86.mode &= ~SYSMODE_PREFIX_REPNE;
+ } else {
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ val1 = fetch_data_long(M.x86.R_SI);
+ val2 = fetch_data_long_abs(M.x86.R_ES, M.x86.R_DI);
+ cmp_long(val1, val2);
+ } else {
+ val1 = fetch_data_word(M.x86.R_SI);
+ val2 = fetch_data_word_abs(M.x86.R_ES, M.x86.R_DI);
+ cmp_word((u16)val1, (u16)val2);
+ }
+ M.x86.R_SI += inc;
+ M.x86.R_DI += inc;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xa8
+****************************************************************************/
+static void x86emuOp_test_AL_IMM(u8 X86EMU_UNUSED(op1))
+{
+ int imm;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("TEST\tAL,");
+ imm = fetch_byte_imm();
+ DECODE_PRINTF2("%04x\n", imm);
+ TRACE_AND_STEP();
+ test_byte(M.x86.R_AL, (u8)imm);
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xa9
+****************************************************************************/
+static void x86emuOp_test_AX_IMM(u8 X86EMU_UNUSED(op1))
+{
+ u32 srcval;
+
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("TEST\tEAX,");
+ srcval = fetch_long_imm();
+ } else {
+ DECODE_PRINTF("TEST\tAX,");
+ srcval = fetch_word_imm();
+ }
+ DECODE_PRINTF2("%x\n", srcval);
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ test_long(M.x86.R_EAX, srcval);
+ } else {
+ test_word(M.x86.R_AX, (u16)srcval);
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xaa
+****************************************************************************/
+static void x86emuOp_stos_byte(u8 X86EMU_UNUSED(op1))
+{
+ int inc;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("STOS\tBYTE\n");
+ if (ACCESS_FLAG(F_DF)) /* down */
+ inc = -1;
+ else
+ inc = 1;
+ TRACE_AND_STEP();
+ if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
+ /* dont care whether REPE or REPNE */
+ /* move them until CX is ZERO. */
+ while (M.x86.R_CX != 0) {
+ store_data_byte_abs(M.x86.R_ES, M.x86.R_DI, M.x86.R_AL);
+ M.x86.R_CX -= 1;
+ M.x86.R_DI += inc;
+ }
+ M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
+ } else {
+ store_data_byte_abs(M.x86.R_ES, M.x86.R_DI, M.x86.R_AL);
+ M.x86.R_DI += inc;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xab
+****************************************************************************/
+static void x86emuOp_stos_word(u8 X86EMU_UNUSED(op1))
+{
+ int inc;
+ u32 count;
+
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("STOS\tDWORD\n");
+ if (ACCESS_FLAG(F_DF)) /* down */
+ inc = -4;
+ else
+ inc = 4;
+ } else {
+ DECODE_PRINTF("STOS\tWORD\n");
+ if (ACCESS_FLAG(F_DF)) /* down */
+ inc = -2;
+ else
+ inc = 2;
+ }
+ TRACE_AND_STEP();
+ count = 1;
+ if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
+ /* dont care whether REPE or REPNE */
+ /* move them until CX is ZERO. */
+ count = M.x86.R_CX;
+ M.x86.R_CX = 0;
+ M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
+ }
+ while (count--) {
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ store_data_long_abs(M.x86.R_ES, M.x86.R_DI, M.x86.R_EAX);
+ } else {
+ store_data_word_abs(M.x86.R_ES, M.x86.R_DI, M.x86.R_AX);
+ }
+ M.x86.R_DI += inc;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xac
+****************************************************************************/
+static void x86emuOp_lods_byte(u8 X86EMU_UNUSED(op1))
+{
+ int inc;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("LODS\tBYTE\n");
+ TRACE_AND_STEP();
+ if (ACCESS_FLAG(F_DF)) /* down */
+ inc = -1;
+ else
+ inc = 1;
+ if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
+ /* dont care whether REPE or REPNE */
+ /* move them until CX is ZERO. */
+ while (M.x86.R_CX != 0) {
+ M.x86.R_AL = fetch_data_byte(M.x86.R_SI);
+ M.x86.R_CX -= 1;
+ M.x86.R_SI += inc;
+ }
+ M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
+ } else {
+ M.x86.R_AL = fetch_data_byte(M.x86.R_SI);
+ M.x86.R_SI += inc;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xad
+****************************************************************************/
+static void x86emuOp_lods_word(u8 X86EMU_UNUSED(op1))
+{
+ int inc;
+ u32 count;
+
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("LODS\tDWORD\n");
+ if (ACCESS_FLAG(F_DF)) /* down */
+ inc = -4;
+ else
+ inc = 4;
+ } else {
+ DECODE_PRINTF("LODS\tWORD\n");
+ if (ACCESS_FLAG(F_DF)) /* down */
+ inc = -2;
+ else
+ inc = 2;
+ }
+ TRACE_AND_STEP();
+ count = 1;
+ if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
+ /* dont care whether REPE or REPNE */
+ /* move them until CX is ZERO. */
+ count = M.x86.R_CX;
+ M.x86.R_CX = 0;
+ M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
+ }
+ while (count--) {
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ M.x86.R_EAX = fetch_data_long(M.x86.R_SI);
+ } else {
+ M.x86.R_AX = fetch_data_word(M.x86.R_SI);
+ }
+ M.x86.R_SI += inc;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xae
+****************************************************************************/
+static void x86emuOp_scas_byte(u8 X86EMU_UNUSED(op1))
+{
+ s8 val2;
+ int inc;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("SCAS\tBYTE\n");
+ TRACE_AND_STEP();
+ if (ACCESS_FLAG(F_DF)) /* down */
+ inc = -1;
+ else
+ inc = 1;
+ if (M.x86.mode & SYSMODE_PREFIX_REPE) {
+ /* REPE */
+ /* move them until CX is ZERO. */
+ while (M.x86.R_CX != 0) {
+ val2 = fetch_data_byte_abs(M.x86.R_ES, M.x86.R_DI);
+ cmp_byte(M.x86.R_AL, val2);
+ M.x86.R_CX -= 1;
+ M.x86.R_DI += inc;
+ if (ACCESS_FLAG(F_ZF) == 0)
+ break;
+ }
+ M.x86.mode &= ~SYSMODE_PREFIX_REPE;
+ } else if (M.x86.mode & SYSMODE_PREFIX_REPNE) {
+ /* REPNE */
+ /* move them until CX is ZERO. */
+ while (M.x86.R_CX != 0) {
+ val2 = fetch_data_byte_abs(M.x86.R_ES, M.x86.R_DI);
+ cmp_byte(M.x86.R_AL, val2);
+ M.x86.R_CX -= 1;
+ M.x86.R_DI += inc;
+ if (ACCESS_FLAG(F_ZF))
+ break; /* zero flag set means equal */
+ }
+ M.x86.mode &= ~SYSMODE_PREFIX_REPNE;
+ } else {
+ val2 = fetch_data_byte_abs(M.x86.R_ES, M.x86.R_DI);
+ cmp_byte(M.x86.R_AL, val2);
+ M.x86.R_DI += inc;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xaf
+****************************************************************************/
+static void x86emuOp_scas_word(u8 X86EMU_UNUSED(op1))
+{
+ int inc;
+ u32 val;
+
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("SCAS\tDWORD\n");
+ if (ACCESS_FLAG(F_DF)) /* down */
+ inc = -4;
+ else
+ inc = 4;
+ } else {
+ DECODE_PRINTF("SCAS\tWORD\n");
+ if (ACCESS_FLAG(F_DF)) /* down */
+ inc = -2;
+ else
+ inc = 2;
+ }
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_REPE) {
+ /* REPE */
+ /* move them until CX is ZERO. */
+ while (M.x86.R_CX != 0) {
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ val = fetch_data_long_abs(M.x86.R_ES, M.x86.R_DI);
+ cmp_long(M.x86.R_EAX, val);
+ } else {
+ val = fetch_data_word_abs(M.x86.R_ES, M.x86.R_DI);
+ cmp_word(M.x86.R_AX, (u16)val);
+ }
+ M.x86.R_CX -= 1;
+ M.x86.R_DI += inc;
+ if (ACCESS_FLAG(F_ZF) == 0)
+ break;
+ }
+ M.x86.mode &= ~SYSMODE_PREFIX_REPE;
+ } else if (M.x86.mode & SYSMODE_PREFIX_REPNE) {
+ /* REPNE */
+ /* move them until CX is ZERO. */
+ while (M.x86.R_CX != 0) {
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ val = fetch_data_long_abs(M.x86.R_ES, M.x86.R_DI);
+ cmp_long(M.x86.R_EAX, val);
+ } else {
+ val = fetch_data_word_abs(M.x86.R_ES, M.x86.R_DI);
+ cmp_word(M.x86.R_AX, (u16)val);
+ }
+ M.x86.R_CX -= 1;
+ M.x86.R_DI += inc;
+ if (ACCESS_FLAG(F_ZF))
+ break; /* zero flag set means equal */
+ }
+ M.x86.mode &= ~SYSMODE_PREFIX_REPNE;
+ } else {
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ val = fetch_data_long_abs(M.x86.R_ES, M.x86.R_DI);
+ cmp_long(M.x86.R_EAX, val);
+ } else {
+ val = fetch_data_word_abs(M.x86.R_ES, M.x86.R_DI);
+ cmp_word(M.x86.R_AX, (u16)val);
+ }
+ M.x86.R_DI += inc;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xb0
+****************************************************************************/
+static void x86emuOp_mov_byte_AL_IMM(u8 X86EMU_UNUSED(op1))
+{
+ u8 imm;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("MOV\tAL,");
+ imm = fetch_byte_imm();
+ DECODE_PRINTF2("%x\n", imm);
+ TRACE_AND_STEP();
+ M.x86.R_AL = imm;
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xb1
+****************************************************************************/
+static void x86emuOp_mov_byte_CL_IMM(u8 X86EMU_UNUSED(op1))
+{
+ u8 imm;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("MOV\tCL,");
+ imm = fetch_byte_imm();
+ DECODE_PRINTF2("%x\n", imm);
+ TRACE_AND_STEP();
+ M.x86.R_CL = imm;
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xb2
+****************************************************************************/
+static void x86emuOp_mov_byte_DL_IMM(u8 X86EMU_UNUSED(op1))
+{
+ u8 imm;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("MOV\tDL,");
+ imm = fetch_byte_imm();
+ DECODE_PRINTF2("%x\n", imm);
+ TRACE_AND_STEP();
+ M.x86.R_DL = imm;
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xb3
+****************************************************************************/
+static void x86emuOp_mov_byte_BL_IMM(u8 X86EMU_UNUSED(op1))
+{
+ u8 imm;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("MOV\tBL,");
+ imm = fetch_byte_imm();
+ DECODE_PRINTF2("%x\n", imm);
+ TRACE_AND_STEP();
+ M.x86.R_BL = imm;
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xb4
+****************************************************************************/
+static void x86emuOp_mov_byte_AH_IMM(u8 X86EMU_UNUSED(op1))
+{
+ u8 imm;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("MOV\tAH,");
+ imm = fetch_byte_imm();
+ DECODE_PRINTF2("%x\n", imm);
+ TRACE_AND_STEP();
+ M.x86.R_AH = imm;
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xb5
+****************************************************************************/
+static void x86emuOp_mov_byte_CH_IMM(u8 X86EMU_UNUSED(op1))
+{
+ u8 imm;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("MOV\tCH,");
+ imm = fetch_byte_imm();
+ DECODE_PRINTF2("%x\n", imm);
+ TRACE_AND_STEP();
+ M.x86.R_CH = imm;
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xb6
+****************************************************************************/
+static void x86emuOp_mov_byte_DH_IMM(u8 X86EMU_UNUSED(op1))
+{
+ u8 imm;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("MOV\tDH,");
+ imm = fetch_byte_imm();
+ DECODE_PRINTF2("%x\n", imm);
+ TRACE_AND_STEP();
+ M.x86.R_DH = imm;
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xb7
+****************************************************************************/
+static void x86emuOp_mov_byte_BH_IMM(u8 X86EMU_UNUSED(op1))
+{
+ u8 imm;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("MOV\tBH,");
+ imm = fetch_byte_imm();
+ DECODE_PRINTF2("%x\n", imm);
+ TRACE_AND_STEP();
+ M.x86.R_BH = imm;
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xb8
+****************************************************************************/
+static void x86emuOp_mov_word_AX_IMM(u8 X86EMU_UNUSED(op1))
+{
+ u32 srcval;
+
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("MOV\tEAX,");
+ srcval = fetch_long_imm();
+ } else {
+ DECODE_PRINTF("MOV\tAX,");
+ srcval = fetch_word_imm();
+ }
+ DECODE_PRINTF2("%x\n", srcval);
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ M.x86.R_EAX = srcval;
+ } else {
+ M.x86.R_AX = (u16)srcval;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xb9
+****************************************************************************/
+static void x86emuOp_mov_word_CX_IMM(u8 X86EMU_UNUSED(op1))
+{
+ u32 srcval;
+
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("MOV\tECX,");
+ srcval = fetch_long_imm();
+ } else {
+ DECODE_PRINTF("MOV\tCX,");
+ srcval = fetch_word_imm();
+ }
+ DECODE_PRINTF2("%x\n", srcval);
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ M.x86.R_ECX = srcval;
+ } else {
+ M.x86.R_CX = (u16)srcval;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xba
+****************************************************************************/
+static void x86emuOp_mov_word_DX_IMM(u8 X86EMU_UNUSED(op1))
+{
+ u32 srcval;
+
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("MOV\tEDX,");
+ srcval = fetch_long_imm();
+ } else {
+ DECODE_PRINTF("MOV\tDX,");
+ srcval = fetch_word_imm();
+ }
+ DECODE_PRINTF2("%x\n", srcval);
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ M.x86.R_EDX = srcval;
+ } else {
+ M.x86.R_DX = (u16)srcval;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xbb
+****************************************************************************/
+static void x86emuOp_mov_word_BX_IMM(u8 X86EMU_UNUSED(op1))
+{
+ u32 srcval;
+
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("MOV\tEBX,");
+ srcval = fetch_long_imm();
+ } else {
+ DECODE_PRINTF("MOV\tBX,");
+ srcval = fetch_word_imm();
+ }
+ DECODE_PRINTF2("%x\n", srcval);
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ M.x86.R_EBX = srcval;
+ } else {
+ M.x86.R_BX = (u16)srcval;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xbc
+****************************************************************************/
+static void x86emuOp_mov_word_SP_IMM(u8 X86EMU_UNUSED(op1))
+{
+ u32 srcval;
+
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("MOV\tESP,");
+ srcval = fetch_long_imm();
+ } else {
+ DECODE_PRINTF("MOV\tSP,");
+ srcval = fetch_word_imm();
+ }
+ DECODE_PRINTF2("%x\n", srcval);
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ M.x86.R_ESP = srcval;
+ } else {
+ M.x86.R_SP = (u16)srcval;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xbd
+****************************************************************************/
+static void x86emuOp_mov_word_BP_IMM(u8 X86EMU_UNUSED(op1))
+{
+ u32 srcval;
+
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("MOV\tEBP,");
+ srcval = fetch_long_imm();
+ } else {
+ DECODE_PRINTF("MOV\tBP,");
+ srcval = fetch_word_imm();
+ }
+ DECODE_PRINTF2("%x\n", srcval);
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ M.x86.R_EBP = srcval;
+ } else {
+ M.x86.R_BP = (u16)srcval;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xbe
+****************************************************************************/
+static void x86emuOp_mov_word_SI_IMM(u8 X86EMU_UNUSED(op1))
+{
+ u32 srcval;
+
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("MOV\tESI,");
+ srcval = fetch_long_imm();
+ } else {
+ DECODE_PRINTF("MOV\tSI,");
+ srcval = fetch_word_imm();
+ }
+ DECODE_PRINTF2("%x\n", srcval);
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ M.x86.R_ESI = srcval;
+ } else {
+ M.x86.R_SI = (u16)srcval;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xbf
+****************************************************************************/
+static void x86emuOp_mov_word_DI_IMM(u8 X86EMU_UNUSED(op1))
+{
+ u32 srcval;
+
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("MOV\tEDI,");
+ srcval = fetch_long_imm();
+ } else {
+ DECODE_PRINTF("MOV\tDI,");
+ srcval = fetch_word_imm();
+ }
+ DECODE_PRINTF2("%x\n", srcval);
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ M.x86.R_EDI = srcval;
+ } else {
+ M.x86.R_DI = (u16)srcval;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/* used by opcodes c0, d0, and d2. */
+static u8(*opcD0_byte_operation[])(u8 d, u8 s) =
+{
+ rol_byte,
+ ror_byte,
+ rcl_byte,
+ rcr_byte,
+ shl_byte,
+ shr_byte,
+ shl_byte, /* sal_byte === shl_byte by definition */
+ sar_byte,
+};
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xc0
+****************************************************************************/
+static void x86emuOp_opcC0_byte_RM_MEM(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ u8 *destreg;
+ uint destoffset;
+ u8 destval;
+ u8 amt;
+
+ /*
+ * Yet another weirdo special case instruction format. Part of
+ * the opcode held below in "RH". Doubly nested case would
+ * result, except that the decoded instruction
+ */
+ START_OF_INSTR();
+ FETCH_DECODE_MODRM(mod, rh, rl);
+#ifdef X86EMU_DEBUG
+ if (DEBUG_DECODE()) {
+ /* XXX DECODE_PRINTF may be changed to something more
+ general, so that it is important to leave the strings
+ in the same format, even though the result is that the
+ above test is done twice. */
+
+ switch (rh) {
+ case 0:
+ DECODE_PRINTF("ROL\t");
+ break;
+ case 1:
+ DECODE_PRINTF("ROR\t");
+ break;
+ case 2:
+ DECODE_PRINTF("RCL\t");
+ break;
+ case 3:
+ DECODE_PRINTF("RCR\t");
+ break;
+ case 4:
+ DECODE_PRINTF("SHL\t");
+ break;
+ case 5:
+ DECODE_PRINTF("SHR\t");
+ break;
+ case 6:
+ DECODE_PRINTF("SAL\t");
+ break;
+ case 7:
+ DECODE_PRINTF("SAR\t");
+ break;
+ }
+ }
+#endif
+ /* know operation, decode the mod byte to find the addressing
+ mode. */
+ switch (mod) {
+ case 0:
+ DECODE_PRINTF("BYTE PTR ");
+ destoffset = decode_rm00_address(rl);
+ amt = fetch_byte_imm();
+ DECODE_PRINTF2(",%x\n", amt);
+ destval = fetch_data_byte(destoffset);
+ TRACE_AND_STEP();
+ destval = (*opcD0_byte_operation[rh]) (destval, amt);
+ store_data_byte(destoffset, destval);
+ break;
+ case 1:
+ DECODE_PRINTF("BYTE PTR ");
+ destoffset = decode_rm01_address(rl);
+ amt = fetch_byte_imm();
+ DECODE_PRINTF2(",%x\n", amt);
+ destval = fetch_data_byte(destoffset);
+ TRACE_AND_STEP();
+ destval = (*opcD0_byte_operation[rh]) (destval, amt);
+ store_data_byte(destoffset, destval);
+ break;
+ case 2:
+ DECODE_PRINTF("BYTE PTR ");
+ destoffset = decode_rm10_address(rl);
+ amt = fetch_byte_imm();
+ DECODE_PRINTF2(",%x\n", amt);
+ destval = fetch_data_byte(destoffset);
+ TRACE_AND_STEP();
+ destval = (*opcD0_byte_operation[rh]) (destval, amt);
+ store_data_byte(destoffset, destval);
+ break;
+ case 3: /* register to register */
+ destreg = DECODE_RM_BYTE_REGISTER(rl);
+ amt = fetch_byte_imm();
+ DECODE_PRINTF2(",%x\n", amt);
+ TRACE_AND_STEP();
+ destval = (*opcD0_byte_operation[rh]) (*destreg, amt);
+ *destreg = destval;
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/* used by opcodes c1, d1, and d3. */
+static u16(*opcD1_word_operation[])(u16 s, u8 d) =
+{
+ rol_word,
+ ror_word,
+ rcl_word,
+ rcr_word,
+ shl_word,
+ shr_word,
+ shl_word, /* sal_byte === shl_byte by definition */
+ sar_word,
+};
+
+/* used by opcodes c1, d1, and d3. */
+static u32 (*opcD1_long_operation[])(u32 s, u8 d) =
+{
+ rol_long,
+ ror_long,
+ rcl_long,
+ rcr_long,
+ shl_long,
+ shr_long,
+ shl_long, /* sal_byte === shl_byte by definition */
+ sar_long,
+};
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xc1
+****************************************************************************/
+static void x86emuOp_opcC1_word_RM_MEM(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ uint destoffset;
+ u8 amt;
+
+ /*
+ * Yet another weirdo special case instruction format. Part of
+ * the opcode held below in "RH". Doubly nested case would
+ * result, except that the decoded instruction
+ */
+ START_OF_INSTR();
+ FETCH_DECODE_MODRM(mod, rh, rl);
+#ifdef X86EMU_DEBUG
+ if (DEBUG_DECODE()) {
+ /* XXX DECODE_PRINTF may be changed to something more
+ general, so that it is important to leave the strings
+ in the same format, even though the result is that the
+ above test is done twice. */
+
+ switch (rh) {
+ case 0:
+ DECODE_PRINTF("ROL\t");
+ break;
+ case 1:
+ DECODE_PRINTF("ROR\t");
+ break;
+ case 2:
+ DECODE_PRINTF("RCL\t");
+ break;
+ case 3:
+ DECODE_PRINTF("RCR\t");
+ break;
+ case 4:
+ DECODE_PRINTF("SHL\t");
+ break;
+ case 5:
+ DECODE_PRINTF("SHR\t");
+ break;
+ case 6:
+ DECODE_PRINTF("SAL\t");
+ break;
+ case 7:
+ DECODE_PRINTF("SAR\t");
+ break;
+ }
+ }
+#endif
+ /* know operation, decode the mod byte to find the addressing
+ mode. */
+ switch (mod) {
+ case 0:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+
+ DECODE_PRINTF("DWORD PTR ");
+ destoffset = decode_rm00_address(rl);
+ amt = fetch_byte_imm();
+ DECODE_PRINTF2(",%x\n", amt);
+ destval = fetch_data_long(destoffset);
+ TRACE_AND_STEP();
+ destval = (*opcD1_long_operation[rh]) (destval, amt);
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+
+ DECODE_PRINTF("WORD PTR ");
+ destoffset = decode_rm00_address(rl);
+ amt = fetch_byte_imm();
+ DECODE_PRINTF2(",%x\n", amt);
+ destval = fetch_data_word(destoffset);
+ TRACE_AND_STEP();
+ destval = (*opcD1_word_operation[rh]) (destval, amt);
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 1:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+
+ DECODE_PRINTF("DWORD PTR ");
+ destoffset = decode_rm01_address(rl);
+ amt = fetch_byte_imm();
+ DECODE_PRINTF2(",%x\n", amt);
+ destval = fetch_data_long(destoffset);
+ TRACE_AND_STEP();
+ destval = (*opcD1_long_operation[rh]) (destval, amt);
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+
+ DECODE_PRINTF("WORD PTR ");
+ destoffset = decode_rm01_address(rl);
+ amt = fetch_byte_imm();
+ DECODE_PRINTF2(",%x\n", amt);
+ destval = fetch_data_word(destoffset);
+ TRACE_AND_STEP();
+ destval = (*opcD1_word_operation[rh]) (destval, amt);
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 2:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+
+ DECODE_PRINTF("DWORD PTR ");
+ destoffset = decode_rm10_address(rl);
+ amt = fetch_byte_imm();
+ DECODE_PRINTF2(",%x\n", amt);
+ destval = fetch_data_long(destoffset);
+ TRACE_AND_STEP();
+ destval = (*opcD1_long_operation[rh]) (destval, amt);
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+
+ DECODE_PRINTF("WORD PTR ");
+ destoffset = decode_rm10_address(rl);
+ amt = fetch_byte_imm();
+ DECODE_PRINTF2(",%x\n", amt);
+ destval = fetch_data_word(destoffset);
+ TRACE_AND_STEP();
+ destval = (*opcD1_word_operation[rh]) (destval, amt);
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 3: /* register to register */
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+
+ destreg = DECODE_RM_LONG_REGISTER(rl);
+ amt = fetch_byte_imm();
+ DECODE_PRINTF2(",%x\n", amt);
+ TRACE_AND_STEP();
+ *destreg = (*opcD1_long_operation[rh]) (*destreg, amt);
+ } else {
+ u16 *destreg;
+
+ destreg = DECODE_RM_WORD_REGISTER(rl);
+ amt = fetch_byte_imm();
+ DECODE_PRINTF2(",%x\n", amt);
+ TRACE_AND_STEP();
+ *destreg = (*opcD1_word_operation[rh]) (*destreg, amt);
+ }
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xc2
+****************************************************************************/
+static void x86emuOp_ret_near_IMM(u8 X86EMU_UNUSED(op1))
+{
+ u16 imm;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("RET\t");
+ imm = fetch_word_imm();
+ DECODE_PRINTF2("%x\n", imm);
+ RETURN_TRACE("RET",M.x86.saved_cs,M.x86.saved_ip);
+ TRACE_AND_STEP();
+ M.x86.R_IP = pop_word();
+ M.x86.R_SP += imm;
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xc3
+****************************************************************************/
+static void x86emuOp_ret_near(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ DECODE_PRINTF("RET\n");
+ RETURN_TRACE("RET",M.x86.saved_cs,M.x86.saved_ip);
+ TRACE_AND_STEP();
+ M.x86.R_IP = pop_word();
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xc4
+****************************************************************************/
+static void x86emuOp_les_R_IMM(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rh, rl;
+ u16 *dstreg;
+ uint srcoffset;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("LES\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ dstreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm00_address(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *dstreg = fetch_data_word(srcoffset);
+ M.x86.R_ES = fetch_data_word(srcoffset + 2);
+ break;
+ case 1:
+ dstreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm01_address(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *dstreg = fetch_data_word(srcoffset);
+ M.x86.R_ES = fetch_data_word(srcoffset + 2);
+ break;
+ case 2:
+ dstreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm10_address(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *dstreg = fetch_data_word(srcoffset);
+ M.x86.R_ES = fetch_data_word(srcoffset + 2);
+ break;
+ case 3: /* register to register */
+ /* UNDEFINED! */
+ TRACE_AND_STEP();
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xc5
+****************************************************************************/
+static void x86emuOp_lds_R_IMM(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rh, rl;
+ u16 *dstreg;
+ uint srcoffset;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("LDS\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ dstreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm00_address(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *dstreg = fetch_data_word(srcoffset);
+ M.x86.R_DS = fetch_data_word(srcoffset + 2);
+ break;
+ case 1:
+ dstreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm01_address(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *dstreg = fetch_data_word(srcoffset);
+ M.x86.R_DS = fetch_data_word(srcoffset + 2);
+ break;
+ case 2:
+ dstreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm10_address(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *dstreg = fetch_data_word(srcoffset);
+ M.x86.R_DS = fetch_data_word(srcoffset + 2);
+ break;
+ case 3: /* register to register */
+ /* UNDEFINED! */
+ TRACE_AND_STEP();
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xc6
+****************************************************************************/
+static void x86emuOp_mov_byte_RM_IMM(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ u8 *destreg;
+ uint destoffset;
+ u8 imm;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("MOV\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ if (rh != 0) {
+ DECODE_PRINTF("ILLEGAL DECODE OF OPCODE c6\n");
+ HALT_SYS();
+ }
+ switch (mod) {
+ case 0:
+ DECODE_PRINTF("BYTE PTR ");
+ destoffset = decode_rm00_address(rl);
+ imm = fetch_byte_imm();
+ DECODE_PRINTF2(",%2x\n", imm);
+ TRACE_AND_STEP();
+ store_data_byte(destoffset, imm);
+ break;
+ case 1:
+ DECODE_PRINTF("BYTE PTR ");
+ destoffset = decode_rm01_address(rl);
+ imm = fetch_byte_imm();
+ DECODE_PRINTF2(",%2x\n", imm);
+ TRACE_AND_STEP();
+ store_data_byte(destoffset, imm);
+ break;
+ case 2:
+ DECODE_PRINTF("BYTE PTR ");
+ destoffset = decode_rm10_address(rl);
+ imm = fetch_byte_imm();
+ DECODE_PRINTF2(",%2x\n", imm);
+ TRACE_AND_STEP();
+ store_data_byte(destoffset, imm);
+ break;
+ case 3: /* register to register */
+ destreg = DECODE_RM_BYTE_REGISTER(rl);
+ imm = fetch_byte_imm();
+ DECODE_PRINTF2(",%2x\n", imm);
+ TRACE_AND_STEP();
+ *destreg = imm;
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xc7
+****************************************************************************/
+static void x86emuOp_mov_word_RM_IMM(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ uint destoffset;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("MOV\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ if (rh != 0) {
+ DECODE_PRINTF("ILLEGAL DECODE OF OPCODE 8F\n");
+ HALT_SYS();
+ }
+ switch (mod) {
+ case 0:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 imm;
+
+ DECODE_PRINTF("DWORD PTR ");
+ destoffset = decode_rm00_address(rl);
+ imm = fetch_long_imm();
+ DECODE_PRINTF2(",%x\n", imm);
+ TRACE_AND_STEP();
+ store_data_long(destoffset, imm);
+ } else {
+ u16 imm;
+
+ DECODE_PRINTF("WORD PTR ");
+ destoffset = decode_rm00_address(rl);
+ imm = fetch_word_imm();
+ DECODE_PRINTF2(",%x\n", imm);
+ TRACE_AND_STEP();
+ store_data_word(destoffset, imm);
+ }
+ break;
+ case 1:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 imm;
+
+ DECODE_PRINTF("DWORD PTR ");
+ destoffset = decode_rm01_address(rl);
+ imm = fetch_long_imm();
+ DECODE_PRINTF2(",%x\n", imm);
+ TRACE_AND_STEP();
+ store_data_long(destoffset, imm);
+ } else {
+ u16 imm;
+
+ DECODE_PRINTF("WORD PTR ");
+ destoffset = decode_rm01_address(rl);
+ imm = fetch_word_imm();
+ DECODE_PRINTF2(",%x\n", imm);
+ TRACE_AND_STEP();
+ store_data_word(destoffset, imm);
+ }
+ break;
+ case 2:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 imm;
+
+ DECODE_PRINTF("DWORD PTR ");
+ destoffset = decode_rm10_address(rl);
+ imm = fetch_long_imm();
+ DECODE_PRINTF2(",%x\n", imm);
+ TRACE_AND_STEP();
+ store_data_long(destoffset, imm);
+ } else {
+ u16 imm;
+
+ DECODE_PRINTF("WORD PTR ");
+ destoffset = decode_rm10_address(rl);
+ imm = fetch_word_imm();
+ DECODE_PRINTF2(",%x\n", imm);
+ TRACE_AND_STEP();
+ store_data_word(destoffset, imm);
+ }
+ break;
+ case 3: /* register to register */
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+ u32 imm;
+
+ destreg = DECODE_RM_LONG_REGISTER(rl);
+ imm = fetch_long_imm();
+ DECODE_PRINTF2(",%x\n", imm);
+ TRACE_AND_STEP();
+ *destreg = imm;
+ } else {
+ u16 *destreg;
+ u16 imm;
+
+ destreg = DECODE_RM_WORD_REGISTER(rl);
+ imm = fetch_word_imm();
+ DECODE_PRINTF2(",%x\n", imm);
+ TRACE_AND_STEP();
+ *destreg = imm;
+ }
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xc8
+****************************************************************************/
+static void x86emuOp_enter(u8 X86EMU_UNUSED(op1))
+{
+ u16 local,frame_pointer;
+ u8 nesting;
+ int i;
+
+ START_OF_INSTR();
+ local = fetch_word_imm();
+ nesting = fetch_byte_imm();
+ DECODE_PRINTF2("ENTER %x\n", local);
+ DECODE_PRINTF2(",%x\n", nesting);
+ TRACE_AND_STEP();
+ push_word(M.x86.R_BP);
+ frame_pointer = M.x86.R_SP;
+ if (nesting > 0) {
+ for (i = 1; i < nesting; i++) {
+ M.x86.R_BP -= 2;
+ push_word(fetch_data_word_abs(M.x86.R_SS, M.x86.R_BP));
+ }
+ push_word(frame_pointer);
+ }
+ M.x86.R_BP = frame_pointer;
+ M.x86.R_SP = (u16)(M.x86.R_SP - local);
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xc9
+****************************************************************************/
+static void x86emuOp_leave(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ DECODE_PRINTF("LEAVE\n");
+ TRACE_AND_STEP();
+ M.x86.R_SP = M.x86.R_BP;
+ M.x86.R_BP = pop_word();
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xca
+****************************************************************************/
+static void x86emuOp_ret_far_IMM(u8 X86EMU_UNUSED(op1))
+{
+ u16 imm;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("RETF\t");
+ imm = fetch_word_imm();
+ DECODE_PRINTF2("%x\n", imm);
+ RETURN_TRACE("RETF",M.x86.saved_cs,M.x86.saved_ip);
+ TRACE_AND_STEP();
+ M.x86.R_IP = pop_word();
+ M.x86.R_CS = pop_word();
+ M.x86.R_SP += imm;
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xcb
+****************************************************************************/
+static void x86emuOp_ret_far(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ DECODE_PRINTF("RETF\n");
+ RETURN_TRACE("RETF",M.x86.saved_cs,M.x86.saved_ip);
+ TRACE_AND_STEP();
+ M.x86.R_IP = pop_word();
+ M.x86.R_CS = pop_word();
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xcc
+****************************************************************************/
+static void x86emuOp_int3(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ DECODE_PRINTF("INT 3\n");
+ TRACE_AND_STEP();
+ if (_X86EMU_intrTab[3]) {
+ (*_X86EMU_intrTab[3])(3);
+ } else {
+ push_word((u16)M.x86.R_FLG);
+ CLEAR_FLAG(F_IF);
+ CLEAR_FLAG(F_TF);
+ push_word(M.x86.R_CS);
+ M.x86.R_CS = mem_access_word(3 * 4 + 2);
+ push_word(M.x86.R_IP);
+ M.x86.R_IP = mem_access_word(3 * 4);
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xcd
+****************************************************************************/
+static void x86emuOp_int_IMM(u8 X86EMU_UNUSED(op1))
+{
+ u8 intnum;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("INT\t");
+ intnum = fetch_byte_imm();
+ DECODE_PRINTF2("%x\n", intnum);
+ TRACE_AND_STEP();
+ if (_X86EMU_intrTab[intnum]) {
+ (*_X86EMU_intrTab[intnum])(intnum);
+ } else {
+ push_word((u16)M.x86.R_FLG);
+ CLEAR_FLAG(F_IF);
+ CLEAR_FLAG(F_TF);
+ push_word(M.x86.R_CS);
+ M.x86.R_CS = mem_access_word(intnum * 4 + 2);
+ push_word(M.x86.R_IP);
+ M.x86.R_IP = mem_access_word(intnum * 4);
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xce
+****************************************************************************/
+static void x86emuOp_into(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ DECODE_PRINTF("INTO\n");
+ TRACE_AND_STEP();
+ if (ACCESS_FLAG(F_OF)) {
+ if (_X86EMU_intrTab[4]) {
+ (*_X86EMU_intrTab[4])(4);
+ } else {
+ push_word((u16)M.x86.R_FLG);
+ CLEAR_FLAG(F_IF);
+ CLEAR_FLAG(F_TF);
+ push_word(M.x86.R_CS);
+ M.x86.R_CS = mem_access_word(4 * 4 + 2);
+ push_word(M.x86.R_IP);
+ M.x86.R_IP = mem_access_word(4 * 4);
+ }
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xcf
+****************************************************************************/
+static void x86emuOp_iret(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ DECODE_PRINTF("IRET\n");
+
+ TRACE_AND_STEP();
+
+ M.x86.R_IP = pop_word();
+ M.x86.R_CS = pop_word();
+ M.x86.R_FLG = pop_word();
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xd0
+****************************************************************************/
+static void x86emuOp_opcD0_byte_RM_1(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ u8 *destreg;
+ uint destoffset;
+ u8 destval;
+
+ /*
+ * Yet another weirdo special case instruction format. Part of
+ * the opcode held below in "RH". Doubly nested case would
+ * result, except that the decoded instruction
+ */
+ START_OF_INSTR();
+ FETCH_DECODE_MODRM(mod, rh, rl);
+#ifdef X86EMU_DEBUG
+ if (DEBUG_DECODE()) {
+ /* XXX DECODE_PRINTF may be changed to something more
+ general, so that it is important to leave the strings
+ in the same format, even though the result is that the
+ above test is done twice. */
+ switch (rh) {
+ case 0:
+ DECODE_PRINTF("ROL\t");
+ break;
+ case 1:
+ DECODE_PRINTF("ROR\t");
+ break;
+ case 2:
+ DECODE_PRINTF("RCL\t");
+ break;
+ case 3:
+ DECODE_PRINTF("RCR\t");
+ break;
+ case 4:
+ DECODE_PRINTF("SHL\t");
+ break;
+ case 5:
+ DECODE_PRINTF("SHR\t");
+ break;
+ case 6:
+ DECODE_PRINTF("SAL\t");
+ break;
+ case 7:
+ DECODE_PRINTF("SAR\t");
+ break;
+ }
+ }
+#endif
+ /* know operation, decode the mod byte to find the addressing
+ mode. */
+ switch (mod) {
+ case 0:
+ DECODE_PRINTF("BYTE PTR ");
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",1\n");
+ destval = fetch_data_byte(destoffset);
+ TRACE_AND_STEP();
+ destval = (*opcD0_byte_operation[rh]) (destval, 1);
+ store_data_byte(destoffset, destval);
+ break;
+ case 1:
+ DECODE_PRINTF("BYTE PTR ");
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",1\n");
+ destval = fetch_data_byte(destoffset);
+ TRACE_AND_STEP();
+ destval = (*opcD0_byte_operation[rh]) (destval, 1);
+ store_data_byte(destoffset, destval);
+ break;
+ case 2:
+ DECODE_PRINTF("BYTE PTR ");
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",1\n");
+ destval = fetch_data_byte(destoffset);
+ TRACE_AND_STEP();
+ destval = (*opcD0_byte_operation[rh]) (destval, 1);
+ store_data_byte(destoffset, destval);
+ break;
+ case 3: /* register to register */
+ destreg = DECODE_RM_BYTE_REGISTER(rl);
+ DECODE_PRINTF(",1\n");
+ TRACE_AND_STEP();
+ destval = (*opcD0_byte_operation[rh]) (*destreg, 1);
+ *destreg = destval;
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xd1
+****************************************************************************/
+static void x86emuOp_opcD1_word_RM_1(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ uint destoffset;
+
+ /*
+ * Yet another weirdo special case instruction format. Part of
+ * the opcode held below in "RH". Doubly nested case would
+ * result, except that the decoded instruction
+ */
+ START_OF_INSTR();
+ FETCH_DECODE_MODRM(mod, rh, rl);
+#ifdef X86EMU_DEBUG
+ if (DEBUG_DECODE()) {
+ /* XXX DECODE_PRINTF may be changed to something more
+ general, so that it is important to leave the strings
+ in the same format, even though the result is that the
+ above test is done twice. */
+ switch (rh) {
+ case 0:
+ DECODE_PRINTF("ROL\t");
+ break;
+ case 1:
+ DECODE_PRINTF("ROR\t");
+ break;
+ case 2:
+ DECODE_PRINTF("RCL\t");
+ break;
+ case 3:
+ DECODE_PRINTF("RCR\t");
+ break;
+ case 4:
+ DECODE_PRINTF("SHL\t");
+ break;
+ case 5:
+ DECODE_PRINTF("SHR\t");
+ break;
+ case 6:
+ DECODE_PRINTF("SAL\t");
+ break;
+ case 7:
+ DECODE_PRINTF("SAR\t");
+ break;
+ }
+ }
+#endif
+ /* know operation, decode the mod byte to find the addressing
+ mode. */
+ switch (mod) {
+ case 0:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+
+ DECODE_PRINTF("DWORD PTR ");
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",1\n");
+ destval = fetch_data_long(destoffset);
+ TRACE_AND_STEP();
+ destval = (*opcD1_long_operation[rh]) (destval, 1);
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+
+ DECODE_PRINTF("WORD PTR ");
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",1\n");
+ destval = fetch_data_word(destoffset);
+ TRACE_AND_STEP();
+ destval = (*opcD1_word_operation[rh]) (destval, 1);
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 1:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+
+ DECODE_PRINTF("DWORD PTR ");
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",1\n");
+ destval = fetch_data_long(destoffset);
+ TRACE_AND_STEP();
+ destval = (*opcD1_long_operation[rh]) (destval, 1);
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+
+ DECODE_PRINTF("WORD PTR ");
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",1\n");
+ destval = fetch_data_word(destoffset);
+ TRACE_AND_STEP();
+ destval = (*opcD1_word_operation[rh]) (destval, 1);
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 2:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+
+ DECODE_PRINTF("DWORD PTR ");
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",1\n");
+ destval = fetch_data_long(destoffset);
+ TRACE_AND_STEP();
+ destval = (*opcD1_long_operation[rh]) (destval, 1);
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+
+ DECODE_PRINTF("BYTE PTR ");
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",1\n");
+ destval = fetch_data_word(destoffset);
+ TRACE_AND_STEP();
+ destval = (*opcD1_word_operation[rh]) (destval, 1);
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 3: /* register to register */
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+ u32 *destreg;
+
+ destreg = DECODE_RM_LONG_REGISTER(rl);
+ DECODE_PRINTF(",1\n");
+ TRACE_AND_STEP();
+ destval = (*opcD1_long_operation[rh]) (*destreg, 1);
+ *destreg = destval;
+ } else {
+ u16 destval;
+ u16 *destreg;
+
+ destreg = DECODE_RM_WORD_REGISTER(rl);
+ DECODE_PRINTF(",1\n");
+ TRACE_AND_STEP();
+ destval = (*opcD1_word_operation[rh]) (*destreg, 1);
+ *destreg = destval;
+ }
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xd2
+****************************************************************************/
+static void x86emuOp_opcD2_byte_RM_CL(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ u8 *destreg;
+ uint destoffset;
+ u8 destval;
+ u8 amt;
+
+ /*
+ * Yet another weirdo special case instruction format. Part of
+ * the opcode held below in "RH". Doubly nested case would
+ * result, except that the decoded instruction
+ */
+ START_OF_INSTR();
+ FETCH_DECODE_MODRM(mod, rh, rl);
+#ifdef X86EMU_DEBUG
+ if (DEBUG_DECODE()) {
+ /* XXX DECODE_PRINTF may be changed to something more
+ general, so that it is important to leave the strings
+ in the same format, even though the result is that the
+ above test is done twice. */
+ switch (rh) {
+ case 0:
+ DECODE_PRINTF("ROL\t");
+ break;
+ case 1:
+ DECODE_PRINTF("ROR\t");
+ break;
+ case 2:
+ DECODE_PRINTF("RCL\t");
+ break;
+ case 3:
+ DECODE_PRINTF("RCR\t");
+ break;
+ case 4:
+ DECODE_PRINTF("SHL\t");
+ break;
+ case 5:
+ DECODE_PRINTF("SHR\t");
+ break;
+ case 6:
+ DECODE_PRINTF("SAL\t");
+ break;
+ case 7:
+ DECODE_PRINTF("SAR\t");
+ break;
+ }
+ }
+#endif
+ /* know operation, decode the mod byte to find the addressing
+ mode. */
+ amt = M.x86.R_CL;
+ switch (mod) {
+ case 0:
+ DECODE_PRINTF("BYTE PTR ");
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",CL\n");
+ destval = fetch_data_byte(destoffset);
+ TRACE_AND_STEP();
+ destval = (*opcD0_byte_operation[rh]) (destval, amt);
+ store_data_byte(destoffset, destval);
+ break;
+ case 1:
+ DECODE_PRINTF("BYTE PTR ");
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",CL\n");
+ destval = fetch_data_byte(destoffset);
+ TRACE_AND_STEP();
+ destval = (*opcD0_byte_operation[rh]) (destval, amt);
+ store_data_byte(destoffset, destval);
+ break;
+ case 2:
+ DECODE_PRINTF("BYTE PTR ");
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",CL\n");
+ destval = fetch_data_byte(destoffset);
+ TRACE_AND_STEP();
+ destval = (*opcD0_byte_operation[rh]) (destval, amt);
+ store_data_byte(destoffset, destval);
+ break;
+ case 3: /* register to register */
+ destreg = DECODE_RM_BYTE_REGISTER(rl);
+ DECODE_PRINTF(",CL\n");
+ TRACE_AND_STEP();
+ destval = (*opcD0_byte_operation[rh]) (*destreg, amt);
+ *destreg = destval;
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xd3
+****************************************************************************/
+static void x86emuOp_opcD3_word_RM_CL(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ uint destoffset;
+ u8 amt;
+
+ /*
+ * Yet another weirdo special case instruction format. Part of
+ * the opcode held below in "RH". Doubly nested case would
+ * result, except that the decoded instruction
+ */
+ START_OF_INSTR();
+ FETCH_DECODE_MODRM(mod, rh, rl);
+#ifdef X86EMU_DEBUG
+ if (DEBUG_DECODE()) {
+ /* XXX DECODE_PRINTF may be changed to something more
+ general, so that it is important to leave the strings
+ in the same format, even though the result is that the
+ above test is done twice. */
+ switch (rh) {
+ case 0:
+ DECODE_PRINTF("ROL\t");
+ break;
+ case 1:
+ DECODE_PRINTF("ROR\t");
+ break;
+ case 2:
+ DECODE_PRINTF("RCL\t");
+ break;
+ case 3:
+ DECODE_PRINTF("RCR\t");
+ break;
+ case 4:
+ DECODE_PRINTF("SHL\t");
+ break;
+ case 5:
+ DECODE_PRINTF("SHR\t");
+ break;
+ case 6:
+ DECODE_PRINTF("SAL\t");
+ break;
+ case 7:
+ DECODE_PRINTF("SAR\t");
+ break;
+ }
+ }
+#endif
+ /* know operation, decode the mod byte to find the addressing
+ mode. */
+ amt = M.x86.R_CL;
+ switch (mod) {
+ case 0:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+
+ DECODE_PRINTF("DWORD PTR ");
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",CL\n");
+ destval = fetch_data_long(destoffset);
+ TRACE_AND_STEP();
+ destval = (*opcD1_long_operation[rh]) (destval, amt);
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+
+ DECODE_PRINTF("WORD PTR ");
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",CL\n");
+ destval = fetch_data_word(destoffset);
+ TRACE_AND_STEP();
+ destval = (*opcD1_word_operation[rh]) (destval, amt);
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 1:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+
+ DECODE_PRINTF("DWORD PTR ");
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",CL\n");
+ destval = fetch_data_long(destoffset);
+ TRACE_AND_STEP();
+ destval = (*opcD1_long_operation[rh]) (destval, amt);
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+
+ DECODE_PRINTF("WORD PTR ");
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",CL\n");
+ destval = fetch_data_word(destoffset);
+ TRACE_AND_STEP();
+ destval = (*opcD1_word_operation[rh]) (destval, amt);
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 2:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+
+ DECODE_PRINTF("DWORD PTR ");
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",CL\n");
+ destval = fetch_data_long(destoffset);
+ TRACE_AND_STEP();
+ destval = (*opcD1_long_operation[rh]) (destval, amt);
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+
+ DECODE_PRINTF("WORD PTR ");
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",CL\n");
+ destval = fetch_data_word(destoffset);
+ TRACE_AND_STEP();
+ destval = (*opcD1_word_operation[rh]) (destval, amt);
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 3: /* register to register */
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+
+ destreg = DECODE_RM_LONG_REGISTER(rl);
+ DECODE_PRINTF(",CL\n");
+ TRACE_AND_STEP();
+ *destreg = (*opcD1_long_operation[rh]) (*destreg, amt);
+ } else {
+ u16 *destreg;
+
+ destreg = DECODE_RM_WORD_REGISTER(rl);
+ DECODE_PRINTF(",CL\n");
+ TRACE_AND_STEP();
+ *destreg = (*opcD1_word_operation[rh]) (*destreg, amt);
+ }
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xd4
+****************************************************************************/
+static void x86emuOp_aam(u8 X86EMU_UNUSED(op1))
+{
+ u8 a;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("AAM\n");
+ a = fetch_byte_imm(); /* this is a stupid encoding. */
+ if (a != 10) {
+ /* fix: add base decoding
+ aam_word(u8 val, int base a) */
+ DECODE_PRINTF("ERROR DECODING AAM\n");
+ TRACE_REGS();
+ HALT_SYS();
+ }
+ TRACE_AND_STEP();
+ /* note the type change here --- returning AL and AH in AX. */
+ M.x86.R_AX = aam_word(M.x86.R_AL);
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xd5
+****************************************************************************/
+static void x86emuOp_aad(u8 X86EMU_UNUSED(op1))
+{
+ u8 a;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("AAD\n");
+ a = fetch_byte_imm();
+ if (a != 10) {
+ /* fix: add base decoding
+ aad_word(u16 val, int base a) */
+ DECODE_PRINTF("ERROR DECODING AAM\n");
+ TRACE_REGS();
+ HALT_SYS();
+ }
+ TRACE_AND_STEP();
+ M.x86.R_AX = aad_word(M.x86.R_AX);
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/* opcode 0xd6 ILLEGAL OPCODE */
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xd7
+****************************************************************************/
+static void x86emuOp_xlat(u8 X86EMU_UNUSED(op1))
+{
+ u16 addr;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("XLAT\n");
+ TRACE_AND_STEP();
+ addr = (u16)(M.x86.R_BX + (u8)M.x86.R_AL);
+ M.x86.R_AL = fetch_data_byte(addr);
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/* instuctions D8 .. DF are in i87_ops.c */
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xe0
+****************************************************************************/
+static void x86emuOp_loopne(u8 X86EMU_UNUSED(op1))
+{
+ s16 ip;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("LOOPNE\t");
+ ip = (s8) fetch_byte_imm();
+ ip += (s16) M.x86.R_IP;
+ DECODE_PRINTF2("%04x\n", ip);
+ TRACE_AND_STEP();
+ M.x86.R_CX -= 1;
+ if (M.x86.R_CX != 0 && !ACCESS_FLAG(F_ZF)) /* CX != 0 and !ZF */
+ M.x86.R_IP = ip;
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xe1
+****************************************************************************/
+static void x86emuOp_loope(u8 X86EMU_UNUSED(op1))
+{
+ s16 ip;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("LOOPE\t");
+ ip = (s8) fetch_byte_imm();
+ ip += (s16) M.x86.R_IP;
+ DECODE_PRINTF2("%04x\n", ip);
+ TRACE_AND_STEP();
+ M.x86.R_CX -= 1;
+ if (M.x86.R_CX != 0 && ACCESS_FLAG(F_ZF)) /* CX != 0 and ZF */
+ M.x86.R_IP = ip;
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xe2
+****************************************************************************/
+static void x86emuOp_loop(u8 X86EMU_UNUSED(op1))
+{
+ s16 ip;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("LOOP\t");
+ ip = (s8) fetch_byte_imm();
+ ip += (s16) M.x86.R_IP;
+ DECODE_PRINTF2("%04x\n", ip);
+ TRACE_AND_STEP();
+ M.x86.R_CX -= 1;
+ if (M.x86.R_CX != 0)
+ M.x86.R_IP = ip;
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xe3
+****************************************************************************/
+static void x86emuOp_jcxz(u8 X86EMU_UNUSED(op1))
+{
+ u16 target;
+ s8 offset;
+
+ /* jump to byte offset if overflow flag is set */
+ START_OF_INSTR();
+ DECODE_PRINTF("JCXZ\t");
+ offset = (s8)fetch_byte_imm();
+ target = (u16)(M.x86.R_IP + offset);
+ DECODE_PRINTF2("%x\n", target);
+ TRACE_AND_STEP();
+ if (M.x86.R_CX == 0)
+ M.x86.R_IP = target;
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xe4
+****************************************************************************/
+static void x86emuOp_in_byte_AL_IMM(u8 X86EMU_UNUSED(op1))
+{
+ u8 port;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("IN\t");
+ port = (u8) fetch_byte_imm();
+ DECODE_PRINTF2("%x,AL\n", port);
+ TRACE_AND_STEP();
+ M.x86.R_AL = (*sys_inb)(port);
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xe5
+****************************************************************************/
+static void x86emuOp_in_word_AX_IMM(u8 X86EMU_UNUSED(op1))
+{
+ u8 port;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("IN\t");
+ port = (u8) fetch_byte_imm();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF2("EAX,%x\n", port);
+ } else {
+ DECODE_PRINTF2("AX,%x\n", port);
+ }
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ M.x86.R_EAX = (*sys_inl)(port);
+ } else {
+ M.x86.R_AX = (*sys_inw)(port);
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xe6
+****************************************************************************/
+static void x86emuOp_out_byte_IMM_AL(u8 X86EMU_UNUSED(op1))
+{
+ u8 port;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("OUT\t");
+ port = (u8) fetch_byte_imm();
+ DECODE_PRINTF2("%x,AL\n", port);
+ TRACE_AND_STEP();
+ (*sys_outb)(port, M.x86.R_AL);
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xe7
+****************************************************************************/
+static void x86emuOp_out_word_IMM_AX(u8 X86EMU_UNUSED(op1))
+{
+ u8 port;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("OUT\t");
+ port = (u8) fetch_byte_imm();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF2("%x,EAX\n", port);
+ } else {
+ DECODE_PRINTF2("%x,AX\n", port);
+ }
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ (*sys_outl)(port, M.x86.R_EAX);
+ } else {
+ (*sys_outw)(port, M.x86.R_AX);
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xe8
+****************************************************************************/
+static void x86emuOp_call_near_IMM(u8 X86EMU_UNUSED(op1))
+{
+ s16 ip16 = 0;
+ s32 ip32 = 0;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("CALL\t");
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ ip32 = (s32) fetch_long_imm();
+ ip32 += (s16) M.x86.R_IP; /* CHECK SIGN */
+ DECODE_PRINTF2("%04x\n", (u16)ip32);
+ CALL_TRACE(M.x86.saved_cs, M.x86.saved_ip, M.x86.R_CS, ip32, "");
+ } else {
+ ip16 = (s16) fetch_word_imm();
+ ip16 += (s16) M.x86.R_IP; /* CHECK SIGN */
+ DECODE_PRINTF2("%04x\n", (u16)ip16);
+ CALL_TRACE(M.x86.saved_cs, M.x86.saved_ip, M.x86.R_CS, ip16, "");
+ }
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ push_long(M.x86.R_EIP);
+ M.x86.R_EIP = ip32 & 0xffff;
+ } else {
+ push_word(M.x86.R_IP);
+ M.x86.R_EIP = ip16;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xe9
+****************************************************************************/
+static void x86emuOp_jump_near_IMM(u8 X86EMU_UNUSED(op1))
+{
+ s32 ip;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("JMP\t");
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ ip = (s32)fetch_long_imm();
+ ip += (s32)M.x86.R_EIP;
+ DECODE_PRINTF2("%08x\n", (u32)ip);
+ TRACE_AND_STEP();
+ M.x86.R_EIP = (u32)ip;
+ } else {
+ ip = (s16)fetch_word_imm();
+ ip += (s16)M.x86.R_IP;
+ DECODE_PRINTF2("%04x\n", (u16)ip);
+ TRACE_AND_STEP();
+ M.x86.R_IP = (u16)ip;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xea
+****************************************************************************/
+static void x86emuOp_jump_far_IMM(u8 X86EMU_UNUSED(op1))
+{
+ u16 cs;
+ u32 ip;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("JMP\tFAR ");
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ ip = fetch_long_imm();
+ } else {
+ ip = fetch_word_imm();
+ }
+ cs = fetch_word_imm();
+ DECODE_PRINTF2("%04x:", cs);
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF2("%08x\n", ip);
+ } else {
+ DECODE_PRINTF2("%04x\n", (u16)ip);
+ }
+ TRACE_AND_STEP();
+ M.x86.R_EIP = ip & 0xffff;
+ M.x86.R_CS = cs;
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xeb
+****************************************************************************/
+static void x86emuOp_jump_byte_IMM(u8 X86EMU_UNUSED(op1))
+{
+ u16 target;
+ s8 offset;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("JMP\t");
+ offset = (s8)fetch_byte_imm();
+ target = (u16)(M.x86.R_IP + offset);
+ DECODE_PRINTF2("%x\n", target);
+ TRACE_AND_STEP();
+ M.x86.R_IP = target;
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xec
+****************************************************************************/
+static void x86emuOp_in_byte_AL_DX(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ DECODE_PRINTF("IN\tAL,DX\n");
+ TRACE_AND_STEP();
+ M.x86.R_AL = (*sys_inb)(M.x86.R_DX);
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xed
+****************************************************************************/
+static void x86emuOp_in_word_AX_DX(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("IN\tEAX,DX\n");
+ } else {
+ DECODE_PRINTF("IN\tAX,DX\n");
+ }
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ M.x86.R_EAX = (*sys_inl)(M.x86.R_DX);
+ } else {
+ M.x86.R_AX = (*sys_inw)(M.x86.R_DX);
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xee
+****************************************************************************/
+static void x86emuOp_out_byte_DX_AL(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ DECODE_PRINTF("OUT\tDX,AL\n");
+ TRACE_AND_STEP();
+ (*sys_outb)(M.x86.R_DX, M.x86.R_AL);
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xef
+****************************************************************************/
+static void x86emuOp_out_word_DX_AX(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("OUT\tDX,EAX\n");
+ } else {
+ DECODE_PRINTF("OUT\tDX,AX\n");
+ }
+ TRACE_AND_STEP();
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ (*sys_outl)(M.x86.R_DX, M.x86.R_EAX);
+ } else {
+ (*sys_outw)(M.x86.R_DX, M.x86.R_AX);
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xf0
+****************************************************************************/
+static void x86emuOp_lock(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ DECODE_PRINTF("LOCK:\n");
+ TRACE_AND_STEP();
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/*opcode 0xf1 ILLEGAL OPERATION */
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xf2
+****************************************************************************/
+static void x86emuOp_repne(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ DECODE_PRINTF("REPNE\n");
+ TRACE_AND_STEP();
+ M.x86.mode |= SYSMODE_PREFIX_REPNE;
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xf3
+****************************************************************************/
+static void x86emuOp_repe(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ DECODE_PRINTF("REPE\n");
+ TRACE_AND_STEP();
+ M.x86.mode |= SYSMODE_PREFIX_REPE;
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xf4
+****************************************************************************/
+static void x86emuOp_halt(u8 X86EMU_UNUSED(op1))
+{
+ START_OF_INSTR();
+ DECODE_PRINTF("HALT\n");
+ TRACE_AND_STEP();
+ HALT_SYS();
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xf5
+****************************************************************************/
+static void x86emuOp_cmc(u8 X86EMU_UNUSED(op1))
+{
+ /* complement the carry flag. */
+ START_OF_INSTR();
+ DECODE_PRINTF("CMC\n");
+ TRACE_AND_STEP();
+ TOGGLE_FLAG(F_CF);
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xf6
+****************************************************************************/
+static void x86emuOp_opcF6_byte_RM(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ u8 *destreg;
+ uint destoffset;
+ u8 destval, srcval;
+
+ /* long, drawn out code follows. Double switch for a total
+ of 32 cases. */
+ START_OF_INSTR();
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0: /* mod=00 */
+ switch (rh) {
+ case 0: /* test byte imm */
+ DECODE_PRINTF("TEST\tBYTE PTR ");
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ srcval = fetch_byte_imm();
+ DECODE_PRINTF2("%02x\n", srcval);
+ destval = fetch_data_byte(destoffset);
+ TRACE_AND_STEP();
+ test_byte(destval, srcval);
+ break;
+ case 1:
+ DECODE_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F6\n");
+ HALT_SYS();
+ break;
+ case 2:
+ DECODE_PRINTF("NOT\tBYTE PTR ");
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF("\n");
+ destval = fetch_data_byte(destoffset);
+ TRACE_AND_STEP();
+ destval = not_byte(destval);
+ store_data_byte(destoffset, destval);
+ break;
+ case 3:
+ DECODE_PRINTF("NEG\tBYTE PTR ");
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF("\n");
+ destval = fetch_data_byte(destoffset);
+ TRACE_AND_STEP();
+ destval = neg_byte(destval);
+ store_data_byte(destoffset, destval);
+ break;
+ case 4:
+ DECODE_PRINTF("MUL\tBYTE PTR ");
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF("\n");
+ destval = fetch_data_byte(destoffset);
+ TRACE_AND_STEP();
+ mul_byte(destval);
+ break;
+ case 5:
+ DECODE_PRINTF("IMUL\tBYTE PTR ");
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF("\n");
+ destval = fetch_data_byte(destoffset);
+ TRACE_AND_STEP();
+ imul_byte(destval);
+ break;
+ case 6:
+ DECODE_PRINTF("DIV\tBYTE PTR ");
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF("\n");
+ destval = fetch_data_byte(destoffset);
+ TRACE_AND_STEP();
+ div_byte(destval);
+ break;
+ case 7:
+ DECODE_PRINTF("IDIV\tBYTE PTR ");
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF("\n");
+ destval = fetch_data_byte(destoffset);
+ TRACE_AND_STEP();
+ idiv_byte(destval);
+ break;
+ }
+ break; /* end mod==00 */
+ case 1: /* mod=01 */
+ switch (rh) {
+ case 0: /* test byte imm */
+ DECODE_PRINTF("TEST\tBYTE PTR ");
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ srcval = fetch_byte_imm();
+ DECODE_PRINTF2("%02x\n", srcval);
+ destval = fetch_data_byte(destoffset);
+ TRACE_AND_STEP();
+ test_byte(destval, srcval);
+ break;
+ case 1:
+ DECODE_PRINTF("ILLEGAL OP MOD=01 RH=01 OP=F6\n");
+ HALT_SYS();
+ break;
+ case 2:
+ DECODE_PRINTF("NOT\tBYTE PTR ");
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF("\n");
+ destval = fetch_data_byte(destoffset);
+ TRACE_AND_STEP();
+ destval = not_byte(destval);
+ store_data_byte(destoffset, destval);
+ break;
+ case 3:
+ DECODE_PRINTF("NEG\tBYTE PTR ");
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF("\n");
+ destval = fetch_data_byte(destoffset);
+ TRACE_AND_STEP();
+ destval = neg_byte(destval);
+ store_data_byte(destoffset, destval);
+ break;
+ case 4:
+ DECODE_PRINTF("MUL\tBYTE PTR ");
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF("\n");
+ destval = fetch_data_byte(destoffset);
+ TRACE_AND_STEP();
+ mul_byte(destval);
+ break;
+ case 5:
+ DECODE_PRINTF("IMUL\tBYTE PTR ");
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF("\n");
+ destval = fetch_data_byte(destoffset);
+ TRACE_AND_STEP();
+ imul_byte(destval);
+ break;
+ case 6:
+ DECODE_PRINTF("DIV\tBYTE PTR ");
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF("\n");
+ destval = fetch_data_byte(destoffset);
+ TRACE_AND_STEP();
+ div_byte(destval);
+ break;
+ case 7:
+ DECODE_PRINTF("IDIV\tBYTE PTR ");
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF("\n");
+ destval = fetch_data_byte(destoffset);
+ TRACE_AND_STEP();
+ idiv_byte(destval);
+ break;
+ }
+ break; /* end mod==01 */
+ case 2: /* mod=10 */
+ switch (rh) {
+ case 0: /* test byte imm */
+ DECODE_PRINTF("TEST\tBYTE PTR ");
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ srcval = fetch_byte_imm();
+ DECODE_PRINTF2("%02x\n", srcval);
+ destval = fetch_data_byte(destoffset);
+ TRACE_AND_STEP();
+ test_byte(destval, srcval);
+ break;
+ case 1:
+ DECODE_PRINTF("ILLEGAL OP MOD=10 RH=01 OP=F6\n");
+ HALT_SYS();
+ break;
+ case 2:
+ DECODE_PRINTF("NOT\tBYTE PTR ");
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF("\n");
+ destval = fetch_data_byte(destoffset);
+ TRACE_AND_STEP();
+ destval = not_byte(destval);
+ store_data_byte(destoffset, destval);
+ break;
+ case 3:
+ DECODE_PRINTF("NEG\tBYTE PTR ");
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF("\n");
+ destval = fetch_data_byte(destoffset);
+ TRACE_AND_STEP();
+ destval = neg_byte(destval);
+ store_data_byte(destoffset, destval);
+ break;
+ case 4:
+ DECODE_PRINTF("MUL\tBYTE PTR ");
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF("\n");
+ destval = fetch_data_byte(destoffset);
+ TRACE_AND_STEP();
+ mul_byte(destval);
+ break;
+ case 5:
+ DECODE_PRINTF("IMUL\tBYTE PTR ");
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF("\n");
+ destval = fetch_data_byte(destoffset);
+ TRACE_AND_STEP();
+ imul_byte(destval);
+ break;
+ case 6:
+ DECODE_PRINTF("DIV\tBYTE PTR ");
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF("\n");
+ destval = fetch_data_byte(destoffset);
+ TRACE_AND_STEP();
+ div_byte(destval);
+ break;
+ case 7:
+ DECODE_PRINTF("IDIV\tBYTE PTR ");
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF("\n");
+ destval = fetch_data_byte(destoffset);
+ TRACE_AND_STEP();
+ idiv_byte(destval);
+ break;
+ }
+ break; /* end mod==10 */
+ case 3: /* mod=11 */
+ switch (rh) {
+ case 0: /* test byte imm */
+ DECODE_PRINTF("TEST\t");
+ destreg = DECODE_RM_BYTE_REGISTER(rl);
+ DECODE_PRINTF(",");
+ srcval = fetch_byte_imm();
+ DECODE_PRINTF2("%02x\n", srcval);
+ TRACE_AND_STEP();
+ test_byte(*destreg, srcval);
+ break;
+ case 1:
+ DECODE_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F6\n");
+ HALT_SYS();
+ break;
+ case 2:
+ DECODE_PRINTF("NOT\t");
+ destreg = DECODE_RM_BYTE_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = not_byte(*destreg);
+ break;
+ case 3:
+ DECODE_PRINTF("NEG\t");
+ destreg = DECODE_RM_BYTE_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = neg_byte(*destreg);
+ break;
+ case 4:
+ DECODE_PRINTF("MUL\t");
+ destreg = DECODE_RM_BYTE_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ mul_byte(*destreg); /*!!! */
+ break;
+ case 5:
+ DECODE_PRINTF("IMUL\t");
+ destreg = DECODE_RM_BYTE_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ imul_byte(*destreg);
+ break;
+ case 6:
+ DECODE_PRINTF("DIV\t");
+ destreg = DECODE_RM_BYTE_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ div_byte(*destreg);
+ break;
+ case 7:
+ DECODE_PRINTF("IDIV\t");
+ destreg = DECODE_RM_BYTE_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ idiv_byte(*destreg);
+ break;
+ }
+ break; /* end mod==11 */
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xf7
+****************************************************************************/
+static void x86emuOp_opcF7_word_RM(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rl, rh;
+ uint destoffset;
+
+ /* long, drawn out code follows. Double switch for a total
+ of 32 cases. */
+ START_OF_INSTR();
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0: /* mod=00 */
+ switch (rh) {
+ case 0: /* test word imm */
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval,srcval;
+
+ DECODE_PRINTF("TEST\tDWORD PTR ");
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ srcval = fetch_long_imm();
+ DECODE_PRINTF2("%x\n", srcval);
+ destval = fetch_data_long(destoffset);
+ TRACE_AND_STEP();
+ test_long(destval, srcval);
+ } else {
+ u16 destval,srcval;
+
+ DECODE_PRINTF("TEST\tWORD PTR ");
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ srcval = fetch_word_imm();
+ DECODE_PRINTF2("%x\n", srcval);
+ destval = fetch_data_word(destoffset);
+ TRACE_AND_STEP();
+ test_word(destval, srcval);
+ }
+ break;
+ case 1:
+ DECODE_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F7\n");
+ HALT_SYS();
+ break;
+ case 2:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+
+ DECODE_PRINTF("NOT\tDWORD PTR ");
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF("\n");
+ destval = fetch_data_long(destoffset);
+ TRACE_AND_STEP();
+ destval = not_long(destval);
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+
+ DECODE_PRINTF("NOT\tWORD PTR ");
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF("\n");
+ destval = fetch_data_word(destoffset);
+ TRACE_AND_STEP();
+ destval = not_word(destval);
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 3:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+
+ DECODE_PRINTF("NEG\tDWORD PTR ");
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF("\n");
+ destval = fetch_data_long(destoffset);
+ TRACE_AND_STEP();
+ destval = neg_long(destval);
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+
+ DECODE_PRINTF("NEG\tWORD PTR ");
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF("\n");
+ destval = fetch_data_word(destoffset);
+ TRACE_AND_STEP();
+ destval = neg_word(destval);
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 4:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+
+ DECODE_PRINTF("MUL\tDWORD PTR ");
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF("\n");
+ destval = fetch_data_long(destoffset);
+ TRACE_AND_STEP();
+ mul_long(destval);
+ } else {
+ u16 destval;
+
+ DECODE_PRINTF("MUL\tWORD PTR ");
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF("\n");
+ destval = fetch_data_word(destoffset);
+ TRACE_AND_STEP();
+ mul_word(destval);
+ }
+ break;
+ case 5:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+
+ DECODE_PRINTF("IMUL\tDWORD PTR ");
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF("\n");
+ destval = fetch_data_long(destoffset);
+ TRACE_AND_STEP();
+ imul_long(destval);
+ } else {
+ u16 destval;
+
+ DECODE_PRINTF("IMUL\tWORD PTR ");
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF("\n");
+ destval = fetch_data_word(destoffset);
+ TRACE_AND_STEP();
+ imul_word(destval);
+ }
+ break;
+ case 6:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+
+ DECODE_PRINTF("DIV\tDWORD PTR ");
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF("\n");
+ destval = fetch_data_long(destoffset);
+ TRACE_AND_STEP();
+ div_long(destval);
+ } else {
+ u16 destval;
+
+ DECODE_PRINTF("DIV\tWORD PTR ");
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF("\n");
+ destval = fetch_data_word(destoffset);
+ TRACE_AND_STEP();
+ div_word(destval);
+ }
+ break;
+ case 7:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+
+ DECODE_PRINTF("IDIV\tDWORD PTR ");
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF("\n");
+ destval = fetch_data_long(destoffset);
+ TRACE_AND_STEP();
+ idiv_long(destval);
+ } else {
+ u16 destval;
+
+ DECODE_PRINTF("IDIV\tWORD PTR ");
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF("\n");
+ destval = fetch_data_word(destoffset);
+ TRACE_AND_STEP();
+ idiv_word(destval);
+ }
+ break;
+ }
+ break; /* end mod==00 */
+ case 1: /* mod=01 */
+ switch (rh) {
+ case 0: /* test word imm */
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval,srcval;
+
+ DECODE_PRINTF("TEST\tDWORD PTR ");
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ srcval = fetch_long_imm();
+ DECODE_PRINTF2("%x\n", srcval);
+ destval = fetch_data_long(destoffset);
+ TRACE_AND_STEP();
+ test_long(destval, srcval);
+ } else {
+ u16 destval,srcval;
+
+ DECODE_PRINTF("TEST\tWORD PTR ");
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ srcval = fetch_word_imm();
+ DECODE_PRINTF2("%x\n", srcval);
+ destval = fetch_data_word(destoffset);
+ TRACE_AND_STEP();
+ test_word(destval, srcval);
+ }
+ break;
+ case 1:
+ DECODE_PRINTF("ILLEGAL OP MOD=01 RH=01 OP=F6\n");
+ HALT_SYS();
+ break;
+ case 2:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+
+ DECODE_PRINTF("NOT\tDWORD PTR ");
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF("\n");
+ destval = fetch_data_long(destoffset);
+ TRACE_AND_STEP();
+ destval = not_long(destval);
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+
+ DECODE_PRINTF("NOT\tWORD PTR ");
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF("\n");
+ destval = fetch_data_word(destoffset);
+ TRACE_AND_STEP();
+ destval = not_word(destval);
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 3:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+
+ DECODE_PRINTF("NEG\tDWORD PTR ");
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF("\n");
+ destval = fetch_data_long(destoffset);
+ TRACE_AND_STEP();
+ destval = neg_long(destval);
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+
+ DECODE_PRINTF("NEG\tWORD PTR ");
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF("\n");
+ destval = fetch_data_word(destoffset);
+ TRACE_AND_STEP();
+ destval = neg_word(destval);
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 4:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+
+ DECODE_PRINTF("MUL\tDWORD PTR ");
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF("\n");
+ destval = fetch_data_long(destoffset);
+ TRACE_AND_STEP();
+ mul_long(destval);
+ } else {
+ u16 destval;
+
+ DECODE_PRINTF("MUL\tWORD PTR ");
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF("\n");
+ destval = fetch_data_word(destoffset);
+ TRACE_AND_STEP();
+ mul_word(destval);
+ }
+ break;
+ case 5:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+
+ DECODE_PRINTF("IMUL\tDWORD PTR ");
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF("\n");
+ destval = fetch_data_long(destoffset);
+ TRACE_AND_STEP();
+ imul_long(destval);
+ } else {
+ u16 destval;
+
+ DECODE_PRINTF("IMUL\tWORD PTR ");
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF("\n");
+ destval = fetch_data_word(destoffset);
+ TRACE_AND_STEP();
+ imul_word(destval);
+ }
+ break;
+ case 6:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+
+ DECODE_PRINTF("DIV\tDWORD PTR ");
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF("\n");
+ destval = fetch_data_long(destoffset);
+ TRACE_AND_STEP();
+ div_long(destval);
+ } else {
+ u16 destval;
+
+ DECODE_PRINTF("DIV\tWORD PTR ");
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF("\n");
+ destval = fetch_data_word(destoffset);
+ TRACE_AND_STEP();
+ div_word(destval);
+ }
+ break;
+ case 7:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+
+ DECODE_PRINTF("IDIV\tDWORD PTR ");
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF("\n");
+ destval = fetch_data_long(destoffset);
+ TRACE_AND_STEP();
+ idiv_long(destval);
+ } else {
+ u16 destval;
+
+ DECODE_PRINTF("IDIV\tWORD PTR ");
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF("\n");
+ destval = fetch_data_word(destoffset);
+ TRACE_AND_STEP();
+ idiv_word(destval);
+ }
+ break;
+ }
+ break; /* end mod==01 */
+ case 2: /* mod=10 */
+ switch (rh) {
+ case 0: /* test word imm */
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval,srcval;
+
+ DECODE_PRINTF("TEST\tDWORD PTR ");
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ srcval = fetch_long_imm();
+ DECODE_PRINTF2("%x\n", srcval);
+ destval = fetch_data_long(destoffset);
+ TRACE_AND_STEP();
+ test_long(destval, srcval);
+ } else {
+ u16 destval,srcval;
+
+ DECODE_PRINTF("TEST\tWORD PTR ");
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ srcval = fetch_word_imm();
+ DECODE_PRINTF2("%x\n", srcval);
+ destval = fetch_data_word(destoffset);
+ TRACE_AND_STEP();
+ test_word(destval, srcval);
+ }
+ break;
+ case 1:
+ DECODE_PRINTF("ILLEGAL OP MOD=10 RH=01 OP=F6\n");
+ HALT_SYS();
+ break;
+ case 2:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+
+ DECODE_PRINTF("NOT\tDWORD PTR ");
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF("\n");
+ destval = fetch_data_long(destoffset);
+ TRACE_AND_STEP();
+ destval = not_long(destval);
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+
+ DECODE_PRINTF("NOT\tWORD PTR ");
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF("\n");
+ destval = fetch_data_word(destoffset);
+ TRACE_AND_STEP();
+ destval = not_word(destval);
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 3:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+
+ DECODE_PRINTF("NEG\tDWORD PTR ");
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF("\n");
+ destval = fetch_data_long(destoffset);
+ TRACE_AND_STEP();
+ destval = neg_long(destval);
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+
+ DECODE_PRINTF("NEG\tWORD PTR ");
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF("\n");
+ destval = fetch_data_word(destoffset);
+ TRACE_AND_STEP();
+ destval = neg_word(destval);
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 4:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+
+ DECODE_PRINTF("MUL\tDWORD PTR ");
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF("\n");
+ destval = fetch_data_long(destoffset);
+ TRACE_AND_STEP();
+ mul_long(destval);
+ } else {
+ u16 destval;
+
+ DECODE_PRINTF("MUL\tWORD PTR ");
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF("\n");
+ destval = fetch_data_word(destoffset);
+ TRACE_AND_STEP();
+ mul_word(destval);
+ }
+ break;
+ case 5:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+
+ DECODE_PRINTF("IMUL\tDWORD PTR ");
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF("\n");
+ destval = fetch_data_long(destoffset);
+ TRACE_AND_STEP();
+ imul_long(destval);
+ } else {
+ u16 destval;
+
+ DECODE_PRINTF("IMUL\tWORD PTR ");
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF("\n");
+ destval = fetch_data_word(destoffset);
+ TRACE_AND_STEP();
+ imul_word(destval);
+ }
+ break;
+ case 6:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+
+ DECODE_PRINTF("DIV\tDWORD PTR ");
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF("\n");
+ destval = fetch_data_long(destoffset);
+ TRACE_AND_STEP();
+ div_long(destval);
+ } else {
+ u16 destval;
+
+ DECODE_PRINTF("DIV\tWORD PTR ");
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF("\n");
+ destval = fetch_data_word(destoffset);
+ TRACE_AND_STEP();
+ div_word(destval);
+ }
+ break;
+ case 7:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+
+ DECODE_PRINTF("IDIV\tDWORD PTR ");
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF("\n");
+ destval = fetch_data_long(destoffset);
+ TRACE_AND_STEP();
+ idiv_long(destval);
+ } else {
+ u16 destval;
+
+ DECODE_PRINTF("IDIV\tWORD PTR ");
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF("\n");
+ destval = fetch_data_word(destoffset);
+ TRACE_AND_STEP();
+ idiv_word(destval);
+ }
+ break;
+ }
+ break; /* end mod==10 */
+ case 3: /* mod=11 */
+ switch (rh) {
+ case 0: /* test word imm */
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+ u32 srcval;
+
+ DECODE_PRINTF("TEST\t");
+ destreg = DECODE_RM_LONG_REGISTER(rl);
+ DECODE_PRINTF(",");
+ srcval = fetch_long_imm();
+ DECODE_PRINTF2("%x\n", srcval);
+ TRACE_AND_STEP();
+ test_long(*destreg, srcval);
+ } else {
+ u16 *destreg;
+ u16 srcval;
+
+ DECODE_PRINTF("TEST\t");
+ destreg = DECODE_RM_WORD_REGISTER(rl);
+ DECODE_PRINTF(",");
+ srcval = fetch_word_imm();
+ DECODE_PRINTF2("%x\n", srcval);
+ TRACE_AND_STEP();
+ test_word(*destreg, srcval);
+ }
+ break;
+ case 1:
+ DECODE_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F6\n");
+ HALT_SYS();
+ break;
+ case 2:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+
+ DECODE_PRINTF("NOT\t");
+ destreg = DECODE_RM_LONG_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = not_long(*destreg);
+ } else {
+ u16 *destreg;
+
+ DECODE_PRINTF("NOT\t");
+ destreg = DECODE_RM_WORD_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = not_word(*destreg);
+ }
+ break;
+ case 3:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+
+ DECODE_PRINTF("NEG\t");
+ destreg = DECODE_RM_LONG_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = neg_long(*destreg);
+ } else {
+ u16 *destreg;
+
+ DECODE_PRINTF("NEG\t");
+ destreg = DECODE_RM_WORD_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = neg_word(*destreg);
+ }
+ break;
+ case 4:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+
+ DECODE_PRINTF("MUL\t");
+ destreg = DECODE_RM_LONG_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ mul_long(*destreg); /*!!! */
+ } else {
+ u16 *destreg;
+
+ DECODE_PRINTF("MUL\t");
+ destreg = DECODE_RM_WORD_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ mul_word(*destreg); /*!!! */
+ }
+ break;
+ case 5:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+
+ DECODE_PRINTF("IMUL\t");
+ destreg = DECODE_RM_LONG_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ imul_long(*destreg);
+ } else {
+ u16 *destreg;
+
+ DECODE_PRINTF("IMUL\t");
+ destreg = DECODE_RM_WORD_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ imul_word(*destreg);
+ }
+ break;
+ case 6:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+
+ DECODE_PRINTF("DIV\t");
+ destreg = DECODE_RM_LONG_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ div_long(*destreg);
+ } else {
+ u16 *destreg;
+
+ DECODE_PRINTF("DIV\t");
+ destreg = DECODE_RM_WORD_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ div_word(*destreg);
+ }
+ break;
+ case 7:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+
+ DECODE_PRINTF("IDIV\t");
+ destreg = DECODE_RM_LONG_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ idiv_long(*destreg);
+ } else {
+ u16 *destreg;
+
+ DECODE_PRINTF("IDIV\t");
+ destreg = DECODE_RM_WORD_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ idiv_word(*destreg);
+ }
+ break;
+ }
+ break; /* end mod==11 */
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xf8
+****************************************************************************/
+static void x86emuOp_clc(u8 X86EMU_UNUSED(op1))
+{
+ /* clear the carry flag. */
+ START_OF_INSTR();
+ DECODE_PRINTF("CLC\n");
+ TRACE_AND_STEP();
+ CLEAR_FLAG(F_CF);
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xf9
+****************************************************************************/
+static void x86emuOp_stc(u8 X86EMU_UNUSED(op1))
+{
+ /* set the carry flag. */
+ START_OF_INSTR();
+ DECODE_PRINTF("STC\n");
+ TRACE_AND_STEP();
+ SET_FLAG(F_CF);
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xfa
+****************************************************************************/
+static void x86emuOp_cli(u8 X86EMU_UNUSED(op1))
+{
+ /* clear interrupts. */
+ START_OF_INSTR();
+ DECODE_PRINTF("CLI\n");
+ TRACE_AND_STEP();
+ CLEAR_FLAG(F_IF);
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xfb
+****************************************************************************/
+static void x86emuOp_sti(u8 X86EMU_UNUSED(op1))
+{
+ /* enable interrupts. */
+ START_OF_INSTR();
+ DECODE_PRINTF("STI\n");
+ TRACE_AND_STEP();
+ SET_FLAG(F_IF);
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xfc
+****************************************************************************/
+static void x86emuOp_cld(u8 X86EMU_UNUSED(op1))
+{
+ /* clear interrupts. */
+ START_OF_INSTR();
+ DECODE_PRINTF("CLD\n");
+ TRACE_AND_STEP();
+ CLEAR_FLAG(F_DF);
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xfd
+****************************************************************************/
+static void x86emuOp_std(u8 X86EMU_UNUSED(op1))
+{
+ /* clear interrupts. */
+ START_OF_INSTR();
+ DECODE_PRINTF("STD\n");
+ TRACE_AND_STEP();
+ SET_FLAG(F_DF);
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xfe
+****************************************************************************/
+static void x86emuOp_opcFE_byte_RM(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rh, rl;
+ u8 destval;
+ uint destoffset;
+ u8 *destreg;
+
+ /* Yet another special case instruction. */
+ START_OF_INSTR();
+ FETCH_DECODE_MODRM(mod, rh, rl);
+#ifdef X86EMU_DEBUG
+ if (DEBUG_DECODE()) {
+ /* XXX DECODE_PRINTF may be changed to something more
+ general, so that it is important to leave the strings
+ in the same format, even though the result is that the
+ above test is done twice. */
+
+ switch (rh) {
+ case 0:
+ DECODE_PRINTF("INC\t");
+ break;
+ case 1:
+ DECODE_PRINTF("DEC\t");
+ break;
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ DECODE_PRINTF2("ILLEGAL OP MAJOR OP 0xFE MINOR OP %x \n", mod);
+ HALT_SYS();
+ break;
+ }
+ }
+#endif
+ switch (mod) {
+ case 0:
+ DECODE_PRINTF("BYTE PTR ");
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF("\n");
+ switch (rh) {
+ case 0: /* inc word ptr ... */
+ destval = fetch_data_byte(destoffset);
+ TRACE_AND_STEP();
+ destval = inc_byte(destval);
+ store_data_byte(destoffset, destval);
+ break;
+ case 1: /* dec word ptr ... */
+ destval = fetch_data_byte(destoffset);
+ TRACE_AND_STEP();
+ destval = dec_byte(destval);
+ store_data_byte(destoffset, destval);
+ break;
+ }
+ break;
+ case 1:
+ DECODE_PRINTF("BYTE PTR ");
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF("\n");
+ switch (rh) {
+ case 0:
+ destval = fetch_data_byte(destoffset);
+ TRACE_AND_STEP();
+ destval = inc_byte(destval);
+ store_data_byte(destoffset, destval);
+ break;
+ case 1:
+ destval = fetch_data_byte(destoffset);
+ TRACE_AND_STEP();
+ destval = dec_byte(destval);
+ store_data_byte(destoffset, destval);
+ break;
+ }
+ break;
+ case 2:
+ DECODE_PRINTF("BYTE PTR ");
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF("\n");
+ switch (rh) {
+ case 0:
+ destval = fetch_data_byte(destoffset);
+ TRACE_AND_STEP();
+ destval = inc_byte(destval);
+ store_data_byte(destoffset, destval);
+ break;
+ case 1:
+ destval = fetch_data_byte(destoffset);
+ TRACE_AND_STEP();
+ destval = dec_byte(destval);
+ store_data_byte(destoffset, destval);
+ break;
+ }
+ break;
+ case 3:
+ destreg = DECODE_RM_BYTE_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ switch (rh) {
+ case 0:
+ TRACE_AND_STEP();
+ *destreg = inc_byte(*destreg);
+ break;
+ case 1:
+ TRACE_AND_STEP();
+ *destreg = dec_byte(*destreg);
+ break;
+ }
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xff
+****************************************************************************/
+static void x86emuOp_opcFF_word_RM(u8 X86EMU_UNUSED(op1))
+{
+ int mod, rh, rl;
+ uint destoffset = 0;
+ u16 *destreg;
+ u16 destval,destval2;
+
+ /* Yet another special case instruction. */
+ START_OF_INSTR();
+ FETCH_DECODE_MODRM(mod, rh, rl);
+#ifdef X86EMU_DEBUG
+ if (DEBUG_DECODE()) {
+ /* XXX DECODE_PRINTF may be changed to something more
+ general, so that it is important to leave the strings
+ in the same format, even though the result is that the
+ above test is done twice. */
+
+ switch (rh) {
+ case 0:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("INC\tDWORD PTR ");
+ } else {
+ DECODE_PRINTF("INC\tWORD PTR ");
+ }
+ break;
+ case 1:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ DECODE_PRINTF("DEC\tDWORD PTR ");
+ } else {
+ DECODE_PRINTF("DEC\tWORD PTR ");
+ }
+ break;
+ case 2:
+ DECODE_PRINTF("CALL\t");
+ break;
+ case 3:
+ DECODE_PRINTF("CALL\tFAR ");
+ break;
+ case 4:
+ DECODE_PRINTF("JMP\t");
+ break;
+ case 5:
+ DECODE_PRINTF("JMP\tFAR ");
+ break;
+ case 6:
+ DECODE_PRINTF("PUSH\t");
+ break;
+ case 7:
+ DECODE_PRINTF("ILLEGAL DECODING OF OPCODE FF\t");
+ HALT_SYS();
+ break;
+ }
+ }
+#endif
+ switch (mod) {
+ case 0:
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF("\n");
+ switch (rh) {
+ case 0: /* inc word ptr ... */
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+
+ destval = fetch_data_long(destoffset);
+ TRACE_AND_STEP();
+ destval = inc_long(destval);
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+
+ destval = fetch_data_word(destoffset);
+ TRACE_AND_STEP();
+ destval = inc_word(destval);
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 1: /* dec word ptr ... */
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+
+ destval = fetch_data_long(destoffset);
+ TRACE_AND_STEP();
+ destval = dec_long(destval);
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+
+ destval = fetch_data_word(destoffset);
+ TRACE_AND_STEP();
+ destval = dec_word(destval);
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 2: /* call word ptr ... */
+ destval = fetch_data_word(destoffset);
+ TRACE_AND_STEP();
+ push_word(M.x86.R_IP);
+ M.x86.R_IP = destval;
+ break;
+ case 3: /* call far ptr ... */
+ destval = fetch_data_word(destoffset);
+ destval2 = fetch_data_word(destoffset + 2);
+ TRACE_AND_STEP();
+ push_word(M.x86.R_CS);
+ M.x86.R_CS = destval2;
+ push_word(M.x86.R_IP);
+ M.x86.R_IP = destval;
+ break;
+ case 4: /* jmp word ptr ... */
+ destval = fetch_data_word(destoffset);
+ TRACE_AND_STEP();
+ M.x86.R_IP = destval;
+ break;
+ case 5: /* jmp far ptr ... */
+ destval = fetch_data_word(destoffset);
+ destval2 = fetch_data_word(destoffset + 2);
+ TRACE_AND_STEP();
+ M.x86.R_IP = destval;
+ M.x86.R_CS = destval2;
+ break;
+ case 6: /* push word ptr ... */
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+
+ destval = fetch_data_long(destoffset);
+ TRACE_AND_STEP();
+ push_long(destval);
+ } else {
+ u16 destval;
+
+ destval = fetch_data_word(destoffset);
+ TRACE_AND_STEP();
+ push_word(destval);
+ }
+ break;
+ }
+ break;
+ case 1:
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF("\n");
+ switch (rh) {
+ case 0:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+
+ destval = fetch_data_long(destoffset);
+ TRACE_AND_STEP();
+ destval = inc_long(destval);
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+
+ destval = fetch_data_word(destoffset);
+ TRACE_AND_STEP();
+ destval = inc_word(destval);
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 1:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+
+ destval = fetch_data_long(destoffset);
+ TRACE_AND_STEP();
+ destval = dec_long(destval);
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+
+ destval = fetch_data_word(destoffset);
+ TRACE_AND_STEP();
+ destval = dec_word(destval);
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 2: /* call word ptr ... */
+ destval = fetch_data_word(destoffset);
+ TRACE_AND_STEP();
+ push_word(M.x86.R_IP);
+ M.x86.R_IP = destval;
+ break;
+ case 3: /* call far ptr ... */
+ destval = fetch_data_word(destoffset);
+ destval2 = fetch_data_word(destoffset + 2);
+ TRACE_AND_STEP();
+ push_word(M.x86.R_CS);
+ M.x86.R_CS = destval2;
+ push_word(M.x86.R_IP);
+ M.x86.R_IP = destval;
+ break;
+ case 4: /* jmp word ptr ... */
+ destval = fetch_data_word(destoffset);
+ TRACE_AND_STEP();
+ M.x86.R_IP = destval;
+ break;
+ case 5: /* jmp far ptr ... */
+ destval = fetch_data_word(destoffset);
+ destval2 = fetch_data_word(destoffset + 2);
+ TRACE_AND_STEP();
+ M.x86.R_IP = destval;
+ M.x86.R_CS = destval2;
+ break;
+ case 6: /* push word ptr ... */
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+
+ destval = fetch_data_long(destoffset);
+ TRACE_AND_STEP();
+ push_long(destval);
+ } else {
+ u16 destval;
+
+ destval = fetch_data_word(destoffset);
+ TRACE_AND_STEP();
+ push_word(destval);
+ }
+ break;
+ }
+ break;
+ case 2:
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF("\n");
+ switch (rh) {
+ case 0:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+
+ destval = fetch_data_long(destoffset);
+ TRACE_AND_STEP();
+ destval = inc_long(destval);
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+
+ destval = fetch_data_word(destoffset);
+ TRACE_AND_STEP();
+ destval = inc_word(destval);
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 1:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+
+ destval = fetch_data_long(destoffset);
+ TRACE_AND_STEP();
+ destval = dec_long(destval);
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+
+ destval = fetch_data_word(destoffset);
+ TRACE_AND_STEP();
+ destval = dec_word(destval);
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 2: /* call word ptr ... */
+ destval = fetch_data_word(destoffset);
+ TRACE_AND_STEP();
+ push_word(M.x86.R_IP);
+ M.x86.R_IP = destval;
+ break;
+ case 3: /* call far ptr ... */
+ destval = fetch_data_word(destoffset);
+ destval2 = fetch_data_word(destoffset + 2);
+ TRACE_AND_STEP();
+ push_word(M.x86.R_CS);
+ M.x86.R_CS = destval2;
+ push_word(M.x86.R_IP);
+ M.x86.R_IP = destval;
+ break;
+ case 4: /* jmp word ptr ... */
+ destval = fetch_data_word(destoffset);
+ TRACE_AND_STEP();
+ M.x86.R_IP = destval;
+ break;
+ case 5: /* jmp far ptr ... */
+ destval = fetch_data_word(destoffset);
+ destval2 = fetch_data_word(destoffset + 2);
+ TRACE_AND_STEP();
+ M.x86.R_IP = destval;
+ M.x86.R_CS = destval2;
+ break;
+ case 6: /* push word ptr ... */
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+
+ destval = fetch_data_long(destoffset);
+ TRACE_AND_STEP();
+ push_long(destval);
+ } else {
+ u16 destval;
+
+ destval = fetch_data_word(destoffset);
+ TRACE_AND_STEP();
+ push_word(destval);
+ }
+ break;
+ }
+ break;
+ case 3:
+ switch (rh) {
+ case 0:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+
+ destreg = DECODE_RM_LONG_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = inc_long(*destreg);
+ } else {
+ u16 *destreg;
+
+ destreg = DECODE_RM_WORD_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = inc_word(*destreg);
+ }
+ break;
+ case 1:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+
+ destreg = DECODE_RM_LONG_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = dec_long(*destreg);
+ } else {
+ u16 *destreg;
+
+ destreg = DECODE_RM_WORD_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = dec_word(*destreg);
+ }
+ break;
+ case 2: /* call word ptr ... */
+ destreg = DECODE_RM_WORD_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ push_word(M.x86.R_IP);
+ M.x86.R_IP = *destreg;
+ break;
+ case 3: /* jmp far ptr ... */
+ DECODE_PRINTF("OPERATION UNDEFINED 0XFF \n");
+ TRACE_AND_STEP();
+ HALT_SYS();
+ break;
+
+ case 4: /* jmp ... */
+ destreg = DECODE_RM_WORD_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ M.x86.R_IP = (u16) (*destreg);
+ break;
+ case 5: /* jmp far ptr ... */
+ DECODE_PRINTF("OPERATION UNDEFINED 0XFF \n");
+ TRACE_AND_STEP();
+ HALT_SYS();
+ break;
+ case 6:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+
+ destreg = DECODE_RM_LONG_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ push_long(*destreg);
+ } else {
+ u16 *destreg;
+
+ destreg = DECODE_RM_WORD_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ push_word(*destreg);
+ }
+ break;
+ case 7:
+ DECODE_PRINTF("OPERATION UNDEFINED 0XFF \n");
+ TRACE_AND_STEP();
+ HALT_SYS();
+ break;
+ }
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/***************************************************************************
+ * Single byte operation code table:
+ **************************************************************************/
+void (*x86emu_optab[256])(u8) =
+{
+/* 0x00 */ x86emuOp_add_byte_RM_R,
+/* 0x01 */ x86emuOp_add_word_RM_R,
+/* 0x02 */ x86emuOp_add_byte_R_RM,
+/* 0x03 */ x86emuOp_add_word_R_RM,
+/* 0x04 */ x86emuOp_add_byte_AL_IMM,
+/* 0x05 */ x86emuOp_add_word_AX_IMM,
+/* 0x06 */ x86emuOp_push_ES,
+/* 0x07 */ x86emuOp_pop_ES,
+
+/* 0x08 */ x86emuOp_or_byte_RM_R,
+/* 0x09 */ x86emuOp_or_word_RM_R,
+/* 0x0a */ x86emuOp_or_byte_R_RM,
+/* 0x0b */ x86emuOp_or_word_R_RM,
+/* 0x0c */ x86emuOp_or_byte_AL_IMM,
+/* 0x0d */ x86emuOp_or_word_AX_IMM,
+/* 0x0e */ x86emuOp_push_CS,
+/* 0x0f */ x86emuOp_two_byte,
+
+/* 0x10 */ x86emuOp_adc_byte_RM_R,
+/* 0x11 */ x86emuOp_adc_word_RM_R,
+/* 0x12 */ x86emuOp_adc_byte_R_RM,
+/* 0x13 */ x86emuOp_adc_word_R_RM,
+/* 0x14 */ x86emuOp_adc_byte_AL_IMM,
+/* 0x15 */ x86emuOp_adc_word_AX_IMM,
+/* 0x16 */ x86emuOp_push_SS,
+/* 0x17 */ x86emuOp_pop_SS,
+
+/* 0x18 */ x86emuOp_sbb_byte_RM_R,
+/* 0x19 */ x86emuOp_sbb_word_RM_R,
+/* 0x1a */ x86emuOp_sbb_byte_R_RM,
+/* 0x1b */ x86emuOp_sbb_word_R_RM,
+/* 0x1c */ x86emuOp_sbb_byte_AL_IMM,
+/* 0x1d */ x86emuOp_sbb_word_AX_IMM,
+/* 0x1e */ x86emuOp_push_DS,
+/* 0x1f */ x86emuOp_pop_DS,
+
+/* 0x20 */ x86emuOp_and_byte_RM_R,
+/* 0x21 */ x86emuOp_and_word_RM_R,
+/* 0x22 */ x86emuOp_and_byte_R_RM,
+/* 0x23 */ x86emuOp_and_word_R_RM,
+/* 0x24 */ x86emuOp_and_byte_AL_IMM,
+/* 0x25 */ x86emuOp_and_word_AX_IMM,
+/* 0x26 */ x86emuOp_segovr_ES,
+/* 0x27 */ x86emuOp_daa,
+
+/* 0x28 */ x86emuOp_sub_byte_RM_R,
+/* 0x29 */ x86emuOp_sub_word_RM_R,
+/* 0x2a */ x86emuOp_sub_byte_R_RM,
+/* 0x2b */ x86emuOp_sub_word_R_RM,
+/* 0x2c */ x86emuOp_sub_byte_AL_IMM,
+/* 0x2d */ x86emuOp_sub_word_AX_IMM,
+/* 0x2e */ x86emuOp_segovr_CS,
+/* 0x2f */ x86emuOp_das,
+
+/* 0x30 */ x86emuOp_xor_byte_RM_R,
+/* 0x31 */ x86emuOp_xor_word_RM_R,
+/* 0x32 */ x86emuOp_xor_byte_R_RM,
+/* 0x33 */ x86emuOp_xor_word_R_RM,
+/* 0x34 */ x86emuOp_xor_byte_AL_IMM,
+/* 0x35 */ x86emuOp_xor_word_AX_IMM,
+/* 0x36 */ x86emuOp_segovr_SS,
+/* 0x37 */ x86emuOp_aaa,
+
+/* 0x38 */ x86emuOp_cmp_byte_RM_R,
+/* 0x39 */ x86emuOp_cmp_word_RM_R,
+/* 0x3a */ x86emuOp_cmp_byte_R_RM,
+/* 0x3b */ x86emuOp_cmp_word_R_RM,
+/* 0x3c */ x86emuOp_cmp_byte_AL_IMM,
+/* 0x3d */ x86emuOp_cmp_word_AX_IMM,
+/* 0x3e */ x86emuOp_segovr_DS,
+/* 0x3f */ x86emuOp_aas,
+
+/* 0x40 */ x86emuOp_inc_AX,
+/* 0x41 */ x86emuOp_inc_CX,
+/* 0x42 */ x86emuOp_inc_DX,
+/* 0x43 */ x86emuOp_inc_BX,
+/* 0x44 */ x86emuOp_inc_SP,
+/* 0x45 */ x86emuOp_inc_BP,
+/* 0x46 */ x86emuOp_inc_SI,
+/* 0x47 */ x86emuOp_inc_DI,
+
+/* 0x48 */ x86emuOp_dec_AX,
+/* 0x49 */ x86emuOp_dec_CX,
+/* 0x4a */ x86emuOp_dec_DX,
+/* 0x4b */ x86emuOp_dec_BX,
+/* 0x4c */ x86emuOp_dec_SP,
+/* 0x4d */ x86emuOp_dec_BP,
+/* 0x4e */ x86emuOp_dec_SI,
+/* 0x4f */ x86emuOp_dec_DI,
+
+/* 0x50 */ x86emuOp_push_AX,
+/* 0x51 */ x86emuOp_push_CX,
+/* 0x52 */ x86emuOp_push_DX,
+/* 0x53 */ x86emuOp_push_BX,
+/* 0x54 */ x86emuOp_push_SP,
+/* 0x55 */ x86emuOp_push_BP,
+/* 0x56 */ x86emuOp_push_SI,
+/* 0x57 */ x86emuOp_push_DI,
+
+/* 0x58 */ x86emuOp_pop_AX,
+/* 0x59 */ x86emuOp_pop_CX,
+/* 0x5a */ x86emuOp_pop_DX,
+/* 0x5b */ x86emuOp_pop_BX,
+/* 0x5c */ x86emuOp_pop_SP,
+/* 0x5d */ x86emuOp_pop_BP,
+/* 0x5e */ x86emuOp_pop_SI,
+/* 0x5f */ x86emuOp_pop_DI,
+
+/* 0x60 */ x86emuOp_push_all,
+/* 0x61 */ x86emuOp_pop_all,
+/* 0x62 */ x86emuOp_illegal_op, /* bound */
+/* 0x63 */ x86emuOp_illegal_op, /* arpl */
+/* 0x64 */ x86emuOp_segovr_FS,
+/* 0x65 */ x86emuOp_segovr_GS,
+/* 0x66 */ x86emuOp_prefix_data,
+/* 0x67 */ x86emuOp_prefix_addr,
+
+/* 0x68 */ x86emuOp_push_word_IMM,
+/* 0x69 */ x86emuOp_imul_word_IMM,
+/* 0x6a */ x86emuOp_push_byte_IMM,
+/* 0x6b */ x86emuOp_imul_byte_IMM,
+/* 0x6c */ x86emuOp_ins_byte,
+/* 0x6d */ x86emuOp_ins_word,
+/* 0x6e */ x86emuOp_outs_byte,
+/* 0x6f */ x86emuOp_outs_word,
+
+/* 0x70 */ x86emuOp_jump_near_O,
+/* 0x71 */ x86emuOp_jump_near_NO,
+/* 0x72 */ x86emuOp_jump_near_B,
+/* 0x73 */ x86emuOp_jump_near_NB,
+/* 0x74 */ x86emuOp_jump_near_Z,
+/* 0x75 */ x86emuOp_jump_near_NZ,
+/* 0x76 */ x86emuOp_jump_near_BE,
+/* 0x77 */ x86emuOp_jump_near_NBE,
+
+/* 0x78 */ x86emuOp_jump_near_S,
+/* 0x79 */ x86emuOp_jump_near_NS,
+/* 0x7a */ x86emuOp_jump_near_P,
+/* 0x7b */ x86emuOp_jump_near_NP,
+/* 0x7c */ x86emuOp_jump_near_L,
+/* 0x7d */ x86emuOp_jump_near_NL,
+/* 0x7e */ x86emuOp_jump_near_LE,
+/* 0x7f */ x86emuOp_jump_near_NLE,
+
+/* 0x80 */ x86emuOp_opc80_byte_RM_IMM,
+/* 0x81 */ x86emuOp_opc81_word_RM_IMM,
+/* 0x82 */ x86emuOp_opc82_byte_RM_IMM,
+/* 0x83 */ x86emuOp_opc83_word_RM_IMM,
+/* 0x84 */ x86emuOp_test_byte_RM_R,
+/* 0x85 */ x86emuOp_test_word_RM_R,
+/* 0x86 */ x86emuOp_xchg_byte_RM_R,
+/* 0x87 */ x86emuOp_xchg_word_RM_R,
+
+/* 0x88 */ x86emuOp_mov_byte_RM_R,
+/* 0x89 */ x86emuOp_mov_word_RM_R,
+/* 0x8a */ x86emuOp_mov_byte_R_RM,
+/* 0x8b */ x86emuOp_mov_word_R_RM,
+/* 0x8c */ x86emuOp_mov_word_RM_SR,
+/* 0x8d */ x86emuOp_lea_word_R_M,
+/* 0x8e */ x86emuOp_mov_word_SR_RM,
+/* 0x8f */ x86emuOp_pop_RM,
+
+/* 0x90 */ x86emuOp_nop,
+/* 0x91 */ x86emuOp_xchg_word_AX_CX,
+/* 0x92 */ x86emuOp_xchg_word_AX_DX,
+/* 0x93 */ x86emuOp_xchg_word_AX_BX,
+/* 0x94 */ x86emuOp_xchg_word_AX_SP,
+/* 0x95 */ x86emuOp_xchg_word_AX_BP,
+/* 0x96 */ x86emuOp_xchg_word_AX_SI,
+/* 0x97 */ x86emuOp_xchg_word_AX_DI,
+
+/* 0x98 */ x86emuOp_cbw,
+/* 0x99 */ x86emuOp_cwd,
+/* 0x9a */ x86emuOp_call_far_IMM,
+/* 0x9b */ x86emuOp_wait,
+/* 0x9c */ x86emuOp_pushf_word,
+/* 0x9d */ x86emuOp_popf_word,
+/* 0x9e */ x86emuOp_sahf,
+/* 0x9f */ x86emuOp_lahf,
+
+/* 0xa0 */ x86emuOp_mov_AL_M_IMM,
+/* 0xa1 */ x86emuOp_mov_AX_M_IMM,
+/* 0xa2 */ x86emuOp_mov_M_AL_IMM,
+/* 0xa3 */ x86emuOp_mov_M_AX_IMM,
+/* 0xa4 */ x86emuOp_movs_byte,
+/* 0xa5 */ x86emuOp_movs_word,
+/* 0xa6 */ x86emuOp_cmps_byte,
+/* 0xa7 */ x86emuOp_cmps_word,
+/* 0xa8 */ x86emuOp_test_AL_IMM,
+/* 0xa9 */ x86emuOp_test_AX_IMM,
+/* 0xaa */ x86emuOp_stos_byte,
+/* 0xab */ x86emuOp_stos_word,
+/* 0xac */ x86emuOp_lods_byte,
+/* 0xad */ x86emuOp_lods_word,
+/* 0xac */ x86emuOp_scas_byte,
+/* 0xad */ x86emuOp_scas_word,
+
+
+/* 0xb0 */ x86emuOp_mov_byte_AL_IMM,
+/* 0xb1 */ x86emuOp_mov_byte_CL_IMM,
+/* 0xb2 */ x86emuOp_mov_byte_DL_IMM,
+/* 0xb3 */ x86emuOp_mov_byte_BL_IMM,
+/* 0xb4 */ x86emuOp_mov_byte_AH_IMM,
+/* 0xb5 */ x86emuOp_mov_byte_CH_IMM,
+/* 0xb6 */ x86emuOp_mov_byte_DH_IMM,
+/* 0xb7 */ x86emuOp_mov_byte_BH_IMM,
+
+/* 0xb8 */ x86emuOp_mov_word_AX_IMM,
+/* 0xb9 */ x86emuOp_mov_word_CX_IMM,
+/* 0xba */ x86emuOp_mov_word_DX_IMM,
+/* 0xbb */ x86emuOp_mov_word_BX_IMM,
+/* 0xbc */ x86emuOp_mov_word_SP_IMM,
+/* 0xbd */ x86emuOp_mov_word_BP_IMM,
+/* 0xbe */ x86emuOp_mov_word_SI_IMM,
+/* 0xbf */ x86emuOp_mov_word_DI_IMM,
+
+/* 0xc0 */ x86emuOp_opcC0_byte_RM_MEM,
+/* 0xc1 */ x86emuOp_opcC1_word_RM_MEM,
+/* 0xc2 */ x86emuOp_ret_near_IMM,
+/* 0xc3 */ x86emuOp_ret_near,
+/* 0xc4 */ x86emuOp_les_R_IMM,
+/* 0xc5 */ x86emuOp_lds_R_IMM,
+/* 0xc6 */ x86emuOp_mov_byte_RM_IMM,
+/* 0xc7 */ x86emuOp_mov_word_RM_IMM,
+/* 0xc8 */ x86emuOp_enter,
+/* 0xc9 */ x86emuOp_leave,
+/* 0xca */ x86emuOp_ret_far_IMM,
+/* 0xcb */ x86emuOp_ret_far,
+/* 0xcc */ x86emuOp_int3,
+/* 0xcd */ x86emuOp_int_IMM,
+/* 0xce */ x86emuOp_into,
+/* 0xcf */ x86emuOp_iret,
+
+/* 0xd0 */ x86emuOp_opcD0_byte_RM_1,
+/* 0xd1 */ x86emuOp_opcD1_word_RM_1,
+/* 0xd2 */ x86emuOp_opcD2_byte_RM_CL,
+/* 0xd3 */ x86emuOp_opcD3_word_RM_CL,
+/* 0xd4 */ x86emuOp_aam,
+/* 0xd5 */ x86emuOp_aad,
+/* 0xd6 */ x86emuOp_illegal_op, /* Undocumented SETALC instruction */
+/* 0xd7 */ x86emuOp_xlat,
+/* 0xd8 */ x86emuOp_esc_coprocess_d8,
+/* 0xd9 */ x86emuOp_esc_coprocess_d9,
+/* 0xda */ x86emuOp_esc_coprocess_da,
+/* 0xdb */ x86emuOp_esc_coprocess_db,
+/* 0xdc */ x86emuOp_esc_coprocess_dc,
+/* 0xdd */ x86emuOp_esc_coprocess_dd,
+/* 0xde */ x86emuOp_esc_coprocess_de,
+/* 0xdf */ x86emuOp_esc_coprocess_df,
+
+/* 0xe0 */ x86emuOp_loopne,
+/* 0xe1 */ x86emuOp_loope,
+/* 0xe2 */ x86emuOp_loop,
+/* 0xe3 */ x86emuOp_jcxz,
+/* 0xe4 */ x86emuOp_in_byte_AL_IMM,
+/* 0xe5 */ x86emuOp_in_word_AX_IMM,
+/* 0xe6 */ x86emuOp_out_byte_IMM_AL,
+/* 0xe7 */ x86emuOp_out_word_IMM_AX,
+
+/* 0xe8 */ x86emuOp_call_near_IMM,
+/* 0xe9 */ x86emuOp_jump_near_IMM,
+/* 0xea */ x86emuOp_jump_far_IMM,
+/* 0xeb */ x86emuOp_jump_byte_IMM,
+/* 0xec */ x86emuOp_in_byte_AL_DX,
+/* 0xed */ x86emuOp_in_word_AX_DX,
+/* 0xee */ x86emuOp_out_byte_DX_AL,
+/* 0xef */ x86emuOp_out_word_DX_AX,
+
+/* 0xf0 */ x86emuOp_lock,
+/* 0xf1 */ x86emuOp_illegal_op,
+/* 0xf2 */ x86emuOp_repne,
+/* 0xf3 */ x86emuOp_repe,
+/* 0xf4 */ x86emuOp_halt,
+/* 0xf5 */ x86emuOp_cmc,
+/* 0xf6 */ x86emuOp_opcF6_byte_RM,
+/* 0xf7 */ x86emuOp_opcF7_word_RM,
+
+/* 0xf8 */ x86emuOp_clc,
+/* 0xf9 */ x86emuOp_stc,
+/* 0xfa */ x86emuOp_cli,
+/* 0xfb */ x86emuOp_sti,
+/* 0xfc */ x86emuOp_cld,
+/* 0xfd */ x86emuOp_std,
+/* 0xfe */ x86emuOp_opcFE_byte_RM,
+/* 0xff */ x86emuOp_opcFF_word_RM,
+};
diff --git a/userspace/sdks/nv570/nvalloc/unix/x86emu/ops2.c b/userspace/sdks/nv570/nvalloc/unix/x86emu/ops2.c
new file mode 100644
index 0000000..6053b48
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/x86emu/ops2.c
@@ -0,0 +1,2877 @@
+/****************************************************************************
+*
+* Realmode X86 Emulator Library
+*
+* Copyright (C) 1996-1999 SciTech Software, Inc.
+* Copyright (C) David Mosberger-Tang
+* Copyright (C) 1999 Egbert Eich
+*
+* ========================================================================
+*
+* Permission to use, copy, modify, distribute, and sell this software and
+* its documentation for any purpose is hereby granted without fee,
+* provided that the above copyright notice appear in all copies and that
+* both that copyright notice and this permission notice appear in
+* supporting documentation, and that the name of the authors not be used
+* in advertising or publicity pertaining to distribution of the software
+* without specific, written prior permission. The authors makes no
+* representations about the suitability of this software for any purpose.
+* It is provided "as is" without express or implied warranty.
+*
+* THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+* EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+* PERFORMANCE OF THIS SOFTWARE.
+*
+* ========================================================================
+*
+* Language: ANSI C
+* Environment: Any
+* Developer: Kendall Bennett
+*
+* Description: This file includes subroutines to implement the decoding
+* and emulation of all the x86 extended two-byte processor
+* instructions.
+*
+****************************************************************************/
+
+#include "x86emu/x86emui.h"
+
+/*----------------------------- Implementation ----------------------------*/
+
+/****************************************************************************
+PARAMETERS:
+op1 - Instruction op code
+
+REMARKS:
+Handles illegal opcodes.
+****************************************************************************/
+static void x86emuOp2_illegal_op(
+ u8 op2)
+{
+ START_OF_INSTR();
+ DECODE_PRINTF("ILLEGAL EXTENDED X86 OPCODE\n");
+ TRACE_REGS();
+DB( NV_PRINTF(LEVEL_INFO,
+ "%04x:%04x: %02X ILLEGAL EXTENDED X86 OPCODE!\n",
+ M.x86.R_CS, M.x86.R_IP - 2, op2);)
+ HALT_SYS();
+ END_OF_INSTR();
+}
+
+#define xorl(a,b) ((a) && !(b)) || (!(a) && (b))
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0f,0x80-0x8F
+****************************************************************************/
+static void x86emuOp2_long_jump(u8 op2)
+{
+ s32 target;
+ const char *name = 0;
+ int cond = 0;
+
+ /* conditional jump to word offset. */
+ START_OF_INSTR();
+ switch (op2) {
+ case 0x80:
+ name = "JO\t";
+ cond = ACCESS_FLAG(F_OF);
+ break;
+ case 0x81:
+ name = "JNO\t";
+ cond = !ACCESS_FLAG(F_OF);
+ break;
+ case 0x82:
+ name = "JB\t";
+ cond = ACCESS_FLAG(F_CF);
+ break;
+ case 0x83:
+ name = "JNB\t";
+ cond = !ACCESS_FLAG(F_CF);
+ break;
+ case 0x84:
+ name = "JZ\t";
+ cond = ACCESS_FLAG(F_ZF);
+ break;
+ case 0x85:
+ name = "JNZ\t";
+ cond = !ACCESS_FLAG(F_ZF);
+ break;
+ case 0x86:
+ name = "JBE\t";
+ cond = ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF);
+ break;
+ case 0x87:
+ name = "JNBE\t";
+ cond = !(ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF));
+ break;
+ case 0x88:
+ name = "JS\t";
+ cond = ACCESS_FLAG(F_SF);
+ break;
+ case 0x89:
+ name = "JNS\t";
+ cond = !ACCESS_FLAG(F_SF);
+ break;
+ case 0x8a:
+ name = "JP\t";
+ cond = ACCESS_FLAG(F_PF);
+ break;
+ case 0x8b:
+ name = "JNP\t";
+ cond = !ACCESS_FLAG(F_PF);
+ break;
+ case 0x8c:
+ name = "JL\t";
+ cond = xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF));
+ break;
+ case 0x8d:
+ name = "JNL\t";
+ cond = !xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF));
+ break;
+ case 0x8e:
+ name = "JLE\t";
+ cond = (xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF)) ||
+ ACCESS_FLAG(F_ZF));
+ break;
+ case 0x8f:
+ name = "JNLE\t";
+ cond = !(xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF)) ||
+ ACCESS_FLAG(F_ZF));
+ break;
+ }
+ DECODE_PRINTF(name);
+ (void)name;
+ target = (s16) fetch_word_imm();
+ target += (s16) M.x86.R_IP;
+ DECODE_PRINTF2("%04x\n", target);
+ TRACE_AND_STEP();
+ if (cond)
+ M.x86.R_IP = (u16)target;
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0f,0x90-0x9F
+****************************************************************************/
+static void x86emuOp2_set_byte(u8 op2)
+{
+ int mod, rl, rh;
+ uint destoffset;
+ u8 *destreg;
+ const char *name = 0;
+ int cond = 0;
+
+ START_OF_INSTR();
+ switch (op2) {
+ case 0x90:
+ name = "SETO\t";
+ cond = ACCESS_FLAG(F_OF);
+ break;
+ case 0x91:
+ name = "SETNO\t";
+ cond = !ACCESS_FLAG(F_OF);
+ break;
+ case 0x92:
+ name = "SETB\t";
+ cond = ACCESS_FLAG(F_CF);
+ break;
+ case 0x93:
+ name = "SETNB\t";
+ cond = !ACCESS_FLAG(F_CF);
+ break;
+ case 0x94:
+ name = "SETZ\t";
+ cond = ACCESS_FLAG(F_ZF);
+ break;
+ case 0x95:
+ name = "SETNZ\t";
+ cond = !ACCESS_FLAG(F_ZF);
+ break;
+ case 0x96:
+ name = "SETBE\t";
+ cond = ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF);
+ break;
+ case 0x97:
+ name = "SETNBE\t";
+ cond = !(ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF));
+ break;
+ case 0x98:
+ name = "SETS\t";
+ cond = ACCESS_FLAG(F_SF);
+ break;
+ case 0x99:
+ name = "SETNS\t";
+ cond = !ACCESS_FLAG(F_SF);
+ break;
+ case 0x9a:
+ name = "SETP\t";
+ cond = ACCESS_FLAG(F_PF);
+ break;
+ case 0x9b:
+ name = "SETNP\t";
+ cond = !ACCESS_FLAG(F_PF);
+ break;
+ case 0x9c:
+ name = "SETL\t";
+ cond = xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF));
+ break;
+ case 0x9d:
+ name = "SETNL\t";
+ cond = xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF));
+ break;
+ case 0x9e:
+ name = "SETLE\t";
+ cond = (xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF)) ||
+ ACCESS_FLAG(F_ZF));
+ break;
+ case 0x9f:
+ name = "SETNLE\t";
+ cond = !(xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF)) ||
+ ACCESS_FLAG(F_ZF));
+ break;
+ }
+ DECODE_PRINTF(name);
+ (void)name;
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ store_data_byte(destoffset, cond ? 0x01 : 0x00);
+ break;
+ case 1:
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ store_data_byte(destoffset, cond ? 0x01 : 0x00);
+ break;
+ case 2:
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ store_data_byte(destoffset, cond ? 0x01 : 0x00);
+ break;
+ case 3: /* register to register */
+ destreg = DECODE_RM_BYTE_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = cond ? 0x01 : 0x00;
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0f,0xa0
+****************************************************************************/
+static void x86emuOp2_push_FS(u8 X86EMU_UNUSED(op2))
+{
+ START_OF_INSTR();
+ DECODE_PRINTF("PUSH\tFS\n");
+ TRACE_AND_STEP();
+ push_word(M.x86.R_FS);
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0f,0xa1
+****************************************************************************/
+static void x86emuOp2_pop_FS(u8 X86EMU_UNUSED(op2))
+{
+ START_OF_INSTR();
+ DECODE_PRINTF("POP\tFS\n");
+ TRACE_AND_STEP();
+ M.x86.R_FS = pop_word();
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0f,0xa3
+****************************************************************************/
+static void x86emuOp2_bt_R(u8 X86EMU_UNUSED(op2))
+{
+ int mod, rl, rh;
+ uint srcoffset;
+ int bit,disp;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("BT\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 srcval;
+ u32 *shiftreg;
+
+ srcoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ bit = *shiftreg & 0x1F;
+ disp = (s16)*shiftreg >> 5;
+ srcval = fetch_data_long(srcoffset+disp);
+ CONDITIONAL_SET_FLAG(srcval & (0x1 << bit),F_CF);
+ } else {
+ u16 srcval;
+ u16 *shiftreg;
+
+ srcoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ bit = *shiftreg & 0xF;
+ disp = (s16)*shiftreg >> 4;
+ srcval = fetch_data_word(srcoffset+disp);
+ CONDITIONAL_SET_FLAG(srcval & (0x1 << bit),F_CF);
+ }
+ break;
+ case 1:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 srcval;
+ u32 *shiftreg;
+
+ srcoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ bit = *shiftreg & 0x1F;
+ disp = (s16)*shiftreg >> 5;
+ srcval = fetch_data_long(srcoffset+disp);
+ CONDITIONAL_SET_FLAG(srcval & (0x1 << bit),F_CF);
+ } else {
+ u16 srcval;
+ u16 *shiftreg;
+
+ srcoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ bit = *shiftreg & 0xF;
+ disp = (s16)*shiftreg >> 4;
+ srcval = fetch_data_word(srcoffset+disp);
+ CONDITIONAL_SET_FLAG(srcval & (0x1 << bit),F_CF);
+ }
+ break;
+ case 2:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 srcval;
+ u32 *shiftreg;
+
+ srcoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ bit = *shiftreg & 0x1F;
+ disp = (s16)*shiftreg >> 5;
+ srcval = fetch_data_long(srcoffset+disp);
+ CONDITIONAL_SET_FLAG(srcval & (0x1 << bit),F_CF);
+ } else {
+ u16 srcval;
+ u16 *shiftreg;
+
+ srcoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ bit = *shiftreg & 0xF;
+ disp = (s16)*shiftreg >> 4;
+ srcval = fetch_data_word(srcoffset+disp);
+ CONDITIONAL_SET_FLAG(srcval & (0x1 << bit),F_CF);
+ }
+ break;
+ case 3: /* register to register */
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *srcreg,*shiftreg;
+
+ srcreg = DECODE_RM_LONG_REGISTER(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ bit = *shiftreg & 0x1F;
+ CONDITIONAL_SET_FLAG(*srcreg & (0x1 << bit),F_CF);
+ } else {
+ u16 *srcreg,*shiftreg;
+
+ srcreg = DECODE_RM_WORD_REGISTER(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ bit = *shiftreg & 0xF;
+ CONDITIONAL_SET_FLAG(*srcreg & (0x1 << bit),F_CF);
+ }
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0f,0xa4
+****************************************************************************/
+static void x86emuOp2_shld_IMM(u8 X86EMU_UNUSED(op2))
+{
+ int mod, rl, rh;
+ uint destoffset;
+ u8 shift;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("SHLD\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+ u32 *shiftreg;
+
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ shift = fetch_byte_imm();
+ DECODE_PRINTF2("%d\n", shift);
+ TRACE_AND_STEP();
+ destval = fetch_data_long(destoffset);
+ destval = shld_long(destval,*shiftreg,shift);
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+ u16 *shiftreg;
+
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ shift = fetch_byte_imm();
+ DECODE_PRINTF2("%d\n", shift);
+ TRACE_AND_STEP();
+ destval = fetch_data_word(destoffset);
+ destval = shld_word(destval,*shiftreg,shift);
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 1:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+ u32 *shiftreg;
+
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ shift = fetch_byte_imm();
+ DECODE_PRINTF2("%d\n", shift);
+ TRACE_AND_STEP();
+ destval = fetch_data_long(destoffset);
+ destval = shld_long(destval,*shiftreg,shift);
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+ u16 *shiftreg;
+
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ shift = fetch_byte_imm();
+ DECODE_PRINTF2("%d\n", shift);
+ TRACE_AND_STEP();
+ destval = fetch_data_word(destoffset);
+ destval = shld_word(destval,*shiftreg,shift);
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 2:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+ u32 *shiftreg;
+
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ shift = fetch_byte_imm();
+ DECODE_PRINTF2("%d\n", shift);
+ TRACE_AND_STEP();
+ destval = fetch_data_long(destoffset);
+ destval = shld_long(destval,*shiftreg,shift);
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+ u16 *shiftreg;
+
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ shift = fetch_byte_imm();
+ DECODE_PRINTF2("%d\n", shift);
+ TRACE_AND_STEP();
+ destval = fetch_data_word(destoffset);
+ destval = shld_word(destval,*shiftreg,shift);
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 3: /* register to register */
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg,*shiftreg;
+
+ destreg = DECODE_RM_LONG_REGISTER(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ shift = fetch_byte_imm();
+ DECODE_PRINTF2("%d\n", shift);
+ TRACE_AND_STEP();
+ *destreg = shld_long(*destreg,*shiftreg,shift);
+ } else {
+ u16 *destreg,*shiftreg;
+
+ destreg = DECODE_RM_WORD_REGISTER(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ shift = fetch_byte_imm();
+ DECODE_PRINTF2("%d\n", shift);
+ TRACE_AND_STEP();
+ *destreg = shld_word(*destreg,*shiftreg,shift);
+ }
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0f,0xa5
+****************************************************************************/
+static void x86emuOp2_shld_CL(u8 X86EMU_UNUSED(op2))
+{
+ int mod, rl, rh;
+ uint destoffset;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("SHLD\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+ u32 *shiftreg;
+
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",CL\n");
+ TRACE_AND_STEP();
+ destval = fetch_data_long(destoffset);
+ destval = shld_long(destval,*shiftreg,M.x86.R_CL);
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+ u16 *shiftreg;
+
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",CL\n");
+ TRACE_AND_STEP();
+ destval = fetch_data_word(destoffset);
+ destval = shld_word(destval,*shiftreg,M.x86.R_CL);
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 1:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+ u32 *shiftreg;
+
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",CL\n");
+ TRACE_AND_STEP();
+ destval = fetch_data_long(destoffset);
+ destval = shld_long(destval,*shiftreg,M.x86.R_CL);
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+ u16 *shiftreg;
+
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",CL\n");
+ TRACE_AND_STEP();
+ destval = fetch_data_word(destoffset);
+ destval = shld_word(destval,*shiftreg,M.x86.R_CL);
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 2:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+ u32 *shiftreg;
+
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",CL\n");
+ TRACE_AND_STEP();
+ destval = fetch_data_long(destoffset);
+ destval = shld_long(destval,*shiftreg,M.x86.R_CL);
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+ u16 *shiftreg;
+
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",CL\n");
+ TRACE_AND_STEP();
+ destval = fetch_data_word(destoffset);
+ destval = shld_word(destval,*shiftreg,M.x86.R_CL);
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 3: /* register to register */
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg,*shiftreg;
+
+ destreg = DECODE_RM_LONG_REGISTER(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",CL\n");
+ TRACE_AND_STEP();
+ *destreg = shld_long(*destreg,*shiftreg,M.x86.R_CL);
+ } else {
+ u16 *destreg,*shiftreg;
+
+ destreg = DECODE_RM_WORD_REGISTER(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",CL\n");
+ TRACE_AND_STEP();
+ *destreg = shld_word(*destreg,*shiftreg,M.x86.R_CL);
+ }
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0f,0xa8
+****************************************************************************/
+static void x86emuOp2_push_GS(u8 X86EMU_UNUSED(op2))
+{
+ START_OF_INSTR();
+ DECODE_PRINTF("PUSH\tGS\n");
+ TRACE_AND_STEP();
+ push_word(M.x86.R_GS);
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0f,0xa9
+****************************************************************************/
+static void x86emuOp2_pop_GS(u8 X86EMU_UNUSED(op2))
+{
+ START_OF_INSTR();
+ DECODE_PRINTF("POP\tGS\n");
+ TRACE_AND_STEP();
+ M.x86.R_GS = pop_word();
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+#if 1
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0f,0xab
+****************************************************************************/
+static void x86emuOp2_bts_R(u8 X86EMU_UNUSED(op2))
+{
+ int mod, rl, rh;
+ uint srcoffset;
+ int bit,disp;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("BTS\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 srcval,mask;
+ u32 *shiftreg;
+
+ srcoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ bit = *shiftreg & 0x1F;
+ disp = (s16)*shiftreg >> 5;
+ srcval = fetch_data_long(srcoffset+disp);
+ mask = (0x1 << bit);
+ CONDITIONAL_SET_FLAG(srcval & mask,F_CF);
+ store_data_long(srcoffset+disp, srcval | mask);
+ } else {
+ u16 srcval,mask;
+ u16 *shiftreg;
+
+ srcoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ bit = *shiftreg & 0xF;
+ disp = (s16)*shiftreg >> 4;
+ srcval = fetch_data_word(srcoffset+disp);
+ mask = (u16)(0x1 << bit);
+ CONDITIONAL_SET_FLAG(srcval & mask,F_CF);
+ store_data_word(srcoffset+disp, srcval | mask);
+ }
+ break;
+ case 1:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 srcval,mask;
+ u32 *shiftreg;
+
+ srcoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ bit = *shiftreg & 0x1F;
+ disp = (s16)*shiftreg >> 5;
+ srcval = fetch_data_long(srcoffset+disp);
+ mask = (0x1 << bit);
+ CONDITIONAL_SET_FLAG(srcval & mask,F_CF);
+ store_data_long(srcoffset+disp, srcval | mask);
+ } else {
+ u16 srcval,mask;
+ u16 *shiftreg;
+
+ srcoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ bit = *shiftreg & 0xF;
+ disp = (s16)*shiftreg >> 4;
+ srcval = fetch_data_word(srcoffset+disp);
+ mask = (u16)(0x1 << bit);
+ CONDITIONAL_SET_FLAG(srcval & mask,F_CF);
+ store_data_word(srcoffset+disp, srcval | mask);
+ }
+ break;
+ case 2:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 srcval,mask;
+ u32 *shiftreg;
+
+ srcoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ bit = *shiftreg & 0x1F;
+ disp = (s16)*shiftreg >> 5;
+ srcval = fetch_data_long(srcoffset+disp);
+ mask = (0x1 << bit);
+ CONDITIONAL_SET_FLAG(srcval & mask,F_CF);
+ store_data_long(srcoffset+disp, srcval | mask);
+ } else {
+ u16 srcval,mask;
+ u16 *shiftreg;
+
+ srcoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ bit = *shiftreg & 0xF;
+ disp = (s16)*shiftreg >> 4;
+ srcval = fetch_data_word(srcoffset+disp);
+ mask = (u16)(0x1 << bit);
+ CONDITIONAL_SET_FLAG(srcval & mask,F_CF);
+ store_data_word(srcoffset+disp, srcval | mask);
+ }
+ break;
+ case 3: /* register to register */
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *srcreg,*shiftreg;
+ u32 mask;
+
+ srcreg = DECODE_RM_LONG_REGISTER(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ bit = *shiftreg & 0x1F;
+ mask = (0x1 << bit);
+ CONDITIONAL_SET_FLAG(*srcreg & mask,F_CF);
+ *srcreg |= mask;
+ } else {
+ u16 *srcreg,*shiftreg;
+ u16 mask;
+
+ srcreg = DECODE_RM_WORD_REGISTER(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ bit = *shiftreg & 0xF;
+ mask = (u16)(0x1 << bit);
+ CONDITIONAL_SET_FLAG(*srcreg & mask,F_CF);
+ *srcreg |= mask;
+ }
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+#endif
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0f,0xac
+****************************************************************************/
+static void x86emuOp2_shrd_IMM(u8 X86EMU_UNUSED(op2))
+{
+ int mod, rl, rh;
+ uint destoffset;
+ u8 shift;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("SHLD\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+ u32 *shiftreg;
+
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ shift = fetch_byte_imm();
+ DECODE_PRINTF2("%d\n", shift);
+ TRACE_AND_STEP();
+ destval = fetch_data_long(destoffset);
+ destval = shrd_long(destval,*shiftreg,shift);
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+ u16 *shiftreg;
+
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ shift = fetch_byte_imm();
+ DECODE_PRINTF2("%d\n", shift);
+ TRACE_AND_STEP();
+ destval = fetch_data_word(destoffset);
+ destval = shrd_word(destval,*shiftreg,shift);
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 1:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+ u32 *shiftreg;
+
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ shift = fetch_byte_imm();
+ DECODE_PRINTF2("%d\n", shift);
+ TRACE_AND_STEP();
+ destval = fetch_data_long(destoffset);
+ destval = shrd_long(destval,*shiftreg,shift);
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+ u16 *shiftreg;
+
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ shift = fetch_byte_imm();
+ DECODE_PRINTF2("%d\n", shift);
+ TRACE_AND_STEP();
+ destval = fetch_data_word(destoffset);
+ destval = shrd_word(destval,*shiftreg,shift);
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 2:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+ u32 *shiftreg;
+
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ shift = fetch_byte_imm();
+ DECODE_PRINTF2("%d\n", shift);
+ TRACE_AND_STEP();
+ destval = fetch_data_long(destoffset);
+ destval = shrd_long(destval,*shiftreg,shift);
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+ u16 *shiftreg;
+
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ shift = fetch_byte_imm();
+ DECODE_PRINTF2("%d\n", shift);
+ TRACE_AND_STEP();
+ destval = fetch_data_word(destoffset);
+ destval = shrd_word(destval,*shiftreg,shift);
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 3: /* register to register */
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg,*shiftreg;
+
+ destreg = DECODE_RM_LONG_REGISTER(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ shift = fetch_byte_imm();
+ DECODE_PRINTF2("%d\n", shift);
+ TRACE_AND_STEP();
+ *destreg = shrd_long(*destreg,*shiftreg,shift);
+ } else {
+ u16 *destreg,*shiftreg;
+
+ destreg = DECODE_RM_WORD_REGISTER(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ shift = fetch_byte_imm();
+ DECODE_PRINTF2("%d\n", shift);
+ TRACE_AND_STEP();
+ *destreg = shrd_word(*destreg,*shiftreg,shift);
+ }
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0f,0xad
+****************************************************************************/
+static void x86emuOp2_shrd_CL(u8 X86EMU_UNUSED(op2))
+{
+ int mod, rl, rh;
+ uint destoffset;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("SHLD\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+ u32 *shiftreg;
+
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",CL\n");
+ TRACE_AND_STEP();
+ destval = fetch_data_long(destoffset);
+ destval = shrd_long(destval,*shiftreg,M.x86.R_CL);
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+ u16 *shiftreg;
+
+ destoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",CL\n");
+ TRACE_AND_STEP();
+ destval = fetch_data_word(destoffset);
+ destval = shrd_word(destval,*shiftreg,M.x86.R_CL);
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 1:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+ u32 *shiftreg;
+
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",CL\n");
+ TRACE_AND_STEP();
+ destval = fetch_data_long(destoffset);
+ destval = shrd_long(destval,*shiftreg,M.x86.R_CL);
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+ u16 *shiftreg;
+
+ destoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",CL\n");
+ TRACE_AND_STEP();
+ destval = fetch_data_word(destoffset);
+ destval = shrd_word(destval,*shiftreg,M.x86.R_CL);
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 2:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 destval;
+ u32 *shiftreg;
+
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",CL\n");
+ TRACE_AND_STEP();
+ destval = fetch_data_long(destoffset);
+ destval = shrd_long(destval,*shiftreg,M.x86.R_CL);
+ store_data_long(destoffset, destval);
+ } else {
+ u16 destval;
+ u16 *shiftreg;
+
+ destoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",CL\n");
+ TRACE_AND_STEP();
+ destval = fetch_data_word(destoffset);
+ destval = shrd_word(destval,*shiftreg,M.x86.R_CL);
+ store_data_word(destoffset, destval);
+ }
+ break;
+ case 3: /* register to register */
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg,*shiftreg;
+
+ destreg = DECODE_RM_LONG_REGISTER(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",CL\n");
+ TRACE_AND_STEP();
+ *destreg = shrd_long(*destreg,*shiftreg,M.x86.R_CL);
+ } else {
+ u16 *destreg,*shiftreg;
+
+ destreg = DECODE_RM_WORD_REGISTER(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",CL\n");
+ TRACE_AND_STEP();
+ *destreg = shrd_word(*destreg,*shiftreg,M.x86.R_CL);
+ }
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0f,0xaf
+****************************************************************************/
+static void x86emuOp2_imul_R_RM(u8 X86EMU_UNUSED(op2))
+{
+ int mod, rl, rh;
+ uint srcoffset;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("IMUL\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+ u32 srcval;
+ u32 res_lo,res_hi;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm00_address(rl);
+ srcval = fetch_data_long(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ imul_long_direct(&res_lo,&res_hi,(s32)*destreg,(s32)srcval);
+ if (res_hi != 0) {
+ SET_FLAG(F_CF);
+ SET_FLAG(F_OF);
+ } else {
+ CLEAR_FLAG(F_CF);
+ CLEAR_FLAG(F_OF);
+ }
+ *destreg = (u32)res_lo;
+ } else {
+ u16 *destreg;
+ u16 srcval;
+ u32 res;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm00_address(rl);
+ srcval = fetch_data_word(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ res = (s16)*destreg * (s16)srcval;
+ if (res > 0xFFFF) {
+ SET_FLAG(F_CF);
+ SET_FLAG(F_OF);
+ } else {
+ CLEAR_FLAG(F_CF);
+ CLEAR_FLAG(F_OF);
+ }
+ *destreg = (u16)res;
+ }
+ break;
+ case 1:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+ u32 srcval;
+ u32 res_lo,res_hi;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm01_address(rl);
+ srcval = fetch_data_long(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ imul_long_direct(&res_lo,&res_hi,(s32)*destreg,(s32)srcval);
+ if (res_hi != 0) {
+ SET_FLAG(F_CF);
+ SET_FLAG(F_OF);
+ } else {
+ CLEAR_FLAG(F_CF);
+ CLEAR_FLAG(F_OF);
+ }
+ *destreg = (u32)res_lo;
+ } else {
+ u16 *destreg;
+ u16 srcval;
+ u32 res;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm01_address(rl);
+ srcval = fetch_data_word(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ res = (s16)*destreg * (s16)srcval;
+ if (res > 0xFFFF) {
+ SET_FLAG(F_CF);
+ SET_FLAG(F_OF);
+ } else {
+ CLEAR_FLAG(F_CF);
+ CLEAR_FLAG(F_OF);
+ }
+ *destreg = (u16)res;
+ }
+ break;
+ case 2:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+ u32 srcval;
+ u32 res_lo,res_hi;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm10_address(rl);
+ srcval = fetch_data_long(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ imul_long_direct(&res_lo,&res_hi,(s32)*destreg,(s32)srcval);
+ if (res_hi != 0) {
+ SET_FLAG(F_CF);
+ SET_FLAG(F_OF);
+ } else {
+ CLEAR_FLAG(F_CF);
+ CLEAR_FLAG(F_OF);
+ }
+ *destreg = (u32)res_lo;
+ } else {
+ u16 *destreg;
+ u16 srcval;
+ u32 res;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm10_address(rl);
+ srcval = fetch_data_word(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ res = (s16)*destreg * (s16)srcval;
+ if (res > 0xFFFF) {
+ SET_FLAG(F_CF);
+ SET_FLAG(F_OF);
+ } else {
+ CLEAR_FLAG(F_CF);
+ CLEAR_FLAG(F_OF);
+ }
+ *destreg = (u16)res;
+ }
+ break;
+ case 3: /* register to register */
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg,*srcreg;
+ u32 res_lo,res_hi;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_LONG_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ imul_long_direct(&res_lo,&res_hi,(s32)*destreg,(s32)*srcreg);
+ if (res_hi != 0) {
+ SET_FLAG(F_CF);
+ SET_FLAG(F_OF);
+ } else {
+ CLEAR_FLAG(F_CF);
+ CLEAR_FLAG(F_OF);
+ }
+ *destreg = (u32)res_lo;
+ } else {
+ u16 *destreg,*srcreg;
+ u32 res;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_WORD_REGISTER(rl);
+ res = (s16)*destreg * (s16)*srcreg;
+ if (res > 0xFFFF) {
+ SET_FLAG(F_CF);
+ SET_FLAG(F_OF);
+ } else {
+ CLEAR_FLAG(F_CF);
+ CLEAR_FLAG(F_OF);
+ }
+ *destreg = (u16)res;
+ }
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0f,0xb2
+****************************************************************************/
+static void x86emuOp2_lss_R_IMM(u8 X86EMU_UNUSED(op2))
+{
+ int mod, rh, rl;
+ u16 *dstreg;
+ uint srcoffset;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("LSS\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ dstreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm00_address(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *dstreg = fetch_data_word(srcoffset);
+ M.x86.R_SS = fetch_data_word(srcoffset + 2);
+ break;
+ case 1:
+ dstreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm01_address(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *dstreg = fetch_data_word(srcoffset);
+ M.x86.R_SS = fetch_data_word(srcoffset + 2);
+ break;
+ case 2:
+ dstreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm10_address(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *dstreg = fetch_data_word(srcoffset);
+ M.x86.R_SS = fetch_data_word(srcoffset + 2);
+ break;
+ case 3: /* register to register */
+ /* UNDEFINED! */
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0f,0xb3
+****************************************************************************/
+static void x86emuOp2_btr_R(u8 X86EMU_UNUSED(op2))
+{
+ int mod, rl, rh;
+ uint srcoffset;
+ int bit,disp;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("BTR\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 srcval,mask;
+ u32 *shiftreg;
+
+ srcoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ bit = *shiftreg & 0x1F;
+ disp = (s16)*shiftreg >> 5;
+ srcval = fetch_data_long(srcoffset+disp);
+ mask = (0x1 << bit);
+ CONDITIONAL_SET_FLAG(srcval & mask,F_CF);
+ store_data_long(srcoffset+disp, srcval & ~mask);
+ } else {
+ u16 srcval,mask;
+ u16 *shiftreg;
+
+ srcoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ bit = *shiftreg & 0xF;
+ disp = (s16)*shiftreg >> 4;
+ srcval = fetch_data_word(srcoffset+disp);
+ mask = (u16)(0x1 << bit);
+ CONDITIONAL_SET_FLAG(srcval & mask,F_CF);
+ store_data_word(srcoffset+disp, (u16)(srcval & ~mask));
+ }
+ break;
+ case 1:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 srcval,mask;
+ u32 *shiftreg;
+
+ srcoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ bit = *shiftreg & 0x1F;
+ disp = (s16)*shiftreg >> 5;
+ srcval = fetch_data_long(srcoffset+disp);
+ mask = (0x1 << bit);
+ CONDITIONAL_SET_FLAG(srcval & mask,F_CF);
+ store_data_long(srcoffset+disp, srcval & ~mask);
+ } else {
+ u16 srcval,mask;
+ u16 *shiftreg;
+
+ srcoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ bit = *shiftreg & 0xF;
+ disp = (s16)*shiftreg >> 4;
+ srcval = fetch_data_word(srcoffset+disp);
+ mask = (u16)(0x1 << bit);
+ CONDITIONAL_SET_FLAG(srcval & mask,F_CF);
+ store_data_word(srcoffset+disp, (u16)(srcval & ~mask));
+ }
+ break;
+ case 2:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 srcval,mask;
+ u32 *shiftreg;
+
+ srcoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ bit = *shiftreg & 0x1F;
+ disp = (s16)*shiftreg >> 5;
+ srcval = fetch_data_long(srcoffset+disp);
+ mask = (0x1 << bit);
+ CONDITIONAL_SET_FLAG(srcval & mask,F_CF);
+ store_data_long(srcoffset+disp, srcval & ~mask);
+ } else {
+ u16 srcval,mask;
+ u16 *shiftreg;
+
+ srcoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ bit = *shiftreg & 0xF;
+ disp = (s16)*shiftreg >> 4;
+ srcval = fetch_data_word(srcoffset+disp);
+ mask = (u16)(0x1 << bit);
+ CONDITIONAL_SET_FLAG(srcval & mask,F_CF);
+ store_data_word(srcoffset+disp, (u16)(srcval & ~mask));
+ }
+ break;
+ case 3: /* register to register */
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *srcreg,*shiftreg;
+ u32 mask;
+
+ srcreg = DECODE_RM_LONG_REGISTER(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ bit = *shiftreg & 0x1F;
+ mask = (0x1 << bit);
+ CONDITIONAL_SET_FLAG(*srcreg & mask,F_CF);
+ *srcreg &= ~mask;
+ } else {
+ u16 *srcreg,*shiftreg;
+ u16 mask;
+
+ srcreg = DECODE_RM_WORD_REGISTER(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ bit = *shiftreg & 0xF;
+ mask = (u16)(0x1 << bit);
+ CONDITIONAL_SET_FLAG(*srcreg & mask,F_CF);
+ *srcreg &= ~mask;
+ }
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0f,0xb4
+****************************************************************************/
+static void x86emuOp2_lfs_R_IMM(u8 X86EMU_UNUSED(op2))
+{
+ int mod, rh, rl;
+ u16 *dstreg;
+ uint srcoffset;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("LFS\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ dstreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm00_address(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *dstreg = fetch_data_word(srcoffset);
+ M.x86.R_FS = fetch_data_word(srcoffset + 2);
+ break;
+ case 1:
+ dstreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm01_address(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *dstreg = fetch_data_word(srcoffset);
+ M.x86.R_FS = fetch_data_word(srcoffset + 2);
+ break;
+ case 2:
+ dstreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm10_address(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *dstreg = fetch_data_word(srcoffset);
+ M.x86.R_FS = fetch_data_word(srcoffset + 2);
+ break;
+ case 3: /* register to register */
+ /* UNDEFINED! */
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0f,0xb5
+****************************************************************************/
+static void x86emuOp2_lgs_R_IMM(u8 X86EMU_UNUSED(op2))
+{
+ int mod, rh, rl;
+ u16 *dstreg;
+ uint srcoffset;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("LGS\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ dstreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm00_address(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *dstreg = fetch_data_word(srcoffset);
+ M.x86.R_GS = fetch_data_word(srcoffset + 2);
+ break;
+ case 1:
+ dstreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm01_address(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *dstreg = fetch_data_word(srcoffset);
+ M.x86.R_GS = fetch_data_word(srcoffset + 2);
+ break;
+ case 2:
+ dstreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm10_address(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *dstreg = fetch_data_word(srcoffset);
+ M.x86.R_GS = fetch_data_word(srcoffset + 2);
+ break;
+ case 3: /* register to register */
+ /* UNDEFINED! */
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0f,0xb6
+****************************************************************************/
+static void x86emuOp2_movzx_byte_R_RM(u8 X86EMU_UNUSED(op2))
+{
+ int mod, rl, rh;
+ uint srcoffset;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("MOVZX\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+ u32 srcval;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm00_address(rl);
+ srcval = fetch_data_byte(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = srcval;
+ } else {
+ u16 *destreg;
+ u16 srcval;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm00_address(rl);
+ srcval = fetch_data_byte(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = srcval;
+ }
+ break;
+ case 1:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+ u32 srcval;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm01_address(rl);
+ srcval = fetch_data_byte(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = srcval;
+ } else {
+ u16 *destreg;
+ u16 srcval;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm01_address(rl);
+ srcval = fetch_data_byte(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = srcval;
+ }
+ break;
+ case 2:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+ u32 srcval;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm10_address(rl);
+ srcval = fetch_data_byte(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = srcval;
+ } else {
+ u16 *destreg;
+ u16 srcval;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm10_address(rl);
+ srcval = fetch_data_byte(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = srcval;
+ }
+ break;
+ case 3: /* register to register */
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+ u8 *srcreg;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_BYTE_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = *srcreg;
+ } else {
+ u16 *destreg;
+ u8 *srcreg;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_BYTE_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = *srcreg;
+ }
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0f,0xb7
+****************************************************************************/
+static void x86emuOp2_movzx_word_R_RM(u8 X86EMU_UNUSED(op2))
+{
+ int mod, rl, rh;
+ uint srcoffset;
+ u32 *destreg;
+ u32 srcval;
+ u16 *srcreg;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("MOVZX\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm00_address(rl);
+ srcval = fetch_data_word(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = srcval;
+ break;
+ case 1:
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm01_address(rl);
+ srcval = fetch_data_word(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = srcval;
+ break;
+ case 2:
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm10_address(rl);
+ srcval = fetch_data_word(srcoffset);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = srcval;
+ break;
+ case 3: /* register to register */
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_WORD_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = *srcreg;
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0f,0xba
+****************************************************************************/
+static void x86emuOp2_btX_I(u8 X86EMU_UNUSED(op2))
+{
+ int mod, rl, rh;
+ uint srcoffset;
+ int bit;
+
+ START_OF_INSTR();
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (rh) {
+ case 4:
+ DECODE_PRINTF("BT\t");
+ break;
+ case 5:
+ DECODE_PRINTF("BTS\t");
+ break;
+ case 6:
+ DECODE_PRINTF("BTR\t");
+ break;
+ case 7:
+ DECODE_PRINTF("BTC\t");
+ break;
+ default:
+ DECODE_PRINTF("ILLEGAL EXTENDED X86 OPCODE\n");
+ TRACE_REGS();
+DB( NV_PRINTF(LEVEL_INFO,
+ "%04x:%04x: %02X%02X ILLEGAL EXTENDED X86 OPCODE EXTENSION!\n",
+ M.x86.R_CS, M.x86.R_IP - 3, op2,
+ (mod << 6) | (rh << 3) | rl);)
+ HALT_SYS();
+ }
+ switch (mod) {
+ case 0:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 srcval, mask;
+ u8 shift;
+
+ srcoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ shift = fetch_byte_imm();
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ bit = shift & 0x1F;
+ srcval = fetch_data_long(srcoffset);
+ mask = (0x1 << bit);
+ CONDITIONAL_SET_FLAG(srcval & mask,F_CF);
+ switch (rh) {
+ case 5:
+ store_data_long(srcoffset, srcval | mask);
+ break;
+ case 6:
+ store_data_long(srcoffset, srcval & ~mask);
+ break;
+ case 7:
+ store_data_long(srcoffset, srcval ^ mask);
+ break;
+ default:
+ break;
+ }
+ } else {
+ u16 srcval, mask;
+ u8 shift;
+
+ srcoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ shift = fetch_byte_imm();
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ bit = shift & 0xF;
+ srcval = fetch_data_word(srcoffset);
+ mask = (0x1 << bit);
+ CONDITIONAL_SET_FLAG(srcval & mask,F_CF);
+ switch (rh) {
+ case 5:
+ store_data_word(srcoffset, srcval | mask);
+ break;
+ case 6:
+ store_data_word(srcoffset, srcval & ~mask);
+ break;
+ case 7:
+ store_data_word(srcoffset, srcval ^ mask);
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ case 1:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 srcval, mask;
+ u8 shift;
+
+ srcoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ shift = fetch_byte_imm();
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ bit = shift & 0x1F;
+ srcval = fetch_data_long(srcoffset);
+ mask = (0x1 << bit);
+ CONDITIONAL_SET_FLAG(srcval & mask,F_CF);
+ switch (rh) {
+ case 5:
+ store_data_long(srcoffset, srcval | mask);
+ break;
+ case 6:
+ store_data_long(srcoffset, srcval & ~mask);
+ break;
+ case 7:
+ store_data_long(srcoffset, srcval ^ mask);
+ break;
+ default:
+ break;
+ }
+ } else {
+ u16 srcval, mask;
+ u8 shift;
+
+ srcoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ shift = fetch_byte_imm();
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ bit = shift & 0xF;
+ srcval = fetch_data_word(srcoffset);
+ mask = (0x1 << bit);
+ CONDITIONAL_SET_FLAG(srcval & mask,F_CF);
+ switch (rh) {
+ case 5:
+ store_data_word(srcoffset, srcval | mask);
+ break;
+ case 6:
+ store_data_word(srcoffset, srcval & ~mask);
+ break;
+ case 7:
+ store_data_word(srcoffset, srcval ^ mask);
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ case 2:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 srcval, mask;
+ u8 shift;
+
+ srcoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ shift = fetch_byte_imm();
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ bit = shift & 0x1F;
+ srcval = fetch_data_long(srcoffset);
+ mask = (0x1 << bit);
+ CONDITIONAL_SET_FLAG(srcval & mask,F_CF);
+ switch (rh) {
+ case 5:
+ store_data_long(srcoffset, srcval | mask);
+ break;
+ case 6:
+ store_data_long(srcoffset, srcval & ~mask);
+ break;
+ case 7:
+ store_data_long(srcoffset, srcval ^ mask);
+ break;
+ default:
+ break;
+ }
+ } else {
+ u16 srcval, mask;
+ u8 shift;
+
+ srcoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ shift = fetch_byte_imm();
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ bit = shift & 0xF;
+ srcval = fetch_data_word(srcoffset);
+ mask = (0x1 << bit);
+ CONDITIONAL_SET_FLAG(srcval & mask,F_CF);
+ switch (rh) {
+ case 5:
+ store_data_word(srcoffset, srcval | mask);
+ break;
+ case 6:
+ store_data_word(srcoffset, srcval & ~mask);
+ break;
+ case 7:
+ store_data_word(srcoffset, srcval ^ mask);
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ case 3: /* register to register */
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *srcreg;
+ u32 mask;
+ u8 shift;
+
+ srcreg = DECODE_RM_LONG_REGISTER(rl);
+ DECODE_PRINTF(",");
+ shift = fetch_byte_imm();
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ bit = shift & 0x1F;
+ mask = (0x1 << bit);
+ CONDITIONAL_SET_FLAG(*srcreg & mask,F_CF);
+ switch (rh) {
+ case 5:
+ *srcreg |= mask;
+ break;
+ case 6:
+ *srcreg &= ~mask;
+ break;
+ case 7:
+ *srcreg ^= mask;
+ break;
+ default:
+ break;
+ }
+ } else {
+ u16 *srcreg;
+ u16 mask;
+ u8 shift;
+
+ srcreg = DECODE_RM_WORD_REGISTER(rl);
+ DECODE_PRINTF(",");
+ shift = fetch_byte_imm();
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ bit = shift & 0xF;
+ mask = (0x1 << bit);
+ CONDITIONAL_SET_FLAG(*srcreg & mask,F_CF);
+ switch (rh) {
+ case 5:
+ *srcreg |= mask;
+ break;
+ case 6:
+ *srcreg &= ~mask;
+ break;
+ case 7:
+ *srcreg ^= mask;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0f,0xbb
+****************************************************************************/
+static void x86emuOp2_btc_R(u8 X86EMU_UNUSED(op2))
+{
+ int mod, rl, rh;
+ uint srcoffset;
+ int bit,disp;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("BTC\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 srcval,mask;
+ u32 *shiftreg;
+
+ srcoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ bit = *shiftreg & 0x1F;
+ disp = (s16)*shiftreg >> 5;
+ srcval = fetch_data_long(srcoffset+disp);
+ mask = (0x1 << bit);
+ CONDITIONAL_SET_FLAG(srcval & mask,F_CF);
+ store_data_long(srcoffset+disp, srcval ^ mask);
+ } else {
+ u16 srcval,mask;
+ u16 *shiftreg;
+
+ srcoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ bit = *shiftreg & 0xF;
+ disp = (s16)*shiftreg >> 4;
+ srcval = fetch_data_word(srcoffset+disp);
+ mask = (u16)(0x1 << bit);
+ CONDITIONAL_SET_FLAG(srcval & mask,F_CF);
+ store_data_word(srcoffset+disp, (u16)(srcval ^ mask));
+ }
+ break;
+ case 1:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 srcval,mask;
+ u32 *shiftreg;
+
+ srcoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ bit = *shiftreg & 0x1F;
+ disp = (s16)*shiftreg >> 5;
+ srcval = fetch_data_long(srcoffset+disp);
+ mask = (0x1 << bit);
+ CONDITIONAL_SET_FLAG(srcval & mask,F_CF);
+ store_data_long(srcoffset+disp, srcval ^ mask);
+ } else {
+ u16 srcval,mask;
+ u16 *shiftreg;
+
+ srcoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ bit = *shiftreg & 0xF;
+ disp = (s16)*shiftreg >> 4;
+ srcval = fetch_data_word(srcoffset+disp);
+ mask = (u16)(0x1 << bit);
+ CONDITIONAL_SET_FLAG(srcval & mask,F_CF);
+ store_data_word(srcoffset+disp, (u16)(srcval ^ mask));
+ }
+ break;
+ case 2:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 srcval,mask;
+ u32 *shiftreg;
+
+ srcoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ bit = *shiftreg & 0x1F;
+ disp = (s16)*shiftreg >> 5;
+ srcval = fetch_data_long(srcoffset+disp);
+ mask = (0x1 << bit);
+ CONDITIONAL_SET_FLAG(srcval & mask,F_CF);
+ store_data_long(srcoffset+disp, srcval ^ mask);
+ } else {
+ u16 srcval,mask;
+ u16 *shiftreg;
+
+ srcoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ bit = *shiftreg & 0xF;
+ disp = (s16)*shiftreg >> 4;
+ srcval = fetch_data_word(srcoffset+disp);
+ mask = (u16)(0x1 << bit);
+ CONDITIONAL_SET_FLAG(srcval & mask,F_CF);
+ store_data_word(srcoffset+disp, (u16)(srcval ^ mask));
+ }
+ break;
+ case 3: /* register to register */
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *srcreg,*shiftreg;
+ u32 mask;
+
+ srcreg = DECODE_RM_LONG_REGISTER(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ bit = *shiftreg & 0x1F;
+ mask = (0x1 << bit);
+ CONDITIONAL_SET_FLAG(*srcreg & mask,F_CF);
+ *srcreg ^= mask;
+ } else {
+ u16 *srcreg,*shiftreg;
+ u16 mask;
+
+ srcreg = DECODE_RM_WORD_REGISTER(rl);
+ DECODE_PRINTF(",");
+ shiftreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ bit = *shiftreg & 0xF;
+ mask = (u16)(0x1 << bit);
+ CONDITIONAL_SET_FLAG(*srcreg & mask,F_CF);
+ *srcreg ^= mask;
+ }
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0f,0xbc
+****************************************************************************/
+static void x86emuOp2_bsf(u8 X86EMU_UNUSED(op2))
+{
+ int mod, rl, rh;
+ uint srcoffset;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("BSF\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch(mod) {
+ case 0:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 srcval, *dstreg;
+
+ srcoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ dstreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ srcval = fetch_data_long(srcoffset);
+ CONDITIONAL_SET_FLAG(srcval == 0, F_ZF);
+ for(*dstreg = 0; *dstreg < 32; (*dstreg)++)
+ if ((srcval >> *dstreg) & 1) break;
+ } else {
+ u16 srcval, *dstreg;
+
+ srcoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ dstreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ srcval = fetch_data_word(srcoffset);
+ CONDITIONAL_SET_FLAG(srcval == 0, F_ZF);
+ for(*dstreg = 0; *dstreg < 16; (*dstreg)++)
+ if ((srcval >> *dstreg) & 1) break;
+ }
+ break;
+ case 1:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 srcval, *dstreg;
+
+ srcoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ dstreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ srcval = fetch_data_long(srcoffset);
+ CONDITIONAL_SET_FLAG(srcval == 0, F_ZF);
+ for(*dstreg = 0; *dstreg < 32; (*dstreg)++)
+ if ((srcval >> *dstreg) & 1) break;
+ } else {
+ u16 srcval, *dstreg;
+
+ srcoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ dstreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ srcval = fetch_data_word(srcoffset);
+ CONDITIONAL_SET_FLAG(srcval == 0, F_ZF);
+ for(*dstreg = 0; *dstreg < 16; (*dstreg)++)
+ if ((srcval >> *dstreg) & 1) break;
+ }
+ break;
+ case 2:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 srcval, *dstreg;
+
+ srcoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ dstreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ srcval = fetch_data_long(srcoffset);
+ CONDITIONAL_SET_FLAG(srcval == 0, F_ZF);
+ for(*dstreg = 0; *dstreg < 32; (*dstreg)++)
+ if ((srcval >> *dstreg) & 1) break;
+ } else {
+ u16 srcval, *dstreg;
+
+ srcoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ dstreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ srcval = fetch_data_word(srcoffset);
+ CONDITIONAL_SET_FLAG(srcval == 0, F_ZF);
+ for(*dstreg = 0; *dstreg < 16; (*dstreg)++)
+ if ((srcval >> *dstreg) & 1) break;
+ }
+ break;
+ case 3: /* register to register */
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 srcval, *dstreg;
+
+ srcval = *DECODE_RM_LONG_REGISTER(rl);
+ DECODE_PRINTF(",");
+ dstreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ CONDITIONAL_SET_FLAG(srcval == 0, F_ZF);
+ for(*dstreg = 0; *dstreg < 32; (*dstreg)++)
+ if ((srcval >> *dstreg) & 1) break;
+ } else {
+ u16 srcval, *dstreg;
+
+ srcval = *DECODE_RM_WORD_REGISTER(rl);
+ DECODE_PRINTF(",");
+ dstreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ CONDITIONAL_SET_FLAG(srcval == 0, F_ZF);
+ for(*dstreg = 0; *dstreg < 16; (*dstreg)++)
+ if ((srcval >> *dstreg) & 1) break;
+ }
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0f,0xbd
+****************************************************************************/
+static void x86emuOp2_bsr(u8 X86EMU_UNUSED(op2))
+{
+ int mod, rl, rh;
+ uint srcoffset;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("BSR\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch(mod) {
+ case 0:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 srcval, *dstreg;
+
+ srcoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ dstreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ srcval = fetch_data_long(srcoffset);
+ CONDITIONAL_SET_FLAG(srcval == 0, F_ZF);
+ for(*dstreg = 31; *dstreg > 0; (*dstreg)--)
+ if ((srcval >> *dstreg) & 1) break;
+ } else {
+ u16 srcval, *dstreg;
+
+ srcoffset = decode_rm00_address(rl);
+ DECODE_PRINTF(",");
+ dstreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ srcval = fetch_data_word(srcoffset);
+ CONDITIONAL_SET_FLAG(srcval == 0, F_ZF);
+ for(*dstreg = 15; *dstreg > 0; (*dstreg)--)
+ if ((srcval >> *dstreg) & 1) break;
+ }
+ break;
+ case 1:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 srcval, *dstreg;
+
+ srcoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ dstreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ srcval = fetch_data_long(srcoffset);
+ CONDITIONAL_SET_FLAG(srcval == 0, F_ZF);
+ for(*dstreg = 31; *dstreg > 0; (*dstreg)--)
+ if ((srcval >> *dstreg) & 1) break;
+ } else {
+ u16 srcval, *dstreg;
+
+ srcoffset = decode_rm01_address(rl);
+ DECODE_PRINTF(",");
+ dstreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ srcval = fetch_data_word(srcoffset);
+ CONDITIONAL_SET_FLAG(srcval == 0, F_ZF);
+ for(*dstreg = 15; *dstreg > 0; (*dstreg)--)
+ if ((srcval >> *dstreg) & 1) break;
+ }
+ break;
+ case 2:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 srcval, *dstreg;
+
+ srcoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ dstreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ srcval = fetch_data_long(srcoffset);
+ CONDITIONAL_SET_FLAG(srcval == 0, F_ZF);
+ for(*dstreg = 31; *dstreg > 0; (*dstreg)--)
+ if ((srcval >> *dstreg) & 1) break;
+ } else {
+ u16 srcval, *dstreg;
+
+ srcoffset = decode_rm10_address(rl);
+ DECODE_PRINTF(",");
+ dstreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ srcval = fetch_data_word(srcoffset);
+ CONDITIONAL_SET_FLAG(srcval == 0, F_ZF);
+ for(*dstreg = 15; *dstreg > 0; (*dstreg)--)
+ if ((srcval >> *dstreg) & 1) break;
+ }
+ break;
+ case 3: /* register to register */
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 srcval, *dstreg;
+
+ srcval = *DECODE_RM_LONG_REGISTER(rl);
+ DECODE_PRINTF(",");
+ dstreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ CONDITIONAL_SET_FLAG(srcval == 0, F_ZF);
+ for(*dstreg = 31; *dstreg > 0; (*dstreg)--)
+ if ((srcval >> *dstreg) & 1) break;
+ } else {
+ u16 srcval, *dstreg;
+
+ srcval = *DECODE_RM_WORD_REGISTER(rl);
+ DECODE_PRINTF(",");
+ dstreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ CONDITIONAL_SET_FLAG(srcval == 0, F_ZF);
+ for(*dstreg = 15; *dstreg > 0; (*dstreg)--)
+ if ((srcval >> *dstreg) & 1) break;
+ }
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0f,0xbe
+****************************************************************************/
+static void x86emuOp2_movsx_byte_R_RM(u8 X86EMU_UNUSED(op2))
+{
+ int mod, rl, rh;
+ uint srcoffset;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("MOVSX\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+ u32 srcval;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm00_address(rl);
+ srcval = (s32)((s8)fetch_data_byte(srcoffset));
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = srcval;
+ } else {
+ u16 *destreg;
+ u16 srcval;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm00_address(rl);
+ srcval = (s16)((s8)fetch_data_byte(srcoffset));
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = srcval;
+ }
+ break;
+ case 1:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+ u32 srcval;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm01_address(rl);
+ srcval = (s32)((s8)fetch_data_byte(srcoffset));
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = srcval;
+ } else {
+ u16 *destreg;
+ u16 srcval;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm01_address(rl);
+ srcval = (s16)((s8)fetch_data_byte(srcoffset));
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = srcval;
+ }
+ break;
+ case 2:
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+ u32 srcval;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm10_address(rl);
+ srcval = (s32)((s8)fetch_data_byte(srcoffset));
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = srcval;
+ } else {
+ u16 *destreg;
+ u16 srcval;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm10_address(rl);
+ srcval = (s16)((s8)fetch_data_byte(srcoffset));
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = srcval;
+ }
+ break;
+ case 3: /* register to register */
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ u32 *destreg;
+ u8 *srcreg;
+
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_BYTE_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = (s32)((s8)*srcreg);
+ } else {
+ u16 *destreg;
+ u8 *srcreg;
+
+ destreg = DECODE_RM_WORD_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_BYTE_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = (s16)((s8)*srcreg);
+ }
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0f,0xbf
+****************************************************************************/
+static void x86emuOp2_movsx_word_R_RM(u8 X86EMU_UNUSED(op2))
+{
+ int mod, rl, rh;
+ uint srcoffset;
+ u32 *destreg;
+ u32 srcval;
+ u16 *srcreg;
+
+ START_OF_INSTR();
+ DECODE_PRINTF("MOVSX\t");
+ FETCH_DECODE_MODRM(mod, rh, rl);
+ switch (mod) {
+ case 0:
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm00_address(rl);
+ srcval = (s32)((s16)fetch_data_word(srcoffset));
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = srcval;
+ break;
+ case 1:
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm01_address(rl);
+ srcval = (s32)((s16)fetch_data_word(srcoffset));
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = srcval;
+ break;
+ case 2:
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcoffset = decode_rm10_address(rl);
+ srcval = (s32)((s16)fetch_data_word(srcoffset));
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = srcval;
+ break;
+ case 3: /* register to register */
+ destreg = DECODE_RM_LONG_REGISTER(rh);
+ DECODE_PRINTF(",");
+ srcreg = DECODE_RM_WORD_REGISTER(rl);
+ DECODE_PRINTF("\n");
+ TRACE_AND_STEP();
+ *destreg = (s32)((s16)*srcreg);
+ break;
+ }
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/***************************************************************************
+ * Double byte operation code table:
+ **************************************************************************/
+void (*x86emu_optab2[256])(u8) =
+{
+/* 0x00 */ x86emuOp2_illegal_op, /* Group F (ring 0 PM) */
+/* 0x01 */ x86emuOp2_illegal_op, /* Group G (ring 0 PM) */
+/* 0x02 */ x86emuOp2_illegal_op, /* lar (ring 0 PM) */
+/* 0x03 */ x86emuOp2_illegal_op, /* lsl (ring 0 PM) */
+/* 0x04 */ x86emuOp2_illegal_op,
+/* 0x05 */ x86emuOp2_illegal_op, /* loadall (undocumented) */
+/* 0x06 */ x86emuOp2_illegal_op, /* clts (ring 0 PM) */
+/* 0x07 */ x86emuOp2_illegal_op, /* loadall (undocumented) */
+/* 0x08 */ x86emuOp2_illegal_op, /* invd (ring 0 PM) */
+/* 0x09 */ x86emuOp2_illegal_op, /* wbinvd (ring 0 PM) */
+/* 0x0a */ x86emuOp2_illegal_op,
+/* 0x0b */ x86emuOp2_illegal_op,
+/* 0x0c */ x86emuOp2_illegal_op,
+/* 0x0d */ x86emuOp2_illegal_op,
+/* 0x0e */ x86emuOp2_illegal_op,
+/* 0x0f */ x86emuOp2_illegal_op,
+
+/* 0x10 */ x86emuOp2_illegal_op,
+/* 0x11 */ x86emuOp2_illegal_op,
+/* 0x12 */ x86emuOp2_illegal_op,
+/* 0x13 */ x86emuOp2_illegal_op,
+/* 0x14 */ x86emuOp2_illegal_op,
+/* 0x15 */ x86emuOp2_illegal_op,
+/* 0x16 */ x86emuOp2_illegal_op,
+/* 0x17 */ x86emuOp2_illegal_op,
+/* 0x18 */ x86emuOp2_illegal_op,
+/* 0x19 */ x86emuOp2_illegal_op,
+/* 0x1a */ x86emuOp2_illegal_op,
+/* 0x1b */ x86emuOp2_illegal_op,
+/* 0x1c */ x86emuOp2_illegal_op,
+/* 0x1d */ x86emuOp2_illegal_op,
+/* 0x1e */ x86emuOp2_illegal_op,
+/* 0x1f */ x86emuOp2_illegal_op,
+
+/* 0x20 */ x86emuOp2_illegal_op, /* mov reg32,creg (ring 0 PM) */
+/* 0x21 */ x86emuOp2_illegal_op, /* mov reg32,dreg (ring 0 PM) */
+/* 0x22 */ x86emuOp2_illegal_op, /* mov creg,reg32 (ring 0 PM) */
+/* 0x23 */ x86emuOp2_illegal_op, /* mov dreg,reg32 (ring 0 PM) */
+/* 0x24 */ x86emuOp2_illegal_op, /* mov reg32,treg (ring 0 PM) */
+/* 0x25 */ x86emuOp2_illegal_op,
+/* 0x26 */ x86emuOp2_illegal_op, /* mov treg,reg32 (ring 0 PM) */
+/* 0x27 */ x86emuOp2_illegal_op,
+/* 0x28 */ x86emuOp2_illegal_op,
+/* 0x29 */ x86emuOp2_illegal_op,
+/* 0x2a */ x86emuOp2_illegal_op,
+/* 0x2b */ x86emuOp2_illegal_op,
+/* 0x2c */ x86emuOp2_illegal_op,
+/* 0x2d */ x86emuOp2_illegal_op,
+/* 0x2e */ x86emuOp2_illegal_op,
+/* 0x2f */ x86emuOp2_illegal_op,
+
+/* 0x30 */ x86emuOp2_illegal_op,
+/* 0x31 */ x86emuOp2_illegal_op,
+/* 0x32 */ x86emuOp2_illegal_op,
+/* 0x33 */ x86emuOp2_illegal_op,
+/* 0x34 */ x86emuOp2_illegal_op,
+/* 0x35 */ x86emuOp2_illegal_op,
+/* 0x36 */ x86emuOp2_illegal_op,
+/* 0x37 */ x86emuOp2_illegal_op,
+/* 0x38 */ x86emuOp2_illegal_op,
+/* 0x39 */ x86emuOp2_illegal_op,
+/* 0x3a */ x86emuOp2_illegal_op,
+/* 0x3b */ x86emuOp2_illegal_op,
+/* 0x3c */ x86emuOp2_illegal_op,
+/* 0x3d */ x86emuOp2_illegal_op,
+/* 0x3e */ x86emuOp2_illegal_op,
+/* 0x3f */ x86emuOp2_illegal_op,
+
+/* 0x40 */ x86emuOp2_illegal_op,
+/* 0x41 */ x86emuOp2_illegal_op,
+/* 0x42 */ x86emuOp2_illegal_op,
+/* 0x43 */ x86emuOp2_illegal_op,
+/* 0x44 */ x86emuOp2_illegal_op,
+/* 0x45 */ x86emuOp2_illegal_op,
+/* 0x46 */ x86emuOp2_illegal_op,
+/* 0x47 */ x86emuOp2_illegal_op,
+/* 0x48 */ x86emuOp2_illegal_op,
+/* 0x49 */ x86emuOp2_illegal_op,
+/* 0x4a */ x86emuOp2_illegal_op,
+/* 0x4b */ x86emuOp2_illegal_op,
+/* 0x4c */ x86emuOp2_illegal_op,
+/* 0x4d */ x86emuOp2_illegal_op,
+/* 0x4e */ x86emuOp2_illegal_op,
+/* 0x4f */ x86emuOp2_illegal_op,
+
+/* 0x50 */ x86emuOp2_illegal_op,
+/* 0x51 */ x86emuOp2_illegal_op,
+/* 0x52 */ x86emuOp2_illegal_op,
+/* 0x53 */ x86emuOp2_illegal_op,
+/* 0x54 */ x86emuOp2_illegal_op,
+/* 0x55 */ x86emuOp2_illegal_op,
+/* 0x56 */ x86emuOp2_illegal_op,
+/* 0x57 */ x86emuOp2_illegal_op,
+/* 0x58 */ x86emuOp2_illegal_op,
+/* 0x59 */ x86emuOp2_illegal_op,
+/* 0x5a */ x86emuOp2_illegal_op,
+/* 0x5b */ x86emuOp2_illegal_op,
+/* 0x5c */ x86emuOp2_illegal_op,
+/* 0x5d */ x86emuOp2_illegal_op,
+/* 0x5e */ x86emuOp2_illegal_op,
+/* 0x5f */ x86emuOp2_illegal_op,
+
+/* 0x60 */ x86emuOp2_illegal_op,
+/* 0x61 */ x86emuOp2_illegal_op,
+/* 0x62 */ x86emuOp2_illegal_op,
+/* 0x63 */ x86emuOp2_illegal_op,
+/* 0x64 */ x86emuOp2_illegal_op,
+/* 0x65 */ x86emuOp2_illegal_op,
+/* 0x66 */ x86emuOp2_illegal_op,
+/* 0x67 */ x86emuOp2_illegal_op,
+/* 0x68 */ x86emuOp2_illegal_op,
+/* 0x69 */ x86emuOp2_illegal_op,
+/* 0x6a */ x86emuOp2_illegal_op,
+/* 0x6b */ x86emuOp2_illegal_op,
+/* 0x6c */ x86emuOp2_illegal_op,
+/* 0x6d */ x86emuOp2_illegal_op,
+/* 0x6e */ x86emuOp2_illegal_op,
+/* 0x6f */ x86emuOp2_illegal_op,
+
+/* 0x70 */ x86emuOp2_illegal_op,
+/* 0x71 */ x86emuOp2_illegal_op,
+/* 0x72 */ x86emuOp2_illegal_op,
+/* 0x73 */ x86emuOp2_illegal_op,
+/* 0x74 */ x86emuOp2_illegal_op,
+/* 0x75 */ x86emuOp2_illegal_op,
+/* 0x76 */ x86emuOp2_illegal_op,
+/* 0x77 */ x86emuOp2_illegal_op,
+/* 0x78 */ x86emuOp2_illegal_op,
+/* 0x79 */ x86emuOp2_illegal_op,
+/* 0x7a */ x86emuOp2_illegal_op,
+/* 0x7b */ x86emuOp2_illegal_op,
+/* 0x7c */ x86emuOp2_illegal_op,
+/* 0x7d */ x86emuOp2_illegal_op,
+/* 0x7e */ x86emuOp2_illegal_op,
+/* 0x7f */ x86emuOp2_illegal_op,
+
+/* 0x80 */ x86emuOp2_long_jump,
+/* 0x81 */ x86emuOp2_long_jump,
+/* 0x82 */ x86emuOp2_long_jump,
+/* 0x83 */ x86emuOp2_long_jump,
+/* 0x84 */ x86emuOp2_long_jump,
+/* 0x85 */ x86emuOp2_long_jump,
+/* 0x86 */ x86emuOp2_long_jump,
+/* 0x87 */ x86emuOp2_long_jump,
+/* 0x88 */ x86emuOp2_long_jump,
+/* 0x89 */ x86emuOp2_long_jump,
+/* 0x8a */ x86emuOp2_long_jump,
+/* 0x8b */ x86emuOp2_long_jump,
+/* 0x8c */ x86emuOp2_long_jump,
+/* 0x8d */ x86emuOp2_long_jump,
+/* 0x8e */ x86emuOp2_long_jump,
+/* 0x8f */ x86emuOp2_long_jump,
+
+/* 0x90 */ x86emuOp2_set_byte,
+/* 0x91 */ x86emuOp2_set_byte,
+/* 0x92 */ x86emuOp2_set_byte,
+/* 0x93 */ x86emuOp2_set_byte,
+/* 0x94 */ x86emuOp2_set_byte,
+/* 0x95 */ x86emuOp2_set_byte,
+/* 0x96 */ x86emuOp2_set_byte,
+/* 0x97 */ x86emuOp2_set_byte,
+/* 0x98 */ x86emuOp2_set_byte,
+/* 0x99 */ x86emuOp2_set_byte,
+/* 0x9a */ x86emuOp2_set_byte,
+/* 0x9b */ x86emuOp2_set_byte,
+/* 0x9c */ x86emuOp2_set_byte,
+/* 0x9d */ x86emuOp2_set_byte,
+/* 0x9e */ x86emuOp2_set_byte,
+/* 0x9f */ x86emuOp2_set_byte,
+
+/* 0xa0 */ x86emuOp2_push_FS,
+/* 0xa1 */ x86emuOp2_pop_FS,
+/* 0xa2 */ x86emuOp2_illegal_op,
+/* 0xa3 */ x86emuOp2_bt_R,
+/* 0xa4 */ x86emuOp2_shld_IMM,
+/* 0xa5 */ x86emuOp2_shld_CL,
+/* 0xa6 */ x86emuOp2_illegal_op,
+/* 0xa7 */ x86emuOp2_illegal_op,
+/* 0xa8 */ x86emuOp2_push_GS,
+/* 0xa9 */ x86emuOp2_pop_GS,
+/* 0xaa */ x86emuOp2_illegal_op,
+/* 0xab */ x86emuOp2_bts_R,
+/* 0xac */ x86emuOp2_shrd_IMM,
+/* 0xad */ x86emuOp2_shrd_CL,
+/* 0xae */ x86emuOp2_illegal_op,
+/* 0xaf */ x86emuOp2_imul_R_RM,
+
+/* 0xb0 */ x86emuOp2_illegal_op, /* TODO: cmpxchg */
+/* 0xb1 */ x86emuOp2_illegal_op, /* TODO: cmpxchg */
+/* 0xb2 */ x86emuOp2_lss_R_IMM,
+/* 0xb3 */ x86emuOp2_btr_R,
+/* 0xb4 */ x86emuOp2_lfs_R_IMM,
+/* 0xb5 */ x86emuOp2_lgs_R_IMM,
+/* 0xb6 */ x86emuOp2_movzx_byte_R_RM,
+/* 0xb7 */ x86emuOp2_movzx_word_R_RM,
+/* 0xb8 */ x86emuOp2_illegal_op,
+/* 0xb9 */ x86emuOp2_illegal_op,
+/* 0xba */ x86emuOp2_btX_I,
+/* 0xbb */ x86emuOp2_btc_R,
+/* 0xbc */ x86emuOp2_bsf,
+/* 0xbd */ x86emuOp2_bsr,
+/* 0xbe */ x86emuOp2_movsx_byte_R_RM,
+/* 0xbf */ x86emuOp2_movsx_word_R_RM,
+
+/* 0xc0 */ x86emuOp2_illegal_op, /* TODO: xadd */
+/* 0xc1 */ x86emuOp2_illegal_op, /* TODO: xadd */
+/* 0xc2 */ x86emuOp2_illegal_op,
+/* 0xc3 */ x86emuOp2_illegal_op,
+/* 0xc4 */ x86emuOp2_illegal_op,
+/* 0xc5 */ x86emuOp2_illegal_op,
+/* 0xc6 */ x86emuOp2_illegal_op,
+/* 0xc7 */ x86emuOp2_illegal_op,
+/* 0xc8 */ x86emuOp2_illegal_op, /* TODO: bswap */
+/* 0xc9 */ x86emuOp2_illegal_op, /* TODO: bswap */
+/* 0xca */ x86emuOp2_illegal_op, /* TODO: bswap */
+/* 0xcb */ x86emuOp2_illegal_op, /* TODO: bswap */
+/* 0xcc */ x86emuOp2_illegal_op, /* TODO: bswap */
+/* 0xcd */ x86emuOp2_illegal_op, /* TODO: bswap */
+/* 0xce */ x86emuOp2_illegal_op, /* TODO: bswap */
+/* 0xcf */ x86emuOp2_illegal_op, /* TODO: bswap */
+
+/* 0xd0 */ x86emuOp2_illegal_op,
+/* 0xd1 */ x86emuOp2_illegal_op,
+/* 0xd2 */ x86emuOp2_illegal_op,
+/* 0xd3 */ x86emuOp2_illegal_op,
+/* 0xd4 */ x86emuOp2_illegal_op,
+/* 0xd5 */ x86emuOp2_illegal_op,
+/* 0xd6 */ x86emuOp2_illegal_op,
+/* 0xd7 */ x86emuOp2_illegal_op,
+/* 0xd8 */ x86emuOp2_illegal_op,
+/* 0xd9 */ x86emuOp2_illegal_op,
+/* 0xda */ x86emuOp2_illegal_op,
+/* 0xdb */ x86emuOp2_illegal_op,
+/* 0xdc */ x86emuOp2_illegal_op,
+/* 0xdd */ x86emuOp2_illegal_op,
+/* 0xde */ x86emuOp2_illegal_op,
+/* 0xdf */ x86emuOp2_illegal_op,
+
+/* 0xe0 */ x86emuOp2_illegal_op,
+/* 0xe1 */ x86emuOp2_illegal_op,
+/* 0xe2 */ x86emuOp2_illegal_op,
+/* 0xe3 */ x86emuOp2_illegal_op,
+/* 0xe4 */ x86emuOp2_illegal_op,
+/* 0xe5 */ x86emuOp2_illegal_op,
+/* 0xe6 */ x86emuOp2_illegal_op,
+/* 0xe7 */ x86emuOp2_illegal_op,
+/* 0xe8 */ x86emuOp2_illegal_op,
+/* 0xe9 */ x86emuOp2_illegal_op,
+/* 0xea */ x86emuOp2_illegal_op,
+/* 0xeb */ x86emuOp2_illegal_op,
+/* 0xec */ x86emuOp2_illegal_op,
+/* 0xed */ x86emuOp2_illegal_op,
+/* 0xee */ x86emuOp2_illegal_op,
+/* 0xef */ x86emuOp2_illegal_op,
+
+/* 0xf0 */ x86emuOp2_illegal_op,
+/* 0xf1 */ x86emuOp2_illegal_op,
+/* 0xf2 */ x86emuOp2_illegal_op,
+/* 0xf3 */ x86emuOp2_illegal_op,
+/* 0xf4 */ x86emuOp2_illegal_op,
+/* 0xf5 */ x86emuOp2_illegal_op,
+/* 0xf6 */ x86emuOp2_illegal_op,
+/* 0xf7 */ x86emuOp2_illegal_op,
+/* 0xf8 */ x86emuOp2_illegal_op,
+/* 0xf9 */ x86emuOp2_illegal_op,
+/* 0xfa */ x86emuOp2_illegal_op,
+/* 0xfb */ x86emuOp2_illegal_op,
+/* 0xfc */ x86emuOp2_illegal_op,
+/* 0xfd */ x86emuOp2_illegal_op,
+/* 0xfe */ x86emuOp2_illegal_op,
+/* 0xff */ x86emuOp2_illegal_op,
+};
diff --git a/userspace/sdks/nv570/nvalloc/unix/x86emu/prim_ops.c b/userspace/sdks/nv570/nvalloc/unix/x86emu/prim_ops.c
new file mode 100644
index 0000000..27c1948
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/x86emu/prim_ops.c
@@ -0,0 +1,2655 @@
+/****************************************************************************
+*
+* Realmode X86 Emulator Library
+*
+* Copyright (C) 1996-1999 SciTech Software, Inc.
+* Copyright (C) David Mosberger-Tang
+* Copyright (C) 1999 Egbert Eich
+*
+* ========================================================================
+*
+* Permission to use, copy, modify, distribute, and sell this software and
+* its documentation for any purpose is hereby granted without fee,
+* provided that the above copyright notice appear in all copies and that
+* both that copyright notice and this permission notice appear in
+* supporting documentation, and that the name of the authors not be used
+* in advertising or publicity pertaining to distribution of the software
+* without specific, written prior permission. The authors makes no
+* representations about the suitability of this software for any purpose.
+* It is provided "as is" without express or implied warranty.
+*
+* THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+* EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+* PERFORMANCE OF THIS SOFTWARE.
+*
+* ========================================================================
+*
+* Language: ANSI C
+* Environment: Any
+* Developer: Kendall Bennett
+*
+* Description: This file contains the code to implement the primitive
+* machine operations used by the emulation code in ops.c
+*
+* Carry Chain Calculation
+*
+* This represents a somewhat expensive calculation which is
+* apparently required to emulate the setting of the OF and AF flag.
+* The latter is not so important, but the former is. The overflow
+* flag is the XOR of the top two bits of the carry chain for an
+* addition (similar for subtraction). Since we do not want to
+* simulate the addition in a bitwise manner, we try to calculate the
+* carry chain given the two operands and the result.
+*
+* So, given the following table, which represents the addition of two
+* bits, we can derive a formula for the carry chain.
+*
+* a b cin r cout
+* 0 0 0 0 0
+* 0 0 1 1 0
+* 0 1 0 1 0
+* 0 1 1 0 1
+* 1 0 0 1 0
+* 1 0 1 0 1
+* 1 1 0 0 1
+* 1 1 1 1 1
+*
+* Construction of table for cout:
+*
+* ab
+* r \ 00 01 11 10
+* |------------------
+* 0 | 0 1 1 1
+* 1 | 0 0 1 0
+*
+* By inspection, one gets: cc = ab + r'(a + b)
+*
+* That represents alot of operations, but NO CHOICE....
+*
+* Borrow Chain Calculation.
+*
+* The following table represents the subtraction of two bits, from
+* which we can derive a formula for the borrow chain.
+*
+* a b bin r bout
+* 0 0 0 0 0
+* 0 0 1 1 1
+* 0 1 0 1 1
+* 0 1 1 0 1
+* 1 0 0 1 0
+* 1 0 1 0 0
+* 1 1 0 0 0
+* 1 1 1 1 1
+*
+* Construction of table for cout:
+*
+* ab
+* r \ 00 01 11 10
+* |------------------
+* 0 | 0 1 0 0
+* 1 | 1 1 1 0
+*
+* By inspection, one gets: bc = a'b + r(a' + b)
+*
+****************************************************************************/
+
+#define PRIM_OPS_NO_REDEFINE_ASM
+#include "x86emu/x86emui.h"
+
+/*------------------------- Global Variables ------------------------------*/
+
+static u32 x86emu_parity_tab[8] =
+{
+ 0x96696996,
+ 0x69969669,
+ 0x69969669,
+ 0x96696996,
+ 0x69969669,
+ 0x96696996,
+ 0x96696996,
+ 0x69969669,
+};
+
+#define PARITY(x) (((x86emu_parity_tab[(x) / 32] >> ((x) % 32)) & 1) == 0)
+#define XOR2(x) (((x) ^ ((x)>>1)) & 0x1)
+
+/*----------------------------- Implementation ----------------------------*/
+
+/****************************************************************************
+REMARKS:
+Implements the AAA instruction and side effects.
+****************************************************************************/
+u16 aaa_word(u16 d)
+{
+ u16 res;
+ if ((d & 0xf) > 0x9 || ACCESS_FLAG(F_AF)) {
+ d += 0x6;
+ d += 0x100;
+ SET_FLAG(F_AF);
+ SET_FLAG(F_CF);
+ } else {
+ CLEAR_FLAG(F_CF);
+ CLEAR_FLAG(F_AF);
+ }
+ res = (u16)(d & 0xFF0F);
+ CLEAR_FLAG(F_SF);
+ CONDITIONAL_SET_FLAG(res == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+ return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the AAA instruction and side effects.
+****************************************************************************/
+u16 aas_word(u16 d)
+{
+ u16 res;
+ if ((d & 0xf) > 0x9 || ACCESS_FLAG(F_AF)) {
+ d -= 0x6;
+ d -= 0x100;
+ SET_FLAG(F_AF);
+ SET_FLAG(F_CF);
+ } else {
+ CLEAR_FLAG(F_CF);
+ CLEAR_FLAG(F_AF);
+ }
+ res = (u16)(d & 0xFF0F);
+ CLEAR_FLAG(F_SF);
+ CONDITIONAL_SET_FLAG(res == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+ return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the AAD instruction and side effects.
+****************************************************************************/
+u16 aad_word(u16 d)
+{
+ u16 l;
+ u8 hb, lb;
+
+ hb = (u8)((d >> 8) & 0xff);
+ lb = (u8)((d & 0xff));
+ l = (u16)((lb + 10 * hb) & 0xFF);
+
+ CLEAR_FLAG(F_CF);
+ CLEAR_FLAG(F_AF);
+ CLEAR_FLAG(F_OF);
+ CONDITIONAL_SET_FLAG(l & 0x80, F_SF);
+ CONDITIONAL_SET_FLAG(l == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(PARITY(l & 0xff), F_PF);
+ return l;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the AAM instruction and side effects.
+****************************************************************************/
+u16 aam_word(u8 d)
+{
+ u16 h, l;
+
+ h = (u16)(d / 10);
+ l = (u16)(d % 10);
+ l |= (u16)(h << 8);
+
+ CLEAR_FLAG(F_CF);
+ CLEAR_FLAG(F_AF);
+ CLEAR_FLAG(F_OF);
+ CONDITIONAL_SET_FLAG(l & 0x80, F_SF);
+ CONDITIONAL_SET_FLAG(l == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(PARITY(l & 0xff), F_PF);
+ return l;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the ADC instruction and side effects.
+****************************************************************************/
+u8 adc_byte(u8 d, u8 s)
+{
+ register u32 res; /* all operands in native machine order */
+ register u32 cc;
+
+ if (ACCESS_FLAG(F_CF))
+ res = 1 + d + s;
+ else
+ res = d + s;
+
+ CONDITIONAL_SET_FLAG(res & 0x100, F_CF);
+ CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
+ CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+
+ /* calculate the carry chain SEE NOTE AT TOP. */
+ cc = (s & d) | ((~res) & (s | d));
+ CONDITIONAL_SET_FLAG(XOR2(cc >> 6), F_OF);
+ CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
+ return (u8)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the ADC instruction and side effects.
+****************************************************************************/
+u16 adc_word(u16 d, u16 s)
+{
+ register u32 res; /* all operands in native machine order */
+ register u32 cc;
+
+ if (ACCESS_FLAG(F_CF))
+ res = 1 + d + s;
+ else
+ res = d + s;
+
+ CONDITIONAL_SET_FLAG(res & 0x10000, F_CF);
+ CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
+ CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+
+ /* calculate the carry chain SEE NOTE AT TOP. */
+ cc = (s & d) | ((~res) & (s | d));
+ CONDITIONAL_SET_FLAG(XOR2(cc >> 14), F_OF);
+ CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
+ return (u16)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the ADC instruction and side effects.
+****************************************************************************/
+u32 adc_long(u32 d, u32 s)
+{
+ register u32 lo; /* all operands in native machine order */
+ register u32 hi;
+ register u32 res;
+ register u32 cc;
+
+ if (ACCESS_FLAG(F_CF)) {
+ lo = 1 + (d & 0xFFFF) + (s & 0xFFFF);
+ res = 1 + d + s;
+ }
+ else {
+ lo = (d & 0xFFFF) + (s & 0xFFFF);
+ res = d + s;
+ }
+ hi = (lo >> 16) + (d >> 16) + (s >> 16);
+
+ CONDITIONAL_SET_FLAG(hi & 0x10000, F_CF);
+ CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
+ CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+
+ /* calculate the carry chain SEE NOTE AT TOP. */
+ cc = (s & d) | ((~res) & (s | d));
+ CONDITIONAL_SET_FLAG(XOR2(cc >> 30), F_OF);
+ CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
+ return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the ADD instruction and side effects.
+****************************************************************************/
+u8 add_byte(u8 d, u8 s)
+{
+ register u32 res; /* all operands in native machine order */
+ register u32 cc;
+
+ res = d + s;
+ CONDITIONAL_SET_FLAG(res & 0x100, F_CF);
+ CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
+ CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+
+ /* calculate the carry chain SEE NOTE AT TOP. */
+ cc = (s & d) | ((~res) & (s | d));
+ CONDITIONAL_SET_FLAG(XOR2(cc >> 6), F_OF);
+ CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
+ return (u8)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the ADD instruction and side effects.
+****************************************************************************/
+u16 add_word(u16 d, u16 s)
+{
+ register u32 res; /* all operands in native machine order */
+ register u32 cc;
+
+ res = d + s;
+ CONDITIONAL_SET_FLAG(res & 0x10000, F_CF);
+ CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
+ CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+
+ /* calculate the carry chain SEE NOTE AT TOP. */
+ cc = (s & d) | ((~res) & (s | d));
+ CONDITIONAL_SET_FLAG(XOR2(cc >> 14), F_OF);
+ CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
+ return (u16)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the ADD instruction and side effects.
+****************************************************************************/
+u32 add_long(u32 d, u32 s)
+{
+ register u32 lo; /* all operands in native machine order */
+ register u32 hi;
+ register u32 res;
+ register u32 cc;
+
+ lo = (d & 0xFFFF) + (s & 0xFFFF);
+ res = d + s;
+ hi = (lo >> 16) + (d >> 16) + (s >> 16);
+
+ CONDITIONAL_SET_FLAG(hi & 0x10000, F_CF);
+ CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
+ CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+
+ /* calculate the carry chain SEE NOTE AT TOP. */
+ cc = (s & d) | ((~res) & (s | d));
+ CONDITIONAL_SET_FLAG(XOR2(cc >> 30), F_OF);
+ CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
+
+ return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the AND instruction and side effects.
+****************************************************************************/
+u8 and_byte(u8 d, u8 s)
+{
+ register u8 res; /* all operands in native machine order */
+
+ res = d & s;
+
+ /* set the flags */
+ CLEAR_FLAG(F_OF);
+ CLEAR_FLAG(F_CF);
+ CLEAR_FLAG(F_AF);
+ CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
+ CONDITIONAL_SET_FLAG(res == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(PARITY(res), F_PF);
+ return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the AND instruction and side effects.
+****************************************************************************/
+u16 and_word(u16 d, u16 s)
+{
+ register u16 res; /* all operands in native machine order */
+
+ res = d & s;
+
+ /* set the flags */
+ CLEAR_FLAG(F_OF);
+ CLEAR_FLAG(F_CF);
+ CLEAR_FLAG(F_AF);
+ CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
+ CONDITIONAL_SET_FLAG(res == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+ return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the AND instruction and side effects.
+****************************************************************************/
+u32 and_long(u32 d, u32 s)
+{
+ register u32 res; /* all operands in native machine order */
+
+ res = d & s;
+
+ /* set the flags */
+ CLEAR_FLAG(F_OF);
+ CLEAR_FLAG(F_CF);
+ CLEAR_FLAG(F_AF);
+ CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
+ CONDITIONAL_SET_FLAG(res == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+ return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the CMP instruction and side effects.
+****************************************************************************/
+u8 cmp_byte(u8 d, u8 s)
+{
+ register u32 res; /* all operands in native machine order */
+ register u32 bc;
+
+ res = d - s;
+ CLEAR_FLAG(F_CF);
+ CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
+ CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+
+ /* calculate the borrow chain. See note at top */
+ bc = (res & (~d | s)) | (~d & s);
+ CONDITIONAL_SET_FLAG(bc & 0x80, F_CF);
+ CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF);
+ CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
+ return d;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the CMP instruction and side effects.
+****************************************************************************/
+u16 cmp_word(u16 d, u16 s)
+{
+ register u32 res; /* all operands in native machine order */
+ register u32 bc;
+
+ res = d - s;
+ CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
+ CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+
+ /* calculate the borrow chain. See note at top */
+ bc = (res & (~d | s)) | (~d & s);
+ CONDITIONAL_SET_FLAG(bc & 0x8000, F_CF);
+ CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF);
+ CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
+ return d;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the CMP instruction and side effects.
+****************************************************************************/
+u32 cmp_long(u32 d, u32 s)
+{
+ register u32 res; /* all operands in native machine order */
+ register u32 bc;
+
+ res = d - s;
+ CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
+ CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+
+ /* calculate the borrow chain. See note at top */
+ bc = (res & (~d | s)) | (~d & s);
+ CONDITIONAL_SET_FLAG(bc & 0x80000000, F_CF);
+ CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF);
+ CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
+ return d;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the DAA instruction and side effects.
+****************************************************************************/
+u8 daa_byte(u8 d)
+{
+ u32 res = d;
+ if ((d & 0xf) > 9 || ACCESS_FLAG(F_AF)) {
+ res += 6;
+ SET_FLAG(F_AF);
+ }
+ if (res > 0x9F || ACCESS_FLAG(F_CF)) {
+ res += 0x60;
+ SET_FLAG(F_CF);
+ }
+ CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
+ CONDITIONAL_SET_FLAG((res & 0xFF) == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+ return (u8)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the DAS instruction and side effects.
+****************************************************************************/
+u8 das_byte(u8 d)
+{
+ if ((d & 0xf) > 9 || ACCESS_FLAG(F_AF)) {
+ d -= 6;
+ SET_FLAG(F_AF);
+ }
+ if (d > 0x9F || ACCESS_FLAG(F_CF)) {
+ d -= 0x60;
+ SET_FLAG(F_CF);
+ }
+ CONDITIONAL_SET_FLAG(d & 0x80, F_SF);
+ CONDITIONAL_SET_FLAG(d == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(PARITY(d & 0xff), F_PF);
+ return d;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the DEC instruction and side effects.
+****************************************************************************/
+u8 dec_byte(u8 d)
+{
+ register u32 res; /* all operands in native machine order */
+ register u32 bc;
+
+ res = d - 1;
+ CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
+ CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+
+ /* calculate the borrow chain. See note at top */
+ /* based on sub_byte, uses s==1. */
+ bc = (res & (~d | 1)) | (~d & 1);
+ /* carry flag unchanged */
+ CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF);
+ CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
+ return (u8)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the DEC instruction and side effects.
+****************************************************************************/
+u16 dec_word(u16 d)
+{
+ register u32 res; /* all operands in native machine order */
+ register u32 bc;
+
+ res = d - 1;
+ CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
+ CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+
+ /* calculate the borrow chain. See note at top */
+ /* based on the sub_byte routine, with s==1 */
+ bc = (res & (~d | 1)) | (~d & 1);
+ /* carry flag unchanged */
+ CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF);
+ CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
+ return (u16)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the DEC instruction and side effects.
+****************************************************************************/
+u32 dec_long(u32 d)
+{
+ register u32 res; /* all operands in native machine order */
+ register u32 bc;
+
+ res = d - 1;
+
+ CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
+ CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+
+ /* calculate the borrow chain. See note at top */
+ bc = (res & (~d | 1)) | (~d & 1);
+ /* carry flag unchanged */
+ CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF);
+ CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
+ return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the INC instruction and side effects.
+****************************************************************************/
+u8 inc_byte(u8 d)
+{
+ register u32 res; /* all operands in native machine order */
+ register u32 cc;
+
+ res = d + 1;
+ CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
+ CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+
+ /* calculate the carry chain SEE NOTE AT TOP. */
+ cc = ((1 & d) | (~res)) & (1 | d);
+ CONDITIONAL_SET_FLAG(XOR2(cc >> 6), F_OF);
+ CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
+ return (u8)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the INC instruction and side effects.
+****************************************************************************/
+u16 inc_word(u16 d)
+{
+ register u32 res; /* all operands in native machine order */
+ register u32 cc;
+
+ res = d + 1;
+ CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
+ CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+
+ /* calculate the carry chain SEE NOTE AT TOP. */
+ cc = (1 & d) | ((~res) & (1 | d));
+ CONDITIONAL_SET_FLAG(XOR2(cc >> 14), F_OF);
+ CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
+ return (u16)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the INC instruction and side effects.
+****************************************************************************/
+u32 inc_long(u32 d)
+{
+ register u32 res; /* all operands in native machine order */
+ register u32 cc;
+
+ res = d + 1;
+ CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
+ CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+
+ /* calculate the carry chain SEE NOTE AT TOP. */
+ cc = (1 & d) | ((~res) & (1 | d));
+ CONDITIONAL_SET_FLAG(XOR2(cc >> 30), F_OF);
+ CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
+ return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the OR instruction and side effects.
+****************************************************************************/
+u8 or_byte(u8 d, u8 s)
+{
+ register u8 res; /* all operands in native machine order */
+
+ res = d | s;
+ CLEAR_FLAG(F_OF);
+ CLEAR_FLAG(F_CF);
+ CLEAR_FLAG(F_AF);
+ CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
+ CONDITIONAL_SET_FLAG(res == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(PARITY(res), F_PF);
+ return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the OR instruction and side effects.
+****************************************************************************/
+u16 or_word(u16 d, u16 s)
+{
+ register u16 res; /* all operands in native machine order */
+
+ res = d | s;
+ /* set the carry flag to be bit 8 */
+ CLEAR_FLAG(F_OF);
+ CLEAR_FLAG(F_CF);
+ CLEAR_FLAG(F_AF);
+ CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
+ CONDITIONAL_SET_FLAG(res == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+ return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the OR instruction and side effects.
+****************************************************************************/
+u32 or_long(u32 d, u32 s)
+{
+ register u32 res; /* all operands in native machine order */
+
+ res = d | s;
+
+ /* set the carry flag to be bit 8 */
+ CLEAR_FLAG(F_OF);
+ CLEAR_FLAG(F_CF);
+ CLEAR_FLAG(F_AF);
+ CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
+ CONDITIONAL_SET_FLAG(res == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+ return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the OR instruction and side effects.
+****************************************************************************/
+u8 neg_byte(u8 s)
+{
+ register u8 res;
+ register u8 bc;
+
+ CONDITIONAL_SET_FLAG(s != 0, F_CF);
+ res = (u8)-s;
+ CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
+ CONDITIONAL_SET_FLAG(PARITY(res), F_PF);
+ /* calculate the borrow chain --- modified such that d=0.
+ substitutiing d=0 into bc= res&(~d|s)|(~d&s);
+ (the one used for sub) and simplifying, since ~d=0xff...,
+ ~d|s == 0xffff..., and res&0xfff... == res. Similarly
+ ~d&s == s. So the simplified result is: */
+ bc = res | s;
+ CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF);
+ CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
+ return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the OR instruction and side effects.
+****************************************************************************/
+u16 neg_word(u16 s)
+{
+ register u16 res;
+ register u16 bc;
+
+ CONDITIONAL_SET_FLAG(s != 0, F_CF);
+ res = (u16)-s;
+ CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
+ CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+
+ /* calculate the borrow chain --- modified such that d=0.
+ substitutiing d=0 into bc= res&(~d|s)|(~d&s);
+ (the one used for sub) and simplifying, since ~d=0xff...,
+ ~d|s == 0xffff..., and res&0xfff... == res. Similarly
+ ~d&s == s. So the simplified result is: */
+ bc = res | s;
+ CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF);
+ CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
+ return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the OR instruction and side effects.
+****************************************************************************/
+u32 neg_long(u32 s)
+{
+ register u32 res;
+ register u32 bc;
+
+ CONDITIONAL_SET_FLAG(s != 0, F_CF);
+ res = (u32)-s;
+ CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
+ CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+
+ /* calculate the borrow chain --- modified such that d=0.
+ substitutiing d=0 into bc= res&(~d|s)|(~d&s);
+ (the one used for sub) and simplifying, since ~d=0xff...,
+ ~d|s == 0xffff..., and res&0xfff... == res. Similarly
+ ~d&s == s. So the simplified result is: */
+ bc = res | s;
+ CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF);
+ CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
+ return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the NOT instruction and side effects.
+****************************************************************************/
+u8 not_byte(u8 s)
+{
+ return ~s;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the NOT instruction and side effects.
+****************************************************************************/
+u16 not_word(u16 s)
+{
+ return ~s;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the NOT instruction and side effects.
+****************************************************************************/
+u32 not_long(u32 s)
+{
+ return ~s;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the RCL instruction and side effects.
+****************************************************************************/
+u8 rcl_byte(u8 d, u8 s)
+{
+ register unsigned int res, cnt, mask, cf;
+
+ /* s is the rotate distance. It varies from 0 - 8. */
+ /* have
+
+ CF B_7 B_6 B_5 B_4 B_3 B_2 B_1 B_0
+
+ want to rotate through the carry by "s" bits. We could
+ loop, but that's inefficient. So the width is 9,
+ and we split into three parts:
+
+ The new carry flag (was B_n)
+ the stuff in B_n-1 .. B_0
+ the stuff in B_7 .. B_n+1
+
+ The new rotate is done mod 9, and given this,
+ for a rotation of n bits (mod 9) the new carry flag is
+ then located n bits from the MSB. The low part is
+ then shifted up cnt bits, and the high part is or'd
+ in. Using CAPS for new values, and lowercase for the
+ original values, this can be expressed as:
+
+ IF n > 0
+ 1) CF <- b_(8-n)
+ 2) B_(7) .. B_(n) <- b_(8-(n+1)) .. b_0
+ 3) B_(n-1) <- cf
+ 4) B_(n-2) .. B_0 <- b_7 .. b_(8-(n-1))
+ */
+ res = d;
+ if ((cnt = s % 9) != 0) {
+ /* extract the new CARRY FLAG. */
+ /* CF <- b_(8-n) */
+ cf = (d >> (8 - cnt)) & 0x1;
+
+ /* get the low stuff which rotated
+ into the range B_7 .. B_cnt */
+ /* B_(7) .. B_(n) <- b_(8-(n+1)) .. b_0 */
+ /* note that the right hand side done by the mask */
+ res = (d << cnt) & 0xff;
+
+ /* now the high stuff which rotated around
+ into the positions B_cnt-2 .. B_0 */
+ /* B_(n-2) .. B_0 <- b_7 .. b_(8-(n-1)) */
+ /* shift it downward, 7-(n-2) = 9-n positions.
+ and mask off the result before or'ing in.
+ */
+ mask = (1 << (cnt - 1)) - 1;
+ res |= (d >> (9 - cnt)) & mask;
+
+ /* if the carry flag was set, or it in. */
+ if (ACCESS_FLAG(F_CF)) { /* carry flag is set */
+ /* B_(n-1) <- cf */
+ res |= 1 << (cnt - 1);
+ }
+ /* set the new carry flag, based on the variable "cf" */
+ CONDITIONAL_SET_FLAG(cf, F_CF);
+ /* OVERFLOW is set *IFF* cnt==1, then it is the
+ xor of CF and the most significant bit. Blecck. */
+ /* parenthesized this expression since it appears to
+ be causing OF to be misset */
+ CONDITIONAL_SET_FLAG(cnt == 1 && XOR2(cf + ((res >> 6) & 0x2)),
+ F_OF);
+
+ }
+ return (u8)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the RCL instruction and side effects.
+****************************************************************************/
+u16 rcl_word(u16 d, u8 s)
+{
+ register unsigned int res, cnt, mask, cf;
+
+ res = d;
+ if ((cnt = s % 17) != 0) {
+ cf = (d >> (16 - cnt)) & 0x1;
+ res = (d << cnt) & 0xffff;
+ mask = (1 << (cnt - 1)) - 1;
+ res |= (d >> (17 - cnt)) & mask;
+ if (ACCESS_FLAG(F_CF)) {
+ res |= 1 << (cnt - 1);
+ }
+ CONDITIONAL_SET_FLAG(cf, F_CF);
+ CONDITIONAL_SET_FLAG(cnt == 1 && XOR2(cf + ((res >> 14) & 0x2)),
+ F_OF);
+ }
+ return (u16)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the RCL instruction and side effects.
+****************************************************************************/
+u32 rcl_long(u32 d, u8 s)
+{
+ register u32 res, cnt, mask, cf;
+
+ res = d;
+ if ((cnt = s % 33) != 0) {
+ cf = (d >> (32 - cnt)) & 0x1;
+ res = (d << cnt) & 0xffffffff;
+ mask = (1 << (cnt - 1)) - 1;
+ res |= (d >> (33 - cnt)) & mask;
+ if (ACCESS_FLAG(F_CF)) { /* carry flag is set */
+ res |= 1 << (cnt - 1);
+ }
+ CONDITIONAL_SET_FLAG(cf, F_CF);
+ CONDITIONAL_SET_FLAG(cnt == 1 && XOR2(cf + ((res >> 30) & 0x2)),
+ F_OF);
+ }
+ return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the RCR instruction and side effects.
+****************************************************************************/
+u8 rcr_byte(u8 d, u8 s)
+{
+ u32 res, cnt;
+ u32 mask, cf, ocf = 0;
+
+ /* rotate right through carry */
+ /*
+ s is the rotate distance. It varies from 0 - 8.
+ d is the byte object rotated.
+
+ have
+
+ CF B_7 B_6 B_5 B_4 B_3 B_2 B_1 B_0
+
+ The new rotate is done mod 9, and given this,
+ for a rotation of n bits (mod 9) the new carry flag is
+ then located n bits from the LSB. The low part is
+ then shifted up cnt bits, and the high part is or'd
+ in. Using CAPS for new values, and lowercase for the
+ original values, this can be expressed as:
+
+ IF n > 0
+ 1) CF <- b_(n-1)
+ 2) B_(8-(n+1)) .. B_(0) <- b_(7) .. b_(n)
+ 3) B_(8-n) <- cf
+ 4) B_(7) .. B_(8-(n-1)) <- b_(n-2) .. b_(0)
+ */
+ res = d;
+ if ((cnt = s % 9) != 0) {
+ /* extract the new CARRY FLAG. */
+ /* CF <- b_(n-1) */
+ if (cnt == 1) {
+ cf = d & 0x1;
+ /* note hackery here. Access_flag(..) evaluates to either
+ 0 if flag not set
+ non-zero if flag is set.
+ doing access_flag(..) != 0 casts that into either
+ 0..1 in any representation of the flags register
+ (i.e. packed bit array or unpacked.)
+ */
+ ocf = ACCESS_FLAG(F_CF) != 0;
+ } else
+ cf = (d >> (cnt - 1)) & 0x1;
+
+ /* B_(8-(n+1)) .. B_(0) <- b_(7) .. b_n */
+ /* note that the right hand side done by the mask
+ This is effectively done by shifting the
+ object to the right. The result must be masked,
+ in case the object came in and was treated
+ as a negative number. Needed??? */
+
+ mask = (1 << (8 - cnt)) - 1;
+ res = (d >> cnt) & mask;
+
+ /* now the high stuff which rotated around
+ into the positions B_cnt-2 .. B_0 */
+ /* B_(7) .. B_(8-(n-1)) <- b_(n-2) .. b_(0) */
+ /* shift it downward, 7-(n-2) = 9-n positions.
+ and mask off the result before or'ing in.
+ */
+ res |= (d << (9 - cnt));
+
+ /* if the carry flag was set, or it in. */
+ if (ACCESS_FLAG(F_CF)) { /* carry flag is set */
+ /* B_(8-n) <- cf */
+ res |= 1 << (8 - cnt);
+ }
+ /* set the new carry flag, based on the variable "cf" */
+ CONDITIONAL_SET_FLAG(cf, F_CF);
+ /* OVERFLOW is set *IFF* cnt==1, then it is the
+ xor of CF and the most significant bit. Blecck. */
+ /* parenthesized... */
+ if (cnt == 1) {
+ CONDITIONAL_SET_FLAG(XOR2(ocf + ((d >> 6) & 0x2)),
+ F_OF);
+ }
+ }
+ return (u8)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the RCR instruction and side effects.
+****************************************************************************/
+u16 rcr_word(u16 d, u8 s)
+{
+ u32 res, cnt;
+ u32 mask, cf, ocf = 0;
+
+ /* rotate right through carry */
+ res = d;
+ if ((cnt = s % 17) != 0) {
+ if (cnt == 1) {
+ cf = d & 0x1;
+ ocf = ACCESS_FLAG(F_CF) != 0;
+ } else
+ cf = (d >> (cnt - 1)) & 0x1;
+ mask = (1 << (16 - cnt)) - 1;
+ res = (d >> cnt) & mask;
+ res |= (d << (17 - cnt));
+ if (ACCESS_FLAG(F_CF)) {
+ res |= 1 << (16 - cnt);
+ }
+ CONDITIONAL_SET_FLAG(cf, F_CF);
+ if (cnt == 1) {
+ CONDITIONAL_SET_FLAG(XOR2(ocf + ((d >> 14) & 0x2)),
+ F_OF);
+ }
+ }
+ return (u16)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the RCR instruction and side effects.
+****************************************************************************/
+u32 rcr_long(u32 d, u8 s)
+{
+ u32 res, cnt;
+ u32 mask, cf, ocf = 0;
+
+ /* rotate right through carry */
+ res = d;
+ if ((cnt = s % 33) != 0) {
+ if (cnt == 1) {
+ cf = d & 0x1;
+ ocf = ACCESS_FLAG(F_CF) != 0;
+ } else
+ cf = (d >> (cnt - 1)) & 0x1;
+ mask = (1 << (32 - cnt)) - 1;
+ res = (d >> cnt) & mask;
+ if (cnt != 1)
+ res |= (d << (33 - cnt));
+ if (ACCESS_FLAG(F_CF)) { /* carry flag is set */
+ res |= 1 << (32 - cnt);
+ }
+ CONDITIONAL_SET_FLAG(cf, F_CF);
+ if (cnt == 1) {
+ CONDITIONAL_SET_FLAG(XOR2(ocf + ((d >> 30) & 0x2)),
+ F_OF);
+ }
+ }
+ return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the ROL instruction and side effects.
+****************************************************************************/
+u8 rol_byte(u8 d, u8 s)
+{
+ register unsigned int res, cnt, mask;
+
+ /* rotate left */
+ /*
+ s is the rotate distance. It varies from 0 - 8.
+ d is the byte object rotated.
+
+ have
+
+ CF B_7 ... B_0
+
+ The new rotate is done mod 8.
+ Much simpler than the "rcl" or "rcr" operations.
+
+ IF n > 0
+ 1) B_(7) .. B_(n) <- b_(8-(n+1)) .. b_(0)
+ 2) B_(n-1) .. B_(0) <- b_(7) .. b_(8-n)
+ */
+ res = d;
+ if ((cnt = s % 8) != 0) {
+ /* B_(7) .. B_(n) <- b_(8-(n+1)) .. b_(0) */
+ res = (d << cnt);
+
+ /* B_(n-1) .. B_(0) <- b_(7) .. b_(8-n) */
+ mask = (1 << cnt) - 1;
+ res |= (d >> (8 - cnt)) & mask;
+
+ /* set the new carry flag, Note that it is the low order
+ bit of the result!!! */
+ CONDITIONAL_SET_FLAG(res & 0x1, F_CF);
+ /* OVERFLOW is set *IFF* s==1, then it is the
+ xor of CF and the most significant bit. Blecck. */
+ CONDITIONAL_SET_FLAG(s == 1 &&
+ XOR2((res & 0x1) + ((res >> 6) & 0x2)),
+ F_OF);
+ } if (s != 0) {
+ /* set the new carry flag, Note that it is the low order
+ bit of the result!!! */
+ CONDITIONAL_SET_FLAG(res & 0x1, F_CF);
+ }
+ return (u8)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the ROL instruction and side effects.
+****************************************************************************/
+u16 rol_word(u16 d, u8 s)
+{
+ register unsigned int res, cnt, mask;
+
+ res = d;
+ if ((cnt = s % 16) != 0) {
+ res = (d << cnt);
+ mask = (1 << cnt) - 1;
+ res |= (d >> (16 - cnt)) & mask;
+ CONDITIONAL_SET_FLAG(res & 0x1, F_CF);
+ CONDITIONAL_SET_FLAG(s == 1 &&
+ XOR2((res & 0x1) + ((res >> 14) & 0x2)),
+ F_OF);
+ } if (s != 0) {
+ /* set the new carry flag, Note that it is the low order
+ bit of the result!!! */
+ CONDITIONAL_SET_FLAG(res & 0x1, F_CF);
+ }
+ return (u16)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the ROL instruction and side effects.
+****************************************************************************/
+u32 rol_long(u32 d, u8 s)
+{
+ register u32 res, cnt, mask;
+
+ res = d;
+ if ((cnt = s % 32) != 0) {
+ res = (d << cnt);
+ mask = (1 << cnt) - 1;
+ res |= (d >> (32 - cnt)) & mask;
+ CONDITIONAL_SET_FLAG(res & 0x1, F_CF);
+ CONDITIONAL_SET_FLAG(s == 1 &&
+ XOR2((res & 0x1) + ((res >> 30) & 0x2)),
+ F_OF);
+ } if (s != 0) {
+ /* set the new carry flag, Note that it is the low order
+ bit of the result!!! */
+ CONDITIONAL_SET_FLAG(res & 0x1, F_CF);
+ }
+ return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the ROR instruction and side effects.
+****************************************************************************/
+u8 ror_byte(u8 d, u8 s)
+{
+ register unsigned int res, cnt, mask;
+
+ /* rotate right */
+ /*
+ s is the rotate distance. It varies from 0 - 8.
+ d is the byte object rotated.
+
+ have
+
+ B_7 ... B_0
+
+ The rotate is done mod 8.
+
+ IF n > 0
+ 1) B_(8-(n+1)) .. B_(0) <- b_(7) .. b_(n)
+ 2) B_(7) .. B_(8-n) <- b_(n-1) .. b_(0)
+ */
+ res = d;
+ if ((cnt = s % 8) != 0) { /* not a typo, do nada if cnt==0 */
+ /* B_(7) .. B_(8-n) <- b_(n-1) .. b_(0) */
+ res = (d << (8 - cnt));
+
+ /* B_(8-(n+1)) .. B_(0) <- b_(7) .. b_(n) */
+ mask = (1 << (8 - cnt)) - 1;
+ res |= (d >> (cnt)) & mask;
+
+ /* set the new carry flag, Note that it is the low order
+ bit of the result!!! */
+ CONDITIONAL_SET_FLAG(res & 0x80, F_CF);
+ /* OVERFLOW is set *IFF* s==1, then it is the
+ xor of the two most significant bits. Blecck. */
+ CONDITIONAL_SET_FLAG(s == 1 && XOR2(res >> 6), F_OF);
+ } else if (s != 0) {
+ /* set the new carry flag, Note that it is the low order
+ bit of the result!!! */
+ CONDITIONAL_SET_FLAG(res & 0x80, F_CF);
+ }
+ return (u8)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the ROR instruction and side effects.
+****************************************************************************/
+u16 ror_word(u16 d, u8 s)
+{
+ register unsigned int res, cnt, mask;
+
+ res = d;
+ if ((cnt = s % 16) != 0) {
+ res = (d << (16 - cnt));
+ mask = (1 << (16 - cnt)) - 1;
+ res |= (d >> (cnt)) & mask;
+ CONDITIONAL_SET_FLAG(res & 0x8000, F_CF);
+ CONDITIONAL_SET_FLAG(s == 1 && XOR2(res >> 14), F_OF);
+ } else if (s != 0) {
+ /* set the new carry flag, Note that it is the low order
+ bit of the result!!! */
+ CONDITIONAL_SET_FLAG(res & 0x8000, F_CF);
+ }
+ return (u16)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the ROR instruction and side effects.
+****************************************************************************/
+u32 ror_long(u32 d, u8 s)
+{
+ register u32 res, cnt, mask;
+
+ res = d;
+ if ((cnt = s % 32) != 0) {
+ res = (d << (32 - cnt));
+ mask = (1 << (32 - cnt)) - 1;
+ res |= (d >> (cnt)) & mask;
+ CONDITIONAL_SET_FLAG(res & 0x80000000, F_CF);
+ CONDITIONAL_SET_FLAG(s == 1 && XOR2(res >> 30), F_OF);
+ } else if (s != 0) {
+ /* set the new carry flag, Note that it is the low order
+ bit of the result!!! */
+ CONDITIONAL_SET_FLAG(res & 0x80000000, F_CF);
+ }
+ return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the SHL instruction and side effects.
+****************************************************************************/
+u8 shl_byte(u8 d, u8 s)
+{
+ unsigned int cnt, res, cf;
+
+ if (s < 8) {
+ cnt = s % 8;
+
+ /* last bit shifted out goes into carry flag */
+ if (cnt > 0) {
+ res = d << cnt;
+ cf = d & (1 << (8 - cnt));
+ CONDITIONAL_SET_FLAG(cf, F_CF);
+ CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
+ CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+ } else {
+ res = (u8) d;
+ }
+
+ if (cnt == 1) {
+ /* Needs simplification. */
+ CONDITIONAL_SET_FLAG(
+ (((res & 0x80) == 0x80) ^
+ (ACCESS_FLAG(F_CF) != 0)),
+ /* was (M.x86.R_FLG&F_CF)==F_CF)), */
+ F_OF);
+ } else {
+ CLEAR_FLAG(F_OF);
+ }
+ } else {
+ res = 0;
+ CONDITIONAL_SET_FLAG((d << (s-1)) & 0x80, F_CF);
+ CLEAR_FLAG(F_OF);
+ CLEAR_FLAG(F_SF);
+ SET_FLAG(F_PF);
+ SET_FLAG(F_ZF);
+ }
+ return (u8)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the SHL instruction and side effects.
+****************************************************************************/
+u16 shl_word(u16 d, u8 s)
+{
+ unsigned int cnt, res, cf;
+
+ if (s < 16) {
+ cnt = s % 16;
+ if (cnt > 0) {
+ res = d << cnt;
+ cf = d & (1 << (16 - cnt));
+ CONDITIONAL_SET_FLAG(cf, F_CF);
+ CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
+ CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+ } else {
+ res = (u16) d;
+ }
+
+ if (cnt == 1) {
+ CONDITIONAL_SET_FLAG(
+ (((res & 0x8000) == 0x8000) ^
+ (ACCESS_FLAG(F_CF) != 0)),
+ F_OF);
+ } else {
+ CLEAR_FLAG(F_OF);
+ }
+ } else {
+ res = 0;
+ CONDITIONAL_SET_FLAG((d << (s-1)) & 0x8000, F_CF);
+ CLEAR_FLAG(F_OF);
+ CLEAR_FLAG(F_SF);
+ SET_FLAG(F_PF);
+ SET_FLAG(F_ZF);
+ }
+ return (u16)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the SHL instruction and side effects.
+****************************************************************************/
+u32 shl_long(u32 d, u8 s)
+{
+ unsigned int cnt, res, cf;
+
+ if (s < 32) {
+ cnt = s % 32;
+ if (cnt > 0) {
+ res = d << cnt;
+ cf = d & (1 << (32 - cnt));
+ CONDITIONAL_SET_FLAG(cf, F_CF);
+ CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
+ CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+ } else {
+ res = d;
+ }
+ if (cnt == 1) {
+ CONDITIONAL_SET_FLAG((((res & 0x80000000) == 0x80000000) ^
+ (ACCESS_FLAG(F_CF) != 0)), F_OF);
+ } else {
+ CLEAR_FLAG(F_OF);
+ }
+ } else {
+ res = 0;
+ CONDITIONAL_SET_FLAG((d << (s-1)) & 0x80000000, F_CF);
+ CLEAR_FLAG(F_OF);
+ CLEAR_FLAG(F_SF);
+ SET_FLAG(F_PF);
+ SET_FLAG(F_ZF);
+ }
+ return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the SHR instruction and side effects.
+****************************************************************************/
+u8 shr_byte(u8 d, u8 s)
+{
+ unsigned int cnt, res, cf;
+
+ if (s < 8) {
+ cnt = s % 8;
+ if (cnt > 0) {
+ cf = d & (1 << (cnt - 1));
+ res = d >> cnt;
+ CONDITIONAL_SET_FLAG(cf, F_CF);
+ CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
+ CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+ } else {
+ res = (u8) d;
+ }
+
+ if (cnt == 1) {
+ CONDITIONAL_SET_FLAG(XOR2(res >> 6), F_OF);
+ } else {
+ CLEAR_FLAG(F_OF);
+ }
+ } else {
+ res = 0;
+ CONDITIONAL_SET_FLAG((d >> (s-1)) & 0x1, F_CF);
+ CLEAR_FLAG(F_OF);
+ CLEAR_FLAG(F_SF);
+ SET_FLAG(F_PF);
+ SET_FLAG(F_ZF);
+ }
+ return (u8)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the SHR instruction and side effects.
+****************************************************************************/
+u16 shr_word(u16 d, u8 s)
+{
+ unsigned int cnt, res, cf;
+
+ if (s < 16) {
+ cnt = s % 16;
+ if (cnt > 0) {
+ cf = d & (1 << (cnt - 1));
+ res = d >> cnt;
+ CONDITIONAL_SET_FLAG(cf, F_CF);
+ CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
+ CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+ } else {
+ res = d;
+ }
+
+ if (cnt == 1) {
+ CONDITIONAL_SET_FLAG(XOR2(res >> 14), F_OF);
+ } else {
+ CLEAR_FLAG(F_OF);
+ }
+ } else {
+ res = 0;
+ CLEAR_FLAG(F_CF);
+ CLEAR_FLAG(F_OF);
+ SET_FLAG(F_ZF);
+ CLEAR_FLAG(F_SF);
+ CLEAR_FLAG(F_PF);
+ }
+ return (u16)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the SHR instruction and side effects.
+****************************************************************************/
+u32 shr_long(u32 d, u8 s)
+{
+ unsigned int cnt, res, cf;
+
+ if (s < 32) {
+ cnt = s % 32;
+ if (cnt > 0) {
+ cf = d & (1 << (cnt - 1));
+ res = d >> cnt;
+ CONDITIONAL_SET_FLAG(cf, F_CF);
+ CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
+ CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+ } else {
+ res = d;
+ }
+ if (cnt == 1) {
+ CONDITIONAL_SET_FLAG(XOR2(res >> 30), F_OF);
+ } else {
+ CLEAR_FLAG(F_OF);
+ }
+ } else {
+ res = 0;
+ CLEAR_FLAG(F_CF);
+ CLEAR_FLAG(F_OF);
+ SET_FLAG(F_ZF);
+ CLEAR_FLAG(F_SF);
+ CLEAR_FLAG(F_PF);
+ }
+ return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the SAR instruction and side effects.
+****************************************************************************/
+u8 sar_byte(u8 d, u8 s)
+{
+ unsigned int cnt, res, cf, mask, sf;
+
+ res = d;
+ sf = d & 0x80;
+ cnt = s % 8;
+ if (cnt > 0 && cnt < 8) {
+ mask = (1 << (8 - cnt)) - 1;
+ cf = d & (1 << (cnt - 1));
+ res = (d >> cnt) & mask;
+ CONDITIONAL_SET_FLAG(cf, F_CF);
+ if (sf) {
+ res |= ~mask;
+ }
+ CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+ CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
+ } else if (cnt >= 8) {
+ if (sf) {
+ res = 0xff;
+ SET_FLAG(F_CF);
+ CLEAR_FLAG(F_ZF);
+ SET_FLAG(F_SF);
+ SET_FLAG(F_PF);
+ } else {
+ res = 0;
+ CLEAR_FLAG(F_CF);
+ SET_FLAG(F_ZF);
+ CLEAR_FLAG(F_SF);
+ CLEAR_FLAG(F_PF);
+ }
+ }
+ return (u8)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the SAR instruction and side effects.
+****************************************************************************/
+u16 sar_word(u16 d, u8 s)
+{
+ unsigned int cnt, res, cf, mask, sf;
+
+ sf = d & 0x8000;
+ cnt = s % 16;
+ res = d;
+ if (cnt > 0 && cnt < 16) {
+ mask = (1 << (16 - cnt)) - 1;
+ cf = d & (1 << (cnt - 1));
+ res = (d >> cnt) & mask;
+ CONDITIONAL_SET_FLAG(cf, F_CF);
+ if (sf) {
+ res |= ~mask;
+ }
+ CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
+ CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+ } else if (cnt >= 16) {
+ if (sf) {
+ res = 0xffff;
+ SET_FLAG(F_CF);
+ CLEAR_FLAG(F_ZF);
+ SET_FLAG(F_SF);
+ SET_FLAG(F_PF);
+ } else {
+ res = 0;
+ CLEAR_FLAG(F_CF);
+ SET_FLAG(F_ZF);
+ CLEAR_FLAG(F_SF);
+ CLEAR_FLAG(F_PF);
+ }
+ }
+ return (u16)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the SAR instruction and side effects.
+****************************************************************************/
+u32 sar_long(u32 d, u8 s)
+{
+ u32 cnt, res, cf, mask, sf;
+
+ sf = d & 0x80000000;
+ cnt = s % 32;
+ res = d;
+ if (cnt > 0 && cnt < 32) {
+ mask = (1 << (32 - cnt)) - 1;
+ cf = d & (1 << (cnt - 1));
+ res = (d >> cnt) & mask;
+ CONDITIONAL_SET_FLAG(cf, F_CF);
+ if (sf) {
+ res |= ~mask;
+ }
+ CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
+ CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+ } else if (cnt >= 32) {
+ if (sf) {
+ res = 0xffffffff;
+ SET_FLAG(F_CF);
+ CLEAR_FLAG(F_ZF);
+ SET_FLAG(F_SF);
+ SET_FLAG(F_PF);
+ } else {
+ res = 0;
+ CLEAR_FLAG(F_CF);
+ SET_FLAG(F_ZF);
+ CLEAR_FLAG(F_SF);
+ CLEAR_FLAG(F_PF);
+ }
+ }
+ return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the SHLD instruction and side effects.
+****************************************************************************/
+u16 shld_word (u16 d, u16 fill, u8 s)
+{
+ unsigned int cnt, res, cf;
+
+ if (s < 16) {
+ cnt = s % 16;
+ if (cnt > 0) {
+ res = (d << cnt) | (fill >> (16-cnt));
+ cf = d & (1 << (16 - cnt));
+ CONDITIONAL_SET_FLAG(cf, F_CF);
+ CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
+ CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+ } else {
+ res = d;
+ }
+ if (cnt == 1) {
+ CONDITIONAL_SET_FLAG((((res & 0x8000) == 0x8000) ^
+ (ACCESS_FLAG(F_CF) != 0)), F_OF);
+ } else {
+ CLEAR_FLAG(F_OF);
+ }
+ } else {
+ res = 0;
+ CONDITIONAL_SET_FLAG((d << (s-1)) & 0x8000, F_CF);
+ CLEAR_FLAG(F_OF);
+ CLEAR_FLAG(F_SF);
+ SET_FLAG(F_PF);
+ SET_FLAG(F_ZF);
+ }
+ return (u16)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the SHLD instruction and side effects.
+****************************************************************************/
+u32 shld_long (u32 d, u32 fill, u8 s)
+{
+ unsigned int cnt, res, cf;
+
+ if (s < 32) {
+ cnt = s % 32;
+ if (cnt > 0) {
+ res = (d << cnt) | (fill >> (32-cnt));
+ cf = d & (1 << (32 - cnt));
+ CONDITIONAL_SET_FLAG(cf, F_CF);
+ CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
+ CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+ } else {
+ res = d;
+ }
+ if (cnt == 1) {
+ CONDITIONAL_SET_FLAG((((res & 0x80000000) == 0x80000000) ^
+ (ACCESS_FLAG(F_CF) != 0)), F_OF);
+ } else {
+ CLEAR_FLAG(F_OF);
+ }
+ } else {
+ res = 0;
+ CONDITIONAL_SET_FLAG((d << (s-1)) & 0x80000000, F_CF);
+ CLEAR_FLAG(F_OF);
+ CLEAR_FLAG(F_SF);
+ SET_FLAG(F_PF);
+ SET_FLAG(F_ZF);
+ }
+ return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the SHRD instruction and side effects.
+****************************************************************************/
+u16 shrd_word (u16 d, u16 fill, u8 s)
+{
+ unsigned int cnt, res, cf;
+
+ if (s < 16) {
+ cnt = s % 16;
+ if (cnt > 0) {
+ cf = d & (1 << (cnt - 1));
+ res = (d >> cnt) | (fill << (16 - cnt));
+ CONDITIONAL_SET_FLAG(cf, F_CF);
+ CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
+ CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+ } else {
+ res = d;
+ }
+
+ if (cnt == 1) {
+ CONDITIONAL_SET_FLAG(XOR2(res >> 14), F_OF);
+ } else {
+ CLEAR_FLAG(F_OF);
+ }
+ } else {
+ res = 0;
+ CLEAR_FLAG(F_CF);
+ CLEAR_FLAG(F_OF);
+ SET_FLAG(F_ZF);
+ CLEAR_FLAG(F_SF);
+ CLEAR_FLAG(F_PF);
+ }
+ return (u16)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the SHRD instruction and side effects.
+****************************************************************************/
+u32 shrd_long (u32 d, u32 fill, u8 s)
+{
+ unsigned int cnt, res, cf;
+
+ if (s < 32) {
+ cnt = s % 32;
+ if (cnt > 0) {
+ cf = d & (1 << (cnt - 1));
+ res = (d >> cnt) | (fill << (32 - cnt));
+ CONDITIONAL_SET_FLAG(cf, F_CF);
+ CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
+ CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+ } else {
+ res = d;
+ }
+ if (cnt == 1) {
+ CONDITIONAL_SET_FLAG(XOR2(res >> 30), F_OF);
+ } else {
+ CLEAR_FLAG(F_OF);
+ }
+ } else {
+ res = 0;
+ CLEAR_FLAG(F_CF);
+ CLEAR_FLAG(F_OF);
+ SET_FLAG(F_ZF);
+ CLEAR_FLAG(F_SF);
+ CLEAR_FLAG(F_PF);
+ }
+ return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the SBB instruction and side effects.
+****************************************************************************/
+u8 sbb_byte(u8 d, u8 s)
+{
+ register u32 res; /* all operands in native machine order */
+ register u32 bc;
+
+ if (ACCESS_FLAG(F_CF))
+ res = d - s - 1;
+ else
+ res = d - s;
+ CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
+ CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+
+ /* calculate the borrow chain. See note at top */
+ bc = (res & (~d | s)) | (~d & s);
+ CONDITIONAL_SET_FLAG(bc & 0x80, F_CF);
+ CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF);
+ CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
+ return (u8)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the SBB instruction and side effects.
+****************************************************************************/
+u16 sbb_word(u16 d, u16 s)
+{
+ register u32 res; /* all operands in native machine order */
+ register u32 bc;
+
+ if (ACCESS_FLAG(F_CF))
+ res = d - s - 1;
+ else
+ res = d - s;
+ CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
+ CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+
+ /* calculate the borrow chain. See note at top */
+ bc = (res & (~d | s)) | (~d & s);
+ CONDITIONAL_SET_FLAG(bc & 0x8000, F_CF);
+ CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF);
+ CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
+ return (u16)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the SBB instruction and side effects.
+****************************************************************************/
+u32 sbb_long(u32 d, u32 s)
+{
+ register u32 res; /* all operands in native machine order */
+ register u32 bc;
+
+ if (ACCESS_FLAG(F_CF))
+ res = d - s - 1;
+ else
+ res = d - s;
+ CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
+ CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+
+ /* calculate the borrow chain. See note at top */
+ bc = (res & (~d | s)) | (~d & s);
+ CONDITIONAL_SET_FLAG(bc & 0x80000000, F_CF);
+ CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF);
+ CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
+ return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the SUB instruction and side effects.
+****************************************************************************/
+u8 sub_byte(u8 d, u8 s)
+{
+ register u32 res; /* all operands in native machine order */
+ register u32 bc;
+
+ res = d - s;
+ CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
+ CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+
+ /* calculate the borrow chain. See note at top */
+ bc = (res & (~d | s)) | (~d & s);
+ CONDITIONAL_SET_FLAG(bc & 0x80, F_CF);
+ CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF);
+ CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
+ return (u8)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the SUB instruction and side effects.
+****************************************************************************/
+u16 sub_word(u16 d, u16 s)
+{
+ register u32 res; /* all operands in native machine order */
+ register u32 bc;
+
+ res = d - s;
+ CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
+ CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+
+ /* calculate the borrow chain. See note at top */
+ bc = (res & (~d | s)) | (~d & s);
+ CONDITIONAL_SET_FLAG(bc & 0x8000, F_CF);
+ CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF);
+ CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
+ return (u16)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the SUB instruction and side effects.
+****************************************************************************/
+u32 sub_long(u32 d, u32 s)
+{
+ register u32 res; /* all operands in native machine order */
+ register u32 bc;
+
+ res = d - s;
+ CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
+ CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+
+ /* calculate the borrow chain. See note at top */
+ bc = (res & (~d | s)) | (~d & s);
+ CONDITIONAL_SET_FLAG(bc & 0x80000000, F_CF);
+ CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF);
+ CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
+ return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the TEST instruction and side effects.
+****************************************************************************/
+void test_byte(u8 d, u8 s)
+{
+ register u32 res; /* all operands in native machine order */
+
+ res = d & s;
+
+ CLEAR_FLAG(F_OF);
+ CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
+ CONDITIONAL_SET_FLAG(res == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+ /* AF == dont care */
+ CLEAR_FLAG(F_CF);
+}
+
+/****************************************************************************
+REMARKS:
+Implements the TEST instruction and side effects.
+****************************************************************************/
+void test_word(u16 d, u16 s)
+{
+ register u32 res; /* all operands in native machine order */
+
+ res = d & s;
+
+ CLEAR_FLAG(F_OF);
+ CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
+ CONDITIONAL_SET_FLAG(res == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+ /* AF == dont care */
+ CLEAR_FLAG(F_CF);
+}
+
+/****************************************************************************
+REMARKS:
+Implements the TEST instruction and side effects.
+****************************************************************************/
+void test_long(u32 d, u32 s)
+{
+ register u32 res; /* all operands in native machine order */
+
+ res = d & s;
+
+ CLEAR_FLAG(F_OF);
+ CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
+ CONDITIONAL_SET_FLAG(res == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+ /* AF == dont care */
+ CLEAR_FLAG(F_CF);
+}
+
+/****************************************************************************
+REMARKS:
+Implements the XOR instruction and side effects.
+****************************************************************************/
+u8 xor_byte(u8 d, u8 s)
+{
+ register u8 res; /* all operands in native machine order */
+
+ res = d ^ s;
+ CLEAR_FLAG(F_OF);
+ CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
+ CONDITIONAL_SET_FLAG(res == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(PARITY(res), F_PF);
+ CLEAR_FLAG(F_CF);
+ CLEAR_FLAG(F_AF);
+ return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the XOR instruction and side effects.
+****************************************************************************/
+u16 xor_word(u16 d, u16 s)
+{
+ register u16 res; /* all operands in native machine order */
+
+ res = d ^ s;
+ CLEAR_FLAG(F_OF);
+ CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
+ CONDITIONAL_SET_FLAG(res == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+ CLEAR_FLAG(F_CF);
+ CLEAR_FLAG(F_AF);
+ return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the XOR instruction and side effects.
+****************************************************************************/
+u32 xor_long(u32 d, u32 s)
+{
+ register u32 res; /* all operands in native machine order */
+
+ res = d ^ s;
+ CLEAR_FLAG(F_OF);
+ CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
+ CONDITIONAL_SET_FLAG(res == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+ CLEAR_FLAG(F_CF);
+ CLEAR_FLAG(F_AF);
+ return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the IMUL instruction and side effects.
+****************************************************************************/
+void imul_byte(u8 s)
+{
+ s16 res = (s16)((s8)M.x86.R_AL * (s8)s);
+
+ M.x86.R_AX = res;
+ if (((M.x86.R_AL & 0x80) == 0 && M.x86.R_AH == 0x00) ||
+ ((M.x86.R_AL & 0x80) != 0 && M.x86.R_AH == 0xFF)) {
+ CLEAR_FLAG(F_CF);
+ CLEAR_FLAG(F_OF);
+ } else {
+ SET_FLAG(F_CF);
+ SET_FLAG(F_OF);
+ }
+}
+
+/****************************************************************************
+REMARKS:
+Implements the IMUL instruction and side effects.
+****************************************************************************/
+void imul_word(u16 s)
+{
+ s32 res = (s16)M.x86.R_AX * (s16)s;
+
+ M.x86.R_AX = (u16)res;
+ M.x86.R_DX = (u16)(res >> 16);
+ if (((M.x86.R_AX & 0x8000) == 0 && M.x86.R_DX == 0x00) ||
+ ((M.x86.R_AX & 0x8000) != 0 && M.x86.R_DX == 0xFF)) {
+ CLEAR_FLAG(F_CF);
+ CLEAR_FLAG(F_OF);
+ } else {
+ SET_FLAG(F_CF);
+ SET_FLAG(F_OF);
+ }
+}
+
+/****************************************************************************
+REMARKS:
+Implements the IMUL instruction and side effects.
+****************************************************************************/
+void imul_long_direct(u32 *res_lo, u32* res_hi,u32 d, u32 s)
+{
+#ifdef __HAS_LONG_LONG__
+ s64 res = (s64)(s32)d * (s32)s;
+
+ *res_lo = (u32)res;
+ *res_hi = (u32)(res >> 32);
+#else
+ u32 d_lo,d_hi,d_sign;
+ u32 s_lo,s_hi,s_sign;
+ u32 rlo_lo,rlo_hi,rhi_lo;
+
+ if ((d_sign = d & 0x80000000) != 0)
+ d = -d;
+ d_lo = d & 0xFFFF;
+ d_hi = d >> 16;
+ if ((s_sign = s & 0x80000000) != 0)
+ s = -s;
+ s_lo = s & 0xFFFF;
+ s_hi = s >> 16;
+ rlo_lo = d_lo * s_lo;
+ rlo_hi = (d_hi * s_lo + d_lo * s_hi) + (rlo_lo >> 16);
+ rhi_lo = d_hi * s_hi + (rlo_hi >> 16);
+ *res_lo = (rlo_hi << 16) | (rlo_lo & 0xFFFF);
+ *res_hi = rhi_lo;
+ if (d_sign != s_sign) {
+ d = ~*res_lo;
+ s = (((d & 0xFFFF) + 1) >> 16) + (d >> 16);
+ *res_lo = ~*res_lo+1;
+ *res_hi = ~*res_hi+(s >> 16);
+ }
+#endif
+}
+
+/****************************************************************************
+REMARKS:
+Implements the IMUL instruction and side effects.
+****************************************************************************/
+void imul_long(u32 s)
+{
+ imul_long_direct(&M.x86.R_EAX,&M.x86.R_EDX,M.x86.R_EAX,s);
+ if (((M.x86.R_EAX & 0x80000000) == 0 && M.x86.R_EDX == 0x00) ||
+ ((M.x86.R_EAX & 0x80000000) != 0 && M.x86.R_EDX == 0xFF)) {
+ CLEAR_FLAG(F_CF);
+ CLEAR_FLAG(F_OF);
+ } else {
+ SET_FLAG(F_CF);
+ SET_FLAG(F_OF);
+ }
+}
+
+/****************************************************************************
+REMARKS:
+Implements the MUL instruction and side effects.
+****************************************************************************/
+void mul_byte(u8 s)
+{
+ u16 res = (u16)(M.x86.R_AL * s);
+
+ M.x86.R_AX = res;
+ if (M.x86.R_AH == 0) {
+ CLEAR_FLAG(F_CF);
+ CLEAR_FLAG(F_OF);
+ } else {
+ SET_FLAG(F_CF);
+ SET_FLAG(F_OF);
+ }
+}
+
+/****************************************************************************
+REMARKS:
+Implements the MUL instruction and side effects.
+****************************************************************************/
+void mul_word(u16 s)
+{
+ u32 res = M.x86.R_AX * s;
+
+ M.x86.R_AX = (u16)res;
+ M.x86.R_DX = (u16)(res >> 16);
+ if (M.x86.R_DX == 0) {
+ CLEAR_FLAG(F_CF);
+ CLEAR_FLAG(F_OF);
+ } else {
+ SET_FLAG(F_CF);
+ SET_FLAG(F_OF);
+ }
+}
+
+/****************************************************************************
+REMARKS:
+Implements the MUL instruction and side effects.
+****************************************************************************/
+void mul_long(u32 s)
+{
+#ifdef __HAS_LONG_LONG__
+ u64 res = (u64)M.x86.R_EAX * s;
+
+ M.x86.R_EAX = (u32)res;
+ M.x86.R_EDX = (u32)(res >> 32);
+#else
+ u32 a,a_lo,a_hi;
+ u32 s_lo,s_hi;
+ u32 rlo_lo,rlo_hi,rhi_lo;
+
+ a = M.x86.R_EAX;
+ a_lo = a & 0xFFFF;
+ a_hi = a >> 16;
+ s_lo = s & 0xFFFF;
+ s_hi = s >> 16;
+ rlo_lo = a_lo * s_lo;
+ rlo_hi = (a_hi * s_lo + a_lo * s_hi) + (rlo_lo >> 16);
+ rhi_lo = a_hi * s_hi + (rlo_hi >> 16);
+ M.x86.R_EAX = (rlo_hi << 16) | (rlo_lo & 0xFFFF);
+ M.x86.R_EDX = rhi_lo;
+#endif
+
+ if (M.x86.R_EDX == 0) {
+ CLEAR_FLAG(F_CF);
+ CLEAR_FLAG(F_OF);
+ } else {
+ SET_FLAG(F_CF);
+ SET_FLAG(F_OF);
+ }
+}
+
+/****************************************************************************
+REMARKS:
+Implements the IDIV instruction and side effects.
+****************************************************************************/
+void idiv_byte(u8 s)
+{
+ s32 dvd, div, mod;
+
+ dvd = (s16)M.x86.R_AX;
+ if (s == 0) {
+ x86emu_intr_raise(0);
+ return;
+ }
+ div = dvd / (s8)s;
+ mod = dvd % (s8)s;
+ if (abs(div) > 0x7f) {
+ x86emu_intr_raise(0);
+ return;
+ }
+ M.x86.R_AL = (s8) div;
+ M.x86.R_AH = (s8) mod;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the IDIV instruction and side effects.
+****************************************************************************/
+void idiv_word(u16 s)
+{
+ s32 dvd, div, mod;
+
+ dvd = (((s32)M.x86.R_DX) << 16) | M.x86.R_AX;
+ if (s == 0) {
+ x86emu_intr_raise(0);
+ return;
+ }
+ div = dvd / (s16)s;
+ mod = dvd % (s16)s;
+ if (abs(div) > 0x7fff) {
+ x86emu_intr_raise(0);
+ return;
+ }
+ CLEAR_FLAG(F_CF);
+ CLEAR_FLAG(F_SF);
+ CONDITIONAL_SET_FLAG(div == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(PARITY(mod & 0xff), F_PF);
+
+ M.x86.R_AX = (u16)div;
+ M.x86.R_DX = (u16)mod;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the IDIV instruction and side effects.
+****************************************************************************/
+void idiv_long(u32 s)
+{
+#ifdef __HAS_LONG_LONG__
+ s64 dvd, div, mod;
+
+ dvd = (((s64)M.x86.R_EDX) << 32) | M.x86.R_EAX;
+ if (s == 0) {
+ x86emu_intr_raise(0);
+ return;
+ }
+ div = dvd / (s32)s;
+ mod = dvd % (s32)s;
+ if (((u64)div >> 32) != 0 &&
+ ((u64)div >> 32) != 0xFFFFFFFFUL) {
+ x86emu_intr_raise(0);
+ return;
+ }
+#else
+ s32 div = 0, mod;
+ s32 h_dvd = M.x86.R_EDX;
+ u32 l_dvd = M.x86.R_EAX;
+ u32 abs_s = s & 0x7FFFFFFF;
+ u32 abs_h_dvd = h_dvd & 0x7FFFFFFF;
+ u32 h_s = abs_s >> 1;
+ u32 l_s = abs_s << 31;
+ int counter = 31;
+ int carry;
+
+ if (s == 0) {
+ x86emu_intr_raise(0);
+ return;
+ }
+ do {
+ div <<= 1;
+ carry = (l_dvd >= l_s) ? 0 : 1;
+
+ if (abs_h_dvd < (h_s + carry)) {
+ h_s >>= 1;
+ l_s = abs_s << (--counter);
+ continue;
+ } else {
+ abs_h_dvd -= (h_s + carry);
+ l_dvd = carry ? ((0xFFFFFFFF - l_s) + l_dvd + 1)
+ : (l_dvd - l_s);
+ h_s >>= 1;
+ l_s = abs_s << (--counter);
+ div |= 1;
+ continue;
+ }
+
+ } while (counter > -1);
+ /* overflow */
+ if (abs_h_dvd || (l_dvd > abs_s)) {
+ x86emu_intr_raise(0);
+ return;
+ }
+ /* sign */
+ div |= ((h_dvd & 0x10000000) ^ (s & 0x10000000));
+ mod = l_dvd;
+
+#endif
+ CLEAR_FLAG(F_CF);
+ CLEAR_FLAG(F_AF);
+ CLEAR_FLAG(F_SF);
+ SET_FLAG(F_ZF);
+ CONDITIONAL_SET_FLAG(PARITY(mod & 0xff), F_PF);
+
+ M.x86.R_EAX = (u32)div;
+ M.x86.R_EDX = (u32)mod;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the DIV instruction and side effects.
+****************************************************************************/
+void div_byte(u8 s)
+{
+ u32 dvd, div, mod;
+
+ dvd = M.x86.R_AX;
+ if (s == 0) {
+ x86emu_intr_raise(0);
+ return;
+ }
+ div = dvd / (u8)s;
+ mod = dvd % (u8)s;
+ if (div > 0xff) {
+ x86emu_intr_raise(0);
+ return;
+ }
+ M.x86.R_AL = (u8)div;
+ M.x86.R_AH = (u8)mod;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the DIV instruction and side effects.
+****************************************************************************/
+void div_word(u16 s)
+{
+ u32 dvd, div, mod;
+
+ dvd = (((u32)M.x86.R_DX) << 16) | M.x86.R_AX;
+ if (s == 0) {
+ x86emu_intr_raise(0);
+ return;
+ }
+ div = dvd / (u16)s;
+ mod = dvd % (u16)s;
+ if (div > 0xffff) {
+ x86emu_intr_raise(0);
+ return;
+ }
+ CLEAR_FLAG(F_CF);
+ CLEAR_FLAG(F_SF);
+ CONDITIONAL_SET_FLAG(div == 0, F_ZF);
+ CONDITIONAL_SET_FLAG(PARITY(mod & 0xff), F_PF);
+
+ M.x86.R_AX = (u16)div;
+ M.x86.R_DX = (u16)mod;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the DIV instruction and side effects.
+****************************************************************************/
+void div_long(u32 s)
+{
+#ifdef __HAS_LONG_LONG__
+ u64 dvd, div, mod;
+
+ dvd = (((u64)M.x86.R_EDX) << 32) | M.x86.R_EAX;
+ if (s == 0) {
+ x86emu_intr_raise(0);
+ return;
+ }
+ div = dvd / (u32)s;
+ mod = dvd % (u32)s;
+ if (div > 0xffffffffULL) {
+ x86emu_intr_raise(0);
+ return;
+ }
+#else
+ s32 div = 0, mod;
+ s32 h_dvd = M.x86.R_EDX;
+ u32 l_dvd = M.x86.R_EAX;
+
+ u32 h_s = s;
+ u32 l_s = 0;
+ int counter = 32;
+ int carry;
+
+ if (s == 0) {
+ x86emu_intr_raise(0);
+ return;
+ }
+ do {
+ div <<= 1;
+ carry = (l_dvd >= l_s) ? 0 : 1;
+
+ if (h_dvd < (h_s + carry)) {
+ h_s >>= 1;
+ l_s = s << (--counter);
+ continue;
+ } else {
+ h_dvd -= (h_s + carry);
+ l_dvd = carry ? ((0xFFFFFFFF - l_s) + l_dvd + 1)
+ : (l_dvd - l_s);
+ h_s >>= 1;
+ l_s = s << (--counter);
+ div |= 1;
+ continue;
+ }
+
+ } while (counter > -1);
+ /* overflow */
+ if (h_dvd || (l_dvd > s)) {
+ x86emu_intr_raise(0);
+ return;
+ }
+ mod = l_dvd;
+#endif
+ CLEAR_FLAG(F_CF);
+ CLEAR_FLAG(F_AF);
+ CLEAR_FLAG(F_SF);
+ SET_FLAG(F_ZF);
+ CONDITIONAL_SET_FLAG(PARITY(mod & 0xff), F_PF);
+
+ M.x86.R_EAX = (u32)div;
+ M.x86.R_EDX = (u32)mod;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the IN string instruction and side effects.
+****************************************************************************/
+void ins(int size)
+{
+ int inc = size;
+
+ if (ACCESS_FLAG(F_DF)) {
+ inc = -size;
+ }
+ if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
+ /* dont care whether REPE or REPNE */
+ /* in until CX is ZERO. */
+ u32 count = ((M.x86.mode & SYSMODE_PREFIX_DATA) ?
+ M.x86.R_ECX : M.x86.R_CX);
+ switch (size) {
+ case 1:
+ while (count--) {
+ store_data_byte_abs(M.x86.R_ES, M.x86.R_DI,
+ (*sys_inb)(M.x86.R_DX));
+ M.x86.R_DI += inc;
+ }
+ break;
+
+ case 2:
+ while (count--) {
+ store_data_word_abs(M.x86.R_ES, M.x86.R_DI,
+ (*sys_inw)(M.x86.R_DX));
+ M.x86.R_DI += inc;
+ }
+ break;
+ case 4:
+ while (count--) {
+ store_data_long_abs(M.x86.R_ES, M.x86.R_DI,
+ (*sys_inl)(M.x86.R_DX));
+ M.x86.R_DI += inc;
+ break;
+ }
+ }
+ M.x86.R_CX = 0;
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ M.x86.R_ECX = 0;
+ }
+ M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
+ } else {
+ switch (size) {
+ case 1:
+ store_data_byte_abs(M.x86.R_ES, M.x86.R_DI,
+ (*sys_inb)(M.x86.R_DX));
+ break;
+ case 2:
+ store_data_word_abs(M.x86.R_ES, M.x86.R_DI,
+ (*sys_inw)(M.x86.R_DX));
+ break;
+ case 4:
+ store_data_long_abs(M.x86.R_ES, M.x86.R_DI,
+ (*sys_inl)(M.x86.R_DX));
+ break;
+ }
+ M.x86.R_DI += inc;
+ }
+}
+
+/****************************************************************************
+REMARKS:
+Implements the OUT string instruction and side effects.
+****************************************************************************/
+void outs(int size)
+{
+ int inc = size;
+
+ if (ACCESS_FLAG(F_DF)) {
+ inc = -size;
+ }
+ if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
+ /* dont care whether REPE or REPNE */
+ /* out until CX is ZERO. */
+ u32 count = ((M.x86.mode & SYSMODE_PREFIX_DATA) ?
+ M.x86.R_ECX : M.x86.R_CX);
+ switch (size) {
+ case 1:
+ while (count--) {
+ (*sys_outb)(M.x86.R_DX,
+ fetch_data_byte_abs(M.x86.R_ES, M.x86.R_SI));
+ M.x86.R_SI += inc;
+ }
+ break;
+
+ case 2:
+ while (count--) {
+ (*sys_outw)(M.x86.R_DX,
+ fetch_data_word_abs(M.x86.R_ES, M.x86.R_SI));
+ M.x86.R_SI += inc;
+ }
+ break;
+ case 4:
+ while (count--) {
+ (*sys_outl)(M.x86.R_DX,
+ fetch_data_long_abs(M.x86.R_ES, M.x86.R_SI));
+ M.x86.R_SI += inc;
+ break;
+ }
+ }
+ M.x86.R_CX = 0;
+ if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+ M.x86.R_ECX = 0;
+ }
+ M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
+ } else {
+ switch (size) {
+ case 1:
+ (*sys_outb)(M.x86.R_DX,
+ fetch_data_byte_abs(M.x86.R_ES, M.x86.R_SI));
+ break;
+ case 2:
+ (*sys_outw)(M.x86.R_DX,
+ fetch_data_word_abs(M.x86.R_ES, M.x86.R_SI));
+ break;
+ case 4:
+ (*sys_outl)(M.x86.R_DX,
+ fetch_data_long_abs(M.x86.R_ES, M.x86.R_SI));
+ break;
+ }
+ M.x86.R_SI += inc;
+ }
+}
+
+/****************************************************************************
+PARAMETERS:
+addr - Address to fetch word from
+
+REMARKS:
+Fetches a word from emulator memory using an absolute address.
+****************************************************************************/
+u16 mem_access_word(int addr)
+{
+DB( if (CHECK_MEM_ACCESS())
+ x86emu_check_mem_access(addr);)
+ return (*sys_rdw)(addr);
+}
+
+/****************************************************************************
+REMARKS:
+Pushes a word onto the stack.
+
+NOTE: Do not inline this, as (*sys_wrX) is already inline!
+****************************************************************************/
+void push_word(u16 w)
+{
+DB( if (CHECK_SP_ACCESS())
+ x86emu_check_sp_access();)
+ M.x86.R_SP -= 2;
+ (*sys_wrw)(((u32)M.x86.R_SS << 4) + M.x86.R_SP, w);
+}
+
+/****************************************************************************
+REMARKS:
+Pushes a long onto the stack.
+
+NOTE: Do not inline this, as (*sys_wrX) is already inline!
+****************************************************************************/
+void push_long(u32 w)
+{
+DB( if (CHECK_SP_ACCESS())
+ x86emu_check_sp_access();)
+ M.x86.R_SP -= 4;
+ (*sys_wrl)(((u32)M.x86.R_SS << 4) + M.x86.R_SP, w);
+}
+
+/****************************************************************************
+REMARKS:
+Pops a word from the stack.
+
+NOTE: Do not inline this, as (*sys_rdX) is already inline!
+****************************************************************************/
+u16 pop_word(void)
+{
+ register u16 res;
+
+DB( if (CHECK_SP_ACCESS())
+ x86emu_check_sp_access();)
+ res = (*sys_rdw)(((u32)M.x86.R_SS << 4) + M.x86.R_SP);
+ M.x86.R_SP += 2;
+ return res;
+}
+
+/****************************************************************************
+REMARKS:
+Pops a long from the stack.
+
+NOTE: Do not inline this, as (*sys_rdX) is already inline!
+****************************************************************************/
+u32 pop_long(void)
+{
+ register u32 res;
+
+DB( if (CHECK_SP_ACCESS())
+ x86emu_check_sp_access();)
+ res = (*sys_rdl)(((u32)M.x86.R_SS << 4) + M.x86.R_SP);
+ M.x86.R_SP += 4;
+ return res;
+}
+
diff --git a/userspace/sdks/nv570/nvalloc/unix/x86emu/sys.c b/userspace/sdks/nv570/nvalloc/unix/x86emu/sys.c
new file mode 100644
index 0000000..9a5527f
--- /dev/null
+++ b/userspace/sdks/nv570/nvalloc/unix/x86emu/sys.c
@@ -0,0 +1,663 @@
+/****************************************************************************
+*
+* Realmode X86 Emulator Library
+*
+* Copyright (C) 1996-1999 SciTech Software, Inc.
+* Copyright (C) David Mosberger-Tang
+* Copyright (C) 1999 Egbert Eich
+*
+* ========================================================================
+*
+* Permission to use, copy, modify, distribute, and sell this software and
+* its documentation for any purpose is hereby granted without fee,
+* provided that the above copyright notice appear in all copies and that
+* both that copyright notice and this permission notice appear in
+* supporting documentation, and that the name of the authors not be used
+* in advertising or publicity pertaining to distribution of the software
+* without specific, written prior permission. The authors makes no
+* representations about the suitability of this software for any purpose.
+* It is provided "as is" without express or implied warranty.
+*
+* THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+* EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+* PERFORMANCE OF THIS SOFTWARE.
+*
+* ========================================================================
+*
+* Language: ANSI C
+* Environment: Any
+* Developer: Kendall Bennett
+*
+* Description: This file includes subroutines which are related to
+* programmed I/O and memory access. Included in this module
+* are default functions with limited usefulness. For real
+* uses these functions will most likely be overriden by the
+* user library.
+*
+****************************************************************************/
+
+#include "x86emu/x86emu.h"
+#include "x86emu/x86emui.h"
+#include "x86emu/regs.h"
+#include "x86emu/debug.h"
+#include "x86emu/prim_ops.h"
+#ifndef NO_SYS_HEADERS
+#include <string.h>
+#endif
+/*------------------------- Global Variables ------------------------------*/
+
+X86EMU_sysEnv _X86EMU_env; /* Global emulator machine state */
+X86EMU_intrFuncs _X86EMU_intrTab[256];
+
+/*----------------------------- Implementation ----------------------------*/
+#if defined(__alpha__) || defined(__alpha)
+/* to cope with broken egcs-1.1.2 :-(((( */
+
+#define ALPHA_UALOADS
+/*
+ * inline functions to do unaligned accesses
+ * from linux/include/asm-alpha/unaligned.h
+ */
+
+/*
+ * EGCS 1.1 knows about arbitrary unaligned loads. Define some
+ * packed structures to talk about such things with.
+ */
+
+#if defined(__GNUC__) && ((__GNUC__ > 2) || (__GNUC_MINOR__ >= 91))
+struct __una_u64 { unsigned long x __attribute__((packed)); };
+struct __una_u32 { unsigned int x __attribute__((packed)); };
+struct __una_u16 { unsigned short x __attribute__((packed)); };
+#endif
+
+static __inline__ unsigned long ldq_u(unsigned long * r11)
+{
+#if defined(__GNUC__) && ((__GNUC__ > 2) || (__GNUC_MINOR__ >= 91))
+ const struct __una_u64 *ptr = (const struct __una_u64 *) r11;
+ return ptr->x;
+#else
+ unsigned long r1,r2;
+ __asm__("ldq_u %0,%3\n\t"
+ "ldq_u %1,%4\n\t"
+ "extql %0,%2,%0\n\t"
+ "extqh %1,%2,%1"
+ :"=&r" (r1), "=&r" (r2)
+ :"r" (r11),
+ "m" (*r11),
+ "m" (*(const unsigned long *)(7+(char *) r11)));
+ return r1 | r2;
+#endif
+}
+
+static __inline__ unsigned long ldl_u(unsigned int * r11)
+{
+#if defined(__GNUC__) && ((__GNUC__ > 2) || (__GNUC_MINOR__ >= 91))
+ const struct __una_u32 *ptr = (const struct __una_u32 *) r11;
+ return ptr->x;
+#else
+ unsigned long r1,r2;
+ __asm__("ldq_u %0,%3\n\t"
+ "ldq_u %1,%4\n\t"
+ "extll %0,%2,%0\n\t"
+ "extlh %1,%2,%1"
+ :"=&r" (r1), "=&r" (r2)
+ :"r" (r11),
+ "m" (*r11),
+ "m" (*(const unsigned long *)(3+(char *) r11)));
+ return r1 | r2;
+#endif
+}
+
+static __inline__ unsigned long ldw_u(unsigned short * r11)
+{
+#if defined(__GNUC__) && ((__GNUC__ > 2) || (__GNUC_MINOR__ >= 91))
+ const struct __una_u16 *ptr = (const struct __una_u16 *) r11;
+ return ptr->x;
+#else
+ unsigned long r1,r2;
+ __asm__("ldq_u %0,%3\n\t"
+ "ldq_u %1,%4\n\t"
+ "extwl %0,%2,%0\n\t"
+ "extwh %1,%2,%1"
+ :"=&r" (r1), "=&r" (r2)
+ :"r" (r11),
+ "m" (*r11),
+ "m" (*(const unsigned long *)(1+(char *) r11)));
+ return r1 | r2;
+#endif
+}
+
+/*
+ * Elemental unaligned stores
+ */
+
+static __inline__ void stq_u(unsigned long r5, unsigned long * r11)
+{
+#if defined(__GNUC__) && ((__GNUC__ > 2) || (__GNUC_MINOR__ >= 91))
+ struct __una_u64 *ptr = (struct __una_u64 *) r11;
+ ptr->x = r5;
+#else
+ unsigned long r1,r2,r3,r4;
+
+ __asm__("ldq_u %3,%1\n\t"
+ "ldq_u %2,%0\n\t"
+ "insqh %6,%7,%5\n\t"
+ "insql %6,%7,%4\n\t"
+ "mskqh %3,%7,%3\n\t"
+ "mskql %2,%7,%2\n\t"
+ "bis %3,%5,%3\n\t"
+ "bis %2,%4,%2\n\t"
+ "stq_u %3,%1\n\t"
+ "stq_u %2,%0"
+ :"=m" (*r11),
+ "=m" (*(unsigned long *)(7+(char *) r11)),
+ "=&r" (r1), "=&r" (r2), "=&r" (r3), "=&r" (r4)
+ :"r" (r5), "r" (r11));
+#endif
+}
+
+static __inline__ void stl_u(unsigned long r5, unsigned int * r11)
+{
+#if defined(__GNUC__) && ((__GNUC__ > 2) || (__GNUC_MINOR__ >= 91))
+ struct __una_u32 *ptr = (struct __una_u32 *) r11;
+ ptr->x = r5;
+#else
+ unsigned long r1,r2,r3,r4;
+
+ __asm__("ldq_u %3,%1\n\t"
+ "ldq_u %2,%0\n\t"
+ "inslh %6,%7,%5\n\t"
+ "insll %6,%7,%4\n\t"
+ "msklh %3,%7,%3\n\t"
+ "mskll %2,%7,%2\n\t"
+ "bis %3,%5,%3\n\t"
+ "bis %2,%4,%2\n\t"
+ "stq_u %3,%1\n\t"
+ "stq_u %2,%0"
+ :"=m" (*r11),
+ "=m" (*(unsigned long *)(3+(char *) r11)),
+ "=&r" (r1), "=&r" (r2), "=&r" (r3), "=&r" (r4)
+ :"r" (r5), "r" (r11));
+#endif
+}
+
+static __inline__ void stw_u(unsigned long r5, unsigned short * r11)
+{
+#if defined(__GNUC__) && ((__GNUC__ > 2) || (__GNUC_MINOR__ >= 91))
+ struct __una_u16 *ptr = (struct __una_u16 *) r11;
+ ptr->x = r5;
+#else
+ unsigned long r1,r2,r3,r4;
+
+ __asm__("ldq_u %3,%1\n\t"
+ "ldq_u %2,%0\n\t"
+ "inswh %6,%7,%5\n\t"
+ "inswl %6,%7,%4\n\t"
+ "mskwh %3,%7,%3\n\t"
+ "mskwl %2,%7,%2\n\t"
+ "bis %3,%5,%3\n\t"
+ "bis %2,%4,%2\n\t"
+ "stq_u %3,%1\n\t"
+ "stq_u %2,%0"
+ :"=m" (*r11),
+ "=m" (*(unsigned long *)(1+(char *) r11)),
+ "=&r" (r1), "=&r" (r2), "=&r" (r3), "=&r" (r4)
+ :"r" (r5), "r" (r11));
+#endif
+}
+
+#elif defined(__GNUC__) && ((__GNUC__ < 3)) && \
+ (defined (__ia64__) || defined (ia64__))
+#define IA64_UALOADS
+/*
+ * EGCS 1.1 knows about arbitrary unaligned loads. Define some
+ * packed structures to talk about such things with.
+ */
+struct __una_u64 { unsigned long x __attribute__((packed)); };
+struct __una_u32 { unsigned int x __attribute__((packed)); };
+struct __una_u16 { unsigned short x __attribute__((packed)); };
+
+static __inline__ unsigned long
+__uldq (const unsigned long * r11)
+{
+ const struct __una_u64 *ptr = (const struct __una_u64 *) r11;
+ return ptr->x;
+}
+
+static __inline__ unsigned long
+uldl (const unsigned int * r11)
+{
+ const struct __una_u32 *ptr = (const struct __una_u32 *) r11;
+ return ptr->x;
+}
+
+static __inline__ unsigned long
+uldw (const unsigned short * r11)
+{
+ const struct __una_u16 *ptr = (const struct __una_u16 *) r11;
+ return ptr->x;
+}
+
+static __inline__ void
+ustq (unsigned long r5, unsigned long * r11)
+{
+ struct __una_u64 *ptr = (struct __una_u64 *) r11;
+ ptr->x = r5;
+}
+
+static __inline__ void
+ustl (unsigned long r5, unsigned int * r11)
+{
+ struct __una_u32 *ptr = (struct __una_u32 *) r11;
+ ptr->x = r5;
+}
+
+static __inline__ void
+ustw (unsigned long r5, unsigned short * r11)
+{
+ struct __una_u16 *ptr = (struct __una_u16 *) r11;
+ ptr->x = r5;
+}
+
+#endif
+
+/****************************************************************************
+PARAMETERS:
+addr - Emulator memory address to read
+
+RETURNS:
+Byte value read from emulator memory.
+
+REMARKS:
+Reads a byte value from the emulator memory.
+****************************************************************************/
+u8 X86API rdb(
+ u32 addr)
+{
+ u8 val;
+
+ if (addr > M.mem_size - 1) {
+ DB(NV_PRINTF(LEVEL_INFO, "mem_read: address %#x out of range!\n", addr);)
+ HALT_SYS();
+ }
+ val = *(u8*)(M.mem_base + addr);
+DB( if (DEBUG_MEM_TRACE())
+ NV_PRINTF(LEVEL_INFO, "%#08x 1 -> %#x\n", addr, val);)
+ return val;
+}
+
+/****************************************************************************
+PARAMETERS:
+addr - Emulator memory address to read
+
+RETURNS:
+Word value read from emulator memory.
+
+REMARKS:
+Reads a word value from the emulator memory.
+****************************************************************************/
+u16 X86API rdw(
+ u32 addr)
+{
+ u16 val = 0;
+
+ if (addr > M.mem_size - 2) {
+ DB(NV_PRINTF(LEVEL_INFO, "mem_read: address %#x out of range!\n", addr);)
+ HALT_SYS();
+ }
+#ifdef __BIG_ENDIAN__
+ if (addr & 0x1) {
+ val = (*(u8*)(M.mem_base + addr) |
+ (*(u8*)(M.mem_base + addr + 1) << 8));
+ }
+ else
+#endif
+#if defined(ALPHA_UALOADS)
+ val = ldw_u((u16*)(M.mem_base + addr));
+#elif defined(IA64_UALOADS)
+ val = uldw((u16*)(M.mem_base + addr));
+#else
+ val = *(u16*)(M.mem_base + addr);
+#endif
+DB( if (DEBUG_MEM_TRACE())
+ NV_PRINTF(LEVEL_INFO, "%#08x 2 -> %#x\n", addr, val);)
+ return val;
+}
+
+/****************************************************************************
+PARAMETERS:
+addr - Emulator memory address to read
+
+RETURNS:
+Long value read from emulator memory.
+REMARKS:
+Reads a long value from the emulator memory.
+****************************************************************************/
+u32 X86API rdl(
+ u32 addr)
+{
+ u32 val = 0;
+
+ if (addr > M.mem_size - 4) {
+ DB(NV_PRINTF(LEVEL_INFO, "mem_read: address %#x out of range!\n", addr);)
+ HALT_SYS();
+ }
+#ifdef __BIG_ENDIAN__
+ if (addr & 0x3) {
+ val = (*(u8*)(M.mem_base + addr + 0) |
+ (*(u8*)(M.mem_base + addr + 1) << 8) |
+ (*(u8*)(M.mem_base + addr + 2) << 16) |
+ (*(u8*)(M.mem_base + addr + 3) << 24));
+ }
+ else
+#endif
+#if defined(ALPHA_UALOADS)
+ val = ldl_u((u32*)(M.mem_base + addr));
+#elif defined(IA64_UALOADS)
+ val = uldl((u32*)(M.mem_base + addr));
+#else
+ val = *(u32*)(M.mem_base + addr);
+#endif
+DB( if (DEBUG_MEM_TRACE())
+ NV_PRINTF(LEVEL_INFO, "%#08x 4 -> %#x\n", addr, val);)
+ return val;
+}
+
+/****************************************************************************
+PARAMETERS:
+addr - Emulator memory address to read
+val - Value to store
+
+REMARKS:
+Writes a byte value to emulator memory.
+****************************************************************************/
+void X86API wrb(
+ u32 addr,
+ u8 val)
+{
+DB( if (DEBUG_MEM_TRACE())
+ NV_PRINTF(LEVEL_INFO, "%#08x 1 <- %#x\n", addr, val);)
+ if (addr > M.mem_size - 1) {
+ DB(NV_PRINTF(LEVEL_INFO, "mem_write: address %#x out of range!\n", addr);)
+ HALT_SYS();
+ }
+ *(u8*)(M.mem_base + addr) = val;
+}
+
+/****************************************************************************
+PARAMETERS:
+addr - Emulator memory address to read
+val - Value to store
+
+REMARKS:
+Writes a word value to emulator memory.
+****************************************************************************/
+void X86API wrw(
+ u32 addr,
+ u16 val)
+{
+DB( if (DEBUG_MEM_TRACE())
+ NV_PRINTF(LEVEL_INFO, "%#08x 2 <- %#x\n", addr, val);)
+ if (addr > M.mem_size - 2) {
+ DB(NV_PRINTF(LEVEL_INFO, "mem_write: address %#x out of range!\n", addr);)
+ HALT_SYS();
+ }
+#ifdef __BIG_ENDIAN__
+ if (addr & 0x1) {
+ *(u8*)(M.mem_base + addr + 0) = (val >> 0) & 0xff;
+ *(u8*)(M.mem_base + addr + 1) = (val >> 8) & 0xff;
+ }
+ else
+#endif
+#if defined(ALPHA_UALOADS)
+ stw_u(val,(u16*)(M.mem_base + addr));
+#elif defined(IA64_UALOADS)
+ ustw(val,(u16*)(M.mem_base + addr));
+#else
+ *(u16*)(M.mem_base + addr) = val;
+#endif
+}
+
+/****************************************************************************
+PARAMETERS:
+addr - Emulator memory address to read
+val - Value to store
+
+REMARKS:
+Writes a long value to emulator memory.
+****************************************************************************/
+void X86API wrl(
+ u32 addr,
+ u32 val)
+{
+DB( if (DEBUG_MEM_TRACE())
+ NV_PRINTF(LEVEL_INFO, "%#08x 4 <- %#x\n", addr, val);)
+ if (addr > M.mem_size - 4) {
+ DB(NV_PRINTF(LEVEL_INFO, "mem_write: address %#x out of range!\n", addr);)
+ HALT_SYS();
+ }
+#ifdef __BIG_ENDIAN__
+ if (addr & 0x1) {
+ *(u8*)(M.mem_base + addr + 0) = (val >> 0) & 0xff;
+ *(u8*)(M.mem_base + addr + 1) = (val >> 8) & 0xff;
+ *(u8*)(M.mem_base + addr + 2) = (val >> 16) & 0xff;
+ *(u8*)(M.mem_base + addr + 3) = (val >> 24) & 0xff;
+ }
+ else
+#endif
+#if defined(ALPHA_UALOADS)
+ stl_u(val,(u32*)(M.mem_base + addr));
+#elif defined(IA64_UALOADS)
+ ustl(val,(u32*)(M.mem_base + addr));
+#else
+ *(u32*)(M.mem_base + addr) = val;
+#endif
+}
+
+/****************************************************************************
+PARAMETERS:
+addr - PIO address to read
+RETURN:
+0
+REMARKS:
+Default PIO byte read function. Doesn't perform real inb.
+****************************************************************************/
+static u8 X86API p_inb(
+ X86EMU_pioAddr addr)
+{
+DB( if (DEBUG_IO_TRACE())
+ NV_PRINTF(LEVEL_INFO, "inb %#04x \n", addr);)
+ return 0;
+}
+
+/****************************************************************************
+PARAMETERS:
+addr - PIO address to read
+RETURN:
+0
+REMARKS:
+Default PIO word read function. Doesn't perform real inw.
+****************************************************************************/
+static u16 X86API p_inw(
+ X86EMU_pioAddr addr)
+{
+DB( if (DEBUG_IO_TRACE())
+ NV_PRINTF(LEVEL_INFO, "inw %#04x \n", addr);)
+ return 0;
+}
+
+/****************************************************************************
+PARAMETERS:
+addr - PIO address to read
+RETURN:
+0
+REMARKS:
+Default PIO long read function. Doesn't perform real inl.
+****************************************************************************/
+static u32 X86API p_inl(
+ X86EMU_pioAddr addr)
+{
+DB( if (DEBUG_IO_TRACE())
+ NV_PRINTF(LEVEL_INFO, "inl %#04x \n", addr);)
+ return 0;
+}
+
+/****************************************************************************
+PARAMETERS:
+addr - PIO address to write
+val - Value to store
+REMARKS:
+Default PIO byte write function. Doesn't perform real outb.
+****************************************************************************/
+static void X86API p_outb(
+ X86EMU_pioAddr addr,
+ u8 val)
+{
+DB( if (DEBUG_IO_TRACE())
+ NV_PRINTF(LEVEL_INFO, "outb %#02x -> %#04x \n", val, addr);)
+ return;
+}
+
+/****************************************************************************
+PARAMETERS:
+addr - PIO address to write
+val - Value to store
+REMARKS:
+Default PIO word write function. Doesn't perform real outw.
+****************************************************************************/
+static void X86API p_outw(
+ X86EMU_pioAddr addr,
+ u16 val)
+{
+DB( if (DEBUG_IO_TRACE())
+ NV_PRINTF(LEVEL_INFO, "outw %#04x -> %#04x \n", val, addr);)
+ return;
+}
+
+/****************************************************************************
+PARAMETERS:
+addr - PIO address to write
+val - Value to store
+REMARKS:
+Default PIO ;ong write function. Doesn't perform real outl.
+****************************************************************************/
+static void X86API p_outl(
+ X86EMU_pioAddr addr,
+ u32 val)
+{
+DB( if (DEBUG_IO_TRACE())
+ NV_PRINTF(LEVEL_INFO, "outl %#08x -> %#04x \n", val, addr);)
+ return;
+}
+
+/*------------------------- Global Variables ------------------------------*/
+
+u8 (X86APIP sys_rdb)(u32 addr) = rdb;
+u16 (X86APIP sys_rdw)(u32 addr) = rdw;
+u32 (X86APIP sys_rdl)(u32 addr) = rdl;
+void (X86APIP sys_wrb)(u32 addr,u8 val) = wrb;
+void (X86APIP sys_wrw)(u32 addr,u16 val) = wrw;
+void (X86APIP sys_wrl)(u32 addr,u32 val) = wrl;
+u8 (X86APIP sys_inb)(X86EMU_pioAddr addr) = p_inb;
+u16 (X86APIP sys_inw)(X86EMU_pioAddr addr) = p_inw;
+u32 (X86APIP sys_inl)(X86EMU_pioAddr addr) = p_inl;
+void (X86APIP sys_outb)(X86EMU_pioAddr addr, u8 val) = p_outb;
+void (X86APIP sys_outw)(X86EMU_pioAddr addr, u16 val) = p_outw;
+void (X86APIP sys_outl)(X86EMU_pioAddr addr, u32 val) = p_outl;
+
+/*----------------------------- Setup -------------------------------------*/
+
+/****************************************************************************
+PARAMETERS:
+funcs - New memory function pointers to make active
+
+REMARKS:
+This function is used to set the pointers to functions which access
+memory space, allowing the user application to override these functions
+and hook them out as necessary for their application.
+****************************************************************************/
+void X86EMU_setupMemFuncs(
+ X86EMU_memFuncs *funcs)
+{
+ sys_rdb = funcs->rdb;
+ sys_rdw = funcs->rdw;
+ sys_rdl = funcs->rdl;
+ sys_wrb = funcs->wrb;
+ sys_wrw = funcs->wrw;
+ sys_wrl = funcs->wrl;
+}
+
+/****************************************************************************
+PARAMETERS:
+funcs - New programmed I/O function pointers to make active
+
+REMARKS:
+This function is used to set the pointers to functions which access
+I/O space, allowing the user application to override these functions
+and hook them out as necessary for their application.
+****************************************************************************/
+void X86EMU_setupPioFuncs(
+ X86EMU_pioFuncs *funcs)
+{
+ sys_inb = funcs->inb;
+ sys_inw = funcs->inw;
+ sys_inl = funcs->inl;
+ sys_outb = funcs->outb;
+ sys_outw = funcs->outw;
+ sys_outl = funcs->outl;
+}
+
+/****************************************************************************
+PARAMETERS:
+funcs - New interrupt vector table to make active
+
+REMARKS:
+This function is used to set the pointers to functions which handle
+interrupt processing in the emulator, allowing the user application to
+hook interrupts as necessary for their application. Any interrupts that
+are not hooked by the user application, and reflected and handled internally
+in the emulator via the interrupt vector table. This allows the application
+to get control when the code being emulated executes specific software
+interrupts.
+****************************************************************************/
+void X86EMU_setupIntrFuncs(
+ X86EMU_intrFuncs funcs[])
+{
+ int i;
+
+ for (i=0; i < 256; i++)
+ _X86EMU_intrTab[i] = NULL;
+ if (funcs) {
+ for (i = 0; i < 256; i++)
+ _X86EMU_intrTab[i] = funcs[i];
+ }
+}
+
+/****************************************************************************
+PARAMETERS:
+int - New software interrupt to prepare for
+
+REMARKS:
+This function is used to set up the emulator state to exceute a software
+interrupt. This can be used by the user application code to allow an
+interrupt to be hooked, examined and then reflected back to the emulator
+so that the code in the emulator will continue processing the software
+interrupt as per normal. This essentially allows system code to actively
+hook and handle certain software interrupts as necessary.
+****************************************************************************/
+void X86EMU_prepareForInt(
+ int num)
+{
+ push_word((u16)M.x86.R_FLG);
+ CLEAR_FLAG(F_IF);
+ CLEAR_FLAG(F_TF);
+ push_word(M.x86.R_CS);
+ M.x86.R_CS = mem_access_word(num * 4 + 2);
+ push_word(M.x86.R_IP);
+ M.x86.R_IP = mem_access_word(num * 4);
+ M.x86.intr = 0;
+}