summaryrefslogtreecommitdiff
path: root/sys/arch/sparc/include/pmap.h
blob: 420ec11914215aa2859cc99680df63c54db9141f (plain)
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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
/*	$OpenBSD: pmap.h,v 1.22 2001/08/18 20:50:18 art Exp $	*/
/*	$NetBSD: pmap.h,v 1.30 1997/08/04 20:00:47 pk Exp $ */

/*
 * Copyright (c) 1996
 * 	The President and Fellows of Harvard College. All rights reserved.
 * Copyright (c) 1992, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * This software was developed by the Computer Systems Engineering group
 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
 * contributed to Berkeley.
 *
 * All advertising materials mentioning features or use of this software
 * must display the following acknowledgement:
 *	This product includes software developed by Aaron Brown and
 *	Harvard University.
 *	This product includes software developed by the University of
 *	California, Lawrence Berkeley Laboratory.
 *
 * @InsertRedistribution@
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by Aaron Brown and
 *	Harvard University.
 *	This product includes software developed by the University of
 *	California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *	@(#)pmap.h	8.1 (Berkeley) 6/11/93
 */

#ifndef	_SPARC_PMAP_H_
#define _SPARC_PMAP_H_

#include <machine/pte.h>

/*
 * Pmap structure.
 *
 * The pmap structure really comes in two variants, one---a single
 * instance---for kernel virtual memory and the other---up to nproc
 * instances---for user virtual memory.  Unfortunately, we have to mash
 * both into the same structure.  Fortunately, they are almost the same.
 *
 * The kernel begins at 0xf8000000 and runs to 0xffffffff (although
 * some of this is not actually used).  Kernel space, including DVMA
 * space (for now?), is mapped identically into all user contexts.
 * There is no point in duplicating this mapping in each user process
 * so they do not appear in the user structures.
 *
 * User space begins at 0x00000000 and runs through 0x1fffffff,
 * then has a `hole', then resumes at 0xe0000000 and runs until it
 * hits the kernel space at 0xf8000000.  This can be mapped
 * contiguously by ignorning the top two bits and pretending the
 * space goes from 0 to 37ffffff.  Typically the lower range is
 * used for text+data and the upper for stack, but the code here
 * makes no such distinction.
 *
 * Since each virtual segment covers 256 kbytes, the user space
 * requires 3584 segments, while the kernel (including DVMA) requires
 * only 512 segments.
 *
 *
 ** FOR THE SUN4/SUN4C
 *
 * The segment map entry for virtual segment vseg is offset in
 * pmap->pm_rsegmap by 0 if pmap is not the kernel pmap, or by
 * NUSEG if it is.  We keep a pointer called pmap->pm_segmap
 * pre-offset by this value.  pmap->pm_segmap thus contains the
 * values to be loaded into the user portion of the hardware segment
 * map so as to reach the proper PMEGs within the MMU.  The kernel
 * mappings are `set early' and are always valid in every context
 * (every change is always propagated immediately).
 *
 * The PMEGs within the MMU are loaded `on demand'; when a PMEG is
 * taken away from context `c', the pmap for context c has its
 * corresponding pm_segmap[vseg] entry marked invalid (the MMU segment
 * map entry is also made invalid at the same time).  Thus
 * pm_segmap[vseg] is the `invalid pmeg' number (127 or 511) whenever
 * the corresponding PTEs are not actually in the MMU.  On the other
 * hand, pm_pte[vseg] is NULL only if no pages in that virtual segment
 * are in core; otherwise it points to a copy of the 32 or 64 PTEs that
 * must be loaded in the MMU in order to reach those pages.
 * pm_npte[vseg] counts the number of valid pages in each vseg.
 *
 * XXX performance: faster to count valid bits?
 *
 * The kernel pmap cannot malloc() PTEs since malloc() will sometimes
 * allocate a new virtual segment.  Since kernel mappings are never
 * `stolen' out of the the MMU, we just keep all its PTEs there, and
 * have no software copies.  Its mmu entries are nonetheless kept on lists
 * so that the code that fiddles with mmu lists has something to fiddle.
 *
 ** FOR THE SUN4M
 *
 * On this architecture, the virtual-to-physical translation (page) tables
 * are *not* stored within the MMU as they are in the earlier Sun architect-
 * ures; instead, they are maintained entirely within physical memory (there
 * is a TLB cache to prevent the high performance hit from keeping all page
 * tables in core). Thus there is no need to dynamically allocate PMEGs or
 * SMEGs; only contexts must be shared.
 *
 * We maintain two parallel sets of tables: one is the actual MMU-edible
 * hierarchy of page tables in allocated kernel memory; these tables refer
 * to each other by physical address pointers in SRMMU format (thus they
 * are not very useful to the kernel's management routines). The other set
 * of tables is similar to those used for the Sun4/100's 3-level MMU; it
 * is a hierarchy of regmap and segmap structures which contain kernel virtual
 * pointers to each other. These must (unfortunately) be kept in sync.
 *
 */
#define NKREG	((int)((-(unsigned)KERNBASE) / NBPRG))	/* i.e., 8 */
#define NUREG	(256 - NKREG)				/* i.e., 248 */

TAILQ_HEAD(mmuhd,mmuentry);

/*
 * data appearing in both user and kernel pmaps
 *
 * note: if we want the same binaries to work on the 4/4c and 4m, we have to
 *       include the fields for both to make sure that the struct kproc
 * 	 is the same size.
 */
struct pmap {
	union	ctxinfo *pm_ctx;	/* current context, if any */
	int	pm_ctxnum;		/* current context's number */
	struct simplelock pm_lock;	/* spinlock */
	int	pm_refcount;		/* just what it says */

	struct mmuhd	pm_reglist;	/* MMU regions on this pmap (4/4c) */
	struct mmuhd	pm_seglist;	/* MMU segments on this pmap (4/4c) */

	void		*pm_regstore;
	struct regmap	*pm_regmap;

	int		*pm_reg_ptps;	/* SRMMU-edible region table for 4m */
	int		pm_reg_ptps_pa;	/* _Physical_ address of pm_reg_ptps */

	int		pm_gap_start;	/* Starting with this vreg there's */
	int		pm_gap_end;	/* no valid mapping until here */

	struct pmap_statistics	pm_stats;	/* pmap statistics */
};

struct regmap {
	struct segmap	*rg_segmap;	/* point to NSGPRG PMEGs */
	int		*rg_seg_ptps; 	/* SRMMU-edible segment tables (NULL
					 * indicates invalid region (4m) */
	smeg_t		rg_smeg;	/* the MMU region number (4c) */
	u_char		rg_nsegmap;	/* number of valid PMEGS */
};

struct segmap {
	int	*sg_pte;		/* points to NPTESG PTEs */
	pmeg_t	sg_pmeg;		/* the MMU segment number (4c) */
	u_char	sg_npte;		/* number of valid PTEs per seg */
};

typedef struct pmap *pmap_t;

/*
 * For each managed physical page, there is a list of all currently
 * valid virtual mappings of that page.  Since there is usually one
 * (or zero) mapping per page, the table begins with an initial entry,
 * rather than a pointer; this head entry is empty iff its pv_pmap
 * field is NULL.
 *
 * Note that these are per machine independent page (so there may be
 * only one for every two hardware pages, e.g.).  Since the virtual
 * address is aligned on a page boundary, the low order bits are free
 * for storing flags.  Only the head of each list has flags.
 *
 * THIS SHOULD BE PART OF THE CORE MAP
 */
struct pvlist {
	struct		pvlist *pv_next;	/* next pvlist, if any */
	struct		pmap *pv_pmap;		/* pmap of this va */
	vaddr_t		pv_va;			/* virtual address */
	int		pv_flags;		/* flags (below) */
};

/*
 * Flags in pv_flags.  Note that PV_MOD must be 1 and PV_REF must be 2
 * since they must line up with the bits in the hardware PTEs (see pte.h).
 * SUN4M bits are at a slightly different location in the PTE.
 * Note: the REF, MOD and ANC flag bits occur only in the head of a pvlist.
 * The cacheable bit (either PV_NC or PV_C4M) is meaningful in each
 * individual pv entry.
 */
#define PV_MOD		1	/* page modified */
#define PV_REF		2	/* page referenced */
#define PV_NC		4	/* page cannot be cached */
#define PV_REF4M	1	/* page referenced (SRMMU) */
#define PV_MOD4M	2	/* page modified (SRMMU) */
#define PV_C4M		4	/* page _can_ be cached (SRMMU) */
#define PV_ANC		0x10	/* page has incongruent aliases */

#if 0
struct kvm_cpustate {
	int		kvm_npmemarr;
	struct memarr	kvm_pmemarr[MA_SIZE];
	int		kvm_seginval;			/* [4,4c] */
	struct segmap	kvm_segmap_store[NKREG*NSEGRG];	/* [4,4c] */
}/*not yet used*/;
#endif

#ifdef _KERNEL

#define PMAP_NULL	((pmap_t)0)

extern struct pmap	kernel_pmap_store;

/*
 * Since PTEs also contain type bits, we have to have some way
 * to tell pmap_enter `this is an IO page' or `this is not to
 * be cached'.  Since physical addresses are always aligned, we
 * can do this with the low order bits.
 *
 * The ordering below is important: PMAP_PGTYPE << PG_TNC must give
 * exactly the PG_NC and PG_TYPE bits.
 */
#define	PMAP_OBIO	1		/* tells pmap_enter to use PG_OBIO */
#define	PMAP_VME16	2		/* etc */
#define	PMAP_VME32	3		/* etc */
#define	PMAP_NC		4		/* tells pmap_enter to set PG_NC */
#define	PMAP_TNC_4	7		/* mask to get PG_TYPE & PG_NC */

#define PMAP_T2PTE_4(x)		(((x) & PMAP_TNC_4) << PG_TNC_SHIFT)
#define PMAP_IOENC_4(io)	(io)

/*
 * On a SRMMU machine, the iospace is encoded in bits [3-6] of the
 * physical address passed to pmap_enter().
 */
#define PMAP_TYPE_SRMMU		0x78	/* mask to get 4m page type */
#define PMAP_PTESHFT_SRMMU	25	/* right shift to put type in pte */
#define PMAP_SHFT_SRMMU		3	/* left shift to extract iospace */
#define	PMAP_TNC_SRMMU		127	/* mask to get PG_TYPE & PG_NC */

/*#define PMAP_IOC      0x00800000      -* IO cacheable, NOT shifted */

#define PMAP_T2PTE_SRMMU(x)	(((x) & PMAP_TYPE_SRMMU) << PMAP_PTESHFT_SRMMU)
#define PMAP_IOENC_SRMMU(io)	((io) << PMAP_SHFT_SRMMU)

/* Encode IO space for pmap_enter() */
#define PMAP_IOENC(io)	(CPU_ISSUN4M ? PMAP_IOENC_SRMMU(io) : PMAP_IOENC_4(io))

int             pmap_dumpsize __P((void));
int             pmap_dumpmmu __P((int (*)__P((dev_t, daddr_t, caddr_t, size_t)),
                                 daddr_t));

#define	pmap_kernel()	(&kernel_pmap_store)
#define	pmap_resident_count(pmap)	pmap_count_ptes(pmap)

#define PMAP_ACTIVATE(pmap, pcb, iscurproc)
#define PMAP_DEACTIVATE(pmap, pcb)
#define PMAP_PREFER(fo, ap)		pmap_prefer((fo), (ap))

#define PMAP_EXCLUDE_DECLS	/* tells MI pmap.h *not* to include decls */

/* FUNCTION DECLARATIONS FOR COMMON PMAP MODULE */

