4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
29 #include <sys/modctl.h>
30 #include <vm/seg_kmem.h>
32 #include <sys/psm_modctl.h>
33 #include <sys/smp_impldefs.h>
34 #include <sys/reboot.h>
36 #include <sys/hypervisor.h>
37 #include <vm/kboot_mmu.h>
38 #include <vm/hat_pte.h>
42 * External reference functions
44 extern void *get_next_mach(void *, char *);
45 extern void close_mach_list(void);
46 extern void open_mach_list(void);
49 * from startup.c - kernel VA range allocator for device mappings
51 extern void *device_arena_alloc(size_t size
, int vm_flag
);
52 extern void device_arena_free(void * vaddr
, size_t size
);
54 void psm_modloadonly(void);
55 void psm_install(void);
58 * Local Function Prototypes
60 static struct modlinkage
*psm_modlinkage_alloc(struct psm_info
*infop
);
61 static void psm_modlinkage_free(struct modlinkage
*mlinkp
);
63 static char *psm_get_impl_module(int first
);
65 static int mod_installpsm(struct modlpsm
*modl
, struct modlinkage
*modlp
);
66 static int mod_removepsm(struct modlpsm
*modl
, struct modlinkage
*modlp
);
67 static int mod_infopsm(struct modlpsm
*modl
, struct modlinkage
*modlp
, int *p0
);
68 struct mod_ops mod_psmops
= {
69 mod_installpsm
, mod_removepsm
, mod_infopsm
72 static struct psm_sw psm_swtab
= {
73 &psm_swtab
, &psm_swtab
, NULL
, NULL
76 kmutex_t psmsw_lock
; /* lock accesses to psmsw */
77 struct psm_sw
*psmsw
= &psm_swtab
; /* start of all psm_sw */
79 static struct modlinkage
*
80 psm_modlinkage_alloc(struct psm_info
*infop
)
83 struct modlinkage
*mlinkp
;
84 struct modlpsm
*mlpsmp
;
87 memsz
= sizeof (struct modlinkage
) + sizeof (struct modlpsm
) +
88 sizeof (struct psm_sw
);
89 mlinkp
= (struct modlinkage
*)kmem_zalloc(memsz
, KM_NOSLEEP
);
91 cmn_err(CE_WARN
, "!psm_mod_init: Cannot install %s",
92 infop
->p_mach_idstring
);
95 mlpsmp
= (struct modlpsm
*)(mlinkp
+ 1);
96 swp
= (struct psm_sw
*)(mlpsmp
+ 1);
98 mlinkp
->ml_rev
= MODREV_1
;
99 mlinkp
->ml_linkage
[0] = (void *)mlpsmp
;
100 mlinkp
->ml_linkage
[1] = (void *)NULL
;
102 mlpsmp
->psm_modops
= &mod_psmops
;
103 mlpsmp
->psm_linkinfo
= infop
->p_mach_desc
;
104 mlpsmp
->psm_swp
= swp
;
106 swp
->psw_infop
= infop
;
112 psm_modlinkage_free(struct modlinkage
*mlinkp
)
117 (void) kmem_free(mlinkp
, (sizeof (struct modlinkage
) +
118 sizeof (struct modlpsm
) + sizeof (struct psm_sw
)));
122 psm_mod_init(void **handlepp
, struct psm_info
*infop
)
124 struct modlinkage
**modlpp
= (struct modlinkage
**)handlepp
;
126 struct modlinkage
*mlinkp
;
129 mlinkp
= psm_modlinkage_alloc(infop
);
135 status
= mod_install(mlinkp
);
137 psm_modlinkage_free(mlinkp
);
147 psm_mod_fini(void **handlepp
, struct psm_info
*infop
)
149 struct modlinkage
**modlpp
= (struct modlinkage
**)handlepp
;
152 status
= mod_remove(*modlpp
);
154 psm_modlinkage_free(*modlpp
);
161 psm_mod_info(void **handlepp
, struct psm_info
*infop
, struct modinfo
*modinfop
)
163 struct modlinkage
**modlpp
= (struct modlinkage
**)handlepp
;
165 struct modlinkage
*mlinkp
;
168 mlinkp
= psm_modlinkage_alloc(infop
);
174 status
= mod_info(mlinkp
, modinfop
);
177 psm_modlinkage_free(mlinkp
);
186 psm_add_intr(int lvl
, avfunc xxintr
, char *name
, int vect
, caddr_t arg
)
188 return (add_avintr((void *)NULL
, lvl
, xxintr
, name
, vect
,
189 arg
, NULL
, NULL
, NULL
));
193 psm_add_nmintr(int lvl
, avfunc xxintr
, char *name
, caddr_t arg
)
195 return (add_nmintr(lvl
, xxintr
, name
, arg
));
201 return (CPU
->cpu_id
);
205 psm_map_phys_new(paddr_t addr
, size_t len
, int prot
)
215 pgoffset
= addr
& MMU_PAGEOFFSET
;
218 * If we're dom0, we're starting from a MA. translate that to a PA
219 * XXPV - what about driver domains???
221 if (DOMAIN_IS_INITDOMAIN(xen_info
)) {
222 base
= pfn_to_pa(xen_assign_pfn(mmu_btop(addr
))) |
223 (addr
& MMU_PAGEOFFSET
);
230 npages
= mmu_btopr(len
+ pgoffset
);
231 cvaddr
= device_arena_alloc(ptob(npages
), VM_NOSLEEP
);
234 hat_devload(kas
.a_hat
, cvaddr
, mmu_ptob(npages
), mmu_btop(base
),
235 prot
, HAT_LOAD_LOCK
);
236 return (cvaddr
+ pgoffset
);
240 psm_unmap_phys(caddr_t addr
, size_t len
)
249 pgoffset
= (uintptr_t)addr
& MMU_PAGEOFFSET
;
250 base
= addr
- pgoffset
;
251 npages
= mmu_btopr(len
+ pgoffset
);
252 hat_unload(kas
.a_hat
, base
, ptob(npages
), HAT_UNLOAD_UNLOCK
);
253 device_arena_free(base
, ptob(npages
));
257 psm_map_new(paddr_t addr
, size_t len
, int prot
)
259 int phys_prot
= PROT_READ
;
261 ASSERT(prot
== (prot
& (PSM_PROT_WRITE
| PSM_PROT_READ
)));
262 if (prot
& PSM_PROT_WRITE
)
263 phys_prot
|= PROT_WRITE
;
265 return (psm_map_phys(addr
, len
, phys_prot
));
272 psm_map_phys(uint32_t addr
, size_t len
, int prot
)
274 return (psm_map_phys_new((paddr_t
)(addr
& 0xffffffff), len
, prot
));
278 psm_map(uint32_t addr
, size_t len
, int prot
)
280 return (psm_map_new((paddr_t
)(addr
& 0xffffffff), len
, prot
));
284 psm_unmap(caddr_t addr
, size_t len
)
293 pgoffset
= (uintptr_t)addr
& MMU_PAGEOFFSET
;
294 base
= addr
- pgoffset
;
295 npages
= mmu_btopr(len
+ pgoffset
);
296 hat_unload(kas
.a_hat
, base
, ptob(npages
), HAT_UNLOAD_UNLOCK
);
297 device_arena_free(base
, ptob(npages
));
302 mod_installpsm(struct modlpsm
*modl
, struct modlinkage
*modlp
)
307 mutex_enter(&psmsw_lock
);
308 psmsw
->psw_back
->psw_forw
= swp
;
309 swp
->psw_back
= psmsw
->psw_back
;
310 swp
->psw_forw
= psmsw
;
311 psmsw
->psw_back
= swp
;
312 swp
->psw_flag
|= PSM_MOD_INSTALL
;
313 mutex_exit(&psmsw_lock
);
319 mod_removepsm(struct modlpsm
*modl
, struct modlinkage
*modlp
)
324 mutex_enter(&psmsw_lock
);
325 if (swp
->psw_flag
& PSM_MOD_IDENTIFY
) {
326 mutex_exit(&psmsw_lock
);
329 if (!(swp
->psw_flag
& PSM_MOD_INSTALL
)) {
330 mutex_exit(&psmsw_lock
);
334 swp
->psw_back
->psw_forw
= swp
->psw_forw
;
335 swp
->psw_forw
->psw_back
= swp
->psw_back
;
336 mutex_exit(&psmsw_lock
);
342 mod_infopsm(struct modlpsm
*modl
, struct modlinkage
*modlp
, int *p0
)
344 *p0
= (int)modl
->psm_swp
->psw_infop
->p_owner
;
349 #define DEFAULT_PSM_MODULE "xpv_uppc"
351 #define DEFAULT_PSM_MODULE "uppc"
355 psm_get_impl_module(int first
)
357 static char **pnamep
;
358 static char *psm_impl_module_list
[] = {
362 static void *mhdl
= NULL
;
363 static char machname
[MAXNAMELEN
];
366 pnamep
= psm_impl_module_list
;
368 if (*pnamep
!= (char *)0)
371 mhdl
= get_next_mach(mhdl
, machname
);
382 mutex_init(&psmsw_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
385 for (this = psm_get_impl_module(1); this != (char *)NULL
;
386 this = psm_get_impl_module(0)) {
387 if (modload("mach", this) == -1)
388 cmn_err(CE_CONT
, "!Skipping psm: %s\n", this);
394 #define NOTSUP_MSG "This version of Solaris xVM does not support this hardware"
396 #define NOTSUP_MSG "This version of Solaris does not support this hardware"
402 struct psm_sw
*swp
, *cswp
;
403 struct psm_ops
*opsp
;
407 mutex_enter(&psmsw_lock
);
408 for (swp
= psmsw
->psw_forw
; swp
!= psmsw
; ) {
409 opsp
= swp
->psw_infop
->p_ops
;
410 if (opsp
->psm_probe
) {
411 if ((*opsp
->psm_probe
)() == PSM_SUCCESS
) {
413 swp
->psw_flag
|= PSM_MOD_IDENTIFY
;
418 /* remove the unsuccessful psm modules */
422 mutex_exit(&psmsw_lock
);
423 (void) strcpy(&machstring
[0], cswp
->psw_infop
->p_mach_idstring
);
424 err
= mod_remove_by_name(cswp
->psw_infop
->p_mach_idstring
);
426 cmn_err(CE_WARN
, "!%s: mod_remove_by_name failed %d",
427 &machstring
[0], err
);
428 mutex_enter(&psmsw_lock
);
430 mutex_exit(&psmsw_lock
);
437 * Return 1 if kernel debugger is present, and 0 if not.
442 return ((boothowto
& RB_DEBUG
) != 0);