|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [mini-os master] kexec: add support for allocating pages from kexec module memory
commit a4cdaa0f2bf3a22f1e874d61260205e88db68c87
Author: Juergen Gross <jgross@xxxxxxxx>
AuthorDate: Tue Jul 15 15:29:30 2025 +0200
Commit: Jan Beulich <jbeulich@xxxxxxxx>
CommitDate: Wed Jul 16 15:04:38 2025 +0200
kexec: add support for allocating pages from kexec module memory
Add the needed functions for allocating and freeing memory pages of
the kexec module.
As the pages are always related to a kexec module record, add the
related utility functions, too. For now only support adding records
and retrieving them.
Signed-off-by: Juergen Gross <jgross@xxxxxxxx>
Reviewed-by: Jason Andryuk <jason.andryuk@xxxxxxx>
---
arch/x86/kexec.c | 16 ++++++++
include/kexec.h | 52 +++++++++++++++++++++++++
kexec.c | 115 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 183 insertions(+)
diff --git a/arch/x86/kexec.c b/arch/x86/kexec.c
index 8c9f8a3..e48df3f 100644
--- a/arch/x86/kexec.c
+++ b/arch/x86/kexec.c
@@ -240,6 +240,9 @@ static void get_mod_addr(unsigned long from, unsigned long
to)
#define min(a, b) ((a) < (b) ? (a) : (b))
void kexec_module(unsigned long start_pfn, unsigned long max_pfn)
{
+ unsigned int i;
+ char *rec_end;
+
/* Reuse already existing kexec module. */
mod_ptr = kexec_check_module();
if ( !mod_ptr && CONFIG_KEXEC_MODULE_PAGES )
@@ -257,11 +260,24 @@ void kexec_module(unsigned long start_pfn, unsigned long
max_pfn)
sizeof(mod_ptr->eye_catcher));
mod_ptr->n_pages = CONFIG_KEXEC_MODULE_PAGES - 1;
memset(mod_ptr->pg2rec, KEXECMOD_PG_FREE, mod_ptr->n_pages);
+ mod_ptr->n_records = 16;
mod_ptr->recs_off = sizeof(struct kexec_module) +
mod_ptr->n_pages + (mod_ptr->n_pages & 1);
set_reserved_range(kexec_mod_start, (unsigned long)mod_ptr +
PAGE_SIZE);
}
+
+ mod_recs = (void *)((unsigned long)mod_ptr + mod_ptr->recs_off);
+ mod_rec_start = (char *)(mod_recs + mod_ptr->n_records);
+ mod_rec_end = mod_rec_start;
+ for ( i = 0; i < mod_ptr->n_records; i++ )
+ {
+ if ( mod_recs[i].type == KEXECMOD_REC_NONE )
+ continue;
+ rec_end = (char *)mod_ptr + mod_recs[i].offset + mod_recs[i].size;
+ if ( mod_rec_end < rec_end )
+ mod_rec_end = rec_end;
+ }
}
void kexec_set_param_loc(const char *cmdline)
diff --git a/include/kexec.h b/include/kexec.h
index b38a9f5..0e0b1a4 100644
--- a/include/kexec.h
+++ b/include/kexec.h
@@ -67,6 +67,9 @@ struct kexec_module_rec {
extern unsigned long kexec_mod_start;
extern struct kexec_module *mod_ptr;
+extern struct kexec_module_rec *mod_recs;
+extern char *mod_rec_start;
+extern char *mod_rec_end;
/* One element of kexec actions (last element must have action KEXEC_CALL): */
struct kexec_action {
@@ -80,6 +83,17 @@ struct kexec_action {
void *src;
};
+#ifdef CONFIG_KEXEC
+unsigned long kexec_alloc_mod_pages(unsigned int recid, unsigned int n);
+void kexec_free_mod_pages(unsigned int recid, unsigned long addr,
+ unsigned int n);
+int kexec_find_mod_record(unsigned int start_idx, unsigned int type,
+ unsigned int *size);
+int kexec_add_mod_record(unsigned int type, void *addr, unsigned int size);
+int kexec_upd_mod_record(unsigned int idx, unsigned int type,
+ void *addr, unsigned int size);
+int kexec_read_mod_record(unsigned int idx, void *addr, unsigned int size);
+
#define KEXEC_MAX_ACTIONS 16
extern char _kexec_start[], _kexec_end[];
@@ -129,4 +143,42 @@ void kexec_move_used_pages_undo(void);
/* Check for kexec module and create kexec memory if needed. */
void kexec_module(unsigned long start_pfn, unsigned long max_pfn);
+#else /* CONFIG_KEXEC */
+static inline unsigned long kexec_alloc_mod_pages(unsigned int recid,
+ unsigned int n)
+{
+ return 0;
+}
+
+static inline void kexec_free_mod_pages(unsigned int recid, unsigned long addr,
+ unsigned int n)
+{
+}
+
+static inline int kexec_find_mod_record(unsigned int start_idx,
+ unsigned int type, unsigned int *size)
+{
+ return 0;
+}
+
+static inline int kexec_add_mod_record(unsigned int type, void *addr,
+ unsigned int size)
+{
+ return 0;
+}
+
+static inline int kexec_upd_mod_record(unsigned int idx, unsigned int type,
+ void *addr, unsigned int size)
+{
+ return 0;
+}
+
+static inline int kexec_read_mod_record(unsigned int idx, void *addr,
+ unsigned int size)
+{
+ return 0;
+}
+
+#endif
+
#endif /* _KEXEC_H */
diff --git a/kexec.c b/kexec.c
index ded2988..f17ed13 100644
--- a/kexec.c
+++ b/kexec.c
@@ -253,3 +253,118 @@ int kexec_add_action(int action, void *dest, void *src,
unsigned int len)
unsigned long kexec_mod_start;
struct kexec_module *mod_ptr;
+struct kexec_module_rec *mod_recs;
+char *mod_rec_start;
+char *mod_rec_end;
+
+unsigned long kexec_alloc_mod_pages(unsigned int recid, unsigned int n)
+{
+ unsigned int first = 0, i;
+
+ for ( i = 0; i < mod_ptr->n_pages; i++ )
+ {
+ if ( i - first == n - 1 )
+ {
+ for ( i = 0; i < n; i++ )
+ mod_ptr->pg2rec[first + i] = recid;
+
+ return kexec_mod_start + PFN_PHYS(first);
+ }
+
+ if ( mod_ptr->pg2rec[i] != KEXECMOD_PG_FREE )
+ first = i + 1;
+ }
+
+ printk("Kexec module out of memory\n");
+ BUG();
+}
+
+void kexec_free_mod_pages(unsigned int recid, unsigned long addr,
+ unsigned int n)
+{
+ unsigned int s = PHYS_PFN(addr - kexec_mod_start);
+ unsigned int i;
+
+ BUG_ON(addr < kexec_mod_start ||
+ addr + PFN_PHYS(n) > (unsigned long)mod_ptr);
+
+ for ( i = 0; i < n; i++ )
+ {
+ BUG_ON(mod_ptr->pg2rec[s + i] != recid);
+ mod_ptr->pg2rec[s + i] = KEXECMOD_PG_FREE;
+ }
+}
+
+int kexec_find_mod_record(unsigned int start_idx, unsigned int type,
+ unsigned int *size)
+{
+ unsigned int i;
+
+ for ( i = start_idx; i < mod_ptr->n_records; i++ )
+ {
+ if ( mod_recs[i].type == type )
+ {
+ *size = mod_recs[i].size;
+ return i;
+ }
+ }
+
+ return -ENOENT;
+}
+
+int kexec_add_mod_record(unsigned int type, void *addr, unsigned int size)
+{
+ unsigned int i;
+
+ if ( mod_rec_end + size > (char *)mod_ptr + PAGE_SIZE )
+ {
+ /* TODO: support compressing record space. */
+ printk("Kexec module record space exhausted\n");
+ BUG();
+ }
+
+ for ( i = 0; i < mod_ptr->n_records; i++ )
+ {
+ if ( mod_recs[i].type == KEXECMOD_REC_NONE )
+ {
+ mod_recs[i].offset = mod_rec_end - (char *)mod_ptr;
+ mod_recs[i].type = type;
+ mod_recs[i].size = size;
+ memcpy(mod_rec_end, addr, size);
+ mod_rec_end = mod_rec_end + size;
+
+ return i;
+ }
+ }
+
+ /* TODO: support extending the mod_recs[] table. */
+ printk("Kexec module record table exhausted\n");
+ BUG();
+}
+
+int kexec_upd_mod_record(unsigned int idx, unsigned int type,
+ void *addr, unsigned int size)
+{
+ if ( idx >= mod_ptr->n_records )
+ return -ENOENT;
+
+ if ( mod_recs[idx].type != type || mod_recs[idx].size != size )
+ return -EINVAL;
+
+ memcpy((char *)mod_ptr + mod_recs[idx].offset, addr, size);
+
+ return 0;
+}
+
+int kexec_read_mod_record(unsigned int idx, void *addr, unsigned int size)
+{
+ if ( idx >= mod_ptr->n_records )
+ return -ENOENT;
+
+ if ( mod_recs[idx].size != size )
+ return -EINVAL;
+
+ memcpy(addr, (char *)mod_ptr + mod_recs[idx].offset, size);
+
+ return 0;
+}
--
generated by git-patchbot for /home/xen/git/mini-os.git#master
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |