1 /*        $NetBSD: wired_map.c,v 1.8 2023/09/21 09:31:50 msaitoh Exp $          */
2 
3 /*-
4  * Copyright (c) 2005 Tadpole Computer Inc.
5  * All rights reserved.
6  *
7  * Written by Garrett D'Amore for Tadpole Computer Inc.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. The name of Tadpole Computer Inc. may not be used to endorse
18  *    or promote products derived from this software without specific
19  *    prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY TADPOLE COMPUTER INC. ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL TADPOLE COMPUTER INC.
25  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  */
33 /*
34  * Copyright (C) 2000 Shuichiro URATA.  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. The name of the author may not be used to endorse or promote products
45  *    derived from this software without specific prior written permission.
46  *
47  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
48  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
49  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
50  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
51  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
52  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
53  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
54  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
55  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
56  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
57  */
58 
59 /*
60  * This code is derived from similar code in the ARC port of NetBSD, but
61  * it now bears little resemblence to it owing to quite different needs
62  * from the mapping logic.
63  */
64 
65 #include <sys/cdefs.h>
66 __KERNEL_RCSID(0, "$NetBSD: wired_map.c,v 1.8 2023/09/21 09:31:50 msaitoh Exp $");
67 
68 #define __PMAP_PRIVATE
69 
70 #include <sys/param.h>
71 #include <sys/systm.h>
72 #include <sys/cpu.h>
73 
74 #include <uvm/uvm_extern.h>
75 
76 #include <machine/pte.h>
77 #include <machine/vmparam.h>
78 #include <machine/wired_map.h>
79 
80 #include <mips/locore.h>
81 #include <mips/pte.h>
82 
83 struct wired_map_entry mips3_wired_map[MIPS3_NWIRED_ENTRY];
84 int mips3_nwired_page;
85 
86 /*
87  * Lower layer API, to supply an explicit page size.  It only wires a
88  * single page at a time.
89  */
90 bool
mips3_wired_enter_page(vaddr_t va,paddr_t pa,vsize_t pgsize)91 mips3_wired_enter_page(vaddr_t va, paddr_t pa, vsize_t pgsize)
92 {
93           struct tlbmask tlb;
94           vaddr_t va0;
95           int found, index;
96 
97           /* make sure entries are aligned */
98           KASSERT((va & (pgsize - 1)) == 0);
99           KASSERT((pa & (pgsize - 1)) == 0);
100 
101           /* TLB entries come in pairs: this is the first address of the pair */
102           va0 = va & ~MIPS3_WIRED_ENTRY_OFFMASK(pgsize);
103 
104           found = 0;
105           for (index = 0; index < mips3_nwired_page; index++) {
106                     if (mips3_wired_map[index].va == va0) {
107                               if ((va & pgsize) == 0) {
108                                         /* EntryLo0 */
109                                         mips3_wired_map[index].pa0 = pa;
110                               } else {
111                                         /* EntryLo1 */
112                                         mips3_wired_map[index].pa1 = pa;
113                               }
114                               found = 1;
115                               break;
116                     }
117           }
118 
119           if (found == 0) {
120                     /* we have to allocate a new wired entry */
121                     if (mips3_nwired_page >= MIPS3_NWIRED_ENTRY) {
122 #ifdef DIAGNOSTIC
123                               printf("mips3_wired_map: entries exhausted\n");
124 #endif
125                               return false;
126                     }
127 
128                     index = mips3_nwired_page;
129                     mips3_nwired_page++;
130                     if (va == va0) {
131                               /* EntryLo0 */
132                               mips3_wired_map[index].pa0 = pa;
133                               mips3_wired_map[index].pa1 = 0;
134                     } else {
135                               /* EntryLo1 */
136                               mips3_wired_map[index].pa0 = 0;
137                               mips3_wired_map[index].pa1 = pa;
138                     }
139                     mips3_wired_map[index].va = va0;
140                     mips3_wired_map[index].pgmask = MIPS3_PG_SIZE_TO_MASK(pgsize);
141 
142                     /* Allocate new wired entry */
143                     mips3_cp0_wired_write(MIPS3_TLB_WIRED_UPAGES +
144                         mips3_nwired_page + 1);
145           }
146 
147           /* map it */
148           tlb.tlb_mask = mips3_wired_map[index].pgmask;
149           tlb.tlb_hi = mips3_vad_to_vpn(va0);
150           if (mips3_wired_map[index].pa0 == 0)
151                     tlb.tlb_lo0 = MIPS3_PG_G;
152           else
153                     tlb.tlb_lo0 =
154                         mips3_paddr_to_tlbpfn(mips3_wired_map[index].pa0) |
155                         MIPS3_PG_IOPAGE(
156                                   PMAP_CCA_FOR_PA(mips3_wired_map[index].pa0));
157           if (mips3_wired_map[index].pa1 == 0)
158                     tlb.tlb_lo1 = MIPS3_PG_G;
159           else
160                     tlb.tlb_lo1 = mips3_paddr_to_tlbpfn(
161                               mips3_wired_map[index].pa1) |
162                         MIPS3_PG_IOPAGE(
163                                   PMAP_CCA_FOR_PA(mips3_wired_map[index].pa1));
164           tlb_write_entry(MIPS3_TLB_WIRED_UPAGES + index, &tlb);
165           return true;
166 }
167 
168 
169 /*
170  * Wire down a mapping from a virtual to physical address.  The size
171  * of the region must be a multiple of MIPS3_WIRED_SIZE, with
172  * matching alignment.
173  *
174  * Typically the caller will just pass a physaddr that is the same as
175  * the vaddr with bits 35-32 set nonzero.
176  */
177 bool
mips3_wired_enter_region(vaddr_t va,paddr_t pa,vsize_t size)178 mips3_wired_enter_region(vaddr_t va, paddr_t pa, vsize_t size)
179 {
180           vaddr_t   vend;
181           /*
182            * This routine allows for wired mappings to be set up,
183            * and handles previously defined mappings and mapping
184            * overlaps reasonably well.  However, caution should be used
185            * not to attempt to change the mapping for a page unless you
186            * are certain that you are the only user of the virtual
187            * address space, otherwise chaos may ensue.
188            */
189 
190           /* offsets within the page have to be identical */
191           KASSERT((va & MIPS3_WIRED_OFFMASK) == (pa & MIPS3_WIRED_OFFMASK));
192 
193           vend = va + size;
194           /* adjust for alignment */
195           va &= ~MIPS3_WIRED_OFFMASK;
196           pa &= ~MIPS3_WIRED_OFFMASK;
197 
198           while (va < vend) {
199                     if (!mips3_wired_enter_page(va, pa, MIPS3_WIRED_SIZE))
200                               return false;
201                     va += MIPS3_WIRED_SIZE;
202                     pa += MIPS3_WIRED_SIZE;
203           }
204           return true;
205 }
206