Changeset View
Changeset View
Standalone View
Standalone View
sys/amd64/amd64/sys_machdep.c
Show First 20 Lines • Show All 59 Lines • ▼ Show 20 Lines | |||||
#include <machine/pcb.h> | #include <machine/pcb.h> | ||||
#include <machine/specialreg.h> | #include <machine/specialreg.h> | ||||
#include <machine/sysarch.h> | #include <machine/sysarch.h> | ||||
#include <machine/tss.h> | #include <machine/tss.h> | ||||
#include <machine/vmparam.h> | #include <machine/vmparam.h> | ||||
#include <security/audit/audit.h> | #include <security/audit/audit.h> | ||||
static void user_ldt_deref(struct proc_ldt *pldt); | |||||
static void user_ldt_derefl(struct proc_ldt *pldt); | |||||
#define MAX_LD 8192 | #define MAX_LD 8192 | ||||
int max_ldt_segment = 512; | int max_ldt_segment = 512; | ||||
SYSCTL_INT(_machdep, OID_AUTO, max_ldt_segment, CTLFLAG_RDTUN, | SYSCTL_INT(_machdep, OID_AUTO, max_ldt_segment, CTLFLAG_RDTUN, | ||||
&max_ldt_segment, 0, | &max_ldt_segment, 0, | ||||
"Maximum number of allowed LDT segments in the single address space"); | "Maximum number of allowed LDT segments in the single address space"); | ||||
static void | static void | ||||
max_ldt_segment_init(void *arg __unused) | max_ldt_segment_init(void *arg __unused) | ||||
{ | { | ||||
if (max_ldt_segment <= 0) | if (max_ldt_segment <= 0) | ||||
max_ldt_segment = 1; | max_ldt_segment = 1; | ||||
if (max_ldt_segment > MAX_LD) | if (max_ldt_segment > MAX_LD) | ||||
max_ldt_segment = MAX_LD; | max_ldt_segment = MAX_LD; | ||||
} | } | ||||
SYSINIT(maxldt, SI_SUB_VM_CONF, SI_ORDER_ANY, max_ldt_segment_init, NULL); | SYSINIT(maxldt, SI_SUB_VM_CONF, SI_ORDER_ANY, max_ldt_segment_init, NULL); | ||||
static void user_ldt_derefl(struct proc_ldt *pldt); | |||||
#ifndef _SYS_SYSPROTO_H_ | #ifndef _SYS_SYSPROTO_H_ | ||||
struct sysarch_args { | struct sysarch_args { | ||||
int op; | int op; | ||||
char *parms; | char *parms; | ||||
}; | }; | ||||
#endif | #endif | ||||
int | int | ||||
▲ Show 20 Lines • Show All 260 Lines • ▼ Show 20 Lines | amd64_set_ioperm(td, uap) | ||||
* XXX | * XXX | ||||
* While this is restricted to root, we should probably figure out | * While this is restricted to root, we should probably figure out | ||||
* whether any other driver is using this i/o address, as so not to | * whether any other driver is using this i/o address, as so not to | ||||
* cause confusion. This probably requires a global 'usage registry'. | * cause confusion. This probably requires a global 'usage registry'. | ||||
*/ | */ | ||||
pcb = td->td_pcb; | pcb = td->td_pcb; | ||||
if (pcb->pcb_tssp == NULL) { | if (pcb->pcb_tssp == NULL) { | ||||
tssp = (struct amd64tss *)kmem_malloc(kernel_arena, | tssp = (struct amd64tss *)kmem_malloc(kernel_arena, | ||||
ctob(IOPAGES+1), M_WAITOK); | ctob(IOPAGES + 1), M_WAITOK); | ||||
pmap_pti_add_kva((vm_offset_t)tssp, (vm_offset_t)tssp + | |||||
ctob(IOPAGES + 1), false); | |||||
iomap = (char *)&tssp[1]; | iomap = (char *)&tssp[1]; | ||||
memset(iomap, 0xff, IOPERM_BITMAP_SIZE); | memset(iomap, 0xff, IOPERM_BITMAP_SIZE); | ||||
critical_enter(); | critical_enter(); | ||||
/* Takes care of tss_rsp0. */ | /* Takes care of tss_rsp0. */ | ||||
memcpy(tssp, &common_tss[PCPU_GET(cpuid)], | memcpy(tssp, &common_tss[PCPU_GET(cpuid)], | ||||
sizeof(struct amd64tss)); | sizeof(struct amd64tss)); | ||||
tssp->tss_iobase = sizeof(*tssp); | tssp->tss_iobase = sizeof(*tssp); | ||||
pcb->pcb_tssp = tssp; | pcb->pcb_tssp = tssp; | ||||
▲ Show 20 Lines • Show All 72 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
struct proc_ldt * | struct proc_ldt * | ||||
user_ldt_alloc(struct proc *p, int force) | user_ldt_alloc(struct proc *p, int force) | ||||
{ | { | ||||
struct proc_ldt *pldt, *new_ldt; | struct proc_ldt *pldt, *new_ldt; | ||||
struct mdproc *mdp; | struct mdproc *mdp; | ||||
struct soft_segment_descriptor sldt; | struct soft_segment_descriptor sldt; | ||||
vm_offset_t sva; | |||||
vm_size_t sz; | |||||
mtx_assert(&dt_lock, MA_OWNED); | mtx_assert(&dt_lock, MA_OWNED); | ||||
mdp = &p->p_md; | mdp = &p->p_md; | ||||
if (!force && mdp->md_ldt != NULL) | if (!force && mdp->md_ldt != NULL) | ||||
return (mdp->md_ldt); | return (mdp->md_ldt); | ||||
mtx_unlock(&dt_lock); | mtx_unlock(&dt_lock); | ||||
new_ldt = malloc(sizeof(struct proc_ldt), M_SUBPROC, M_WAITOK); | new_ldt = malloc(sizeof(struct proc_ldt), M_SUBPROC, M_WAITOK); | ||||
new_ldt->ldt_base = (caddr_t)kmem_malloc(kernel_arena, | sz = max_ldt_segment * sizeof(struct user_segment_descriptor); | ||||
max_ldt_segment * sizeof(struct user_segment_descriptor), | sva = kmem_malloc(kernel_arena, sz, M_WAITOK | M_ZERO); | ||||
M_WAITOK | M_ZERO); | new_ldt->ldt_base = (caddr_t)sva; | ||||
pmap_pti_add_kva(sva, sva + sz, false); | |||||
new_ldt->ldt_refcnt = 1; | new_ldt->ldt_refcnt = 1; | ||||
sldt.ssd_base = (uint64_t)new_ldt->ldt_base; | sldt.ssd_base = sva; | ||||
sldt.ssd_limit = max_ldt_segment * | sldt.ssd_limit = sz - 1; | ||||
sizeof(struct user_segment_descriptor) - 1; | |||||
sldt.ssd_type = SDT_SYSLDT; | sldt.ssd_type = SDT_SYSLDT; | ||||
sldt.ssd_dpl = SEL_KPL; | sldt.ssd_dpl = SEL_KPL; | ||||
sldt.ssd_p = 1; | sldt.ssd_p = 1; | ||||
sldt.ssd_long = 0; | sldt.ssd_long = 0; | ||||
sldt.ssd_def32 = 0; | sldt.ssd_def32 = 0; | ||||
sldt.ssd_gran = 0; | sldt.ssd_gran = 0; | ||||
mtx_lock(&dt_lock); | mtx_lock(&dt_lock); | ||||
pldt = mdp->md_ldt; | pldt = mdp->md_ldt; | ||||
if (pldt != NULL && !force) { | if (pldt != NULL && !force) { | ||||
kmem_free(kernel_arena, (vm_offset_t)new_ldt->ldt_base, | pmap_pti_remove_kva(sva, sva + sz); | ||||
max_ldt_segment * sizeof(struct user_segment_descriptor)); | kmem_free(kernel_arena, sva, sz); | ||||
free(new_ldt, M_SUBPROC); | free(new_ldt, M_SUBPROC); | ||||
return (pldt); | return (pldt); | ||||
} | } | ||||
if (pldt != NULL) { | if (pldt != NULL) { | ||||
bcopy(pldt->ldt_base, new_ldt->ldt_base, max_ldt_segment * | bcopy(pldt->ldt_base, new_ldt->ldt_base, max_ldt_segment * | ||||
sizeof(struct user_segment_descriptor)); | sizeof(struct user_segment_descriptor)); | ||||
user_ldt_derefl(pldt); | user_ldt_derefl(pldt); | ||||
Show All 30 Lines | if (td == curthread) | ||||
lldt(GSEL(GNULL_SEL, SEL_KPL)); | lldt(GSEL(GNULL_SEL, SEL_KPL)); | ||||
critical_exit(); | critical_exit(); | ||||
user_ldt_deref(pldt); | user_ldt_deref(pldt); | ||||
} | } | ||||
static void | static void | ||||
user_ldt_derefl(struct proc_ldt *pldt) | user_ldt_derefl(struct proc_ldt *pldt) | ||||
{ | { | ||||
vm_offset_t sva; | |||||
vm_size_t sz; | |||||
if (--pldt->ldt_refcnt == 0) { | if (--pldt->ldt_refcnt == 0) { | ||||
kmem_free(kernel_arena, (vm_offset_t)pldt->ldt_base, | sva = (vm_offset_t)pldt->ldt_base; | ||||
max_ldt_segment * sizeof(struct user_segment_descriptor)); | sz = max_ldt_segment * sizeof(struct user_segment_descriptor); | ||||
pmap_pti_remove_kva(sva, sva + sz); | |||||
kmem_free(kernel_arena, sva, sz); | |||||
free(pldt, M_SUBPROC); | free(pldt, M_SUBPROC); | ||||
} | } | ||||
} | } | ||||
void | static void | ||||
user_ldt_deref(struct proc_ldt *pldt) | user_ldt_deref(struct proc_ldt *pldt) | ||||
{ | { | ||||
mtx_assert(&dt_lock, MA_OWNED); | mtx_assert(&dt_lock, MA_OWNED); | ||||
user_ldt_derefl(pldt); | user_ldt_derefl(pldt); | ||||
mtx_unlock(&dt_lock); | mtx_unlock(&dt_lock); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 208 Lines • Show Last 20 Lines |