mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 17:47:41 +02:00
liveupdate: register luo_ser as KHO subtree
Entirely remove the LUO FDT wrapper since the FDT only carries the compatible string and the pointer to the centralized struct luo_ser. Instead, register the struct luo_ser via the KHO raw subtree API, placing the compatibility string inside the structure itself. Acked-by: Mike Rapoport (Microsoft) <rppt@kernel.org> Reviewed-by: Pratyush Yadav (Google) <pratyush@kernel.org> Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com> Link: https://patch.msgid.link/20260603154402.468928-5-pasha.tatashin@soleen.com Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
This commit is contained in:
parent
d376e4b55c
commit
cf071b3536
|
|
@ -10,11 +10,11 @@
|
|||
*
|
||||
* Live Update Orchestrator uses the stable Application Binary Interface
|
||||
* defined below to pass state from a pre-update kernel to a post-update
|
||||
* kernel. The ABI is built upon the Kexec HandOver framework and uses a
|
||||
* Flattened Device Tree to describe the preserved data.
|
||||
* kernel. The ABI is built upon the Kexec HandOver framework and registers
|
||||
* the central `struct luo_ser` via the KHO raw subtree API.
|
||||
*
|
||||
* This interface is a contract. Any modification to the FDT structure, node
|
||||
* properties, compatible strings, or the layout of the `__packed` serialization
|
||||
* This interface is a contract. Any modification to the structure fields,
|
||||
* compatible strings, or the layout of the `__packed` serialization
|
||||
* structures defined here constitutes a breaking change. Such changes require
|
||||
* incrementing the version number in the relevant `_COMPATIBLE` string to
|
||||
* prevent a new kernel from misinterpreting data from an old kernel.
|
||||
|
|
@ -23,31 +23,15 @@
|
|||
* however, backward/forward compatibility is only guaranteed for kernels
|
||||
* supporting the same ABI version.
|
||||
*
|
||||
* FDT Structure Overview:
|
||||
* KHO Structure Overview:
|
||||
* The entire LUO state is encapsulated within a single KHO entry named "LUO".
|
||||
* This entry contains an FDT with the following layout:
|
||||
*
|
||||
* .. code-block:: none
|
||||
*
|
||||
* / {
|
||||
* compatible = "luo-v2";
|
||||
* luo-abi-header = <phys_addr_of_luo_ser>;
|
||||
* };
|
||||
*
|
||||
* Main LUO Node (/):
|
||||
*
|
||||
* - compatible: "luo-v2"
|
||||
* Identifies the overall LUO ABI version.
|
||||
* - luo-abi-header: u64
|
||||
* The physical address of `struct luo_ser`.
|
||||
* This entry contains the `struct luo_ser` structure.
|
||||
*
|
||||
* Serialization Structures:
|
||||
* The FDT properties point to memory regions containing arrays of simple,
|
||||
* `__packed` structures. These structures contain the actual preserved state.
|
||||
*
|
||||
* - struct luo_ser:
|
||||
* The central ABI structure that contains the overall state of the LUO.
|
||||
* It includes the liveupdate-number and pointers to sessions and FLBs.
|
||||
* It includes the compatibility string, the liveupdate-number, and pointers
|
||||
* to sessions and FLBs.
|
||||
*
|
||||
* - struct luo_session_header_ser:
|
||||
* Header for the session array. Contains the total page count of the
|
||||
|
|
@ -78,26 +62,27 @@
|
|||
#ifndef _LINUX_KHO_ABI_LUO_H
|
||||
#define _LINUX_KHO_ABI_LUO_H
|
||||
|
||||
#include <linux/align.h>
|
||||
#include <uapi/linux/liveupdate.h>
|
||||
|
||||
/*
|
||||
* The LUO FDT hooks all LUO state for sessions, fds, etc.
|
||||
* The LUO state is registered under this KHO entry name.
|
||||
*/
|
||||
#define LUO_FDT_SIZE PAGE_SIZE
|
||||
#define LUO_FDT_KHO_ENTRY_NAME "LUO"
|
||||
#define LUO_FDT_COMPATIBLE "luo-v2"
|
||||
#define LUO_FDT_ABI_HEADER "luo-abi-header"
|
||||
#define LUO_KHO_ENTRY_NAME "LUO"
|
||||
#define LUO_ABI_COMPATIBLE "luo-v3"
|
||||
#define LUO_ABI_COMPAT_LEN ALIGN(sizeof(LUO_ABI_COMPATIBLE), 8)
|
||||
|
||||
/**
|
||||
* struct luo_ser - Centralized LUO ABI header.
|
||||
* @compatible: Compatibility string identifying the LUO ABI version.
|
||||
* @liveupdate_num: A counter tracking the number of successful live updates.
|
||||
* @sessions_pa: Physical address of the first session block header.
|
||||
* @flbs_pa: Physical address of the FLB header.
|
||||
*
|
||||
* This structure is the root of all preserved LUO state. It is pointed to by
|
||||
* the "luo-abi-header" property in the LUO FDT.
|
||||
* This structure is the root of all preserved LUO state.
|
||||
*/
|
||||
struct luo_ser {
|
||||
char compatible[LUO_ABI_COMPAT_LEN];
|
||||
u64 liveupdate_num;
|
||||
u64 sessions_pa;
|
||||
u64 flbs_pa;
|
||||
|
|
@ -111,7 +96,7 @@ struct luo_ser {
|
|||
* @data: Private data
|
||||
* @token: User provided token for this file
|
||||
*
|
||||
* If this structure is modified, LUO_SESSION_COMPATIBLE must be updated.
|
||||
* If this structure is modified, `LUO_ABI_COMPATIBLE` must be updated.
|
||||
*/
|
||||
struct luo_file_ser {
|
||||
char compatible[LIVEUPDATE_HNDL_COMPAT_LENGTH];
|
||||
|
|
@ -142,7 +127,7 @@ struct luo_file_set_ser {
|
|||
* physical memory preserved across the kexec. It provides the necessary
|
||||
* metadata to interpret the array of session entries that follow.
|
||||
*
|
||||
* If this structure is modified, `LUO_FDT_COMPATIBLE` must be updated.
|
||||
* If this structure is modified, `LUO_ABI_COMPATIBLE` must be updated.
|
||||
*/
|
||||
struct luo_session_header_ser {
|
||||
u64 count;
|
||||
|
|
@ -159,7 +144,7 @@ struct luo_session_header_ser {
|
|||
* session) is created and passed to the new kernel, allowing it to reconstruct
|
||||
* the session context.
|
||||
*
|
||||
* If this structure is modified, `LUO_FDT_COMPATIBLE` must be updated.
|
||||
* If this structure is modified, `LUO_ABI_COMPATIBLE` must be updated.
|
||||
*/
|
||||
struct luo_session_ser {
|
||||
char name[LIVEUPDATE_SESSION_NAME_LENGTH];
|
||||
|
|
@ -180,7 +165,7 @@ struct luo_session_ser {
|
|||
* This structure is located at the physical address specified by the
|
||||
* flbs_pa in luo_ser.
|
||||
*
|
||||
* If this structure is modified, `LUO_FDT_COMPATIBLE` must be updated.
|
||||
* If this structure is modified, `LUO_ABI_COMPATIBLE` must be updated.
|
||||
*/
|
||||
struct luo_flb_header_ser {
|
||||
u64 pgcnt;
|
||||
|
|
@ -202,7 +187,7 @@ struct luo_flb_header_ser {
|
|||
* passed to the new kernel. Each entry allows the LUO core to restore one
|
||||
* global, shared object.
|
||||
*
|
||||
* If this structure is modified, `LUO_FDT_COMPATIBLE` must be updated.
|
||||
* If this structure is modified, `LUO_ABI_COMPATIBLE` must be updated.
|
||||
*/
|
||||
struct luo_flb_ser {
|
||||
char name[LIVEUPDATE_FLB_COMPAT_LENGTH];
|
||||
|
|
|
|||
|
|
@ -54,7 +54,6 @@
|
|||
#include <linux/kexec_handover.h>
|
||||
#include <linux/kho/abi/luo.h>
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/libfdt.h>
|
||||
#include <linux/liveupdate.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/mm.h>
|
||||
|
|
@ -67,8 +66,7 @@
|
|||
|
||||
static struct {
|
||||
bool enabled;
|
||||
void *fdt_out;
|
||||
void *fdt_in;
|
||||
struct luo_ser *luo_ser_out;
|
||||
u64 liveupdate_num;
|
||||
} luo_global;
|
||||
|
||||
|
|
@ -85,11 +83,10 @@ early_param("liveupdate", early_liveupdate_param);
|
|||
|
||||
static int __init luo_early_startup(void)
|
||||
{
|
||||
phys_addr_t luo_ser_phys;
|
||||
struct luo_ser *luo_ser;
|
||||
int err, header_size;
|
||||
phys_addr_t fdt_phys;
|
||||
const void *ptr;
|
||||
u64 luo_ser_pa;
|
||||
size_t len;
|
||||
int err;
|
||||
|
||||
if (!kho_is_enabled()) {
|
||||
if (liveupdate_enabled())
|
||||
|
|
@ -98,40 +95,29 @@ static int __init luo_early_startup(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Retrieve LUO subtree, and verify its format. */
|
||||
err = kho_retrieve_subtree(LUO_FDT_KHO_ENTRY_NAME, &fdt_phys, NULL);
|
||||
/* Retrieve LUO state from KHO. */
|
||||
err = kho_retrieve_subtree(LUO_KHO_ENTRY_NAME, &luo_ser_phys, &len);
|
||||
if (err) {
|
||||
if (err != -ENOENT) {
|
||||
pr_err("failed to retrieve FDT '%s' from KHO: %pe\n",
|
||||
LUO_FDT_KHO_ENTRY_NAME, ERR_PTR(err));
|
||||
pr_err("failed to retrieve LUO state '%s' from KHO: %pe\n",
|
||||
LUO_KHO_ENTRY_NAME, ERR_PTR(err));
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
luo_global.fdt_in = phys_to_virt(fdt_phys);
|
||||
err = fdt_node_check_compatible(luo_global.fdt_in, 0,
|
||||
LUO_FDT_COMPATIBLE);
|
||||
if (err) {
|
||||
pr_err("FDT '%s' is incompatible with '%s' [%d]\n",
|
||||
LUO_FDT_KHO_ENTRY_NAME, LUO_FDT_COMPATIBLE, err);
|
||||
|
||||
if (len < sizeof(*luo_ser)) {
|
||||
pr_err("LUO state is too small (%zu < %zu)\n", len, sizeof(*luo_ser));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
header_size = 0;
|
||||
ptr = fdt_getprop(luo_global.fdt_in, 0, LUO_FDT_ABI_HEADER, &header_size);
|
||||
if (!ptr || header_size != sizeof(u64)) {
|
||||
pr_err("Unable to get ABI header '%s' [%d]\n",
|
||||
LUO_FDT_ABI_HEADER, header_size);
|
||||
|
||||
luo_ser = phys_to_virt(luo_ser_phys);
|
||||
if (strncmp(luo_ser->compatible, LUO_ABI_COMPATIBLE, LUO_ABI_COMPAT_LEN)) {
|
||||
pr_err("LUO state is incompatible with '%s'\n", LUO_ABI_COMPATIBLE);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
luo_ser_pa = get_unaligned((u64 *)ptr);
|
||||
luo_ser = phys_to_virt(luo_ser_pa);
|
||||
|
||||
luo_global.liveupdate_num = luo_ser->liveupdate_num;
|
||||
pr_info("Retrieved live update data, liveupdate number: %lld\n",
|
||||
luo_global.liveupdate_num);
|
||||
|
|
@ -164,37 +150,20 @@ static int __init liveupdate_early_init(void)
|
|||
}
|
||||
early_initcall(liveupdate_early_init);
|
||||
|
||||
/* Called during boot to create outgoing LUO fdt tree */
|
||||
static int __init luo_fdt_setup(void)
|
||||
/* Called during boot to create outgoing LUO state */
|
||||
static int __init luo_state_setup(void)
|
||||
{
|
||||
struct luo_ser *luo_ser;
|
||||
u64 luo_ser_pa;
|
||||
void *fdt_out;
|
||||
int err;
|
||||
|
||||
fdt_out = kho_alloc_preserve(LUO_FDT_SIZE);
|
||||
if (IS_ERR(fdt_out)) {
|
||||
pr_err("failed to allocate/preserve FDT memory\n");
|
||||
return PTR_ERR(fdt_out);
|
||||
}
|
||||
|
||||
luo_ser = kho_alloc_preserve(sizeof(*luo_ser));
|
||||
if (IS_ERR(luo_ser)) {
|
||||
err = PTR_ERR(luo_ser);
|
||||
goto exit_free_fdt;
|
||||
pr_err("failed to allocate/preserve LUO state memory\n");
|
||||
return PTR_ERR(luo_ser);
|
||||
}
|
||||
luo_ser_pa = virt_to_phys(luo_ser);
|
||||
|
||||
err = fdt_create(fdt_out, LUO_FDT_SIZE);
|
||||
err |= fdt_finish_reservemap(fdt_out);
|
||||
err |= fdt_begin_node(fdt_out, "");
|
||||
err |= fdt_property_string(fdt_out, "compatible", LUO_FDT_COMPATIBLE);
|
||||
err |= fdt_property(fdt_out, LUO_FDT_ABI_HEADER, &luo_ser_pa,
|
||||
sizeof(luo_ser_pa));
|
||||
err |= fdt_end_node(fdt_out);
|
||||
err |= fdt_finish(fdt_out);
|
||||
if (err)
|
||||
goto exit_free_luo_ser;
|
||||
strscpy(luo_ser->compatible, LUO_ABI_COMPATIBLE, sizeof(luo_ser->compatible));
|
||||
luo_ser->liveupdate_num = luo_global.liveupdate_num + 1;
|
||||
|
||||
err = luo_session_setup_outgoing(&luo_ser->sessions_pa);
|
||||
if (err)
|
||||
|
|
@ -204,21 +173,17 @@ static int __init luo_fdt_setup(void)
|
|||
if (err)
|
||||
goto exit_free_luo_ser;
|
||||
|
||||
luo_ser->liveupdate_num = luo_global.liveupdate_num + 1;
|
||||
|
||||
err = kho_add_subtree(LUO_FDT_KHO_ENTRY_NAME, fdt_out,
|
||||
fdt_totalsize(fdt_out));
|
||||
err = kho_add_subtree(LUO_KHO_ENTRY_NAME, luo_ser, sizeof(*luo_ser));
|
||||
if (err)
|
||||
goto exit_free_luo_ser;
|
||||
luo_global.fdt_out = fdt_out;
|
||||
|
||||
luo_global.luo_ser_out = luo_ser;
|
||||
|
||||
return 0;
|
||||
|
||||
exit_free_luo_ser:
|
||||
kho_unpreserve_free(luo_ser);
|
||||
exit_free_fdt:
|
||||
kho_unpreserve_free(fdt_out);
|
||||
pr_err("failed to prepare LUO FDT: %d\n", err);
|
||||
pr_err("failed to prepare LUO state: %d\n", err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
|
@ -234,7 +199,7 @@ static int __init luo_late_startup(void)
|
|||
if (!liveupdate_enabled())
|
||||
return 0;
|
||||
|
||||
err = luo_fdt_setup();
|
||||
err = luo_state_setup();
|
||||
if (err)
|
||||
luo_global.enabled = false;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user