AquilaOS documentation
How it works, and its code
Toggle main menu visibility
Loading...
Searching...
No Matches
tlb.c
Go to the documentation of this file.
1
29
30
#include <
core/system.h
>
31
#include <
core/arch.h
>
32
#include <
cpu/cpu.h
>
33
#include <
mm/mm.h
>
34
#include <
mm/pmap.h
>
35
#include <
mm/vm.h
>
36
#include <
platform/misc.h
>
37
#include <
sys/cpu.h
>
38
#include <
sys/lock.h
>
39
40
/* above this many pages, the whole TLB is flushed instead */
41
#define FLUSH_PAGES_MAX 32
42
43
#define ICR_ASSERT 0x4000
44
45
/* how many times the kernel's mappings changed; each CPU's TLB has
46
* the kernel's mappings of one of these generations
47
* (cpu->arch.kernel_gen) */
48
static
uint64_t
kernel_gen
;
49
50
/* the request to the other CPUs: flush [sva, eva) of pmap, or leave pmap
51
* for the kernel's page tables */
52
static
struct
{
53
struct
pmap
*
pmap
;
54
vaddr_t
sva
,
eva
;
55
int
leave
;
56
volatile
uint32_t
pending
;
/* the CPUs that haven't done it yet */
57
}
request
;
58
60
static
void
flush
(
vaddr_t
sva,
vaddr_t
eva)
61
{
62
if
((eva - sva) /
PAGE_SIZE
>
FLUSH_PAGES_MAX
) {
63
tlb_flush
();
64
return
;
65
}
66
67
for
(
vaddr_t
va = sva; va < eva; va +=
PAGE_SIZE
)
68
asm
volatile
(
"invlpg (%0)"
::
"r"
(va) :
"memory"
);
69
}
70
73
static
void
request_do
(
struct
pmap
*
pmap
,
vaddr_t
sva,
vaddr_t
eva,
int
leave)
74
{
75
struct
pmap
*loaded = curcpu()->arch.pmap;
76
77
if
(leave) {
78
if
(loaded ==
pmap
)
79
pmap_switch
(
kvm_space
.
pmap
);
80
}
else
if
(
pmap
==
kvm_space
.
pmap
|| loaded ==
pmap
) {
81
flush
(sva, eva);
82
}
83
}
84
87
void
x86_tlb_ipi
(
void
)
88
{
89
uint32_t
me = 1U << curcpu()->id;
90
91
if
(!(__atomic_load_n(&
request
.pending, __ATOMIC_ACQUIRE) & me))
92
return
;
93
94
request_do
(
request
.pmap,
request
.sva,
request
.eva,
request
.leave);
95
curcpu()->arch.tlb_flushes++;
96
__atomic_and_fetch(&
request
.pending, ~me, __ATOMIC_RELEASE);
97
}
98
99
/* Runs in the kernel lock's wait loop: does a pending TLB request, so
100
* that the CPU holding the lock isn't kept waiting for this one. */
101
void
arch_lock_spin
(
void
)
102
{
103
x86_tlb_ipi
();
104
asm
volatile
(
"pause"
);
105
}
106
107
/* Runs when the running CPU takes the kernel lock: flushes its TLB if
108
* the kernel's mappings changed since it last held the lock. */
109
void
arch_lock_taken
(
void
)
110
{
111
struct
cpu
*
cpu
= curcpu();
112
113
if
(
cpu
->
arch
.
kernel_gen
!=
kernel_gen
) {
114
tlb_flush
();
115
cpu
->
arch
.
kernel_gen
=
kernel_gen
;
116
}
117
}
118
119
/*
120
* Flushes a range of an address space from every TLB that may have it,
121
* after its mappings changed, and waits until the other CPUs have done
122
* it. The caller holds the kernel lock.
123
*/
124
void
tlb_shootdown
(
struct
pmap
*
pmap
,
vaddr_t
sva,
vaddr_t
eva,
int
leave)
125
{
126
uint32_t
me = 1U << curcpu()->id;
127
128
request_do
(
pmap
, sva, eva, leave);
129
130
/* the kernel's mappings: the other CPUs flush when they take the
131
* lock */
132
if
(
pmap
==
kvm_space
.
pmap
) {
133
curcpu()->arch.kernel_gen = ++
kernel_gen
;
134
return
;
135
}
136
137
uint32_t
others = __atomic_load_n(&
pmap
->
cpus
, __ATOMIC_ACQUIRE) & ~me;
138
139
if
(!others)
140
return
;
141
142
request
.pmap =
pmap
;
143
request
.sva = sva;
144
request
.eva = eva;
145
request
.leave = leave;
146
__atomic_store_n(&
request
.pending, others, __ATOMIC_RELEASE);
147
148
for
(
int
i = 0; i <
cpus_count
; ++i)
149
if
(others & (1U << i))
150
x86_lapic_ipi
(
cpus
[i].
arch
.
apic_id
,
X86_TLB_VECTOR
|
ICR_ASSERT
);
151
152
while
(__atomic_load_n(&
request
.pending, __ATOMIC_ACQUIRE))
153
asm
volatile
(
"pause"
);
154
}
155
156
/*
157
* Records that the running CPU switched page tables, so that TLB requests
158
* go to the CPUs that may have a mapping cached.
159
*/
160
void
pmap_loaded
(
struct
pmap
*from,
struct
pmap
*to)
161
{
162
uint32_t
me = 1U << curcpu()->id;
163
164
if
(from)
165
__atomic_and_fetch(&from->
cpus
, ~me, __ATOMIC_RELEASE);
166
167
__atomic_or_fetch(&to->
cpus
, me, __ATOMIC_RELEASE);
168
}
arch_lock_spin
void arch_lock_spin(void)
Runs in the kernel lock's wait loop, on each turn.
Definition
smp.c:20
arch_lock_taken
void arch_lock_taken(void)
Runs once this CPU has taken the kernel lock.
Definition
smp.c:25
PAGE_SIZE
#define PAGE_SIZE
Definition
system.h:7
tlb_flush
static void tlb_flush(void)
Flushes every translation from this CPU's TLB.
Definition
mm.h:43
vaddr_t
uint64_t vaddr_t
Definition
mm.h:40
pmap_loaded
void pmap_loaded(struct pmap *from, struct pmap *to)
Definition
pmap.c:157
tlb_shootdown
void tlb_shootdown(struct pmap *pmap, vaddr_t sva, vaddr_t eva, int leave)
Definition
pmap.c:130
x86_tlb_ipi
void x86_tlb_ipi(void)
Does the pending request if it is for the running CPU.
Definition
tlb.c:87
ICR_ASSERT
#define ICR_ASSERT
Definition
smp.c:46
arch.h
system.h
cpu.h
mm.h
pmap.h
cpu.h
cpus
struct cpu cpus[CPUS_MAX]
Definition
sched.c:28
cpus_count
int cpus_count
Definition
sched.c:29
lock.h
misc.h
X86_TLB_VECTOR
#define X86_TLB_VECTOR
Definition
misc.h:15
x86_lapic_ipi
void x86_lapic_ipi(uint32_t id, uint32_t icr)
Sends an IPI to a CPU, and waits until it is delivered.
Definition
apic.c:342
pmap_switch
struct pmap * pmap_switch(struct pmap *pmap)
Switches this CPU to an address space's page tables.
Definition
pmap.c:164
uint32_t
unsigned int uint32_t
Definition
stddef.h:22
uint64_t
unsigned long long int uint64_t
Definition
stddef.h:23
[struct].request::pmap
struct pmap * pmap
[struct].request::leave
int leave
[struct].request::sva
vaddr_t sva
[struct].request::eva
vaddr_t eva
[struct].request::pending
volatile uint32_t pending
arch_cpu::kernel_gen
uint64_t kernel_gen
Definition
cpu.h:135
arch_cpu::apic_id
uint32_t apic_id
Definition
cpu.h:125
cpu
A processor, and what runs on it.
Definition
cpu.h:11
cpu::arch
struct arch_cpu arch
Definition
cpu.h:17
pmap
An address space's page tables, on x86.
Definition
pmap.h:9
pmap::cpus
volatile uint32_t cpus
Definition
pmap.h:8
vm_space::pmap
struct pmap * pmap
its page tables (the architecture's)
Definition
vm.h:27
flush
static void flush(vaddr_t sva, vaddr_t eva)
Flushes [sva, eva) from the running CPU's TLB.
Definition
tlb.c:60
request
static struct @012362346107137024144356360042152075235052321043 request
request_do
static void request_do(struct pmap *pmap, vaddr_t sva, vaddr_t eva, int leave)
Does what a request asks of the running CPU: flush the range, if the CPU may have it,...
Definition
tlb.c:73
kernel_gen
static uint64_t kernel_gen
Definition
tlb.c:48
FLUSH_PAGES_MAX
#define FLUSH_PAGES_MAX
Definition
tlb.c:41
vm.h
kvm_space
struct vm_space kvm_space
Definition
vmm.c:17
kernel
arch
i386
mm
tlb.c
Generated by
1.18.0