設定

硬體周邊裝置會透過匯流排 (例如 PCI 匯流排) 連接至 CPU。

開機時,BIOS (或同等平台啟動軟體) 會探索連接至 PCI 匯流排的所有周邊裝置。每個周邊裝置都會指派資源 (特別是中斷向量,以及設定暫存器的位址範圍)。

這會導致每次重新啟動時,分配給每個周邊裝置的實際資源可能不同。作業系統軟體啟動時,會列舉匯流排,並啟動所有支援裝置的驅動程式。驅動程式接著會呼叫 PCI 函式,取得裝置的設定資訊,以便對應暫存器並繫結至中斷。

基底位址暫存器

基底位址暫存器 (BAR) 是每個 PCI 裝置上的設定暫存器。BIOS 會在這裡儲存裝置資訊,例如指派的中斷向量和控制暫存器的位址。此外,該處也會儲存其他裝置專屬資訊。

驅動程式會從傳入的命名空間連線至 fuchsia.hardware.pci/Device 通訊協定:

#include <fidl/fuchsia.hardware.pci/cpp/wire.h>

// In Driver::Start(fdf::DriverContext context)
zx::result pci_client_end = context.incoming().Connect<fuchsia_hardware_pci::Service::Device>();
if (pci_client_end.is_error()) {
  return pci_client_end.take_error();
}
fidl::WireSyncClient<fuchsia_hardware_pci::Device> pci(std::move(pci_client_end.value()));

在 fuchsia.hardware.pci/Device 用戶端上呼叫 GetBar(bar_id),即可擷取 BAR 資源 (其中 bar_id 是 BAR 暫存器編號,開頭為 0),然後呼叫 fdf::MmioBuffer::Create(),將 BAR 的 VMO 對應至驅動程式庫的位址空間:

zx::result<fdf::MmioBuffer> MmioBuffer::Create(zx_off_t offset, size_t size, zx::vmo vmo,
                                               uint32_t cache_policy);

cache_policy 參數會決定存取的快取政策,並可採用下列值:

cache_policy 值 意義
ZX_CACHE_POLICY_CACHED 使用硬體快取
ZX_CACHE_POLICY_UNCACHED 停用快取
ZX_CACHE_POLICY_UNCACHED_DEVICE 停用快取,並視為裝置記憶體
ZX_CACHE_POLICY_WRITE_COMBINING 未快取,但會合併寫入

請注意,ZX_CACHE_POLICY_UNCACHED_DEVICE 取決於架構,在某些架構上可能等同於 ZX_CACHE_POLICY_UNCACHED。

讀取和寫入記憶體

fdf::MmioBuffer::Create() 傳回有效緩衝區後,您就可以透過 fdf::MmioBuffer 介面存取 BAR,例如:

#include <fidl/fuchsia.hardware.pci/cpp/wire.h>
#include <lib/driver/mmio/cpp/mmio-buffer.h>

fidl::WireResult bar_result = pci->GetBar(0);
if (!bar_result.ok()) {
  return zx::error(bar_result.status());
}
if (bar_result->is_error()) {
  return bar_result->take_error();
}

fuchsia_hardware_pci::wire::Bar& bar = bar_result->value()->result;
if (!bar.result.is_vmo()) {
  return zx::error(ZX_ERR_WRONG_TYPE);
}

zx::result<fdf::MmioBuffer> mmio = fdf::MmioBuffer::Create(
    0, bar.size, std::move(bar.result.vmo()), ZX_CACHE_POLICY_UNCACHED_DEVICE);
if (mmio.is_ok()) {
  mmio->Write32(0x1234, REGISTER_X);  // configure register X for deep sleep mode
}