Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions .github/workflows/generate-plantuml.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: Generate PlantUML
on:
push:
branches:
- 'main'
paths:
- 'doc/**.puml'
pull_request:
paths:
- 'doc/**.puml'

permissions:
contents: read

jobs:
generate_plantuml:
runs-on: ubuntu-latest
name: plantuml
steps:
- name: checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false

- name: install plantuml
run: sudo apt-get install -y plantuml

- name: generate diagrams
run: |
find doc -name "*.puml" | while read f; do
arch=$(basename "$(dirname "$f")")
mkdir -p "doc/generated/$arch"
plantuml -tsvg -o "$(realpath "doc/generated/$arch")" "$f"
done

- name: upload diagrams
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: plantuml-diagrams
path: doc/generated/
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
- [That does change subsequent values](#that-does-change-subsequent-values)
- [Function prototype changes](#function-prototype-changes)
- [Finalizing](#finalizing)
- [Documentation](#documentation)
- [Development environments](#development-environments)

<!-- markdown-toc end -->
Expand Down Expand Up @@ -2139,6 +2140,10 @@ From this point, you can follow our regular process to make a kernel release.
>
> [TODO] Add link to instruction on our process

# Documentation

See [`doc/README.md`](doc/README.md) for architecture diagrams and other documentation.

# Development environments

Docker-based environments for building and running hypervisor components
Expand Down
7 changes: 7 additions & 0 deletions doc/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Documentation

## Architecture Diagrams

Diagrams are auto-generated by CI from [PlantUML](https://plantuml.com/).

[Download all diagrams (latest CI build)](https://nightly.link/xcp-ng/hypervisor-dev/workflows/generate-plantuml/main/plantuml-diagrams.zip)
103 changes: 103 additions & 0 deletions doc/riscv/xen-console.puml
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
@startuml xen-console
title Xen PV Console — RISC-V (hvc0)

skinparam sequenceMessageAlign center
skinparam participantPadding 20
skinparam boxPadding 10

actor "User" as user
participant "dom0\nxenconsoled\n(tools/console/daemon/io.c)" as xcd
participant "Xen\nhypervisor\n(xen/common/)" as xen
participant "domU\nLinux hvc0\n(drivers/tty/hvc/hvc_xen.c)" as domu

== Initialization ==

note over xen
Domain build: tools/libs/guest/xg_dom_riscv.c
alloc_magic_pages() + xg_dom_boot.c xc_dom_gnttab_seed()
end note

xen -> xen : alloc_magic_pages()\n populate 4 guest physmap pages at GUEST_MAGIC_BASE\n console page = base + CONSOLE_PFN_OFFSET(0)\n zero page → xencons_interface {in[1024], out[2048]}\n HVM_PARAM_CONSOLE_PFN = console_pfn\n (xg_dom_riscv.c:alloc_magic_pages)
xen -> xen : allocate interdomain event channel\n(evtchn_alloc_unbound)\nHVM_PARAM_CONSOLE_EVTCHN = evtchn
xen -> xen : xc_dom_gnttab_seed()\n domU grant table[GNTTAB_RESERVED_CONSOLE=0] =\n { flags=GTF_permit_access,\n domid=dom0,\n frame=console_gfn }\n domU grants dom0 access to its console page\n (xg_dom_boot.c:xc_dom_set_gnttab_entry)
xen -> xen : write xenstore entries\n/local/domain/<domid>/console/\n ring-ref = GNTTAB_RESERVED_CONSOLE (0)\n port = <evtchn_port>

xen --> domu : pass console MFN + evtchn\nvia xen_start_info\n(xen_start_info->console.domU.{mfn,evtchn})

note over domu
hvc_xen.c: xen_pv_console_init()
end note

domu -> domu : map shared page\ngfn_to_virt(mfn) → intf
domu -> domu : bind evtchn to Linux IRQ\nbind_evtchn_to_irq_lateeoi(evtchn)
domu -> domu : register hvc ops\nhvc_alloc(HVC_COOKIE, irq, &domU_hvc_ops)

note over xcd
xenconsoled: console_create_ring()
tools/console/daemon/io.c
end note

xcd -> xen : xs_gather("/local/domain/<domid>/console")\nread ring-ref + port
xen --> xcd : ring-ref, remote_port
xcd -> xen : xengnttab_map_grant_ref(domid, GNTTAB_RESERVED_CONSOLE=0)\n[ring-ref is fallback GFN if grant table unavailable]\nmap domU grant entry 0 → console page (xencons_interface*)
xen --> xcd : intf mapped
xcd -> xen : xenevtchn_bind_interdomain(domid, remote_port)\nbind interdomain event channel
xen --> xcd : local_port

note over xcd, domu
Shared page (xencons_interface) now accessible by both sides.
Event channel fully bound: xcd.local_port ↔ domu.evtchn
end note

== Console Input (user types a character) ==

user -> xcd : keystroke on pty master

note over xcd
handle_tty_write()
tools/console/daemon/io.c
end note

xcd -> xcd : write char to in[] ring\nintf->in[in_prod++ & mask] = char\nxen_mb()
xcd -> xen : xenevtchn_notify(local_port)\n[SBI ecall → evtchn_send()]

note over xen
xen/common/event_channel.c: evtchn_send()
xen/common/event_2l.c: evtchn_2l_set_pending()
end note

xen -> xen : set evtchn_pending bit\nguest_test_and_set_bit(port, shared_info.evtchn_pending)
xen -> xen : set evtchn_pending_sel\nguest_test_and_set_bit(word, vcpu_info.evtchn_pending_sel)
xen -> xen : vcpu_mark_events_pending(d1v0)\n set vcpu->arch.hvip.IRQ_VS_EVTCHN\n vcpu_kick(d1v0)\n vcpu_unblock(d1v0)

alt d1v0 running on pcpu1 (is_running=true)
xen -> xen : smp_send_event_check_mask(pcpu1)\n→ sbi_send_ipi()\n→ OpenSBI sets mip.SSIP on pcpu1
note over xen
pcpu1: SSIP fires (sie.SSIE=1)
do_trap(IRQ_S_SOFT)
csr_clear(sip, SSIP)
Comment thread
olkur marked this conversation as resolved.
leave_hypervisor_to_guest()
→ context_restore_csrs()
→ csr_write(HVIP, vcpu->arch.hvip)
sret → VS-mode with virtual interrupt pending
end note
else d1v0 blocked (is_running=false)
xen -> xen : vcpu_unblock(d1v0)\n→ vcpu_wake()\n→ sched_wake() [s->wake(), scheduler callback]\n→ cpu_raise_softirq(SCHEDULE_SOFTIRQ)\n→ sbi_send_ipi() wakes pcpu1 idle WFI\n→ scheduler runs d1v0\n→ context_restore_csrs() writes HVIP
end

xen --> domu : virtual interrupt delivered\n(hvip.IRQ_VS_EVTCHN → vsip.SSIP in VS-mode)

note over domu
Linux evtchn IRQ fires:
hvc_console.c: __hvc_poll() → domU_read_console()
hvc_xen.c
end note

domu -> domu : read char from in[] ring\nbuf[i] = intf->in[in_cons++ & mask]\nxen_mb()\nintf->in_cons updated

domu -> xen : notify_remote_via_evtchn(evtchn)\n[signal dom0: buffer consumed]
xen -> xcd : event channel notification\n→ xenevtchn_pending() fires

domu -> domu : tty_insert_flip_char(buf[i])\ntty_flip_buffer_push()\n→ char appears on hvc0

@enduml
Loading