| // Copyright 2023 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "qemu-riscv64.h" |
| |
| #include <assert.h> |
| #include <fidl/fuchsia.hardware.platform.bus/cpp/driver/fidl.h> |
| #include <fidl/fuchsia.hardware.platform.bus/cpp/fidl.h> |
| #include <lib/ddk/binding_driver.h> |
| #include <lib/ddk/debug.h> |
| #include <lib/ddk/device.h> |
| #include <lib/ddk/driver.h> |
| #include <lib/ddk/platform-defs.h> |
| #include <lib/zx/result.h> |
| #include <stdint.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <zircon/threads.h> |
| |
| #include <fbl/alloc_checker.h> |
| |
| #include "fidl/fuchsia.hardware.platform.bus/cpp/natural_types.h" |
| #include "lib/fdf/cpp/arena.h" |
| |
| namespace board_qemu_riscv64 { |
| namespace fpbus = fuchsia_hardware_platform_bus; |
| |
| void QemuRiscv64::SysinfoInit() { |
| fdf::Arena arena('RISC'); |
| fpbus::BootloaderInfo bootloader_info; |
| bootloader_info.vendor() = "<unknown>"; |
| { |
| fidl::Arena fidl_arena; |
| auto result = pbus_.buffer(arena)->SetBootloaderInfo(fidl::ToWire(fidl_arena, bootloader_info)); |
| if (!result.ok()) { |
| zxlogf(ERROR, "SetBoardInfo request failed: %s", result.FormatDescription().data()); |
| } else if (result->is_error()) { |
| zxlogf(ERROR, "SetBoardInfo failed: %s", zx_status_get_string(result->error_value())); |
| } |
| } |
| } |
| |
| void QemuRiscv64::DdkInit(ddk::InitTxn txn) { |
| SysinfoInit(); |
| zx::result<> result = SysmemInit(); |
| if (result.is_error()) { |
| zxlogf(ERROR, "Couldn't initialize sysmem: %s", result.status_string()); |
| return txn.Reply(result.error_value()); |
| } |
| |
| result = RtcInit(); |
| if (result.is_error()) { |
| zxlogf(ERROR, "Couldn't initialize rtc: %s", result.status_string()); |
| return txn.Reply(result.error_value()); |
| } |
| |
| result = PcirootInit(); |
| if (result.is_error()) { |
| zxlogf(ERROR, "Couldn't initialize pciroot: %s", result.status_string()); |
| return txn.Reply(result.error_value()); |
| } |
| |
| zxlogf(DEBUG, "Init successful"); |
| txn.Reply(ZX_OK); |
| } |
| |
| zx_status_t QemuRiscv64::Create(void* ctx, zx_device_t* parent) { |
| auto endpoints = fdf::CreateEndpoints<fuchsia_hardware_platform_bus::PlatformBus>(); |
| if (endpoints.is_error()) { |
| return endpoints.error_value(); |
| } |
| |
| zx_status_t status = device_connect_runtime_protocol( |
| parent, fpbus::Service::PlatformBus::ServiceName, fpbus::Service::PlatformBus::Name, |
| endpoints->server.TakeHandle().release()); |
| if (status != ZX_OK) { |
| zxlogf(ERROR, "Failed to connect to platform bus: %s", zx_status_get_string(status)); |
| return status; |
| } |
| |
| fbl::AllocChecker ac; |
| auto board = fbl::make_unique_checked<QemuRiscv64>(&ac, parent, std::move(endpoints->client)); |
| if (!ac.check()) { |
| return ZX_ERR_NO_MEMORY; |
| } |
| |
| status = board->DdkAdd("qemu-riscv64", DEVICE_ADD_NON_BINDABLE); |
| if (status != ZX_OK) { |
| zxlogf(ERROR, "DdkAdd failed: %s", zx_status_get_string(status)); |
| return status; |
| } |
| |
| [[maybe_unused]] auto ptr = board.release(); |
| return ZX_OK; |
| } |
| |
| } // namespace board_qemu_riscv64 |
| |
| static constexpr zx_driver_ops_t driver_ops = []() { |
| zx_driver_ops_t ops = {}; |
| ops.version = DRIVER_OPS_VERSION; |
| ops.bind = board_qemu_riscv64::QemuRiscv64::Create; |
| return ops; |
| }(); |
| |
| // clang-format off |
| ZIRCON_DRIVER(qemu-riscv64, driver_ops, "zircon", "0.1"); |
| // clang-format on |