arch/riscv/kernel/hibernate.c

Source file repositories/reference/linux-study-clean/arch/riscv/kernel/hibernate.c

File Facts

System
Linux kernel
Corpus path
arch/riscv/kernel/hibernate.c
Extension
.c
Size
10475 bytes
Lines
427
Domain
Architecture Layer
Bucket
arch/riscv
Inferred role
Architecture Layer: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

struct arch_hibernate_hdr_invariants {
	char		uts_version[__NEW_UTS_LEN + 1];
};

/**
 * struct arch_hibernate_hdr - helper parameters that help us to restore the image.
 * @invariants: container to store kernel build version.
 * @hartid: to make sure same boot_cpu executes the hibernate/restore code.
 * @saved_satp: original page table used by the hibernated image.
 * @restore_cpu_addr: the kernel's image address to restore the CPU context.
 */
static struct arch_hibernate_hdr {
	struct arch_hibernate_hdr_invariants invariants;
	unsigned long	hartid;
	unsigned long	saved_satp;
	unsigned long	restore_cpu_addr;
} resume_hdr;

static void arch_hdr_invariants(struct arch_hibernate_hdr_invariants *i)
{
	memset(i, 0, sizeof(*i));
	memcpy(i->uts_version, init_utsname()->version, sizeof(i->uts_version));
}

/*
 * Check if the given pfn is in the 'nosave' section.
 */
int pfn_is_nosave(unsigned long pfn)
{
	unsigned long nosave_begin_pfn = sym_to_pfn(&__nosave_begin);
	unsigned long nosave_end_pfn = sym_to_pfn(&__nosave_end - 1);

	return ((pfn >= nosave_begin_pfn) && (pfn <= nosave_end_pfn));
}

void notrace save_processor_state(void)
{
}

void notrace restore_processor_state(void)
{
}

/*
 * Helper parameters need to be saved to the hibernation image header.
 */
int arch_hibernation_header_save(void *addr, unsigned int max_size)
{
	struct arch_hibernate_hdr *hdr = addr;

	if (max_size < sizeof(*hdr))
		return -EOVERFLOW;

	arch_hdr_invariants(&hdr->invariants);

	hdr->hartid = cpuid_to_hartid_map(sleep_cpu);
	hdr->saved_satp = csr_read(CSR_SATP);
	hdr->restore_cpu_addr = (unsigned long)__hibernate_cpu_resume;

	return 0;
}
EXPORT_SYMBOL_GPL(arch_hibernation_header_save);

/*
 * Retrieve the helper parameters from the hibernation image header.
 */
int arch_hibernation_header_restore(void *addr)
{
	struct arch_hibernate_hdr_invariants invariants;
	struct arch_hibernate_hdr *hdr = addr;
	int ret = 0;

	arch_hdr_invariants(&invariants);

	if (memcmp(&hdr->invariants, &invariants, sizeof(invariants))) {
		pr_crit("Hibernate image not generated by this kernel!\n");
		return -EINVAL;
	}

	sleep_cpu = riscv_hartid_to_cpuid(hdr->hartid);
	if (sleep_cpu < 0) {
		pr_crit("Hibernated on a CPU not known to this kernel!\n");
		sleep_cpu = -EINVAL;
		return -EINVAL;
	}

#ifdef CONFIG_SMP
	ret = bringup_hibernate_cpu(sleep_cpu);
	if (ret) {
		sleep_cpu = -EINVAL;

Annotation

Implementation Notes