/* * Copyright (c) 2021 Advanced Micro Devices, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef __DEV_AMDGPU_AMDGPU_VM_HH__ #define __DEV_AMDGPU_AMDGPU_VM_HH__ #include #include "arch/amdgpu/vega/pagetable_walker.hh" #include "base/intmath.hh" #include "dev/amdgpu/amdgpu_defines.hh" #include "mem/packet.hh" #include "mem/translation_gen.hh" #include "sim/serialize.hh" /** * MMIO offsets for graphics register bus manager (GRBM). These values were * taken from linux header files. The header files can be found here: * * https://github.com/RadeonOpenCompute/ROCK-Kernel-Driver/blob/roc-4.3.x/ * drivers/gpu/drm/amd/include/ asic_reg/gc/gc_9_0_offset.h * https://github.com/RadeonOpenCompute/ROCK-Kernel-Driver/blob/roc-4.3.x/ * drivers/gpu/drm/amd/include/ asic_reg/mmhub/mmhub_1_0_offset.h */ #define mmVM_INVALIDATE_ENG17_ACK 0x08c6 #define mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32 0x08eb #define mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32 0x08ec #define mmVM_CONTEXT0_PAGE_TABLE_START_ADDR_LO32 0x090b #define mmVM_CONTEXT0_PAGE_TABLE_START_ADDR_HI32 0x090c #define mmVM_CONTEXT0_PAGE_TABLE_END_ADDR_LO32 0x092b #define mmVM_CONTEXT0_PAGE_TABLE_END_ADDR_HI32 0x092c #define mmMC_VM_FB_OFFSET 0x096b #define mmMC_VM_FB_LOCATION_BASE 0x0980 #define mmMC_VM_FB_LOCATION_TOP 0x0981 #define mmMC_VM_AGP_TOP 0x0982 #define mmMC_VM_AGP_BOT 0x0983 #define mmMC_VM_AGP_BASE 0x0984 #define mmMC_VM_SYSTEM_APERTURE_LOW_ADDR 0x0985 #define mmMC_VM_SYSTEM_APERTURE_HIGH_ADDR 0x0986 #define mmMMHUB_VM_INVALIDATE_ENG17_SEM 0x06e2 #define mmMMHUB_VM_INVALIDATE_ENG17_REQ 0x06f4 #define mmMMHUB_VM_INVALIDATE_ENG17_ACK 0x0706 #define mmMMHUB_VM_FB_LOCATION_BASE 0x082c #define mmMMHUB_VM_FB_LOCATION_TOP 0x082d // AMD GPUs support 16 different virtual address spaces static constexpr int AMDGPU_VM_COUNT = 16; // These apertures have a fixed page size static constexpr int AMDGPU_AGP_PAGE_SIZE = 4096; static constexpr int AMDGPU_GART_PAGE_SIZE = 4096; static constexpr int AMDGPU_MMHUB_PAGE_SIZE = 4096; // Vega page size can be any power of 2 between 4kB and 1GB. static constexpr int AMDGPU_USER_PAGE_SIZE = 4096; namespace gem5 { class AMDGPUVM : public Serializable { private: typedef struct GEM5_PACKED { // Page table addresses: from (Base + Start) to (End) union { struct { uint32_t ptBaseL; uint32_t ptBaseH; }; Addr ptBase; }; union { struct { uint32_t ptStartL; uint32_t ptStartH; }; Addr ptStart; }; union { struct { uint32_t ptEndL; uint32_t ptEndH; }; Addr ptEnd; }; } AMDGPUVMContext; typedef struct AMDGPUSysVMContext : AMDGPUVMContext { Addr agpBase; Addr agpTop; Addr agpBot; Addr fbBase; Addr fbTop; Addr fbOffset; Addr sysAddrL; Addr sysAddrH; } AMDGPUSysVMContext; AMDGPUSysVMContext vmContext0; std::vector vmContexts; // MMHUB aperture. These addresses mirror the framebuffer, so addresses // can be calculated by subtracting the base address. uint64_t mmhubBase = 0x0; uint64_t mmhubTop = 0x0; /** * List of TLBs associated with the GPU device. This is used for flushing * the TLBs upon a driver request. */ std::vector gpu_tlbs; public: AMDGPUVM(); /** * Return base address of GART table in framebuffer. */ Addr gartBase(); /** * Return size of GART in number of PTEs. */ Addr gartSize(); /** * Copy of GART table. Typically resides in device memory, however we use * a copy in gem5 to simplify the interface. */ std::unordered_map gartTable; void readMMIO(PacketPtr pkt, Addr offset); void writeMMIO(PacketPtr pkt, Addr offset); /** * Methods for resolving apertures */ bool inAGP(Addr vaddr) { return ((vaddr >= vmContext0.agpBot) && (vaddr <= vmContext0.agpTop)); } Addr getAGPBot() { return vmContext0.agpBot; } Addr getAGPTop() { return vmContext0.agpTop; } Addr getAGPBase() { return vmContext0.agpBase; } bool inMMHUB(Addr vaddr) { return ((vaddr >= getMMHUBBase()) && (vaddr <= getMMHUBTop())); } Addr getMMHUBBase() { return mmhubBase; } Addr getMMHUBTop() { return mmhubTop; } bool inFB(Addr vaddr) { return ((vaddr >= vmContext0.fbBase) && (vaddr <= vmContext0.fbTop)); } Addr getFBBase() { return vmContext0.fbBase; } Addr getFBTop() { return vmContext0.fbTop; } Addr getFBOffset() { return vmContext0.fbOffset; } bool inSys(Addr vaddr) { return ((vaddr >= vmContext0.sysAddrL) && (vaddr <= vmContext0.sysAddrH)); } Addr getSysAddrRangeLow () { return vmContext0.sysAddrL; } Addr getSysAddrRangeHigh () { return vmContext0.sysAddrH; } Addr getMmioAperture(Addr addr) { // Aperture ranges: // NBIO 0x0 - 0x4280 // IH 0x4280 - 0x4980 // SDMA0 0x4980 - 0x5180 // SDMA1 0x5180 - 0x5980 // GRBM 0x8000 - 0xD000 // GFX 0x28000 - 0x3F000 // MMHUB 0x68000 - 0x6a120 if (IH_BASE <= addr && addr < IH_BASE + IH_SIZE) return IH_BASE; else if (SDMA0_BASE <= addr && addr < SDMA0_BASE + SDMA_SIZE) return SDMA0_BASE; else if (SDMA1_BASE <= addr && addr < SDMA1_BASE + SDMA_SIZE) return SDMA1_BASE; else if (GRBM_BASE <= addr && addr < GRBM_BASE + GRBM_SIZE) return GRBM_BASE; else if (GFX_BASE <= addr && addr < GFX_BASE + GFX_SIZE) return GFX_BASE; else if (MMHUB_BASE <= addr && addr < MMHUB_BASE + MMHUB_SIZE) return MMHUB_BASE; else { warn_once("Accessing unsupported MMIO aperture! Assuming NBIO\n"); return NBIO_BASE; } } // Gettig mapped aperture base addresses Addr getFrameAperture(Addr addr) { if (addr < gartBase()) { warn_once("Accessing unsupported frame apperture!\n"); return ~0; } else if (gartBase() <= addr && addr < (gartBase() + gartSize())) { return gartBase(); } else { warn_once("Accessing unsupported frame apperture!\n"); return ~0; } } /** * Page table base/start accessors for user VMIDs. */ void setPageTableBase(uint16_t vmid, Addr ptBase) { vmContexts[vmid].ptBase = ptBase; } Addr getPageTableBase(uint16_t vmid) { assert(vmid > 0 && vmid < vmContexts.size()); return vmContexts[vmid].ptBase; } Addr getPageTableStart(uint16_t vmid) { assert(vmid > 0 && vmid < vmContexts.size()); return vmContexts[vmid].ptStart; } /** * Control methods for TLBs associated with the GPU device. */ void registerTLB(VegaISA::GpuTLB *tlb); void invalidateTLBs(); void serialize(CheckpointOut &cp) const override; void unserialize(CheckpointIn &cp) override; /** * Translation range generators * * AGP - Legacy interface to device memory. Addr range is set via MMIO * GART - Legacy privledged translation table. Table in device memory * MMHUB - Shadow range of VRAM */ class AGPTranslationGen : public TranslationGen { private: AMDGPUVM *vm; void translate(Range &range) const override; public: AGPTranslationGen(AMDGPUVM *_vm, Addr vaddr, Addr size) : TranslationGen(vaddr, size), vm(_vm) {} }; class GARTTranslationGen : public TranslationGen { private: AMDGPUVM *vm; void translate(Range &range) const override; public: GARTTranslationGen(AMDGPUVM *_vm, Addr vaddr, Addr size) : TranslationGen(vaddr, size), vm(_vm) {} }; class MMHUBTranslationGen : public TranslationGen { private: AMDGPUVM *vm; void translate(Range &range) const override; public: MMHUBTranslationGen(AMDGPUVM *_vm, Addr vaddr, Addr size) : TranslationGen(vaddr, size), vm(_vm) {} }; class UserTranslationGen : public TranslationGen { private: AMDGPUVM *vm; VegaISA::Walker *walker; int vmid; void translate(Range &range) const override; public: UserTranslationGen(AMDGPUVM *_vm, VegaISA::Walker *_walker, int _vmid, Addr vaddr, Addr size) : TranslationGen(vaddr, size), vm(_vm), walker(_walker), vmid(_vmid) {} }; }; } // namespace gem5 #endif // __DEV_AMDGPU_AMDGPU_VM_HH__