mmu_ps3.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. /*-
  2. * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
  3. *
  4. * Copyright (C) 2010 Nathan Whitehorn
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. * 1. Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. * 2. Redistributions in binary form must reproduce the above copyright
  13. * notice, this list of conditions and the following disclaimer in the
  14. * documentation and/or other materials provided with the distribution.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  17. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  18. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  19. * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  20. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  21. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  22. * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  23. * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  24. * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  25. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. #include <sys/cdefs.h>
  28. __FBSDID("$FreeBSD$");
  29. #include <sys/param.h>
  30. #include <sys/kernel.h>
  31. #include <sys/ktr.h>
  32. #include <sys/lock.h>
  33. #include <sys/msgbuf.h>
  34. #include <sys/mutex.h>
  35. #include <sys/proc.h>
  36. #include <sys/sysctl.h>
  37. #include <sys/systm.h>
  38. #include <sys/vmmeter.h>
  39. #include <vm/vm.h>
  40. #include <vm/vm_param.h>
  41. #include <vm/vm_kern.h>
  42. #include <vm/vm_page.h>
  43. #include <vm/vm_map.h>
  44. #include <vm/vm_object.h>
  45. #include <vm/vm_extern.h>
  46. #include <vm/vm_pageout.h>
  47. #include <vm/uma.h>
  48. #include <powerpc/aim/mmu_oea64.h>
  49. #include "ps3-hvcall.h"
  50. #define VSID_HASH_MASK 0x0000007fffffffffUL
  51. #define PTESYNC() __asm __volatile("ptesync")
  52. extern int ps3fb_remap(void);
  53. static uint64_t mps3_vas_id;
  54. /*
  55. * Kernel MMU interface
  56. */
  57. static void mps3_install(void);
  58. static void mps3_bootstrap(vm_offset_t kernelstart,
  59. vm_offset_t kernelend);
  60. static void mps3_cpu_bootstrap(int ap);
  61. static int64_t mps3_pte_synch(struct pvo_entry *);
  62. static int64_t mps3_pte_clear(struct pvo_entry *, uint64_t ptebit);
  63. static int64_t mps3_pte_unset(struct pvo_entry *);
  64. static int64_t mps3_pte_insert(struct pvo_entry *);
  65. static struct pmap_funcs mps3_methods = {
  66. .install = mps3_install,
  67. .bootstrap = mps3_bootstrap,
  68. .cpu_bootstrap = mps3_cpu_bootstrap,
  69. };
  70. static struct moea64_funcs mps3_funcs = {
  71. .pte_synch = mps3_pte_synch,
  72. .pte_clear = mps3_pte_clear,
  73. .pte_unset = mps3_pte_unset,
  74. .pte_insert = mps3_pte_insert,
  75. };
  76. MMU_DEF_INHERIT(ps3_mmu, "mmu_ps3", mps3_methods, oea64_mmu);
  77. static struct mtx mps3_table_lock;
  78. static void
  79. mps3_install()
  80. {
  81. moea64_ops = &mps3_funcs;
  82. }
  83. static void
  84. mps3_bootstrap(vm_offset_t kernelstart, vm_offset_t kernelend)
  85. {
  86. uint64_t final_pteg_count;
  87. mtx_init(&mps3_table_lock, "page table", NULL, MTX_DEF);
  88. moea64_early_bootstrap(kernelstart, kernelend);
  89. /* In case we had a page table already */
  90. lv1_destruct_virtual_address_space(0);
  91. /* Allocate new hardware page table */
  92. lv1_construct_virtual_address_space(
  93. 20 /* log_2(moea64_pteg_count) */, 2 /* n page sizes */,
  94. (24UL << 56) | (16UL << 48) /* page sizes 16 MB + 64 KB */,
  95. &mps3_vas_id, &final_pteg_count
  96. );
  97. lv1_select_virtual_address_space(mps3_vas_id);
  98. moea64_pteg_count = final_pteg_count / sizeof(struct lpteg);
  99. moea64_mid_bootstrap(kernelstart, kernelend);
  100. moea64_late_bootstrap(kernelstart, kernelend);
  101. }
  102. static void
  103. mps3_cpu_bootstrap(int ap)
  104. {
  105. struct slb *slb = PCPU_GET(aim.slb);
  106. register_t seg0;
  107. int i;
  108. mtmsr(mfmsr() & ~PSL_DR & ~PSL_IR);
  109. /*
  110. * Select the page table we configured above and set up the FB mapping
  111. * so we can have a console.
  112. */
  113. lv1_select_virtual_address_space(mps3_vas_id);
  114. if (!ap)
  115. ps3fb_remap();
  116. /*
  117. * Install kernel SLB entries
  118. */
  119. __asm __volatile ("slbia");
  120. __asm __volatile ("slbmfee %0,%1; slbie %0;" : "=r"(seg0) : "r"(0));
  121. for (i = 0; i < 64; i++) {
  122. if (!(slb[i].slbe & SLBE_VALID))
  123. continue;
  124. __asm __volatile ("slbmte %0, %1" ::
  125. "r"(slb[i].slbv), "r"(slb[i].slbe));
  126. }
  127. }
  128. static int64_t
  129. mps3_pte_synch_locked(struct pvo_entry *pvo)
  130. {
  131. uint64_t halfbucket[4], rcbits;
  132. PTESYNC();
  133. lv1_read_htab_entries(mps3_vas_id, pvo->pvo_pte.slot & ~0x3UL,
  134. &halfbucket[0], &halfbucket[1], &halfbucket[2], &halfbucket[3],
  135. &rcbits);
  136. /* Check if present in page table */
  137. if ((halfbucket[pvo->pvo_pte.slot & 0x3] & LPTE_AVPN_MASK) !=
  138. ((pvo->pvo_vpn >> (ADDR_API_SHFT64 - ADDR_PIDX_SHFT)) &
  139. LPTE_AVPN_MASK))
  140. return (-1);
  141. if (!(halfbucket[pvo->pvo_pte.slot & 0x3] & LPTE_VALID))
  142. return (-1);
  143. /*
  144. * rcbits contains the low 12 bits of each PTE's 2nd part,
  145. * spaced at 16-bit intervals
  146. */
  147. return ((rcbits >> ((3 - (pvo->pvo_pte.slot & 0x3))*16)) &
  148. (LPTE_CHG | LPTE_REF));
  149. }
  150. static int64_t
  151. mps3_pte_synch(struct pvo_entry *pvo)
  152. {
  153. int64_t retval;
  154. mtx_lock(&mps3_table_lock);
  155. retval = mps3_pte_synch_locked(pvo);
  156. mtx_unlock(&mps3_table_lock);
  157. return (retval);
  158. }
  159. static int64_t
  160. mps3_pte_clear(struct pvo_entry *pvo, uint64_t ptebit)
  161. {
  162. int64_t refchg;
  163. struct lpte pte;
  164. mtx_lock(&mps3_table_lock);
  165. refchg = mps3_pte_synch_locked(pvo);
  166. if (refchg < 0) {
  167. mtx_unlock(&mps3_table_lock);
  168. return (refchg);
  169. }
  170. moea64_pte_from_pvo(pvo, &pte);
  171. pte.pte_lo |= refchg;
  172. pte.pte_lo &= ~ptebit;
  173. /* XXX: race on RC bits between write and sync. Anything to do? */
  174. lv1_write_htab_entry(mps3_vas_id, pvo->pvo_pte.slot, pte.pte_hi,
  175. pte.pte_lo);
  176. mtx_unlock(&mps3_table_lock);
  177. return (refchg);
  178. }
  179. static int64_t
  180. mps3_pte_unset(struct pvo_entry *pvo)
  181. {
  182. int64_t refchg;
  183. mtx_lock(&mps3_table_lock);
  184. refchg = mps3_pte_synch_locked(pvo);
  185. if (refchg < 0) {
  186. STAT_MOEA64(moea64_pte_overflow--);
  187. mtx_unlock(&mps3_table_lock);
  188. return (-1);
  189. }
  190. /* XXX: race on RC bits between unset and sync. Anything to do? */
  191. lv1_write_htab_entry(mps3_vas_id, pvo->pvo_pte.slot, 0, 0);
  192. mtx_unlock(&mps3_table_lock);
  193. STAT_MOEA64(moea64_pte_valid--);
  194. return (refchg & (LPTE_REF | LPTE_CHG));
  195. }
  196. static int64_t
  197. mps3_pte_insert(struct pvo_entry *pvo)
  198. {
  199. int result;
  200. struct lpte pte, evicted;
  201. uint64_t index;
  202. if (pvo->pvo_vaddr & PVO_HID) {
  203. /* Hypercall needs primary PTEG */
  204. pvo->pvo_vaddr &= ~PVO_HID;
  205. pvo->pvo_pte.slot ^= (moea64_pteg_mask << 3);
  206. }
  207. pvo->pvo_pte.slot &= ~7UL;
  208. moea64_pte_from_pvo(pvo, &pte);
  209. evicted.pte_hi = 0;
  210. PTESYNC();
  211. mtx_lock(&mps3_table_lock);
  212. result = lv1_insert_htab_entry(mps3_vas_id, pvo->pvo_pte.slot,
  213. pte.pte_hi, pte.pte_lo, LPTE_LOCKED | LPTE_WIRED, 0,
  214. &index, &evicted.pte_hi, &evicted.pte_lo);
  215. mtx_unlock(&mps3_table_lock);
  216. if (result != 0) {
  217. /* No freeable slots in either PTEG? We're hosed. */
  218. panic("mps3_pte_insert: overflow (%d)", result);
  219. return (-1);
  220. }
  221. /*
  222. * See where we ended up.
  223. */
  224. if ((index & ~7UL) != pvo->pvo_pte.slot)
  225. pvo->pvo_vaddr |= PVO_HID;
  226. pvo->pvo_pte.slot = index;
  227. STAT_MOEA64(moea64_pte_valid++);
  228. if (evicted.pte_hi) {
  229. KASSERT((evicted.pte_hi & (LPTE_WIRED | LPTE_LOCKED)) == 0,
  230. ("Evicted a wired PTE"));
  231. STAT_MOEA64(moea64_pte_valid--);
  232. STAT_MOEA64(moea64_pte_overflow++);
  233. }
  234. return (0);
  235. }