Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/powerpc/aim/moea64_native.c
105332 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause AND BSD-4-Clause
3
*
4
* Copyright (c) 2001 The NetBSD Foundation, Inc.
5
* All rights reserved.
6
*
7
* This code is derived from software contributed to The NetBSD Foundation
8
* by Matt Thomas <[email protected]> of Allegro Networks, Inc.
9
*
10
* Redistribution and use in source and binary forms, with or without
11
* modification, are permitted provided that the following conditions
12
* are met:
13
* 1. Redistributions of source code must retain the above copyright
14
* notice, this list of conditions and the following disclaimer.
15
* 2. Redistributions in binary form must reproduce the above copyright
16
* notice, this list of conditions and the following disclaimer in the
17
* documentation and/or other materials provided with the distribution.
18
*
19
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
* POSSIBILITY OF SUCH DAMAGE.
30
*/
31
/*-
32
* Copyright (C) 1995, 1996 Wolfgang Solfrank.
33
* Copyright (C) 1995, 1996 TooLs GmbH.
34
* All rights reserved.
35
*
36
* Redistribution and use in source and binary forms, with or without
37
* modification, are permitted provided that the following conditions
38
* are met:
39
* 1. Redistributions of source code must retain the above copyright
40
* notice, this list of conditions and the following disclaimer.
41
* 2. Redistributions in binary form must reproduce the above copyright
42
* notice, this list of conditions and the following disclaimer in the
43
* documentation and/or other materials provided with the distribution.
44
* 3. All advertising materials mentioning features or use of this software
45
* must display the following acknowledgement:
46
* This product includes software developed by TooLs GmbH.
47
* 4. The name of TooLs GmbH may not be used to endorse or promote products
48
* derived from this software without specific prior written permission.
49
*
50
* THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
51
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
52
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
53
* IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
54
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
55
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
56
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
57
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
58
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
59
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
60
*
61
* $NetBSD: pmap.c,v 1.28 2000/03/26 20:42:36 kleink Exp $
62
*/
63
/*-
64
* Copyright (C) 2001 Benno Rice.
65
* All rights reserved.
66
*
67
* Redistribution and use in source and binary forms, with or without
68
* modification, are permitted provided that the following conditions
69
* are met:
70
* 1. Redistributions of source code must retain the above copyright
71
* notice, this list of conditions and the following disclaimer.
72
* 2. Redistributions in binary form must reproduce the above copyright
73
* notice, this list of conditions and the following disclaimer in the
74
* documentation and/or other materials provided with the distribution.
75
*
76
* THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR
77
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
78
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
79
* IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
80
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
81
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
82
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
83
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
84
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
85
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
86
*/
87
88
#include <sys/cdefs.h>
89
/*
90
* Native 64-bit page table operations for running without a hypervisor.
91
*/
92
93
#include <sys/param.h>
94
#include <sys/kernel.h>
95
#include <sys/ktr.h>
96
#include <sys/lock.h>
97
#include <sys/mutex.h>
98
#include <sys/proc.h>
99
#include <sys/sched.h>
100
#include <sys/sysctl.h>
101
#include <sys/systm.h>
102
#include <sys/rwlock.h>
103
#include <sys/endian.h>
104
105
#include <sys/kdb.h>
106
107
#include <vm/vm.h>
108
#include <vm/vm_param.h>
109
#include <vm/vm_kern.h>
110
#include <vm/vm_page.h>
111
#include <vm/vm_map.h>
112
#include <vm/vm_object.h>
113
#include <vm/vm_extern.h>
114
#include <vm/vm_pageout.h>
115
116
#include <machine/cpu.h>
117
#include <machine/hid.h>
118
#include <machine/md_var.h>
119
#include <machine/mmuvar.h>
120
121
#include "mmu_oea64.h"
122
123
#define PTESYNC() __asm __volatile("ptesync");
124
#define TLBSYNC() __asm __volatile("tlbsync; ptesync");
125
#define SYNC() __asm __volatile("sync");
126
#define EIEIO() __asm __volatile("eieio");
127
128
#define VSID_HASH_MASK 0x0000007fffffffffULL
129
130
/* POWER9 only permits a 64k partition table size. */
131
#define PART_SIZE 0x10000
132
133
/* Actual page sizes (to be used with tlbie, when L=0) */
134
#define AP_4K 0x00
135
#define AP_16M 0x80
136
137
#define LPTE_KERNEL_VSID_BIT (KERNEL_VSID_BIT << \
138
(16 - (ADDR_API_SHFT64 - ADDR_PIDX_SHFT)))
139
140
/* Abbreviated Virtual Address Page - high bits */
141
#define LPTE_AVA_PGNHI_MASK 0x0000000000000F80ULL
142
#define LPTE_AVA_PGNHI_SHIFT 7
143
144
/* Effective Address Page - low bits */
145
#define EA_PAGELO_MASK 0x7ffULL
146
#define EA_PAGELO_SHIFT 11
147
148
static bool moea64_crop_tlbie;
149
static bool moea64_need_lock;
150
151
/*
152
* The tlbie instruction has two forms: an old one used by PowerISA
153
* 2.03 and prior, and a newer one used by PowerISA 2.06 and later.
154
* We need to support both.
155
*/
156
static __inline void
157
TLBIE(uint64_t vpn, uint64_t oldptehi)
158
{
159
#ifndef __powerpc64__
160
register_t vpn_hi, vpn_lo;
161
register_t msr;
162
register_t scratch, intr;
163
#endif
164
165
static volatile u_int tlbie_lock = 0;
166
bool need_lock = moea64_need_lock;
167
168
vpn <<= ADDR_PIDX_SHFT;
169
170
/* Hobo spinlock: we need stronger guarantees than mutexes provide */
171
if (need_lock) {
172
while (!atomic_cmpset_int(&tlbie_lock, 0, 1));
173
isync(); /* Flush instruction queue once lock acquired */
174
175
if (moea64_crop_tlbie) {
176
vpn &= ~(0xffffULL << 48);
177
#ifdef __powerpc64__
178
if ((oldptehi & LPTE_BIG) != 0)
179
__asm __volatile("tlbie %0, 1" :: "r"(vpn) :
180
"memory");
181
else
182
__asm __volatile("tlbie %0, 0" :: "r"(vpn) :
183
"memory");
184
__asm __volatile("eieio; tlbsync; ptesync" :::
185
"memory");
186
tlbie_lock = 0;
187
return;
188
#endif
189
}
190
}
191
192
#ifdef __powerpc64__
193
/*
194
* If this page has LPTE_BIG set and is from userspace, then
195
* it must be a superpage with 4KB base/16MB actual page size.
196
*/
197
if ((oldptehi & LPTE_BIG) != 0 &&
198
(oldptehi & LPTE_KERNEL_VSID_BIT) == 0)
199
vpn |= AP_16M;
200
201
__asm __volatile("tlbie %0, %1" :: "r"(vpn), "r"(0) : "memory");
202
__asm __volatile("eieio; tlbsync; ptesync" ::: "memory");
203
#else
204
vpn_hi = (uint32_t)(vpn >> 32);
205
vpn_lo = (uint32_t)vpn;
206
207
intr = intr_disable();
208
__asm __volatile("\
209
mfmsr %0; \
210
mr %1, %0; \
211
insrdi %1,%5,1,0; \
212
mtmsrd %1; isync; \
213
\
214
sld %1,%2,%4; \
215
or %1,%1,%3; \
216
tlbie %1; \
217
\
218
mtmsrd %0; isync; \
219
eieio; \
220
tlbsync; \
221
ptesync;"
222
: "=r"(msr), "=r"(scratch) : "r"(vpn_hi), "r"(vpn_lo), "r"(32), "r"(1)
223
: "memory");
224
intr_restore(intr);
225
#endif
226
227
/* No barriers or special ops -- taken care of by ptesync above */
228
if (need_lock)
229
tlbie_lock = 0;
230
}
231
232
#define DISABLE_TRANS(msr) msr = mfmsr(); mtmsr(msr & ~PSL_DR)
233
#define ENABLE_TRANS(msr) mtmsr(msr)
234
235
/*
236
* PTEG data.
237
*/
238
static volatile struct lpte *moea64_pteg_table;
239
static struct rwlock moea64_eviction_lock;
240
241
static volatile struct pate *moea64_part_table;
242
243
/*
244
* Dump function.
245
*/
246
static void *moea64_dump_pmap_native(void *ctx, void *buf,
247
u_long *nbytes);
248
249
/*
250
* PTE calls.
251
*/
252
static int64_t moea64_pte_insert_native(struct pvo_entry *);
253
static int64_t moea64_pte_synch_native(struct pvo_entry *);
254
static int64_t moea64_pte_clear_native(struct pvo_entry *, uint64_t);
255
static int64_t moea64_pte_replace_native(struct pvo_entry *, int);
256
static int64_t moea64_pte_unset_native(struct pvo_entry *);
257
static int64_t moea64_pte_insert_sp_native(struct pvo_entry *);
258
static int64_t moea64_pte_unset_sp_native(struct pvo_entry *);
259
static int64_t moea64_pte_replace_sp_native(struct pvo_entry *);
260
261
/*
262
* Utility routines.
263
*/
264
static void moea64_bootstrap_native(
265
vm_offset_t kernelstart, vm_offset_t kernelend);
266
static void moea64_cpu_bootstrap_native(int ap);
267
static void tlbia(void);
268
static void moea64_install_native(void);
269
270
static struct pmap_funcs moea64_native_methods = {
271
.install = moea64_install_native,
272
273
/* Internal interfaces */
274
.bootstrap = moea64_bootstrap_native,
275
.cpu_bootstrap = moea64_cpu_bootstrap_native,
276
.dumpsys_dump_pmap = moea64_dump_pmap_native,
277
};
278
279
static struct moea64_funcs moea64_native_funcs = {
280
.pte_synch = moea64_pte_synch_native,
281
.pte_clear = moea64_pte_clear_native,
282
.pte_unset = moea64_pte_unset_native,
283
.pte_replace = moea64_pte_replace_native,
284
.pte_insert = moea64_pte_insert_native,
285
.pte_insert_sp = moea64_pte_insert_sp_native,
286
.pte_unset_sp = moea64_pte_unset_sp_native,
287
.pte_replace_sp = moea64_pte_replace_sp_native,
288
};
289
290
MMU_DEF_INHERIT(oea64_mmu_native, MMU_TYPE_G5, moea64_native_methods, oea64_mmu);
291
292
static void
293
moea64_install_native(void)
294
{
295
296
/* Install the MOEA64 ops. */
297
moea64_ops = &moea64_native_funcs;
298
299
moea64_install();
300
}
301
302
static int64_t
303
moea64_pte_synch_native(struct pvo_entry *pvo)
304
{
305
volatile struct lpte *pt = moea64_pteg_table + pvo->pvo_pte.slot;
306
uint64_t ptelo, pvo_ptevpn;
307
308
PMAP_LOCK_ASSERT(pvo->pvo_pmap, MA_OWNED);
309
310
pvo_ptevpn = moea64_pte_vpn_from_pvo_vpn(pvo);
311
312
rw_rlock(&moea64_eviction_lock);
313
if ((be64toh(pt->pte_hi) & LPTE_AVPN_MASK) != pvo_ptevpn) {
314
/* Evicted */
315
rw_runlock(&moea64_eviction_lock);
316
return (-1);
317
}
318
319
PTESYNC();
320
ptelo = be64toh(pt->pte_lo);
321
322
rw_runlock(&moea64_eviction_lock);
323
324
return (ptelo & (LPTE_REF | LPTE_CHG));
325
}
326
327
static int64_t
328
moea64_pte_clear_native(struct pvo_entry *pvo, uint64_t ptebit)
329
{
330
volatile struct lpte *pt = moea64_pteg_table + pvo->pvo_pte.slot;
331
struct lpte properpt;
332
uint64_t ptelo;
333
334
PMAP_LOCK_ASSERT(pvo->pvo_pmap, MA_OWNED);
335
336
moea64_pte_from_pvo(pvo, &properpt);
337
338
rw_rlock(&moea64_eviction_lock);
339
if ((be64toh(pt->pte_hi) & LPTE_AVPN_MASK) !=
340
(properpt.pte_hi & LPTE_AVPN_MASK)) {
341
/* Evicted */
342
rw_runlock(&moea64_eviction_lock);
343
return (-1);
344
}
345
346
if (ptebit == LPTE_REF) {
347
/* See "Resetting the Reference Bit" in arch manual */
348
PTESYNC();
349
/* 2-step here safe: precision is not guaranteed */
350
ptelo = be64toh(pt->pte_lo);
351
352
/* One-byte store to avoid touching the C bit */
353
((volatile uint8_t *)(&pt->pte_lo))[6] =
354
#if BYTE_ORDER == BIG_ENDIAN
355
((uint8_t *)(&properpt.pte_lo))[6];
356
#else
357
((uint8_t *)(&properpt.pte_lo))[1];
358
#endif
359
rw_runlock(&moea64_eviction_lock);
360
361
critical_enter();
362
TLBIE(pvo->pvo_vpn, properpt.pte_hi);
363
critical_exit();
364
} else {
365
rw_runlock(&moea64_eviction_lock);
366
ptelo = moea64_pte_unset_native(pvo);
367
moea64_pte_insert_native(pvo);
368
}
369
370
return (ptelo & (LPTE_REF | LPTE_CHG));
371
}
372
373
static __always_inline int64_t
374
moea64_pte_unset_locked(volatile struct lpte *pt, uint64_t vpn)
375
{
376
uint64_t ptelo, ptehi;
377
378
/*
379
* Invalidate the pte, briefly locking it to collect RC bits. No
380
* atomics needed since this is protected against eviction by the lock.
381
*/
382
isync();
383
critical_enter();
384
ptehi = (be64toh(pt->pte_hi) & ~LPTE_VALID) | LPTE_LOCKED;
385
pt->pte_hi = htobe64(ptehi);
386
PTESYNC();
387
TLBIE(vpn, ptehi);
388
ptelo = be64toh(pt->pte_lo);
389
*((volatile int32_t *)(&pt->pte_hi) + 1) = 0; /* Release lock */
390
critical_exit();
391
392
/* Keep statistics */
393
STAT_MOEA64(moea64_pte_valid--);
394
395
return (ptelo & (LPTE_CHG | LPTE_REF));
396
}
397
398
static int64_t
399
moea64_pte_unset_native(struct pvo_entry *pvo)
400
{
401
volatile struct lpte *pt = moea64_pteg_table + pvo->pvo_pte.slot;
402
int64_t ret;
403
uint64_t pvo_ptevpn;
404
405
pvo_ptevpn = moea64_pte_vpn_from_pvo_vpn(pvo);
406
407
rw_rlock(&moea64_eviction_lock);
408
409
if ((be64toh(pt->pte_hi) & LPTE_AVPN_MASK) != pvo_ptevpn) {
410
/* Evicted */
411
STAT_MOEA64(moea64_pte_overflow--);
412
ret = -1;
413
} else
414
ret = moea64_pte_unset_locked(pt, pvo->pvo_vpn);
415
416
rw_runlock(&moea64_eviction_lock);
417
418
return (ret);
419
}
420
421
static int64_t
422
moea64_pte_replace_inval_native(struct pvo_entry *pvo,
423
volatile struct lpte *pt)
424
{
425
struct lpte properpt;
426
uint64_t ptelo, ptehi;
427
428
moea64_pte_from_pvo(pvo, &properpt);
429
430
rw_rlock(&moea64_eviction_lock);
431
if ((be64toh(pt->pte_hi) & LPTE_AVPN_MASK) !=
432
(properpt.pte_hi & LPTE_AVPN_MASK)) {
433
/* Evicted */
434
STAT_MOEA64(moea64_pte_overflow--);
435
rw_runlock(&moea64_eviction_lock);
436
return (-1);
437
}
438
439
/*
440
* Replace the pte, briefly locking it to collect RC bits. No
441
* atomics needed since this is protected against eviction by the lock.
442
*/
443
isync();
444
critical_enter();
445
ptehi = (be64toh(pt->pte_hi) & ~LPTE_VALID) | LPTE_LOCKED;
446
pt->pte_hi = htobe64(ptehi);
447
PTESYNC();
448
TLBIE(pvo->pvo_vpn, ptehi);
449
ptelo = be64toh(pt->pte_lo);
450
EIEIO();
451
pt->pte_lo = htobe64(properpt.pte_lo);
452
EIEIO();
453
pt->pte_hi = htobe64(properpt.pte_hi); /* Release lock */
454
PTESYNC();
455
critical_exit();
456
rw_runlock(&moea64_eviction_lock);
457
458
return (ptelo & (LPTE_CHG | LPTE_REF));
459
}
460
461
static int64_t
462
moea64_pte_replace_native(struct pvo_entry *pvo, int flags)
463
{
464
volatile struct lpte *pt = moea64_pteg_table + pvo->pvo_pte.slot;
465
struct lpte properpt;
466
int64_t ptelo;
467
468
if (flags == 0) {
469
/* Just some software bits changing. */
470
moea64_pte_from_pvo(pvo, &properpt);
471
472
rw_rlock(&moea64_eviction_lock);
473
if ((be64toh(pt->pte_hi) & LPTE_AVPN_MASK) !=
474
(properpt.pte_hi & LPTE_AVPN_MASK)) {
475
rw_runlock(&moea64_eviction_lock);
476
return (-1);
477
}
478
pt->pte_hi = htobe64(properpt.pte_hi);
479
ptelo = be64toh(pt->pte_lo);
480
rw_runlock(&moea64_eviction_lock);
481
} else {
482
/* Otherwise, need reinsertion and deletion */
483
ptelo = moea64_pte_replace_inval_native(pvo, pt);
484
}
485
486
return (ptelo);
487
}
488
489
static void
490
moea64_cpu_bootstrap_native(int ap)
491
{
492
int i = 0;
493
#ifdef __powerpc64__
494
struct slb *slb = PCPU_GET(aim.slb);
495
register_t seg0;
496
#endif
497
498
/*
499
* Initialize segment registers and MMU
500
*/
501
502
mtmsr(mfmsr() & ~PSL_DR & ~PSL_IR);
503
504
switch(mfpvr() >> 16) {
505
case IBMPOWER9:
506
mtspr(SPR_HID0, mfspr(SPR_HID0) & ~HID0_RADIX);
507
break;
508
}
509
510
/*
511
* Install kernel SLB entries
512
*/
513
514
#ifdef __powerpc64__
515
__asm __volatile ("slbia");
516
__asm __volatile ("slbmfee %0,%1; slbie %0;" : "=r"(seg0) :
517
"r"(0));
518
519
for (i = 0; i < n_slbs; i++) {
520
if (!(slb[i].slbe & SLBE_VALID))
521
continue;
522
523
__asm __volatile ("slbmte %0, %1" ::
524
"r"(slb[i].slbv), "r"(slb[i].slbe));
525
}
526
#else
527
for (i = 0; i < 16; i++)
528
mtsrin(i << ADDR_SR_SHFT, kernel_pmap->pm_sr[i]);
529
#endif
530
531
/*
532
* Install page table
533
*/
534
535
if (cpu_features2 & PPC_FEATURE2_ARCH_3_00)
536
mtspr(SPR_PTCR,
537
((uintptr_t)moea64_part_table & ~DMAP_BASE_ADDRESS) |
538
flsl((PART_SIZE >> 12) - 1));
539
else
540
__asm __volatile ("ptesync; mtsdr1 %0; isync"
541
:: "r"(((uintptr_t)moea64_pteg_table & ~DMAP_BASE_ADDRESS)
542
| (uintptr_t)(flsl(moea64_pteg_mask >> 11))));
543
tlbia();
544
}
545
546
static void
547
moea64_bootstrap_native(vm_offset_t kernelstart, vm_offset_t kernelend)
548
{
549
vm_size_t size;
550
vm_offset_t off;
551
vm_paddr_t pa;
552
register_t msr;
553
554
moea64_early_bootstrap(kernelstart, kernelend);
555
556
switch (mfpvr() >> 16) {
557
case IBMPOWER8:
558
case IBMPOWER8E:
559
case IBMPOWER8NVL:
560
case IBMPOWER9:
561
case IBMPOWER10:
562
case IBMPOWER11:
563
moea64_need_lock = false;
564
break;
565
case IBMPOWER4:
566
case IBMPOWER4PLUS:
567
case IBM970:
568
case IBM970FX:
569
case IBM970GX:
570
case IBM970MP:
571
moea64_crop_tlbie = true;
572
default:
573
moea64_need_lock = true;
574
}
575
/*
576
* Allocate PTEG table.
577
*/
578
579
size = moea64_pteg_count * sizeof(struct lpteg);
580
CTR2(KTR_PMAP, "moea64_bootstrap: %lu PTEGs, %lu bytes",
581
moea64_pteg_count, size);
582
rw_init(&moea64_eviction_lock, "pte eviction");
583
584
/*
585
* We now need to allocate memory. This memory, to be allocated,
586
* has to reside in a page table. The page table we are about to
587
* allocate. We don't have BAT. So drop to data real mode for a minute
588
* as a measure of last resort. We do this a couple times.
589
*/
590
/*
591
* PTEG table must be aligned on a 256k boundary, but can be placed
592
* anywhere with that alignment on POWER ISA 3+ systems. On earlier
593
* systems, offset addition is done by the CPU with bitwise OR rather
594
* than addition, so the table must also be aligned on a boundary of
595
* its own size. Pick the larger of the two, which works on all
596
* systems.
597
*/
598
moea64_pteg_table = (struct lpte *)moea64_bootstrap_alloc(size,
599
MAX(256*1024, size));
600
if (hw_direct_map)
601
moea64_pteg_table =
602
(struct lpte *)PHYS_TO_DMAP((vm_offset_t)moea64_pteg_table);
603
/* Allocate partition table (ISA 3.0). */
604
if (cpu_features2 & PPC_FEATURE2_ARCH_3_00) {
605
moea64_part_table =
606
(struct pate *)moea64_bootstrap_alloc(PART_SIZE, PART_SIZE);
607
moea64_part_table =
608
(struct pate *)PHYS_TO_DMAP((vm_offset_t)moea64_part_table);
609
}
610
DISABLE_TRANS(msr);
611
bzero(__DEVOLATILE(void *, moea64_pteg_table), moea64_pteg_count *
612
sizeof(struct lpteg));
613
if (cpu_features2 & PPC_FEATURE2_ARCH_3_00) {
614
bzero(__DEVOLATILE(void *, moea64_part_table), PART_SIZE);
615
moea64_part_table[0].pagetab = htobe64(
616
(DMAP_TO_PHYS((vm_offset_t)moea64_pteg_table)) |
617
(uintptr_t)(flsl((moea64_pteg_count - 1) >> 11)));
618
}
619
ENABLE_TRANS(msr);
620
621
CTR1(KTR_PMAP, "moea64_bootstrap: PTEG table at %p", moea64_pteg_table);
622
623
moea64_mid_bootstrap(kernelstart, kernelend);
624
625
/*
626
* Add a mapping for the page table itself if there is no direct map.
627
*/
628
if (!hw_direct_map) {
629
size = moea64_pteg_count * sizeof(struct lpteg);
630
off = (vm_offset_t)(moea64_pteg_table);
631
DISABLE_TRANS(msr);
632
for (pa = off; pa < off + size; pa += PAGE_SIZE)
633
pmap_kenter(pa, pa);
634
ENABLE_TRANS(msr);
635
}
636
637
/* Bring up virtual memory */
638
moea64_late_bootstrap(kernelstart, kernelend);
639
}
640
641
static void
642
tlbia(void)
643
{
644
vm_offset_t i;
645
#ifndef __powerpc64__
646
register_t msr, scratch;
647
#endif
648
649
i = 0xc00; /* IS = 11 */
650
switch (mfpvr() >> 16) {
651
case IBM970:
652
case IBM970FX:
653
case IBM970MP:
654
case IBM970GX:
655
case IBMPOWER4:
656
case IBMPOWER4PLUS:
657
case IBMPOWER5:
658
case IBMPOWER5PLUS:
659
i = 0; /* IS not supported */
660
break;
661
}
662
663
TLBSYNC();
664
665
for (; i < 0x400000; i += 0x00001000) {
666
#ifdef __powerpc64__
667
__asm __volatile("tlbiel %0" :: "r"(i));
668
#else
669
__asm __volatile("\
670
mfmsr %0; \
671
mr %1, %0; \
672
insrdi %1,%3,1,0; \
673
mtmsrd %1; \
674
isync; \
675
\
676
tlbiel %2; \
677
\
678
mtmsrd %0; \
679
isync;"
680
: "=r"(msr), "=r"(scratch) : "r"(i), "r"(1));
681
#endif
682
}
683
684
EIEIO();
685
TLBSYNC();
686
}
687
688
static int
689
atomic_pte_lock(volatile struct lpte *pte, uint64_t bitmask, uint64_t *oldhi)
690
{
691
int ret;
692
#ifdef __powerpc64__
693
uint64_t temp;
694
#else
695
uint32_t oldhihalf;
696
#endif
697
698
/*
699
* Note: in principle, if just the locked bit were set here, we
700
* could avoid needing the eviction lock. However, eviction occurs
701
* so rarely that it isn't worth bothering about in practice.
702
*/
703
#ifdef __powerpc64__
704
/*
705
* Note: Success of this sequence has the side effect of invalidating
706
* the PTE, as we are setting it to LPTE_LOCKED and discarding the
707
* other bits, including LPTE_V.
708
*/
709
__asm __volatile (
710
"1:\tldarx %1, 0, %3\n\t" /* load old value */
711
"and. %0,%1,%4\n\t" /* check if any bits set */
712
"bne 2f\n\t" /* exit if any set */
713
"stdcx. %5, 0, %3\n\t" /* attempt to store */
714
"bne- 1b\n\t" /* spin if failed */
715
"li %0, 1\n\t" /* success - retval = 1 */
716
"b 3f\n\t" /* we've succeeded */
717
"2:\n\t"
718
"stdcx. %1, 0, %3\n\t" /* clear reservation (74xx) */
719
"li %0, 0\n\t" /* failure - retval = 0 */
720
"3:\n\t"
721
: "=&r" (ret), "=&r"(temp), "=m" (pte->pte_hi)
722
: "r" ((volatile char *)&pte->pte_hi),
723
"r" (htobe64(bitmask)), "r" (htobe64(LPTE_LOCKED)),
724
"m" (pte->pte_hi)
725
: "cr0", "cr1", "cr2", "memory");
726
*oldhi = be64toh(temp);
727
#else
728
/*
729
* This code is used on bridge mode only.
730
*/
731
__asm __volatile (
732
"1:\tlwarx %1, 0, %3\n\t" /* load old value */
733
"and. %0,%1,%4\n\t" /* check if any bits set */
734
"bne 2f\n\t" /* exit if any set */
735
"stwcx. %5, 0, %3\n\t" /* attempt to store */
736
"bne- 1b\n\t" /* spin if failed */
737
"li %0, 1\n\t" /* success - retval = 1 */
738
"b 3f\n\t" /* we've succeeded */
739
"2:\n\t"
740
"stwcx. %1, 0, %3\n\t" /* clear reservation (74xx) */
741
"li %0, 0\n\t" /* failure - retval = 0 */
742
"3:\n\t"
743
: "=&r" (ret), "=&r"(oldhihalf), "=m" (pte->pte_hi)
744
: "r" ((volatile char *)&pte->pte_hi + 4),
745
"r" ((uint32_t)bitmask), "r" ((uint32_t)LPTE_LOCKED),
746
"m" (pte->pte_hi)
747
: "cr0", "cr1", "cr2", "memory");
748
749
*oldhi = (pte->pte_hi & 0xffffffff00000000ULL) | oldhihalf;
750
#endif
751
752
return (ret);
753
}
754
755
static uintptr_t
756
moea64_insert_to_pteg_native(struct lpte *pvo_pt, uintptr_t slotbase,
757
uint64_t mask)
758
{
759
volatile struct lpte *pt;
760
uint64_t oldptehi, va;
761
uintptr_t k;
762
int i, j;
763
764
/* Start at a random slot */
765
i = mftb() % 8;
766
for (j = 0; j < 8; j++) {
767
k = slotbase + (i + j) % 8;
768
pt = &moea64_pteg_table[k];
769
/* Invalidate and seize lock only if no bits in mask set */
770
if (atomic_pte_lock(pt, mask, &oldptehi)) /* Lock obtained */
771
break;
772
}
773
774
if (j == 8)
775
return (-1);
776
777
if (oldptehi & LPTE_VALID) {
778
KASSERT(!(oldptehi & LPTE_WIRED), ("Unmapped wired entry"));
779
/*
780
* Need to invalidate old entry completely: see
781
* "Modifying a Page Table Entry". Need to reconstruct
782
* the virtual address for the outgoing entry to do that.
783
*/
784
va = oldptehi >> (ADDR_SR_SHFT - ADDR_API_SHFT64);
785
if (oldptehi & LPTE_HID)
786
va = (((k >> 3) ^ moea64_pteg_mask) ^ va) &
787
(ADDR_PIDX >> ADDR_PIDX_SHFT);
788
else
789
va = ((k >> 3) ^ va) & (ADDR_PIDX >> ADDR_PIDX_SHFT);
790
va |= (oldptehi & LPTE_AVPN_MASK) <<
791
(ADDR_API_SHFT64 - ADDR_PIDX_SHFT);
792
PTESYNC();
793
TLBIE(va, oldptehi);
794
STAT_MOEA64(moea64_pte_valid--);
795
STAT_MOEA64(moea64_pte_overflow++);
796
}
797
798
/*
799
* Update the PTE as per "Adding a Page Table Entry". Lock is released
800
* by setting the high doubleworld.
801
*/
802
pt->pte_lo = htobe64(pvo_pt->pte_lo);
803
EIEIO();
804
pt->pte_hi = htobe64(pvo_pt->pte_hi);
805
PTESYNC();
806
807
/* Keep statistics */
808
STAT_MOEA64(moea64_pte_valid++);
809
810
return (k);
811
}
812
813
static __always_inline int64_t
814
moea64_pte_insert_locked(struct pvo_entry *pvo, struct lpte *insertpt,
815
uint64_t mask)
816
{
817
uintptr_t slot;
818
819
/*
820
* First try primary hash.
821
*/
822
slot = moea64_insert_to_pteg_native(insertpt, pvo->pvo_pte.slot,
823
mask | LPTE_WIRED | LPTE_LOCKED);
824
if (slot != -1) {
825
pvo->pvo_pte.slot = slot;
826
return (0);
827
}
828
829
/*
830
* Now try secondary hash.
831
*/
832
pvo->pvo_vaddr ^= PVO_HID;
833
insertpt->pte_hi ^= LPTE_HID;
834
pvo->pvo_pte.slot ^= (moea64_pteg_mask << 3);
835
slot = moea64_insert_to_pteg_native(insertpt, pvo->pvo_pte.slot,
836
mask | LPTE_WIRED | LPTE_LOCKED);
837
if (slot != -1) {
838
pvo->pvo_pte.slot = slot;
839
return (0);
840
}
841
842
return (-1);
843
}
844
845
static int64_t
846
moea64_pte_insert_native(struct pvo_entry *pvo)
847
{
848
struct lpte insertpt;
849
int64_t ret;
850
851
/* Initialize PTE */
852
moea64_pte_from_pvo(pvo, &insertpt);
853
854
/* Make sure further insertion is locked out during evictions */
855
rw_rlock(&moea64_eviction_lock);
856
857
pvo->pvo_pte.slot &= ~7ULL; /* Base slot address */
858
ret = moea64_pte_insert_locked(pvo, &insertpt, LPTE_VALID);
859
if (ret == -1) {
860
/*
861
* Out of luck. Find a PTE to sacrifice.
862
*/
863
864
/* Lock out all insertions for a bit */
865
if (!rw_try_upgrade(&moea64_eviction_lock)) {
866
rw_runlock(&moea64_eviction_lock);
867
rw_wlock(&moea64_eviction_lock);
868
}
869
/* Don't evict large pages */
870
ret = moea64_pte_insert_locked(pvo, &insertpt, LPTE_BIG);
871
rw_wunlock(&moea64_eviction_lock);
872
/* No freeable slots in either PTEG? We're hosed. */
873
if (ret == -1)
874
panic("moea64_pte_insert: overflow");
875
} else
876
rw_runlock(&moea64_eviction_lock);
877
878
return (0);
879
}
880
881
static void *
882
moea64_dump_pmap_native(void *ctx, void *buf, u_long *nbytes)
883
{
884
struct dump_context *dctx;
885
u_long ptex, ptex_end;
886
887
dctx = (struct dump_context *)ctx;
888
ptex = dctx->ptex;
889
ptex_end = ptex + dctx->blksz / sizeof(struct lpte);
890
ptex_end = MIN(ptex_end, dctx->ptex_end);
891
*nbytes = (ptex_end - ptex) * sizeof(struct lpte);
892
893
if (*nbytes == 0)
894
return (NULL);
895
896
dctx->ptex = ptex_end;
897
return (__DEVOLATILE(struct lpte *, moea64_pteg_table) + ptex);
898
}
899
900
static __always_inline uint64_t
901
moea64_vpn_from_pte(uint64_t ptehi, uintptr_t slot)
902
{
903
uint64_t pgn, pgnlo, vsid;
904
905
vsid = (ptehi & LPTE_AVA_MASK) >> LPTE_VSID_SHIFT;
906
if ((ptehi & LPTE_HID) != 0)
907
slot ^= (moea64_pteg_mask << 3);
908
pgnlo = ((vsid & VSID_HASH_MASK) ^ (slot >> 3)) & EA_PAGELO_MASK;
909
pgn = ((ptehi & LPTE_AVA_PGNHI_MASK) << (EA_PAGELO_SHIFT -
910
LPTE_AVA_PGNHI_SHIFT)) | pgnlo;
911
return ((vsid << 16) | pgn);
912
}
913
914
static __always_inline int64_t
915
moea64_pte_unset_sp_locked(struct pvo_entry *pvo)
916
{
917
volatile struct lpte *pt;
918
uint64_t ptehi, refchg, vpn;
919
vm_offset_t eva;
920
921
refchg = 0;
922
eva = PVO_VADDR(pvo) + HPT_SP_SIZE;
923
924
for (; pvo != NULL && PVO_VADDR(pvo) < eva;
925
pvo = RB_NEXT(pvo_tree, &pvo->pvo_pmap->pmap_pvo, pvo)) {
926
pt = moea64_pteg_table + pvo->pvo_pte.slot;
927
ptehi = be64toh(pt->pte_hi);
928
if ((ptehi & LPTE_AVPN_MASK) !=
929
moea64_pte_vpn_from_pvo_vpn(pvo)) {
930
/* Evicted: invalidate new entry */
931
STAT_MOEA64(moea64_pte_overflow--);
932
vpn = moea64_vpn_from_pte(ptehi, pvo->pvo_pte.slot);
933
CTR1(KTR_PMAP, "Evicted page in pte_unset_sp: vpn=%jx",
934
(uintmax_t)vpn);
935
/* Assume evicted page was modified */
936
refchg |= LPTE_CHG;
937
} else
938
vpn = pvo->pvo_vpn;
939
940
refchg |= moea64_pte_unset_locked(pt, vpn);
941
}
942
943
return (refchg);
944
}
945
946
static int64_t
947
moea64_pte_unset_sp_native(struct pvo_entry *pvo)
948
{
949
uint64_t refchg;
950
951
PMAP_LOCK_ASSERT(pvo->pvo_pmap, MA_OWNED);
952
KASSERT((PVO_VADDR(pvo) & HPT_SP_MASK) == 0,
953
("%s: va %#jx unaligned", __func__, (uintmax_t)PVO_VADDR(pvo)));
954
955
rw_rlock(&moea64_eviction_lock);
956
refchg = moea64_pte_unset_sp_locked(pvo);
957
rw_runlock(&moea64_eviction_lock);
958
959
return (refchg);
960
}
961
962
static __always_inline int64_t
963
moea64_pte_insert_sp_locked(struct pvo_entry *pvo)
964
{
965
struct lpte insertpt;
966
int64_t ret;
967
vm_offset_t eva;
968
969
eva = PVO_VADDR(pvo) + HPT_SP_SIZE;
970
971
for (; pvo != NULL && PVO_VADDR(pvo) < eva;
972
pvo = RB_NEXT(pvo_tree, &pvo->pvo_pmap->pmap_pvo, pvo)) {
973
moea64_pte_from_pvo(pvo, &insertpt);
974
pvo->pvo_pte.slot &= ~7ULL; /* Base slot address */
975
976
ret = moea64_pte_insert_locked(pvo, &insertpt, LPTE_VALID);
977
if (ret == -1) {
978
/* Lock out all insertions for a bit */
979
if (!rw_try_upgrade(&moea64_eviction_lock)) {
980
rw_runlock(&moea64_eviction_lock);
981
rw_wlock(&moea64_eviction_lock);
982
}
983
/* Don't evict large pages */
984
ret = moea64_pte_insert_locked(pvo, &insertpt,
985
LPTE_BIG);
986
rw_downgrade(&moea64_eviction_lock);
987
/* No freeable slots in either PTEG? We're hosed. */
988
if (ret == -1)
989
panic("moea64_pte_insert_sp: overflow");
990
}
991
}
992
993
return (0);
994
}
995
996
static int64_t
997
moea64_pte_insert_sp_native(struct pvo_entry *pvo)
998
{
999
PMAP_LOCK_ASSERT(pvo->pvo_pmap, MA_OWNED);
1000
KASSERT((PVO_VADDR(pvo) & HPT_SP_MASK) == 0,
1001
("%s: va %#jx unaligned", __func__, (uintmax_t)PVO_VADDR(pvo)));
1002
1003
rw_rlock(&moea64_eviction_lock);
1004
moea64_pte_insert_sp_locked(pvo);
1005
rw_runlock(&moea64_eviction_lock);
1006
1007
return (0);
1008
}
1009
1010
static int64_t
1011
moea64_pte_replace_sp_native(struct pvo_entry *pvo)
1012
{
1013
uint64_t refchg;
1014
1015
PMAP_LOCK_ASSERT(pvo->pvo_pmap, MA_OWNED);
1016
KASSERT((PVO_VADDR(pvo) & HPT_SP_MASK) == 0,
1017
("%s: va %#jx unaligned", __func__, (uintmax_t)PVO_VADDR(pvo)));
1018
1019
rw_rlock(&moea64_eviction_lock);
1020
refchg = moea64_pte_unset_sp_locked(pvo);
1021
moea64_pte_insert_sp_locked(pvo);
1022
rw_runlock(&moea64_eviction_lock);
1023
1024
return (refchg);
1025
}
1026
1027