Emulating hardware (vdev wdt-sp805) (2024)

The wdt-sp805 vdev emulates a hardware watchdog for ARM platforms.

When it constructs and configures itself, the wdt-sp805 vdev defines its virtual hardware, and specifies default values such as clock frequency.

Since it emulates an actual physical device, this vdev:

  • is architecture-specific
  • doesn't require a custom driver in the guest; the guest's driver for the equivalent hardware device should suffice

For information about how to configure and use the vdev, see the vdev wdt-sp805 reference in the User's Guide “Virtual Device Reference” chapter.

Note:

The wdt-sp805 vdev emulates the ARM Watchdog Module (SP805); for more information about this hardware device, see the ARM Information Centre Documentation at http://infocenter.arm.com/help/topic/com.arm.doc.ddi0270b/index.html

This vdev doesn't support controller interrupts or multiple clock modes (i.e., WDOGCLK as a distinct sub-multiple of the PCLK interface clock).

Defining defaults

Before it parses the options passed to it through the VM configuration, the wdt-sp805 vdev must provide default values for some options. Specifically, it must provide default values for options that are in fact actually optional; that is, options that can be omitted from the VM configuration without causing the VM startup to fail.

For example, if the user doesn't specify the frequency or the loc options, the wdt-sp805 vdev will use the values defined by, respectively, DEFAULT_FREQ and SP805_ARMFM_BASE_ADDR. When it begins processing its configuration options, the vdev loads these default values into the structure that defines it (see “Initializing the vdev state” below).

Hardware emulation

Since the wdt-sp805 vdev emulates hardware and to a driver in the guest must be indistinguishable from an actual physical device, it must present the guest with the same interfaces that the physical device presents.

Below is a portion of the values the vdev defines so that it can emulate the SP805 watchdog as specified for the ARMv8 foundation model: the base address for the watchdog device on the hardware, the offsets from the base address for the relevant device registers, the clock frequency, and some flags:

#define SP805_ARMFM_BASE_ADDR 0x1C0F0000 ///< Base address#define DEFAULT_FREQ 25000000UL ///< Interface clock frequency#define WDOG_LOAD 0x0000 ///< Load register#define WDOG_VALUE 0x0004 ///< Value register#define WDOG_CONTROL 0x0008 ///< Control register #define WDOG_CONTROL_INTEN (1 << 0) ///< Enable the counter & the interrupt #define WDOG_CONTROL_RESEN (1 << 1) ///< Unmask module reset output...#define PCELLID2 0x0FF8 ///< Prime Cell ID 2#define PCELLID3 0x0FFC ///< Prime Cell ID 3

Note: Note that vdev trace vdev doesn't do any virtual hardware setup of the sort that vdev wdt-sp805 does; it doesn't need to because it isn't emulating a hardware device.

Defining the device

The vdev defines itself as a data structure. This structure is initialized by the startup, and updated as the state of the vdev changes:

/// One instance of an SP805 watchdog timerstruct sp805_state { struct wdog_state s_wdog; ///< State of the generic watchdog device struct guest_timer *s_gtimer; ///< Virtual timer used to fire events uint64_t s_resolution; ///< Timer resolution uint64_t s_freq; ///< Interface clock frequency uint64_t s_scale; ///< Amount to scale counter to convert to gtimer resolution uint64_t s_scaled_reload; ///< Reload value, prescaled to gtimer resolution uint32_t wdog_load; ///< Load register (R/W) uint32_t wdog_value; ///< Value register (RO) uint32_t wdog_control; ///< Control register (RW) uint32_t wdog_intclr; ///< Interrupt clear register (WO) uint32_t wdog_ris; ///< Raw interrupt status register (RO) uint32_t wdog_mis; ///< Masked interrupt status register (RO) uint32_t wdog_lock; ///< Lock register (RW) enum sp805_states timer_state; ///< Current timer state};

The vdev also specifies its possible states, which are the same as the states of the hardware device it is emulating:

