File: abs_lowcore.c

package info (click to toggle)
linux 6.1.153-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm-proposed-updates
  • size: 1,496,348 kB
  • sloc: ansic: 23,476,872; asm: 266,650; sh: 110,570; makefile: 49,899; python: 36,950; perl: 36,836; cpp: 6,055; yacc: 4,908; lex: 2,725; awk: 1,440; ruby: 25; sed: 5
file content (95 lines) | stat: -rw-r--r-- 2,237 bytes parent folder | download | duplicates (8)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
// SPDX-License-Identifier: GPL-2.0

#include <linux/pgtable.h>
#include <asm/abs_lowcore.h>

#define ABS_LOWCORE_UNMAPPED	1
#define ABS_LOWCORE_LAP_ON	2
#define ABS_LOWCORE_IRQS_ON	4

unsigned long __bootdata_preserved(__abs_lowcore);
bool __ro_after_init abs_lowcore_mapped;

int abs_lowcore_map(int cpu, struct lowcore *lc, bool alloc)
{
	unsigned long addr = __abs_lowcore + (cpu * sizeof(struct lowcore));
	unsigned long phys = __pa(lc);
	int rc, i;

	for (i = 0; i < LC_PAGES; i++) {
		rc = __vmem_map_4k_page(addr, phys, PAGE_KERNEL, alloc);
		if (rc) {
			/*
			 * Do not unmap allocated page tables in case the
			 * allocation was not requested. In such a case the
			 * request is expected coming from an atomic context,
			 * while the unmap attempt might sleep.
			 */
			if (alloc) {
				for (--i; i >= 0; i--) {
					addr -= PAGE_SIZE;
					vmem_unmap_4k_page(addr);
				}
			}
			return rc;
		}
		addr += PAGE_SIZE;
		phys += PAGE_SIZE;
	}
	return 0;
}

void abs_lowcore_unmap(int cpu)
{
	unsigned long addr = __abs_lowcore + (cpu * sizeof(struct lowcore));
	int i;

	for (i = 0; i < LC_PAGES; i++) {
		vmem_unmap_4k_page(addr);
		addr += PAGE_SIZE;
	}
}

struct lowcore *get_abs_lowcore(unsigned long *flags)
{
	unsigned long irq_flags;
	union ctlreg0 cr0;
	int cpu;

	*flags = 0;
	cpu = get_cpu();
	if (abs_lowcore_mapped) {
		return ((struct lowcore *)__abs_lowcore) + cpu;
	} else {
		if (cpu != 0)
			panic("Invalid unmapped absolute lowcore access\n");
		local_irq_save(irq_flags);
		if (!irqs_disabled_flags(irq_flags))
			*flags |= ABS_LOWCORE_IRQS_ON;
		__ctl_store(cr0.val, 0, 0);
		if (cr0.lap) {
			*flags |= ABS_LOWCORE_LAP_ON;
			__ctl_clear_bit(0, 28);
		}
		*flags |= ABS_LOWCORE_UNMAPPED;
		return lowcore_ptr[0];
	}
}

void put_abs_lowcore(struct lowcore *lc, unsigned long flags)
{
	if (abs_lowcore_mapped) {
		if (flags)
			panic("Invalid mapped absolute lowcore release\n");
	} else {
		if (smp_processor_id() != 0)
			panic("Invalid mapped absolute lowcore access\n");
		if (!(flags & ABS_LOWCORE_UNMAPPED))
			panic("Invalid unmapped absolute lowcore release\n");
		if (flags & ABS_LOWCORE_LAP_ON)
			__ctl_set_bit(0, 28);
		if (flags & ABS_LOWCORE_IRQS_ON)
			local_irq_enable();
	}
	put_cpu();
}