Skip to content

Commit

Permalink
Use driver store path for xilinx_xrt on Windows (#7679)
Browse files Browse the repository at this point in the history
* Provide internal access to platform specific xilinx_xrt()

Expose xrt_core::environment::xilinx_xrt() in module_loader.cpp
Code to platform specific requirements.

Add detail platform specific implementation.  Default is to return
environment variable XILINX_XRT if set.

On linux conditionally /usr or /opt/xilinx/xrt.
On windows same directory as xrt_coreutil.dll (to be change next commit)

Signed-off-by: Soren Soe <[email protected]>

* Use driver store path for xilinx_xrt on Windows

Implement xrt_core::environment::xilinx_xrt() on Windows to use driver
store path if available.

- If XILINX_XRT is set in environment, then return the value of XILINX_XRT
- Else compute as driver store path if available (new)
- Else return same directory as xrt_coreutil.dll is loaded from

Add internal API for obtaining absolute path of xclbin file. For
Windows, the xclbin path will be the same as xilinx_xrt().

The code for xilinx_xrt() and xclbin_path() is conditional based on
platform.  xilinx_xrt() is used to load the xrt_core shim library,
hence cannot be implemented at shim layer.

Signed-off-by: Soren Soe <[email protected]>

* Conditionally compile for windows when WDK is available

Signed-off-by: Soren Soe <[email protected]>

* Use compile defintion for WDK available

---------

Signed-off-by: Soren Soe <[email protected]>
  • Loading branch information
stsoe authored Aug 29, 2023
1 parent f227c85 commit b01bb53
Show file tree
Hide file tree
Showing 5 changed files with 379 additions and 26 deletions.
27 changes: 27 additions & 0 deletions src/runtime_src/core/common/detail/linux/xilinx_xrt.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.
#include <boost/filesystem/path.hpp>
#include <stdexcept>
#include <string>
namespace xrt_core::detail {

namespace bfs = boost::filesystem;

bfs::path
xilinx_xrt()
{
#if defined (__aarch64__) || defined (__arm__)
return bfs::path("/usr");
#else
return bfs::path("/opt/xilinx/xrt");
#endif
}

bfs::path
xclbin_path(const std::string& xclbin)
{
throw std::runtime_error("xclbin repo path not yet implemented on Linux");
}

} // xrt_core::detail

266 changes: 266 additions & 0 deletions src/runtime_src/core/common/detail/windows/xilinx_xrt.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,266 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.

#include "core/common/debug.h"
#include "core/common/dlfcn.h"

#pragma warning(disable : 4005)
#include <windows.h>
#include <ntstatus.h>

#if defined(XRT_WINDOWS_HAS_WDK)
# include <d3dkmthk.h>
#endif

#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/path.hpp>
#include <string>
#include <cstring>
#include <cstdlib>

#if defined(XRT_WINDOWS_HAS_WDK)
namespace xrt_core::detail::windows {

// D3DKMTQueryAdapterInfo returns path rooted in \SystemRoot\, but no
// other API understands this path, so replace it with the actual
// system root.
static std::string
replace_systemroot(std::string str)
{
auto pos = str.find("\\SystemRoot\\");
if (pos != 0)
return str;

char system_root[MAX_PATH] = {};
if (GetWindowsDirectoryA(system_root, sizeof(system_root)) == 0)
throw std::runtime_error("Unable to get Windows directory");

str.replace(pos, std::strlen("\\SystemRoot"), system_root);
return str;
}

// Windows APIs return wchar_t strings, but we want to use std::string.
// Convert to utf8 multibyte string.
static std::string
utf8(const std::wstring& wstr)
{
auto size = WideCharToMultiByte(CP_UTF8, 0, wstr.data(), -1, NULL, 0, NULL, NULL);
std::string str(size, 0);
auto result = WideCharToMultiByte(
CP_UTF8, // CodePage
0, // dwFlags conversion type must be 0 for CP_UTF8
wstr.data(), // lpWideCharStr
-1, // cchWideChar -1 indicates null terminated string
str.data(), // lpMultiByteStr output buffer
size, // cbMultiByte size of output buffer
NULL, // lpDefaultChar, NULL implies system default
NULL); // lpUsedDefaultChar must be NULL for CP_UTF8

// strip included null terminator from std::string
while (str.back() == '\0')
str.pop_back();

if (result == 0)
throw std::runtime_error("Unable to convert wide string to multi-byte");

return str;
}

// Manage gdi dll loading and symbol lookup
class gdilib
{
using dll_guard = std::unique_ptr<void, decltype(&xrt_core::dlclose)>;
dll_guard dll;

public:
gdilib(const char* dllnm)
: dll(xrt_core::dlopen(dllnm, 0), xrt_core::dlclose)
{}

template <typename FunctionType>
FunctionType
get(const char* symbol) const
{
if (auto dllsym = xrt_core::dlsym(dll.get(), symbol))
return static_cast<FunctionType>(dllsym);

throw std::runtime_error("No such symbol '" + std::string(symbol) + "' in gdi32.dll");
}
};

static gdilib gdi("gdi32.dll");

// Abstraction for adapter opened by D3DKMTEnumAdapters3. Move semantics for
// storing in container, while making sure all enumerated adapters are eventually
// closed using D3DKMTCloseAdapter
struct adapter
{
D3DKMT_ADAPTERINFO m_info = {};

adapter() = default;

~adapter()
{
if (!m_info.hAdapter)
return;

D3DKMT_CLOSEADAPTER close_adapter_args = {};
close_adapter_args.hAdapter = m_info.hAdapter;
D3DKMTCloseAdapter(&close_adapter_args);
}

// Movable
adapter(adapter&& rhs)
: m_info(std::move(rhs.m_info))
{
// Avoid double close
rhs.m_info.hAdapter = 0;
}

// Not copyable
adapter(const adapter&) = delete;
adapter& operator=(const adapter&) = delete;

D3DKMT_HANDLE
handle() const
{
return m_info.hAdapter;
}

// Query the driver store path for this adapter
std::string
driver_store_path() const
{
auto adapter_info = gdi.get<PFND3DKMT_QUERYADAPTERINFO>("D3DKMTQueryAdapterInfo");

D3DKMT_QUERYADAPTERINFO query_adapter_info = {};
D3DDDI_QUERYREGISTRY_INFO query_registry_info = {};
query_adapter_info.hAdapter = handle();
query_adapter_info.Type = KMTQAITYPE_QUERYREGISTRY;
query_adapter_info.pPrivateDriverData = &query_registry_info;
query_adapter_info.PrivateDriverDataSize = sizeof(query_registry_info);
query_registry_info.QueryType = D3DDDI_QUERYREGISTRY_DRIVERSTOREPATH;
auto status = adapter_info(&query_adapter_info);
if (status != STATUS_SUCCESS)
throw std::runtime_error("D3DKMTQueryAdapterInfo failed KMTQAITYPE_QUERYREGISTRY");

if (query_registry_info.Status != D3DDDI_QUERYREGISTRY_STATUS_BUFFER_OVERFLOW)
throw std::runtime_error("Unexpected D3DDDI_QUERYREGISTRY_STATUS");

// Save the size of the output value
// Valid only when Status == D3DDDI_QUERYREGISTRY_STATUS_BUFFER_OVERFLOW
auto output_value_size = query_registry_info.OutputValueSize;

// Allocate variable sized query registey info buffer and query again
std::vector<char> buffer(sizeof(D3DDDI_QUERYREGISTRY_INFO) + output_value_size);
std::memcpy(buffer.data(), &query_registry_info, sizeof(D3DDDI_QUERYREGISTRY_INFO));
query_adapter_info.pPrivateDriverData = buffer.data();
query_adapter_info.PrivateDriverDataSize = static_cast<UINT>(buffer.size());
status = adapter_info(&query_adapter_info);
if (status != STATUS_SUCCESS)
throw std::runtime_error("D3DKMTQueryAdapterInfo failed KMTQAITYPE_QUERYREGISTRY");

// Interpret the data, throw on error
auto query_info = reinterpret_cast<D3DDDI_QUERYREGISTRY_INFO*>(buffer.data());
if (query_info->Status != D3DDDI_QUERYREGISTRY_STATUS_SUCCESS)
throw std::runtime_error("D3DDDI_QUERYREGISTRY_STATUS_SUCCESS failed");

// Return the driver path
std::wstring wstr{query_info->OutputString, query_info->OutputString + output_value_size};
return replace_systemroot(utf8(wstr));
}
};

// Abstraction to manage list of enumerated adapters
struct adapter_list
{
std::vector<adapter> m_adapters;

adapter_list()
{
// Determine size of adapter list
D3DKMT_ENUMADAPTERS3 enum_adapters_args = {};
enum_adapters_args.Filter.IncludeComputeOnly = 1;
auto enum_adapters = gdi.get<PFND3DKMT_ENUMADAPTERS3>("D3DKMTEnumAdapters3");
auto status = enum_adapters(&enum_adapters_args);
if (status != STATUS_SUCCESS)
throw std::runtime_error("D3DKMTEnumAdapters3 failed ");

m_adapters.resize(enum_adapters_args.NumAdapters);

// Enumerate adapters
enum_adapters_args.pAdapters = reinterpret_cast<D3DKMT_ADAPTERINFO*>(m_adapters.data());
status = enum_adapters(&enum_adapters_args);
if (status != STATUS_SUCCESS)
throw std::runtime_error("D3DKMTEnumAdapters3 failed");
m_adapters.resize(enum_adapters_args.NumAdapters);
}

// Return first matching adapter
const adapter*
find(const std::string& match)
{
const std::wstring driver_description{match.begin(), match.end()};
auto adapter_info = gdi.get<PFND3DKMT_QUERYADAPTERINFO>("D3DKMTQueryAdapterInfo");
for (const auto& adapter : m_adapters) {
D3DKMT_QUERYADAPTERINFO query_adapter_info_args = {};
D3DKMT_DRIVER_DESCRIPTION query_driver_description = {};
query_adapter_info_args.hAdapter = adapter.handle();
query_adapter_info_args.Type = KMTQAITYPE_DRIVER_DESCRIPTION;
query_adapter_info_args.pPrivateDriverData = &query_driver_description;
query_adapter_info_args.PrivateDriverDataSize = sizeof(query_driver_description);
auto status = adapter_info(&query_adapter_info_args);
if (status != STATUS_SUCCESS)
throw std::runtime_error("D3DKMTQueryAdapterInfo failed KMTQAITYPE_DRIVER_DESCRIPTION");

if (std::wstring(query_driver_description.DriverDescription) == driver_description)
return &adapter;
}

return nullptr;
}
};

} // xrt_core::detail::windows
#endif // XRT_WINDOWS_HAS_WDK

namespace xrt_core::detail {

namespace bfs = boost::filesystem;

bfs::path
xilinx_xrt()
{
#if defined(XRT_WINDOWS_HAS_WDK)
// For wdf make sure to continue loading from same location as coreutil
windows::adapter_list adapters;

// Tight coupling with KMD driver description string
auto adapter = adapters.find("IPU Compute Accelerator Device");

// If no matching adapter found, return coreutil path (legacy)
if (!adapter)
return bfs::path(xrt_core::dlpath("xrt_coreutil.dll")).parent_path();

return adapter->driver_store_path();
#else
// Without WDK we can't query the driver store path, so return coreutil path
return bfs::path(xrt_core::dlpath("xrt_coreutil.dll")).parent_path();
#endif
}

bfs::path
xclbin_path(const std::string& xclbin)
{
// For time being, xclbin repo is same as xilinx_xrt
static auto repo = xilinx_xrt();
auto xpath = repo / xclbin;

if (!bfs::exists(xpath))
throw std::runtime_error("xclbin not found: " + xpath.string());

return xpath;
}

} // xrt_core::detail

12 changes: 12 additions & 0 deletions src/runtime_src/core/common/detail/xilinx_xrt.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.
#ifndef core_common_detail_xilinx_xrt_h
#define core_common_detail_xilinx_xrt_h

#ifdef _WIN32
# include "core/common/detail/windows/xilinx_xrt.h"
#else
# include "core/common/detail/linux/xilinx_xrt.h"
#endif

#endif
53 changes: 42 additions & 11 deletions src/runtime_src/core/common/module_loader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@

#include "core/common/dlfcn.h"
#include "core/common/config_reader.h"
#include "detail/xilinx_xrt.h"

#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/path.hpp>
#include <iostream>


#ifdef _WIN32
# pragma warning (disable : 4996)
#endif
Expand Down Expand Up @@ -96,22 +96,35 @@ shim_name()
}

