1/*-
2 * Copyright (c) 2017 John Baldwin <jhb@FreeBSD.org>
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 *
25 */
26
27#include <sys/types.h>
28#include <sys/elf.h>
29#include <sys/proc.h>
30#include <sys/ptrace.h>
31#include <sys/reg.h>
32#include <machine/pcb.h>
33#ifdef VFP
34#include <machine/vfp.h>
35#endif
36
37#ifdef VFP
38static bool
39get_arm_vfp(struct regset *rs, struct thread *td, void *buf, size_t *sizep)
40{
41	if (buf != NULL) {
42		KASSERT(*sizep == sizeof(mcontext_vfp_t),
43		    ("%s: invalid size", __func__));
44		get_vfpcontext(td, buf);
45	}
46	*sizep = sizeof(mcontext_vfp_t);
47	return (true);
48}
49
50static bool
51set_arm_vfp(struct regset *rs, struct thread *td, void *buf,
52    size_t size)
53{
54	KASSERT(size == sizeof(mcontext_vfp_t), ("%s: invalid size", __func__));
55	set_vfpcontext(td, buf);
56	return (true);
57}
58
59static struct regset regset_arm_vfp = {
60	.note = NT_ARM_VFP,
61	.size = sizeof(mcontext_vfp_t),
62	.get = get_arm_vfp,
63	.set = set_arm_vfp,
64};
65ELF_REGSET(regset_arm_vfp);
66#endif
67
68static bool
69get_arm_tls(struct regset *rs, struct thread *td, void *buf,
70    size_t *sizep)
71{
72	if (buf != NULL) {
73		KASSERT(*sizep == sizeof(td->td_pcb->pcb_regs.sf_tpidrurw),
74		    ("%s: invalid size", __func__));
75		memcpy(buf, &td->td_pcb->pcb_regs.sf_tpidrurw,
76		    sizeof(td->td_pcb->pcb_regs.sf_tpidrurw));
77	}
78	*sizep = sizeof(td->td_pcb->pcb_regs.sf_tpidrurw);
79
80	return (true);
81}
82
83static struct regset regset_arm_tls = {
84	.note = NT_ARM_TLS,
85	.size = sizeof(uint32_t),
86	.get = get_arm_tls,
87};
88ELF_REGSET(regset_arm_tls);
89
90int
91cpu_ptrace(struct thread *td, int req, void *addr, int data)
92{
93#ifdef VFP
94	mcontext_vfp_t vfp;
95#endif
96	int error;
97
98	switch (req) {
99#ifdef VFP
100	case PT_GETVFPREGS:
101		get_vfpcontext(td, &vfp);
102		error = copyout(&vfp, addr, sizeof(vfp));
103		break;
104	case PT_SETVFPREGS:
105		error = copyin(addr, &vfp, sizeof(vfp));
106		if (error == 0)
107			set_vfpcontext(td, &vfp);
108		break;
109#endif
110	default:
111		error = EINVAL;
112	}
113
114	return (error);
115}
116