riscv32/riscv64/riscv128 -> max_xlen -> phys_mem_map_init() -> riscv_cpu_init(mem_map, max_xlen) -> cpu_register_ram(0x80000000, ram_size) -> cpu_register_ram(0x00000000, 64 KiB) -> cpu_register_device(CLINT) -> cpu_register_device(PLIC) -> cpu_register_device(HTIF)
Machine topology is fixed and explicitEach RISC-V machine name chooses XLEN, then registers RAM and devices into one `PhysMemoryMap`.
CLINT and PLIC feed CPU interrupt stateTimer and external interrupt data flows converge on RISC-V `mip` bits.
CLINT reads expose emulated time and `timecmp`; writes clear timer interrupt state. PLIC IRQ signals set or clear pending bits, and `plic_update_mip()` projects pending external interrupts into machine and supervisor interrupt-pending bits.
device raises IRQ -> set_irq(IRQSignal) -> plic_set_irq(irq_num, state) -> plic_pending_irq changes -> plic_update_mip() -> riscv_cpu_set_mip(MIP_MEIP | MIP_SEIP)
VirtIO devices are placed in a linear MMIO bankEvery configured device advances `vbus->addr` by `VIRTIO_SIZE` and gets the next PLIC IRQ.
VIRTIO_BASE_ADDR = 0x40010000 VIRTIO_SIZE = 0x1000 VIRTIO_IRQ = 1 console -> net -> block drives -> 9P fs -> keyboard -> tablet each device: vbus->irq = &plic_irq[next_irq] virtio_*_init(vbus, backend) vbus->addr += VIRTIO_SIZE next_irq++
Boot payloads are copied into guest RAMBIOS, optional kernel/initrd, FDT, and a low-RAM trampoline form the initial guest view.
`copy_bios()` copies the BIOS at RAM base, aligns and copies the kernel, places initrd near the lower half of RAM, builds an FDT in low RAM, and writes a small trampoline at `0x1000` to jump to `0x80000000` with `a0=hartid` and `a1=dtb`.
RAM_BASE_ADDR + 0: BIOS bytes aligned kernel bytes optional initrd bytes low RAM: 0x1000 boot trampoline 0x1000 + 64 flattened device tree
Machine class hooks drive schedulingThe generic run loop asks the machine for sleep time and CPU execution.
`riscv_machine_get_sleep_duration()` shortens host sleep when the CLINT timer should fire or the CPU is not powered down. `riscv_machine_interp()` delegates the execution slice to the CPU interpreter.
virt_machine_run()
-> virt_machine_get_sleep_duration()
RISC-V: consult timer compare and power-down state
-> select(...)
-> virt_machine_interp(MAX_EXEC_CYCLE)
RISC-V: riscv_cpu_interp(cpu_state, n)