static bfs::path
xilinx_xrt()
get_xilinx_xrt()
{
bfs::path xrt(value_or_empty(getenv("XILINX_XRT")));
if (xrt.empty()){
#if defined (__aarch64__) || defined (__arm__)
xrt = bfs::path("/usr");
#elif defined (_WIN32)
xrt = bfs::path(xrt_core::dlpath("xrt_coreutil.dll")).parent_path();
#else
throw std::runtime_error("XILINX_XRT not set");
#endif
}
if (!xrt.empty())
return xrt;

return xrt_core::detail::xilinx_xrt();
}

static bfs::path
xilinx_xrt()
{
static bfs::path xrt = get_xilinx_xrt();
return xrt;
}

static bfs::path
xclbin_path(const std::string& xclbin)
{
bfs::path xpath(xclbin);
if (!xpath.is_absolute())
xpath = xrt_core::detail::xclbin_path(xclbin);

if (bfs::exists(xpath) && bfs::is_regular_file(xpath))
return xpath;

throw std::runtime_error("No such xclbin '" + xpath.string() + "'");
}

static bfs::path
module_path(const std::string& module)
{
Expand All @@ -133,7 +146,9 @@ static bfs::path
shim_path()
{
auto path = xilinx_xrt();
std::cout << "xilinx_xrt: " << path << '\n';
auto name = shim_name();
std::cout << "shim_name: " << name << '\n';

#ifdef _WIN32
path /= name + ".dll";
Expand Down Expand Up @@ -224,4 +239,20 @@ driver_loader()
load_library(p);
}

namespace environment {

std::string
xilinx_xrt()
{
return ::xilinx_xrt().string();
}

std::string
xclbin_path(const std::string& xclbin_name)
{
return ::xclbin_path(xclbin_name).string();
}

} // environment

} // xrt_core
Loading

0 comments on commit b01bb53

Please sign in to comment.