struct proc;
void		pmap_bootstrap __P((int nmmu, int nctx, int nregion));
int		pmap_count_ptes __P((struct pmap *));
void		pmap_prefer __P((vaddr_t, vaddr_t *));
int		pmap_pa_exists __P((paddr_t));
void		*pmap_bootstrap_alloc __P((int));
void		pmap_unwire __P((pmap_t, vaddr_t));
void		pmap_collect __P((pmap_t));
void		pmap_copy __P((pmap_t, pmap_t, vaddr_t, vsize_t, vaddr_t));
pmap_t		pmap_create __P((void));
void		pmap_destroy __P((pmap_t));
void		pmap_init __P((void));
vaddr_t		pmap_map __P((vaddr_t, paddr_t, paddr_t, int));
vaddr_t		pmap_phys_address __P((int));
void		pmap_pinit __P((pmap_t));
void		pmap_reference __P((pmap_t));
void		pmap_release __P((pmap_t));
void		pmap_remove __P((pmap_t, vaddr_t, vaddr_t));
void		pmap_update __P((void));
void		pmap_init __P((void));
int		pmap_page_index __P((paddr_t));
void		pmap_virtual_space __P((vaddr_t *, vaddr_t *));
void		pmap_redzone __P((void));
void		kvm_setcache __P((caddr_t, int, int));
#define		kvm_uncache(addr, npages) kvm_setcache(addr, npages, 0)
#define		kvm_recache(addr, npages) kvm_setcache(addr, npages, 1)
void		pmap_cache_enable __P((void));
struct user;
void		switchexit __P((struct proc *));
int		mmu_pagein __P((struct pmap *pm, vaddr_t, int));
void		pmap_writetext __P((unsigned char *, int));

/* SUN4/SUN4C SPECIFIC DECLARATIONS */

#if defined(SUN4) || defined(SUN4C)
boolean_t	pmap_clear_modify4_4c __P((struct vm_page *));
boolean_t	pmap_clear_reference4_4c __P((struct vm_page *));
void		pmap_copy_page4_4c __P((paddr_t, paddr_t));
int		pmap_enter4_4c __P((pmap_t, vaddr_t, paddr_t, vm_prot_t, int));
boolean_t	pmap_extract4_4c __P((pmap_t, vaddr_t, paddr_t *));
boolean_t	pmap_is_modified4_4c __P((struct vm_page *));
boolean_t	pmap_is_referenced4_4c __P((struct vm_page *));
void		pmap_kenter_pa4_4c __P((vaddr_t, paddr_t, vm_prot_t));
void		pmap_kenter_pgs4_4c __P((vaddr_t, struct vm_page **, int));
void		pmap_kremove4_4c __P((vaddr_t, vsize_t));
void		pmap_page_protect4_4c __P((struct vm_page *, vm_prot_t));
void		pmap_protect4_4c __P((pmap_t, vaddr_t, vaddr_t, vm_prot_t));
void		pmap_zero_page4_4c __P((paddr_t));
void		pmap_changeprot4_4c __P((pmap_t, vaddr_t, vm_prot_t, int));
#endif

/* SIMILAR DECLARATIONS FOR SUN4M MODULE */

#if defined(SUN4M)
boolean_t	pmap_clear_modify4m __P((struct vm_page *));
boolean_t	pmap_clear_reference4m __P((struct vm_page *));
void		pmap_copy_page4m __P((paddr_t, paddr_t));
int		pmap_enter4m __P((pmap_t, vaddr_t, paddr_t, vm_prot_t, int));
boolean_t	pmap_extract4m __P((pmap_t, vaddr_t, paddr_t *));
boolean_t	pmap_is_modified4m __P((struct vm_page *));
boolean_t	pmap_is_referenced4m __P((struct vm_page *));
void		pmap_kenter_pa4m __P((vaddr_t, paddr_t, vm_prot_t));
void		pmap_kenter_pgs4m __P((vaddr_t, struct vm_page **, int));
void		pmap_kremove4m __P((vaddr_t, vsize_t));
void		pmap_page_protect4m __P((struct vm_page *, vm_prot_t));
void		pmap_protect4m __P((pmap_t, vaddr_t, vaddr_t, vm_prot_t));
void		pmap_zero_page4m __P((paddr_t));
void		pmap_changeprot4m __P((pmap_t, vaddr_t, vm_prot_t, int));
#endif /* defined SUN4M */

#if !defined(SUN4M) && (defined(SUN4) || defined(SUN4C))

