schedule_cpu_rm() clears the cpupool pointer of the scheduling
resource before calling sched_deinit_pdata():
sr->cpupool = NULL;
...
sched_deinit_pdata(data->old_ops, data->ppriv_old, cpu);
For RTDS, rt_deinit_pdata() calls move_repl_timer() when the
replenishment timer lives on the cpu being removed, and
move_repl_timer() dereferences get_sched_res(old_cpu)->cpupool
without checking it for NULL. Removing a pCPU owning the timer from
an RTDS cpupool therefore dereferences NULL + 0x10 (the res_valid
member) and panics:
(XEN) Data Abort Trap. Syndrome=0x1c28005
(XEN) Walking Hypervisor VA 0x10 on CPU0 via TTBR ...
(XEN) Xen call trace:
(XEN) [<...>] find_next_bit+0x74/0xa8 (PC)
(XEN) [<...>] rt.c#move_repl_timer+0xb8/0xec (LR)
(XEN)
(XEN) Panic on CPU 0:
(XEN) CPU0: Unexpected Trap: Data Abort
Reproducer, on any host with at least 2 pCPUs and RTDS compiled in
(observed on arm64, but the path is common code):
xl cpupool-create name="test" sched="rtds"
xl cpupool-cpu-remove Pool-0 1
xl cpupool-cpu-add test 1
xl cpupool-cpu-remove test 1
The last command moves the RTDS replenishment timer to cpu1 (first
and only cpu of the pool) and then removes cpu1, hitting the NULL
dereference in the sched_deinit_pdata() callback.
Use the cpupool back-pointer of the scheduler instead of the one of
the scheduling resource. It is set by cpupool_create() before any
pCPU can be assigned to the pool and stays valid for the whole
lifetime of the scheduler, so it is still available when
rt_deinit_pdata() runs. Other schedulers already rely on it the same
way, e.g. credit2 in cpu_add_to_runqueue().
Fixes: b6f5334aea ("sched: fix cpu offlining with core scheduling")
Signed-off-by: Oleksii Moisieiev <oleksii_moisieiev@epam.com>
Reviewed-by: Juergen Gross <jgross@suse.com>
XEN_DOMCTL_SCHEDOP_putvcpuinfo can flip the RTDS_extratime bit on a vCPU
that is currently depleted (cur_budget == 0, possibly sitting on the
depleted queue). rt_dom_cntl() touches only svc->flags; cur_budget is
left unchanged. As a result the next code path that calls runq_insert()
on this vCPU - rt_unit_wake() after a domain_unpause(),
rt_context_saved() following a delayed runq add, or repl_timer_handler()
after a replenishment - places the vCPU on the run queue, because
has_extratime(svc) is now true and runq_insert() admits extratime units
regardless of cur_budget:
/* add svc to runq if svc still has budget or its extratime is set */
if ( svc->cur_budget > 0 ||
has_extratime(svc) )
deadline_runq_insert(svc, &svc->q_elem, runq);
else
list_add(&svc->q_elem, &prv->depletedq);
The very next rt_schedule() iterates the run queue from runq_pick()
and trips the ASSERT(iter_svc->cur_budget > 0) at the bottom of the
loop, panicking the host. Observed trace:
Assertion 'iter_svc->cur_budget > 0' failed at common/sched/rt.c:1035
----[ Xen-4.22-unstable arm64 debug=y ubsan=y Not tainted ]----
[<...>] rt.c#rt_schedule+0x1558/0x33e0 (PC)
[<...>] core.c#do_schedule+0x2e4/0x15b4
[<...>] core.c#schedule+0xb14/0xe50
[<...>] softirq.c#__do_softirq+0x20c/0x3d4
[<...>] do_softirq+0x14/0x1c
[<...>] domain.c#idle_loop+0x194/0x558
Minimal reproducer: pin a single-vCPU domU to a pCPU, program RTDS with
extratime off and a low utilisation (e.g. budget = 10ms / period = 100ms)
so the vCPU spends most of its time in the depleted queue, pause the
domain, issue a putvcpuinfo that sets XEN_DOMCTL_SCHEDRT_extra, then
unpause. As soon as the schedule softirq fires on the pCPU, the BUG
hits. The same sequence is reachable without an explicit pause: any
window in which rt_dom_cntl() runs between burn_budget()'s budget
exhaustion and rt_context_saved()'s runq_insert() also closes onto the
same broken state, because the per-scheduler lock is dropped between
those two points.
The semantics for "extratime gets exhausted budget refilled" already
live in burn_budget():
if ( has_extratime(svc) )
{
svc->priority_level++;
svc->cur_budget = svc->budget;
}
Apply the same priority-demotion-and-refill in rt_dom_cntl() when the
flag transitions from off to on while the vCPU is depleted, clear
RTDS_depleted to match, and - if the vCPU is currently on the depleted
queue - move it to the run queue using the same q_remove() +
runq_insert() pattern already used by repl_timer_handler(). The vCPU
remains on the replenishment queue throughout, so its normal
replenishment cadence is preserved.
The complementary transition (on -> off) is already safe: clearing the
flag only narrows the runq_insert() admission condition, so subsequent
depleted insertions correctly route to the depleted queue.
No other call sites need changes: with cur_budget restored before the
flag is observable to runq_insert(), runq_pick()'s long-standing
invariant (every run-queue entry has cur_budget > 0) is preserved.
Fixes: 463b958317 ("xen:rtds: towards work conserving RTDS")
Signed-off-by: Oleksii Moisieiev <oleksii_moisieiev@epam.com>
Reviewed-by: Juergen Gross <jgross@suse.com>
Release-Acked-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
In RTDS, removing the last eligible pCPU kills repl_timer. When a pCPU
is later re-added, rt_switch_sched() reinitializes the timer object.
cpupool_unassign_cpu_start() refuses to remove the last pCPU from a
populated cpupool: if any domain is still alive while the system is
active it returns -EBUSY, otherwise all domains are first moved to
cpupool0. Consequently, by the time the killed-timer branch runs, no
units remain in the pool and replq is guaranteed to be empty.
Document this invariant by asserting list_empty(replq) right after
init_timer(). This catches any future regression in cpupool semantics
that would leave pending replenishment events behind across a
TIMER_STATUS_killed -> init_timer() transition, where the timer would
otherwise stay disarmed until an unrelated event reprogrammed it.
Signed-off-by: Oleksii Moisieiev <oleksii_moisieiev@epam.com>
Reviewed-by: Juergen Gross <jgross@suse.com>
Acked-by: Jan Beulich <jbeulich@suse.com>
In RTDS, burn_budget() increments priority_level for extratime units
whenever cur_budget is exhausted. As priority_level is unsigned and was
unbounded, it could eventually overflow to 0.
A wrapped value of 0 is the highest RTDS priority, so an extratime unit
could unexpectedly regain top priority and preempt units with active
real-time reservations, violating EDF intent.
Fix this by saturating priority_level at RTDS_MAX_PRIORITY_LEVEL instead
of incrementing unconditionally. Budget refill semantics are unchanged.
Normal behavior is unchanged. Once saturated, priority_level remains at
the lowest priority until the next period update resets it.
Fixes: 463b958317 (xen:rtds: towards work conserving RTDS)
Signed-off-by: Oleksii Moisieiev <oleksii_moisieiev@epam.com>
Reviewed-by: Juergen Gross <jgross@suse.com>
Acked-by: Jan Beulich <jbeulich@suse.com>
In exynos4210_uart_init_postirq(), when setup_irq() returns an error
the failure was only logged via dprintk() and execution continued,
unconditionally clearing UINTM and setting UMCON_INT_EN. This enabled
receive and transmit interrupt lines with no handler registered. On
platforms where the GIC receives these asserted lines, the result is
either repeated spurious-interrupt warnings or an unhandled interrupt
fault.
Add an early return in the setup_irq() error branch so that the
interrupt-enable writes to UINTM and UMCON are skipped when IRQ
registration fails.
Signed-off-by: Oleksii Moisieiev <oleksii_moisieiev@epam.com>
Reviewed-by: Michal Orzel <michal.orzel@amd.com>
In cuart_init_postirq(), two code paths could reach the
interrupt-enable write to IER without a handler being registered:
- When no valid IRQ number was provided (uart->irq <= 0), the original
positive-condition guard (if uart->irq > 0) skipped the irqaction
setup but still fell through to the IER write, enabling the receive
data interrupt with no handler installed.
- When setup_irq() returned an error, only an error message was
printed and execution continued to the IER write, arming the
receive hardware interrupt line with no handler to service it. On
platforms where the GIC receives this asserted line, the result is
either repeated spurious-interrupt warnings or an unhandled
interrupt fault.
Restructure cuart_init_postirq() to use early returns in both error
paths.
Signed-off-by: Oleksii Moisieiev <oleksii_moisieiev@epam.com>
Reviewed-by: Oleksandr Tyshchenko <oleksandr_tyshchenko@epam.com>
Reviewed-by: Michal Orzel <michal.orzel@amd.com>
In pl011_init_postirq(), two code paths could reach the
interrupt-unmask write to IMSC without a handler being registered:
- When no valid IRQ number was provided (uart->irq <= 0), the original
positive-condition guard (if uart->irq > 0) skipped the irqaction
setup but still fell through to the IMSC write, unmasking
RTI|OEI|BEI|PEI|FEI|TXI|RXI with no handler installed.
- When setup_irq() returned an error, only an error message was
printed and execution continued to the IMSC write, arming all
hardware interrupt lines with no handler to service them. On
platforms where the GIC receives these asserted lines, the result
is either repeated spurious-interrupt warnings or an unhandled
interrupt fault.
Restructure pl011_init_postirq() to use early returns: return
immediately when no valid IRQ is provided, and return after logging
the error when setup_irq() fails. The interrupt-enable write to IMSC
is only reached when IRQ registration succeeds.
Signed-off-by: Oleksii Moisieiev <oleksii_moisieiev@epam.com>
Reviewed-by: Michal Orzel <michal.orzel@amd.com>
In scif_uart_init_postirq(), when setup_irq() returns an error the
failure was only logged via dprintk() and execution continued,
unconditionally writing TIE|RIE|REIE into the Serial Control Register
(SCSCR). This armed all three hardware interrupt lines (TX FIFO empty,
RX data ready, receive error) with no handler registered to service
them. On platforms where the GIC receives these asserted lines, the
result is either repeated spurious-interrupt warnings or an unhandled
interrupt fault.
The fix adds an early return inside the error branch. The
interrupt-enable write to SCSCR is skipped entirely when no handler is
registered.
SCIF TX continues to operate correctly after this change. The Xen
serial framework never calls serial_async_transmit() for SCIF, so
port->txbuf is always NULL. This causes __serial_putc() to take the
synchronous finite-capacity path, which polls the SCFSR_TDFE hardware
flag directly and does not depend on the interrupt mechanism. RX
wouldn't work if irq wasn't registered.
As a secondary clean-up, the hardware error-flag clearing sequence is
moved to before the setup_irq() call so that error bits accumulated
since init_preirq() are cleared unconditionally, regardless of whether
IRQ registration succeeds.
Signed-off-by: Oleksii Moisieiev <oleksii_moisieiev@epam.com>
Reviewed-by: Michal Orzel <michal.orzel@amd.com>
The RTDS domain-wide XEN_DOMCTL_SCHEDOP_putinfo path only checks for
zero values before applying period and budget to all vCPUs in the
domain.
This is weaker than the per-vCPU XEN_DOMCTL_SCHEDOP_putvcpuinfo path,
which already rejects values below the minimum, above the maximum, and
cases where budget exceeds period.
Use the same validation rules for putinfo as for putvcpuinfo, so
invalid domain-wide updates are rejected with -EINVAL instead of being
applied inconsistently.
Signed-off-by: Oleksii Moisieiev <oleksii_moisieiev@epam.com>
Reviewed-by: Juergen Gross <jgross@suse.com>
Move the SCI (System Control and Management Interface) resource cleanup
earlier in the domain_relinquish_resources() sequence to ensure proper
cleanup ordering during domain destruction.
The SCI cleanup is now performed before TEE (Trusted Execution Environment)
cleanup rather than after P2M mapping cleanup. This reordering ensures that
SCI resources are properly released before other subsystems that might
depend on them are torn down.
This change addresses potential resource cleanup dependencies where SCI
resources need to be released before P2M mappings are cleaned up, preventing
potential issues during domain destruction on ARM platforms with SCI support.
Fixes: e2cc10867b ("xen/arm: add generic SCI subsystem")
Signed-off-by: Oleksii Moisieiev <oleksii_moisieiev@epam.com>
Acked-by: Julien Grall <jgrall@amazon.com>
Remove redundant domid_free() call in the XEN_DOMCTL_createdomain error
handling path to prevent a double-free condition.
When domain_create() fails, it internally calls _domain_destroy() during
its cleanup routine, which already invokes domid_free() to release the
allocated domain ID. The additional domid_free() call in the domctl error
path creates a double-free scenario, triggering an assertion failure in
domid.c:
Assertion 'rc' failed at common/domid.c:84
The domain creation flow is:
1. domid_alloc() allocates a domain ID
2. domain_create() is called with the allocated ID
3. If domain_create() fails:
a) domain_create() calls _domain_destroy() internally
b) _domain_destroy() calls domid_free() to release the ID
c) domctl incorrectly calls domid_free() again
This double-free violates the domain ID management invariants and causes
system instability. The fix ensures domid_free() is called exactly once
per allocated domain ID, maintaining proper resource cleanup
semantics.
Signed-off-by: Oleksii Moisieiev <oleksii_moisieiev@epam.com>
Fixes: 2d50650607 ("xen/domain: unify domain ID allocation")
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
This patch adds the basic framework for ARM SCI mediator. SCI is System
Control Interface, which is designed to redirect requests from the Domains
to ARM specific Firmware (for example SCMI). This will allow the devices,
passed-through to the different Domains, to access to the System resources
(such as clocks/resets etc) by sending requests to the firmware.
ARM SCI subsystem allows to implement different SCI drivers to handle
specific ARM firmware interfaces (like ARM SCMI) and mediate requests
-between the Domains and the Firmware. Also it allows SCI drivers to perform
proper action during Domain creation/destruction which is vital for
handling use cases like Domain reboot.
This patch introduces new DEVICE_FIRMWARE device subclass for probing SCI
drivers basing on device tree, SCI drivers register itself with
DT_DEVICE_START/END macro. On init - the SCI drivers should register its
SCI ops with sci_register(). Only one SCI driver can be supported.
At run-time, the following SCI API calls are introduced:
- sci_domain_sanitise_config() called from arch_sanitise_domain_config()
- sci_domain_init() called from arch_domain_create()
- sci_relinquish_resources() called from domain_relinquish_resources()
- sci_domain_destroy() called from arch_domain_destroy()
- sci_handle_call() called from vsmccc_handle_call()
- sci_dt_handle_node()
- sci_dt_finalize() called from handle_node() (Dom0 DT)
Signed-off-by: Oleksii Moisieiev <oleksii_moisieiev@epam.com>
Signed-off-by: Grygorii Strashko <grygorii_strashko@epam.com>
Reviewed-by: Stefano Stabellini <sstabellini@kernel.org>