enum sp805_states { WDT_DISABLED, WDT_RUNNING, WDT_EXPIRED};

Defining the options

The code snippets below shows how vdev wdt-sp805 defines its options:

enum { OPT_FREQUENCY_IDX = WDOG_OPT_NUM_OPTS, OPT_NUM_OPTS};...sp805_register(void) { static const char *const sp805_options[OPT_NUM_OPTS+1] = { WDOG_OPTIONS, [OPT_FREQUENCY_IDX] = "frequency", [OPT_NUM_OPTS] = NULL, };...

This is exactly like how the trace vdev defines its options (see “Defining the options” in the “The Basics: vdev trace” chapter).

Like other vdevs, the wdt-sp805 vdev needs to define only those options that are specific to itself. Common options, such as the loc option, are defined by the qvm process, which looks after parsing them (see “Common vdev options” in the User's Guide).

Unlike many vdevs, however, this control function for the watchdog vdevs calls a common function, wdog_control(); this function looks after parsing the action option, which is common to both watchdogs. Thus, for these vdevs the code looking after parsing their options is in three places: the qvm process for common options, wdog_control() defined in the qvm/wdog.h header file for options common to both vdevs, and the *_control() function for each vdev.

Creating a timer

Notice that at the end of its startup stage, this vdev calls guest_timer_create(), adjusting the timer resolution if necessary:

case VDEV_CTRL_OPTIONS_END: state->s_gtimer = guest_timer_create(NULL, vdp, NULL, &state->s_resolution); if (state->s_gtimer == NULL) { // If the timer creation failed, the resolution variable has the reason. return (int)state->s_resolution; } if (state->s_resolution > state->s_freq) { // The qvm timer resolution is greater than the watchdog module's interface clock. state->s_scale = state->s_resolution / state->s_freq; state->s_scaled_reload = state->wdog_load * state->s_scale; } else { state->s_scale = state->s_freq / state->s_resolution; state->s_scaled_reload = state->wdog_load / state->s_scale; } break;

Populating the vdev factory and registering the vdev

Like vdev trace, vdev wdt-sp805 populates a factory page for itself (sp805_factory), and calls vdev_register_factory() to register itself.

The sp805_factory factory page is not very different from the vdtrace_factory data structure used by the trace vdev (see “Defining the vdev in the factory structure” in the “The Basics: vdev trace” chapter). Note, however, the sp805_timer member, which references the sp805_timer() function (see “Timer management functions” in this chapter).

Initializing the vdev state

When it starts, this vdev must initialize some values, such as its location in memory and the register base address. Note that the location of the device is set in guest-physical memory (QST_MEMORY; see the “qvm_state_types” in the Virtual Device Developer's API Reference); and that the location of the vdev is set to the ARMv8 foundation model location (SP805_ARMFM_BASE_ADDR):

 case VDEV_CTRL_OPTIONS_START: vdp->v_block.type = QST_MEMORY; vdp->v_block.location = SP805_ARMFM_BASE_ADDR; vdp->v_block.length = 0x1000; // Initialize non-zero registers to reset values state->wdog_load = 0xFFFFFFFF; state->wdog_value = 0xFFFFFFFF; state->s_freq = DEFAULT_FREQ; state->s_wdog.ws_vdev = vdp; break;
Emulating hardware (vdev wdt-sp805) (2024)
Top Articles
Latest Posts
Article information

Author: Margart Wisoky

Last Updated:

Views: 6338

Rating: 4.8 / 5 (58 voted)

Reviews: 81% of readers found this page helpful

Author information

Name: Margart Wisoky

Birthday: 1993-05-13

Address: 2113 Abernathy Knoll, New Tamerafurt, CT 66893-2169

Phone: +25815234346805

Job: Central Developer

Hobby: Machining, Pottery, Rafting, Cosplaying, Jogging, Taekwondo, Scouting

Introduction: My name is Margart Wisoky, I am a gorgeous, shiny, successful, beautiful, adventurous, excited, pleasant person who loves writing and wants to share my knowledge and understanding with you.