#define		pmap_clear_modify	pmap_clear_modify4_4c
#define		pmap_clear_reference	pmap_clear_reference4_4c
#define		pmap_copy_page		pmap_copy_page4_4c
#define		pmap_enter		pmap_enter4_4c
#define		pmap_extract		pmap_extract4_4c
#define		pmap_is_modified	pmap_is_modified4_4c
#define		pmap_is_referenced	pmap_is_referenced4_4c
#define		pmap_kenter_pa		pmap_kenter_pa4_4c
#define		pmap_kenter_pgs		pmap_kenter_pgs4_4c
#define		pmap_kremove		pmap_kremove4_4c
#define		pmap_page_protect	pmap_page_protect4_4c
#define		pmap_protect		pmap_protect4_4c
#define		pmap_zero_page		pmap_zero_page4_4c
#define		pmap_changeprot		pmap_changeprot4_4c

#elif defined(SUN4M) && !(defined(SUN4) || defined(SUN4C))

#define	  	pmap_clear_modify	pmap_clear_modify4m
#define		pmap_clear_reference	pmap_clear_reference4m
#define		pmap_copy_page		pmap_copy_page4m
#define		pmap_enter		pmap_enter4m
#define		pmap_extract		pmap_extract4m
#define		pmap_is_modified	pmap_is_modified4m
#define		pmap_is_referenced	pmap_is_referenced4m
#define		pmap_kenter_pa		pmap_kenter_pa4m
#define		pmap_kenter_pgs		pmap_kenter_pgs4m
#define		pmap_kremove		pmap_kremove4m
#define		pmap_page_protect	pmap_page_protect4m
#define		pmap_protect		pmap_protect4m
#define		pmap_zero_page		pmap_zero_page4m
#define		pmap_changeprot		pmap_changeprot4m

#else  /* must use function pointers */

extern boolean_t	(*pmap_clear_modify_p) __P((struct vm_page *));
extern boolean_t	(*pmap_clear_reference_p) __P((struct vm_page *));
extern void		(*pmap_copy_page_p) __P((paddr_t, paddr_t));
extern int		(*pmap_enter_p) __P((pmap_t, vaddr_t, paddr_t,
					     vm_prot_t, int));
extern boolean_t	(*pmap_extract_p) __P((pmap_t, vaddr_t, paddr_t *));
extern boolean_t	(*pmap_is_modified_p) __P((struct vm_page *));
extern boolean_t	(*pmap_is_referenced_p) __P((struct vm_page *));
extern void		(*pmap_kenter_pa_p) __P((vaddr_t, paddr_t, vm_prot_t));
extern void		(*pmap_kenter_pgs_p) __P((vaddr_t, struct vm_page **,
						  int));
extern void		(*pmap_kremove_p) __P((vaddr_t, vsize_t));
extern void		(*pmap_page_protect_p) __P((struct vm_page *, 
						    vm_prot_t));
extern void		(*pmap_protect_p) __P((pmap_t, vaddr_t, vaddr_t,
					       vm_prot_t));
extern void		(*pmap_zero_page_p) __P((paddr_t));
extern void		(*pmap_changeprot_p) __P((pmap_t, vaddr_t,
						  vm_prot_t, int));

#define		pmap_clear_modify	(*pmap_clear_modify_p)
#define		pmap_clear_reference	(*pmap_clear_reference_p)
#define		pmap_copy_page		(*pmap_copy_page_p)
#define		pmap_enter		(*pmap_enter_p)
#define		pmap_extract		(*pmap_extract_p)
#define		pmap_is_modified	(*pmap_is_modified_p)
#define		pmap_is_referenced	(*pmap_is_referenced_p)
#define		pmap_kenter_pa		(*pmap_kenter_pa_p)
#define		pmap_kenter_pgs		(*pmap_kenter_pgs_p)
#define		pmap_kremove		(*pmap_kremove_p)
#define		pmap_page_protect	(*pmap_page_protect_p)
#define		pmap_protect		(*pmap_protect_p)
#define		pmap_zero_page		(*pmap_zero_page_p)
#define		pmap_changeprot		(*pmap_changeprot_p)

#endif

#endif /* _KERNEL */

#endif /* _SPARC_PMAP_H_ */