Changeset View
Changeset View
Standalone View
Standalone View
sys/x86/x86/dbreg.c
- This file was added.
/*- | |||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD | |||||
* | |||||
* Copyright (c) 2021 Klara Inc. | |||||
* | |||||
* Portions of this software were developed by Mitchell Horne | |||||
* under sponsorship from Klara Inc. | |||||
* | |||||
* Redistribution and use in source and binary forms, with or without | |||||
* modification, are permitted provided that the following conditions | |||||
* are met: | |||||
* 1. Redistributions of source code must retain the above copyright | |||||
* notice, this list of conditions and the following disclaimer | |||||
* in this position and unchanged. | |||||
* 2. Redistributions in binary form must reproduce the above copyright | |||||
* notice, this list of conditions and the following disclaimer in the | |||||
* documentation and/or other materials provided with the distribution. | |||||
* | |||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR | |||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |||||
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, | |||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||||
*/ | |||||
kib: Was this code copy/pasted with trivial modifications?
I really do not think that the new… | |||||
mhorneAuthorUnsubmitted Done Inline ActionsI made some new additions to this file in D29155, but still something that can be considered trivial. I do not feel strongly about keeping the notice. mhorne: I made some new additions to this file in D29155, but still something that can be considered… | |||||
/*- | |||||
* Mach Operating System | |||||
* Copyright (c) 1991,1990 Carnegie Mellon University | |||||
* All Rights Reserved. | |||||
* | |||||
* Permission to use, copy, modify and distribute this software and its | |||||
* documentation is hereby granted, provided that both the copyright | |||||
* notice and this permission notice appear in all copies of the | |||||
Not Done Inline ActionsIsn't this #ifdef redundant? Even if the file is used for gdb && !ddb configs eventually. kib: Isn't this #ifdef redundant? Even if the file is used for gdb && !ddb configs eventually. | |||||
* software, derivative works or modified versions, and any portions | |||||
* thereof, and that both notices appear in supporting documentation. | |||||
* | |||||
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS | |||||
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR | |||||
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. | |||||
* | |||||
* Carnegie Mellon requests users of this software to return to | |||||
* | |||||
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU | |||||
* School of Computer Science | |||||
* Carnegie Mellon University | |||||
* Pittsburgh PA 15213-3890 | |||||
* | |||||
* any improvements or extensions that they make and grant Carnegie the | |||||
* rights to redistribute these changes. | |||||
*/ | |||||
#include "opt_ddb.h" | |||||
#include <sys/types.h> | |||||
#include <sys/pcpu.h> | |||||
#include <sys/smp.h> | |||||
#include <sys/systm.h> | |||||
#include <machine/frame.h> | |||||
#include <machine/reg.h> | |||||
#ifdef DDB | |||||
#include <ddb/ddb.h> | |||||
#include <ddb/db_sym.h> | |||||
#endif | |||||
#define NDBREGS 4 | |||||
#ifdef __amd64__ | |||||
#define MAXWATCHSIZE 8 | |||||
#else | |||||
#define MAXWATCHSIZE 4 | |||||
#endif | |||||
/* | |||||
* Set a watchpoint in the debug register denoted by 'watchnum'. | |||||
*/ | |||||
static void | |||||
dbreg_set_watchreg(int watchnum, vm_offset_t watchaddr, vm_size_t size, | |||||
int access, struct dbreg *d) | |||||
{ | |||||
int len; | |||||
MPASS(watchnum >= 0 && watchnum < NDBREGS); | |||||
/* size must be 1 for an execution breakpoint */ | |||||
if (access == DBREG_DR7_EXEC) | |||||
size = 1; | |||||
/* | |||||
* we can watch a 1, 2, or 4 byte sized location | |||||
*/ | |||||
switch (size) { | |||||
case 1: | |||||
len = DBREG_DR7_LEN_1; | |||||
break; | |||||
case 2: | |||||
len = DBREG_DR7_LEN_2; | |||||
break; | |||||
case 4: | |||||
len = DBREG_DR7_LEN_4; | |||||
break; | |||||
#if MAXWATCHSIZE >= 8 | |||||
case 8: | |||||
len = DBREG_DR7_LEN_8; | |||||
break; | |||||
#endif | |||||
default: | |||||
return; | |||||
} | |||||
/* clear the bits we are about to affect */ | |||||
d->dr[7] &= ~DBREG_DR7_MASK(watchnum); | |||||
/* set drN register to the address, N=watchnum */ | |||||
DBREG_DRX(d, watchnum) = watchaddr; | |||||
/* enable the watchpoint */ | |||||
d->dr[7] |= DBREG_DR7_SET(watchnum, len, access, | |||||
DBREG_DR7_GLOBAL_ENABLE); | |||||
} | |||||
/* | |||||
* Remove a watchpoint from the debug register denoted by 'watchnum'. | |||||
*/ | |||||
static void | |||||
dbreg_clr_watchreg(int watchnum, struct dbreg *d) | |||||
{ | |||||
MPASS(watchnum >= 0 && watchnum < NDBREGS); | |||||
d->dr[7] &= ~DBREG_DR7_MASK(watchnum); | |||||
DBREG_DRX(d, watchnum) = 0; | |||||
} | |||||
/* | |||||
* Sync the debug registers. Other cores will read these values from the PCPU | |||||
* area when they resume. | |||||
*/ | |||||
static void | |||||
dbreg_sync(struct dbreg *dp) | |||||
{ | |||||
#ifdef __amd64__ | |||||
struct pcpu *pc; | |||||
int cpu, c; | |||||
cpu = PCPU_GET(cpuid); | |||||
CPU_FOREACH(c) { | |||||
if (c == cpu) | |||||
continue; | |||||
pc = pcpu_find(c); | |||||
memcpy(pc->pc_dbreg, dp, sizeof(*dp)); | |||||
pc->pc_dbreg_cmd = PC_DBREG_CMD_LOAD; | |||||
} | |||||
#endif | |||||
} | |||||
int | |||||
dbreg_set_watchpoint(vm_offset_t addr, vm_size_t size) | |||||
{ | |||||
struct dbreg *d; | |||||
int avail, i, wsize; | |||||
#ifdef __amd64__ | |||||
d = (struct dbreg *)PCPU_PTR(dbreg); | |||||
#else | |||||
/* debug registers aren't stored in PCPU on i386. */ | |||||
struct dbreg d_temp; | |||||
d = &d_temp; | |||||
#endif | |||||
fill_dbregs(NULL, d); | |||||
/* | |||||
* Check if there are enough available registers to cover the desired | |||||
* area. | |||||
*/ | |||||
avail = 0; | |||||
for (i = 0; i < NDBREGS; i++) { | |||||
if (!DBREG_DR7_ENABLED(d->dr[7], i)) | |||||
avail++; | |||||
} | |||||
if (avail * MAXWATCHSIZE < size) | |||||
return (-1); | |||||
for (i = 0; i < NDBREGS && size > 0; i++) { | |||||
if (!DBREG_DR7_ENABLED(d->dr[7], i)) { | |||||
if (size >= 8 || (avail == 1 && size > 4)) | |||||
wsize = 8; | |||||
else if (size > 2) | |||||
wsize = 4; | |||||
else | |||||
wsize = size; | |||||
dbreg_set_watchreg(i, addr, wsize, DBREG_DR7_WRONLY, d); | |||||
addr += wsize; | |||||
size -= wsize; | |||||
avail--; | |||||
} | |||||
} | |||||
set_dbregs(NULL, d); | |||||
dbreg_sync(d); | |||||
return (0); | |||||
} | |||||
int | |||||
dbreg_clr_watchpoint(vm_offset_t addr, vm_size_t size) | |||||
{ | |||||
struct dbreg *d; | |||||
int i; | |||||
#ifdef __amd64__ | |||||
d = (struct dbreg *)PCPU_PTR(dbreg); | |||||
#else | |||||
/* debug registers aren't stored in PCPU on i386. */ | |||||
struct dbreg d_temp; | |||||
d = &d_temp; | |||||
#endif | |||||
fill_dbregs(NULL, d); | |||||
for (i = 0; i < NDBREGS; i++) { | |||||
if (DBREG_DR7_ENABLED(d->dr[7], i)) { | |||||
if (DBREG_DRX((d), i) >= addr && | |||||
DBREG_DRX((d), i) < addr + size) | |||||
dbreg_clr_watchreg(i, d); | |||||
} | |||||
} | |||||
set_dbregs(NULL, d); | |||||
dbreg_sync(d); | |||||
return (0); | |||||
} | |||||
#ifdef DDB | |||||
static const char * | |||||
watchtype_str(int type) | |||||
{ | |||||
switch (type) { | |||||
case DBREG_DR7_EXEC: | |||||
return ("execute"); | |||||
case DBREG_DR7_RDWR: | |||||
return ("read/write"); | |||||
case DBREG_DR7_WRONLY: | |||||
return ("write"); | |||||
default: | |||||
return ("invalid"); | |||||
} | |||||
} | |||||
void | |||||
dbreg_list_watchpoints(void) | |||||
{ | |||||
struct dbreg d; | |||||
int i, len, type; | |||||
fill_dbregs(NULL, &d); | |||||
db_printf("\nhardware watchpoints:\n"); | |||||
db_printf(" watch status type len address\n"); | |||||
db_printf(" ----- -------- ---------- --- ----------\n"); | |||||
for (i = 0; i < NDBREGS; i++) { | |||||
if (DBREG_DR7_ENABLED(d.dr[7], i)) { | |||||
type = DBREG_DR7_ACCESS(d.dr[7], i); | |||||
len = DBREG_DR7_LEN(d.dr[7], i); | |||||
db_printf(" %-5d %-8s %10s %3d ", | |||||
i, "enabled", watchtype_str(type), len + 1); | |||||
db_printsym((db_addr_t)DBREG_DRX(&d, i), DB_STGY_ANY); | |||||
db_printf("\n"); | |||||
} else { | |||||
db_printf(" %-5d disabled\n", i); | |||||
} | |||||
} | |||||
} | |||||
#endif |
Was this code copy/pasted with trivial modifications?
I really do not think that the new license is applicable to it.