quark_x10xx: add new target quark_x10xx 29/1829/4
authorAdrian Burns <adrian.burns@intel.com>
Thu, 6 Feb 2014 17:11:15 +0000 (17:11 +0000)
committerAndreas Fritiofson <andreas.fritiofson@gmail.com>
Tue, 11 Feb 2014 13:07:29 +0000 (13:07 +0000)
Intel Quark X10xx SoC debug support added
Lakemont version 1 (LMT1) is the x86 core in Quark X10xx SoC
Generic x86 32-bit code is in x86_32_common.c/h

Change-Id: If2bf77275cd0277a82558cd9895b4c66155cf368
Signed-off-by: adrian.burns@intel.com
Reviewed-on: http://openocd.zylin.com/1829
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
README
doc/openocd.texi
src/target/Makefile.am
src/target/lakemont.c [new file with mode: 0644]
src/target/lakemont.h [new file with mode: 0644]
src/target/quark_x10xx.c [new file with mode: 0644]
src/target/target.c
src/target/x86_32_common.c [new file with mode: 0644]
src/target/x86_32_common.h [new file with mode: 0644]
tcl/board/quark_x10xx_board.cfg [new file with mode: 0644]
tcl/target/quark_x10xx.cfg [new file with mode: 0644]

diff --git a/README b/README
index 60338d0763b25b5a4f0b7b30b7956bfa4f15ac92..a9ccd0018d8da0a12aa76818332b749748f380f5 100644 (file)
--- a/README
+++ b/README
@@ -117,7 +117,7 @@ Debug targets
 
 ARM11, ARM7, ARM9, AVR32, Cortex-A, Cortex-R, Cortex-M,
 Feroceon/Dragonite, DSP563xx, DSP5680xx, FA526, MIPS EJTAG, NDS32,
-XScale.
+XScale, Intel Quark.
 
 Flash drivers
 -------------
index f614c62949add89d247eb440858b36cb0d6add33..76e335b8f23c2466606b37baaa65a18b4b759223 100644 (file)
@@ -156,9 +156,9 @@ USB-based, parallel port-based, and other standalone boxes that run
 OpenOCD internally. @xref{Debug Adapter Hardware}.
 
 @b{GDB Debug:} It allows ARM7 (ARM7TDMI and ARM720t), ARM9 (ARM920T,
-ARM922T, ARM926EJ--S, ARM966E--S), XScale (PXA25x, IXP42x) and
-Cortex-M3 (Stellaris LM3, ST STM32 and Energy Micro EFM32) based cores to be
-debugged via the GDB protocol.
+ARM922T, ARM926EJ--S, ARM966E--S), XScale (PXA25x, IXP42x), Cortex-M3
+(Stellaris LM3, ST STM32 and Energy Micro EFM32) and Intel Quark (x10xx)
+based cores to be debugged via the GDB protocol.
 
 @b{Flash Programming:} Flash writing is supported for external
 CFI-compatible NOR flashes (Intel and AMD/Spansion command set) and several
@@ -7542,6 +7542,47 @@ the peripherals.
 @xref{targetevents,,Target Events}.
 @end deffn
 
+@section Intel Architecture
+
+Intel Quark X10xx is the first product in the Quark family of SoCs. It is an IA-32
+(Pentium x86 ISA) compatible SoC. The core CPU in the X10xx is codenamed Lakemont.
+Lakemont version 1 (LMT1) is used in X10xx. The CPU TAP (Lakemont TAP) is used for
+software debug and the CLTAP is used for SoC level operations.
+Useful docs are here: https://communities.intel.com/community/makers/documentation
+@itemize
+@item Intel Quark SoC X1000 OpenOCD/GDB/Eclipse App Note (web search for doc num 330015)
+@item Intel Quark SoC X1000 Debug Operations User Guide (web search for doc num 329866)
+@item Intel Quark SoC X1000 Datasheet (web search for doc num 329676)
+@end itemize
+
+@subsection x86 32-bit specific commands
+The three main address spaces for x86 are memory, I/O and configuration space.
+These commands allow a user to read and write to the 64Kbyte I/O address space.
+
+@deffn Command {x86_32 idw} address
+Display the contents of a 32-bit I/O port from address range 0x0000 - 0xffff.
+@end deffn
+
+@deffn Command {x86_32 idh} address
+Display the contents of a 16-bit I/O port from address range 0x0000 - 0xffff.
+@end deffn
+
+@deffn Command {x86_32 idb} address
+Display the contents of a 8-bit I/O port from address range 0x0000 - 0xffff.
+@end deffn
+
+@deffn Command {x86_32 iww} address
+Write the contents of a 32-bit I/O port to address range 0x0000 - 0xffff.
+@end deffn
+
+@deffn Command {x86_32 iwh} address
+Write the contents of a 16-bit I/O port to address range 0x0000 - 0xffff.
+@end deffn
+
+@deffn Command {x86_32 iwb} address
+Write the contents of a 8-bit I/O port to address range 0x0000 - 0xffff.
+@end deffn
+
 @section OpenRISC Architecture
 
 The OpenRISC CPU is a soft core. It is used in a programmable SoC which can be
index 4d9ea418a39a9319ecdeaf90ef013a40e153979c..159f0fa4307c426935c971445caa7178519d15ab 100644 (file)
@@ -35,6 +35,7 @@ libtarget_la_SOURCES = \
        $(AVR32_SRC) \
        $(MIPS32_SRC) \
        $(NDS32_SRC) \
+       $(INTEL_IA32_SRC) \
        avrt.c \
        dsp563xx.c \
        dsp563xx_once.c \
@@ -124,6 +125,10 @@ NDS32_SRC = \
        nds32_v3m.c \
        nds32_aice.c
 
+INTEL_IA32_SRC = \
+       quark_x10xx.c \
+       lakemont.c \
+       x86_32_common.c
 
 noinst_HEADERS = \
        algorithm.h \
@@ -191,7 +196,9 @@ noinst_HEADERS = \
        nds32_v3_common.h \
        nds32_v3.h \
        nds32_v3m.h \
-       nds32_aice.h
+       nds32_aice.h \
+       lakemont.h \
+       x86_32_common.h
 
 ocddatadir = $(pkglibdir)
 nobase_dist_ocddata_DATA =
diff --git a/src/target/lakemont.c b/src/target/lakemont.c
new file mode 100644 (file)
index 0000000..70c785c
--- /dev/null
@@ -0,0 +1,1111 @@
+/*
+ * Copyright(c) 2013 Intel Corporation.
+ *
+ * Adrian Burns (adrian.burns@intel.com)
+ * Thomas Faust (thomas.faust@intel.com)
+ * Ivan De Cesaris (ivan.de.cesaris@intel.com)
+ * Julien Carreno (julien.carreno@intel.com)
+ * Jeffrey Maxwell (jeffrey.r.maxwell@intel.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Contact Information:
+ * Intel Corporation
+ */
+
+/*
+ * @file
+ * This implements the probemode operations for Lakemont 1 (LMT1).
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <helper/log.h>
+
+#include "target.h"
+#include "target_type.h"
+#include "lakemont.h"
+#include "register.h"
+#include "breakpoints.h"
+#include "x86_32_common.h"
+
+static int irscan(struct target *t, uint8_t *out,
+                       uint8_t *in, uint8_t ir_len);
+static int drscan(struct target *t, uint8_t *out, uint8_t *in, uint8_t len);
+static int save_context(struct target *target);
+static int restore_context(struct target *target);
+static uint32_t get_tapstatus(struct target *t);
+static int enter_probemode(struct target *t);
+static int exit_probemode(struct target *t);
+static int halt_prep(struct target *t);
+static int do_halt(struct target *t);
+static int do_resume(struct target *t);
+static int read_all_core_hw_regs(struct target *t);
+static int write_all_core_hw_regs(struct target *t);
+static int read_hw_reg(struct target *t,
+                       int reg, uint32_t *regval, uint8_t cache);
+static int write_hw_reg(struct target *t,
+                       int reg, uint32_t regval, uint8_t cache);
+static struct reg_cache *lakemont_build_reg_cache
+                       (struct target *target);
+static int submit_reg_pir(struct target *t, int num);
+static int submit_instruction_pir(struct target *t, int num);
+static int submit_pir(struct target *t, uint64_t op);
+static int lakemont_get_core_reg(struct reg *reg);
+static int lakemont_set_core_reg(struct reg *reg, uint8_t *buf);
+
+static struct scan_blk scan;
+
+/* registers and opcodes for register access, pm_idx is used to identify the
+ * registers that are modified for lakemont probemode specific operations
+ */
+static const struct {
+       uint8_t id;
+       const char *name;
+       uint64_t op;
+       uint8_t pm_idx;
+       unsigned bits;
+       enum reg_type type;
+       const char *group;
+       const char *feature;
+} regs[] = {
+       /* general purpose registers */
+       { EAX, "eax", 0x000000D01D660000, 0, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
+       { ECX, "ecx", 0x000000501D660000, 1, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
+       { EDX, "edx", 0x000000901D660000, 2, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
+       { EBX, "ebx", 0x000000101D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
+       { ESP, "esp", 0x000000E01D660000, NOT_PMREG, 32, REG_TYPE_DATA_PTR, "general", "org.gnu.gdb.i386.core" },
+       { EBP, "ebp", 0x000000601D660000, NOT_PMREG, 32, REG_TYPE_DATA_PTR, "general", "org.gnu.gdb.i386.core" },
+       { ESI, "esi", 0x000000A01D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
+       { EDI, "edi", 0x000000201D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
+
+       /* instruction pointer & flags */
+       { EIP, "eip", 0x000000C01D660000, 3, 32, REG_TYPE_CODE_PTR, "general", "org.gnu.gdb.i386.core" },
+       { EFLAGS, "eflags", 0x000000401D660000, 4, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
+
+       /* segment registers */
+       { CS, "cs", 0x000000281D660000, 5, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
+       { SS, "ss", 0x000000C81D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
+       { DS, "ds", 0x000000481D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
+       { ES, "es", 0x000000A81D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
+       { FS, "fs", 0x000000881D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
+       { GS, "gs", 0x000000081D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
+
+       /* floating point unit registers - not accessible via JTAG - here to satisfy GDB */
+       { ST0, "st0", 0x0, NOT_AVAIL_REG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
+       { ST1, "st1", 0x0, NOT_AVAIL_REG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
+       { ST2, "st2", 0x0, NOT_AVAIL_REG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
+       { ST3, "st3", 0x0, NOT_AVAIL_REG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
+       { ST4, "st4", 0x0, NOT_AVAIL_REG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
+       { ST5, "st5", 0x0, NOT_AVAIL_REG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
+       { ST6, "st6", 0x0, NOT_AVAIL_REG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
+       { ST7, "st7", 0x0, NOT_AVAIL_REG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
+       { FCTRL, "fctrl", 0x0, NOT_AVAIL_REG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
+       { FSTAT, "fstat", 0x0, NOT_AVAIL_REG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
+       { FTAG, "ftag", 0x0, NOT_AVAIL_REG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
+       { FISEG, "fiseg", 0x0, NOT_AVAIL_REG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
+       { FIOFF, "fioff", 0x0, NOT_AVAIL_REG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
+       { FOSEG, "foseg", 0x0, NOT_AVAIL_REG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
+       { FOOFF, "fooff", 0x0, NOT_AVAIL_REG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
+       { FOP, "fop", 0x0, NOT_AVAIL_REG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
+
+       /* control registers */
+       { CR0, "cr0", 0x000000001D660000, 6, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+       { CR2, "cr2", 0x000000BC1D660000, 7, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+       { CR3, "cr3", 0x000000801D660000, 8, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+       { CR4, "cr4", 0x0000002C1D660000, 9, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+
+       /* debug registers */
+       { DR0, "dr0", 0x0000007C1D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+       { DR1, "dr1", 0x000000FC1D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+       { DR2, "dr2", 0x000000021D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+       { DR3, "dr3", 0x000000821D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+       { DR6, "dr6", 0x000000301D660000, 10, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+       { DR7, "dr7", 0x000000B01D660000, 11, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+
+       /* descriptor tables */
+       { IDTB, "idtbase", 0x000000581D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+       { IDTL, "idtlimit", 0x000000D81D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+       { IDTAR, "idtar", 0x000000981D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+       { GDTB, "gdtbase", 0x000000B81D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+       { GDTL, "gdtlimit", 0x000000781D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+       { GDTAR, "gdtar", 0x000000381D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+       { TR, "tr", 0x000000701D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+       { LDTR, "ldtr", 0x000000F01D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+       { LDTB, "ldbase", 0x000000041D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+       { LDTL, "ldlimit", 0x000000841D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+       { LDTAR, "ldtar", 0x000000F81D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+
+       /* segment registers */
+       { CSB, "csbase", 0x000000F41D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+       { CSL, "cslimit", 0x0000000C1D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+       { CSAR, "csar", 0x000000741D660000, 12, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+       { DSB, "dsbase", 0x000000941D660000, 13, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+       { DSL, "dslimit", 0x000000541D660000, 14, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+       { DSAR, "dsar", 0x000000141D660000, 15, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+       { ESB, "esbase", 0x0000004C1D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+       { ESL, "eslimit", 0x000000CC1D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+       { ESAR, "esar", 0x0000008C1D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+       { FSB, "fsbase", 0x000000641D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+       { FSL, "fslimit", 0x000000E41D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+       { FSAR, "fsar", 0x000000A41D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+       { GSB, "gsbase", 0x000000C41D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+       { GSL, "gslimit", 0x000000241D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+       { GSAR, "gsar", 0x000000441D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+       { SSB, "ssbase", 0x000000341D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+       { SSL, "sslimit", 0x000000B41D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+       { SSAR, "ssar", 0x000000D41D660000, 16, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+       { TSSB, "tssbase", 0x000000E81D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+       { TSSL, "tsslimit", 0x000000181D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+       { TSSAR, "tssar", 0x000000681D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+       /* probemode control register */
+       { PMCR, "pmcr", 0x000000421D660000, 17, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+};
+
+static const struct {
+       uint8_t id;
+       const char *name;
+       uint64_t op;
+} instructions[] = {
+       /* memory read/write */
+       { MEMRDB32, "MEMRDB32", 0x0909090909090851 },
+       { MEMRDB16, "MEMRDB16", 0x09090909090851E6 },
+       { MEMRDH32, "MEMRDH32", 0x090909090908D166 },
+       { MEMRDH16, "MEMRDH16", 0x090909090908D1E6 },
+       { MEMRDW32, "MEMRDW32", 0x09090909090908D1 },
+       { MEMRDW16, "MEMRDW16", 0x0909090908D1E666 },
+       { MEMWRB32, "MEMWRB32", 0x0909090909090811 },
+       { MEMWRB16, "MEMWRB16", 0x09090909090811E6 },
+       { MEMWRH32, "MEMWRH32", 0x0909090909089166 },
+       { MEMWRH16, "MEMWRH16", 0x09090909090891E6 },
+       { MEMWRW32, "MEMWRW32", 0x0909090909090891 },
+       { MEMWRW16, "MEMWRW16", 0x090909090891E666 },
+       /* IO read/write */
+       { IORDB32, "IORDB32", 0x0909090909090937 },
+       { IORDB16, "IORDB16", 0x09090909090937E6 },
+       { IORDH32, "IORDH32", 0x090909090909B766 },
+       { IORDH16, "IORDH16", 0x090909090909B7E6 },
+       { IORDW32, "IORDW32", 0x09090909090909B7 },
+       { IORDW16, "IORDW16", 0x0909090909B7E666 },
+       { IOWRB32, "IOWRB32", 0x0909090909090977 },
+       { IOWRB16, "IOWRB16", 0x09090909090977E6 },
+       { IOWRH32, "IOWRH32", 0x090909090909F766 },
+       { IOWRH16, "IOWRH16", 0x090909090909F7E6 },
+       { IOWRW32, "IOWRW32", 0x09090909090909F7 },
+       { IOWRW16, "IOWRW16", 0x0909090909F7E666 },
+       /* lakemont1 core shadow ram access opcodes */
+       { SRAMACCESS, "SRAMACCESS", 0x0000000E9D660000 },
+       { SRAM2PDR, "SRAM2PDR", 0x4CF0000000000000 },
+       { PDR2SRAM, "PDR2SRAM", 0x0CF0000000000000 },
+       { WBINVD, "WBINVD", 0x09090909090990F0 },
+};
+
+bool check_not_halted(const struct target *t)
+{
+       bool halted = t->state == TARGET_HALTED;
+       if (!halted)
+               LOG_ERROR("target running, halt it first");
+       return !halted;
+}
+
+static int irscan(struct target *t, uint8_t *out,
+                       uint8_t *in, uint8_t ir_len)
+{
+       int retval = ERROR_OK;
+       struct x86_32_common *x86_32 = target_to_x86_32(t);
+       if (NULL == t->tap) {
+               retval = ERROR_FAIL;
+               LOG_ERROR("%s invalid target tap", __func__);
+               return retval;
+       }
+       if (ir_len != t->tap->ir_length) {
+               retval = ERROR_FAIL;
+               if (t->tap->enabled)
+                       LOG_ERROR("%s tap enabled but tap irlen=%d",
+                                       __func__, t->tap->ir_length);
+               else
+                       LOG_ERROR("%s tap not enabled and irlen=%d",
+                                       __func__, t->tap->ir_length);
+               return retval;
+       }
+       struct scan_field *fields = &scan.field;
+       fields->num_bits = ir_len;
+       fields->out_value = out;
+       fields->in_value = in;
+       jtag_add_ir_scan(x86_32->curr_tap, fields, TAP_IDLE);
+       if (x86_32->flush) {
+               retval = jtag_execute_queue();
+               if (retval != ERROR_OK)
+                       LOG_ERROR("%s failed to execute queue", __func__);
+       }
+       return retval;
+}
+
+static int drscan(struct target *t, uint8_t *out, uint8_t *in, uint8_t len)
+{
+       int retval = ERROR_OK;
+       uint64_t data = 0;
+       struct x86_32_common *x86_32 = target_to_x86_32(t);
+       if (NULL == t->tap) {
+               retval = ERROR_FAIL;
+               LOG_ERROR("%s invalid target tap", __func__);
+               return retval;
+       }
+       if (len > MAX_SCAN_SIZE || 0 == len) {
+               retval = ERROR_FAIL;
+               LOG_ERROR("%s data len is %d bits, max is %d bits",
+                               __func__, len, MAX_SCAN_SIZE);
+               return retval;
+       }
+       struct scan_field *fields = &scan.field;
+       fields->out_value = out;
+       fields->in_value = in;
+       fields->num_bits = len;
+       jtag_add_dr_scan(x86_32->curr_tap, 1, fields, TAP_IDLE);
+       if (x86_32->flush) {
+               retval = jtag_execute_queue();
+               if (retval != ERROR_OK) {
+                       LOG_ERROR("%s drscan failed to execute queue", __func__);
+                       return retval;
+               }
+       }
+       if (in != NULL) {
+               if (len >= 8) {
+                       for (int n = (len / 8) - 1 ; n >= 0; n--)
+                               data = (data << 8) + *(in+n);
+               } else
+                       LOG_DEBUG("dr in 0x%02" PRIx8, *in);
+       } else {
+               LOG_ERROR("%s no drscan data", __func__);
+               retval = ERROR_FAIL;
+       }
+       return retval;
+}
+
+static int save_context(struct target *t)
+{
+       int err;
+       /* read core registers from lakemont sram */
+       err = read_all_core_hw_regs(t);
+       if (err != ERROR_OK) {
+               LOG_ERROR("%s error reading regs", __func__);
+               return err;
+       }
+       return ERROR_OK;
+}
+
+static int restore_context(struct target *t)
+{
+       int err = ERROR_OK;
+       uint32_t i;
+       struct x86_32_common *x86_32 = target_to_x86_32(t);
+
+       /* write core regs into the core PM SRAM from the reg_cache */
+       err = write_all_core_hw_regs(t);
+       if (err != ERROR_OK) {
+               LOG_ERROR("%s error writing regs", __func__);
+               return err;
+       }
+
+       for (i = 0; i < (x86_32->cache->num_regs); i++) {
+               x86_32->cache->reg_list[i].dirty = 0;
+               x86_32->cache->reg_list[i].valid = 0;
+       }
+       return err;
+}
+
+/*
+ * we keep reg_cache in sync with hardware at halt/resume time, we avoid
+ * writing to real hardware here bacause pm_regs reflects the hardware
+ * while we are halted then reg_cache syncs with hw on resume
+ * TODO - in order for "reg eip force" to work it assume get/set reads
+ * and writes from hardware, may be other reasons also because generally
+ * other openocd targets read/write from hardware in get/set - watch this!
+ */
+static int lakemont_get_core_reg(struct reg *reg)
+{
+       int retval = ERROR_OK;
+       struct lakemont_core_reg *lakemont_reg = reg->arch_info;
+       struct target *t = lakemont_reg->target;
+       if (check_not_halted(t))
+               return ERROR_TARGET_NOT_HALTED;
+       LOG_DEBUG("reg=%s, value=%08" PRIx32, reg->name,
+                       buf_get_u32(reg->value, 0, 32));
+       return retval;
+}
+
+static int lakemont_set_core_reg(struct reg *reg, uint8_t *buf)
+{
+       struct lakemont_core_reg *lakemont_reg = reg->arch_info;
+       struct target *t = lakemont_reg->target;
+       uint32_t value = buf_get_u32(buf, 0, 32);
+       LOG_DEBUG("reg=%s, newval=%08" PRIx32, reg->name, value);
+       if (check_not_halted(t))
+               return ERROR_TARGET_NOT_HALTED;
+       buf_set_u32(reg->value, 0, 32, value);
+       reg->dirty = 1;
+       reg->valid = 1;
+       return ERROR_OK;
+}
+
+static const struct reg_arch_type lakemont_reg_type = {
+       /* these get called if reg_cache doesnt have a "valid" value
+        * of an individual reg eg "reg eip" but not for "reg" block
+        */
+       .get = lakemont_get_core_reg,
+       .set = lakemont_set_core_reg,
+};
+
+struct reg_cache *lakemont_build_reg_cache(struct target *t)
+{
+       struct x86_32_common *x86_32 = target_to_x86_32(t);
+       int num_regs = ARRAY_SIZE(regs);
+       struct reg_cache **cache_p = register_get_last_cache_p(&t->reg_cache);
+       struct reg_cache *cache = malloc(sizeof(struct reg_cache));
+       struct reg *reg_list = malloc(sizeof(struct reg) * num_regs);
+       struct lakemont_core_reg *arch_info = malloc(sizeof(struct lakemont_core_reg) * num_regs);
+       struct reg_feature *feature;
+       int i;
+
+       if (cache == NULL || reg_list == NULL || arch_info == NULL) {
+               free(cache);
+               free(reg_list);
+               free(arch_info);
+               LOG_ERROR("%s out of memory", __func__);
+               return NULL;
+       }
+
+       /* Build the process context cache */
+       cache->name = "lakemont registers";
+       cache->next = NULL;
+       cache->reg_list = reg_list;
+       cache->num_regs = num_regs;
+       (*cache_p) = cache;
+       x86_32->cache = cache;
+
+       for (i = 0; i < num_regs; i++) {
+               arch_info[i].target = t;
+               arch_info[i].x86_32_common = x86_32;
+               arch_info[i].op = regs[i].op;
+               arch_info[i].pm_idx = regs[i].pm_idx;
+               reg_list[i].name = regs[i].name;
+               reg_list[i].size = 32;
+               reg_list[i].value = calloc(1, 4);
+               reg_list[i].dirty = 0;
+               reg_list[i].valid = 0;
+               reg_list[i].type = &lakemont_reg_type;
+               reg_list[i].arch_info = &arch_info[i];
+
+               reg_list[i].group = regs[i].group;
+               reg_list[i].number = i;
+               reg_list[i].exist = true;
+               reg_list[i].caller_save = true; /* gdb defaults to true */
+
+               feature = calloc(1, sizeof(struct reg_feature));
+               if (feature) {
+                       feature->name = regs[i].feature;
+                       reg_list[i].feature = feature;
+               } else
+                       LOG_ERROR("%s unable to allocate feature list", __func__);
+
+               reg_list[i].reg_data_type = calloc(1, sizeof(struct reg_data_type));
+               if (reg_list[i].reg_data_type)
+                       reg_list[i].reg_data_type->type = regs[i].type;
+               else
+                       LOG_ERROR("%s unable to allocate reg type list", __func__);
+       }
+       return cache;
+}
+
+static uint32_t get_tapstatus(struct target *t)
+{
+       scan.out[0] = TAPSTATUS;
+       if (irscan(t, scan.out, NULL, LMT_IRLEN) != ERROR_OK)
+               return 0;
+       if (drscan(t, NULL, scan.out, TS_SIZE) != ERROR_OK)
+               return 0;
+       return buf_get_u32(scan.out, 0, 32);
+}
+
+static int enter_probemode(struct target *t)
+{
+       uint32_t tapstatus = 0;
+       tapstatus = get_tapstatus(t);
+       LOG_DEBUG("TS before PM enter = %08" PRIx32, tapstatus);
+       if (tapstatus & TS_PM_BIT) {
+               LOG_DEBUG("core already in probemode");
+               return ERROR_OK;
+       }
+       scan.out[0] = PROBEMODE;
+       if (irscan(t, scan.out, NULL, LMT_IRLEN) != ERROR_OK)
+               return ERROR_FAIL;
+       scan.out[0] = 1;
+       if (drscan(t, scan.out, scan.in, 1) != ERROR_OK)
+               return ERROR_FAIL;
+       tapstatus = get_tapstatus(t);
+       LOG_DEBUG("TS after PM enter = %08" PRIx32, tapstatus);
+       if ((tapstatus & TS_PM_BIT) && (!(tapstatus & TS_EN_PM_BIT)))
+               return ERROR_OK;
+       else {
+               LOG_ERROR("%s PM enter error, tapstatus = %08" PRIx32
+                               , __func__, tapstatus);
+               return ERROR_FAIL;
+       }
+}
+
+static int exit_probemode(struct target *t)
+{
+       uint32_t tapstatus = get_tapstatus(t);
+       LOG_DEBUG("TS before PM exit = %08" PRIx32, tapstatus);
+
+       if (!(tapstatus & TS_PM_BIT)) {
+               LOG_USER("core not in PM");
+               return ERROR_OK;
+       }
+       scan.out[0] = PROBEMODE;
+       if (irscan(t, scan.out, NULL, LMT_IRLEN) != ERROR_OK)
+               return ERROR_FAIL;
+       scan.out[0] = 0;
+       if (drscan(t, scan.out, scan.in, 1) != ERROR_OK)
+               return ERROR_FAIL;
+       return ERROR_OK;
+}
+
+/* do whats needed to properly enter probemode for debug on lakemont */
+static int halt_prep(struct target *t)
+{
+       struct x86_32_common *x86_32 = target_to_x86_32(t);
+       if (write_hw_reg(t, DSB, PM_DSB, 0) != ERROR_OK)
+               return ERROR_FAIL;
+       LOG_DEBUG("write %s %08" PRIx32, regs[DSB].name, PM_DSB);
+       if (write_hw_reg(t, DSL, PM_DSL, 0) != ERROR_OK)
+               return ERROR_FAIL;
+       LOG_DEBUG("write %s %08" PRIx32, regs[DSL].name, PM_DSL);
+       if (write_hw_reg(t, DSAR, PM_DSAR, 0) != ERROR_OK)
+               return ERROR_FAIL;
+       LOG_DEBUG("write DSAR %08" PRIx32, PM_DSAR);
+       if (write_hw_reg(t, DR7, PM_DR7, 0) != ERROR_OK)
+               return ERROR_FAIL;
+       LOG_DEBUG("write DR7 %08" PRIx32, PM_DR7);
+
+       uint32_t eflags = buf_get_u32(x86_32->cache->reg_list[EFLAGS].value, 0, 32);
+       uint32_t csar = buf_get_u32(x86_32->cache->reg_list[CSAR].value, 0, 32);
+       uint32_t ssar = buf_get_u32(x86_32->cache->reg_list[SSAR].value, 0, 32);
+       uint32_t cr0 = buf_get_u32(x86_32->cache->reg_list[CR0].value, 0, 32);
+
+       /* clear VM86 and IF bits if they are set */
+       LOG_DEBUG("EFLAGS = %08" PRIx32 ", VM86 = %d, IF = %d", eflags,
+                       eflags & EFLAGS_VM86 ? 1 : 0,
+                       eflags & EFLAGS_IF ? 1 : 0);
+       if (eflags & EFLAGS_VM86
+               || eflags & EFLAGS_IF) {
+               x86_32->pm_regs[I(EFLAGS)] = eflags & ~(EFLAGS_VM86 | EFLAGS_IF);
+               if (write_hw_reg(t, EFLAGS, x86_32->pm_regs[I(EFLAGS)], 0) != ERROR_OK)
+                       return ERROR_FAIL;
+               LOG_DEBUG("EFLAGS now = %08" PRIx32 ", VM86 = %d, IF = %d",
+                               x86_32->pm_regs[I(EFLAGS)],
+                               x86_32->pm_regs[I(EFLAGS)] & EFLAGS_VM86 ? 1 : 0,
+                               x86_32->pm_regs[I(EFLAGS)] & EFLAGS_IF ? 1 : 0);
+       }
+
+       /* set CPL to 0 for memory access */
+       if (csar & CSAR_DPL) {
+               x86_32->pm_regs[I(CSAR)] = csar & ~CSAR_DPL;
+               if (write_hw_reg(t, CSAR, x86_32->pm_regs[I(CSAR)], 0) != ERROR_OK)
+                       return ERROR_FAIL;
+               LOG_DEBUG("write CSAR_CPL to 0 %08" PRIx32, x86_32->pm_regs[I(CSAR)]);
+       }
+       if (ssar & SSAR_DPL) {
+               x86_32->pm_regs[I(SSAR)] = ssar & ~CSAR_DPL;
+               if (write_hw_reg(t, SSAR, x86_32->pm_regs[I(SSAR)], 0) != ERROR_OK)
+                       return ERROR_FAIL;
+               LOG_DEBUG("write SSAR_CPL to 0 %08" PRIx32, x86_32->pm_regs[I(SSAR)]);
+       }
+
+       /* if cache's are enabled, disable and flush */
+       if (!(cr0 & CR0_CD)) {
+               LOG_DEBUG("caching enabled CR0 = %08" PRIx32, cr0);
+               if (cr0 & CR0_PG) {
+                       x86_32->pm_regs[I(CR0)] = cr0 & ~CR0_PG;
+                       if (write_hw_reg(t, CR0, x86_32->pm_regs[I(CR0)], 0) != ERROR_OK)
+                               return ERROR_FAIL;
+                       LOG_DEBUG("cleared paging CR0_PG = %08" PRIx32, x86_32->pm_regs[I(CR0)]);
+                       /* submit wbinvd to flush cache */
+                       if (submit_reg_pir(t, WBINVD) != ERROR_OK)
+                               return ERROR_FAIL;
+                       x86_32->pm_regs[I(CR0)] =
+                               x86_32->pm_regs[I(CR0)] | (CR0_CD | CR0_NW | CR0_PG);
+                       if (write_hw_reg(t, CR0, x86_32->pm_regs[I(CR0)], 0) != ERROR_OK)
+                               return ERROR_FAIL;
+                       LOG_DEBUG("set CD, NW and PG, CR0 = %08" PRIx32, x86_32->pm_regs[I(CR0)]);
+               }
+       }
+       return ERROR_OK;
+}
+
+static int do_halt(struct target *t)
+{
+       /* needs proper handling later if doing a halt errors out */
+       t->state = TARGET_DEBUG_RUNNING;
+       if (enter_probemode(t) != ERROR_OK)
+               return ERROR_FAIL;
+       if (save_context(t) != ERROR_OK)
+               return ERROR_FAIL;
+       if (halt_prep(t) != ERROR_OK)
+               return ERROR_FAIL;
+       t->state = TARGET_HALTED;
+
+       return target_call_event_callbacks(t, TARGET_EVENT_HALTED);
+}
+
+static int do_resume(struct target *t)
+{
+       /* needs proper handling later */
+       t->state = TARGET_DEBUG_RUNNING;
+       if (restore_context(t) != ERROR_OK)
+               return ERROR_FAIL;
+       if (exit_probemode(t) != ERROR_OK)
+               return ERROR_FAIL;
+       t->state = TARGET_RUNNING;
+
+       t->debug_reason = DBG_REASON_NOTHALTED;
+       LOG_USER("target running");
+
+       return target_call_event_callbacks(t, TARGET_EVENT_RESUMED);
+}
+
+static int read_all_core_hw_regs(struct target *t)
+{
+       int err;
+       uint32_t regval, i;
+       struct x86_32_common *x86_32 = target_to_x86_32(t);
+       for (i = 0; i < (x86_32->cache->num_regs); i++) {
+               if (NOT_AVAIL_REG == regs[i].pm_idx)
+                       continue;
+               err = read_hw_reg(t, regs[i].id, &regval, 1);
+               if (err != ERROR_OK) {
+                       LOG_ERROR("%s error saving reg %s",
+                                       __func__, x86_32->cache->reg_list[i].name);
+                       return err;
+               }
+       }
+       LOG_DEBUG("read_all_core_hw_regs read %d registers ok", i);
+       return ERROR_OK;
+}
+
+static int write_all_core_hw_regs(struct target *t)
+{
+       int err;
+       uint32_t i;
+       struct x86_32_common *x86_32 = target_to_x86_32(t);
+       for (i = 0; i < (x86_32->cache->num_regs); i++) {
+               if (NOT_AVAIL_REG == regs[i].pm_idx)
+                       continue;
+               err = write_hw_reg(t, i, 0, 1);
+               if (err != ERROR_OK) {
+                       LOG_ERROR("%s error restoring reg %s",
+                                       __func__, x86_32->cache->reg_list[i].name);
+                       return err;
+               }
+       }
+       LOG_DEBUG("write_all_core_hw_regs wrote %d registers ok", i);
+       return ERROR_OK;
+}
+
+/* read reg from lakemont core shadow ram, update reg cache if needed */
+static int read_hw_reg(struct target *t, int reg, uint32_t *regval, uint8_t cache)
+{
+       struct x86_32_common *x86_32 = target_to_x86_32(t);
+       struct lakemont_core_reg *arch_info;
+       arch_info = x86_32->cache->reg_list[reg].arch_info;
+       x86_32->flush = 0; /* dont flush scans till we have a batch */
+       if (submit_reg_pir(t, reg) != ERROR_OK)
+               return ERROR_FAIL;
+       if (submit_instruction_pir(t, SRAMACCESS) != ERROR_OK)
+               return ERROR_FAIL;
+       if (submit_instruction_pir(t, SRAM2PDR) != ERROR_OK)
+               return ERROR_FAIL;
+       x86_32->flush = 1;
+       scan.out[0] = RDWRPDR;
+       if (irscan(t, scan.out, NULL, LMT_IRLEN) != ERROR_OK)
+               return ERROR_FAIL;
+       if (drscan(t, NULL, scan.out, PDR_SIZE) != ERROR_OK)
+               return ERROR_FAIL;
+
+       jtag_add_sleep(DELAY_SUBMITPIR);
+       *regval = buf_get_u32(scan.out, 0, 32);
+       if (cache) {
+               buf_set_u32(x86_32->cache->reg_list[reg].value, 0, 32, *regval);
+               x86_32->cache->reg_list[reg].valid = 1;
+               x86_32->cache->reg_list[reg].dirty = 0;
+       }
+       LOG_DEBUG("reg=%s, op=0x%016" PRIx64 ", val=%08" PRIx32,
+                       x86_32->cache->reg_list[reg].name,
+                       arch_info->op,
+                       *regval);
+       return ERROR_OK;
+}
+
+/* write lakemont core shadow ram reg, update reg cache if needed */
+static int write_hw_reg(struct target *t, int reg, uint32_t regval, uint8_t cache)
+{
+       struct x86_32_common *x86_32 = target_to_x86_32(t);
+       struct lakemont_core_reg *arch_info;
+       arch_info = x86_32->cache->reg_list[reg].arch_info;
+
+       uint8_t reg_buf[4];
+       if (cache)
+               regval = buf_get_u32(x86_32->cache->reg_list[reg].value, 0, 32);
+       buf_set_u32(reg_buf, 0, 32, regval);
+       LOG_DEBUG("reg=%s, op=0x%016" PRIx64 ", val=%08" PRIx32,
+                       x86_32->cache->reg_list[reg].name,
+                       arch_info->op,
+                       regval);
+
+       scan.out[0] = RDWRPDR;
+       x86_32->flush = 0; /* dont flush scans till we have a batch */
+       if (irscan(t, scan.out, NULL, LMT_IRLEN) != ERROR_OK)
+               return ERROR_FAIL;
+       if (drscan(t, reg_buf, scan.out, PDR_SIZE) != ERROR_OK)
+               return ERROR_FAIL;
+       if (submit_reg_pir(t, reg) != ERROR_OK)
+               return ERROR_FAIL;
+       if (submit_instruction_pir(t, SRAMACCESS) != ERROR_OK)
+               return ERROR_FAIL;
+       x86_32->flush = 1;
+       if (submit_instruction_pir(t, PDR2SRAM) != ERROR_OK)
+               return ERROR_FAIL;
+
+       /* we are writing from the cache so ensure we reset flags */
+       if (cache) {
+               x86_32->cache->reg_list[reg].dirty = 0;
+               x86_32->cache->reg_list[reg].valid = 0;
+       }
+       return ERROR_OK;
+}
+
+static bool is_paging_enabled(struct target *t)
+{
+       struct x86_32_common *x86_32 = target_to_x86_32(t);
+       if (x86_32->pm_regs[I(CR0)] & CR0_PG)
+               return true;
+       else
+               return false;
+}
+
+static uint8_t get_num_user_regs(struct target *t)
+{
+       struct x86_32_common *x86_32 = target_to_x86_32(t);
+       return x86_32->cache->num_regs;
+}
+/* value of the CR0.PG (paging enabled) bit influences memory reads/writes */
+static int disable_paging(struct target *t)
+{
+       struct x86_32_common *x86_32 = target_to_x86_32(t);
+       x86_32->pm_regs[I(CR0)] = x86_32->pm_regs[I(CR0)] & ~CR0_PG;
+       int err = x86_32->write_hw_reg(t, CR0, x86_32->pm_regs[I(CR0)], 0);
+       if (err != ERROR_OK) {
+               LOG_ERROR("%s error disabling paging", __func__);
+               return err;
+       }
+       return err;
+}
+
+static int enable_paging(struct target *t)
+{
+       struct x86_32_common *x86_32 = target_to_x86_32(t);
+       x86_32->pm_regs[I(CR0)] = (x86_32->pm_regs[I(CR0)] | CR0_PG);
+       int err = x86_32->write_hw_reg(t, CR0, x86_32->pm_regs[I(CR0)], 0);
+       if (err != ERROR_OK) {
+               LOG_ERROR("%s error enabling paging", __func__);
+               return err;
+       }
+       return err;
+}
+
+static bool sw_bpts_supported(struct target *t)
+{
+       uint32_t tapstatus = get_tapstatus(t);
+       if (tapstatus & TS_SBP_BIT)
+               return true;
+       else
+               return false;
+}
+
+static int transaction_status(struct target *t)
+{
+       uint32_t tapstatus = get_tapstatus(t);
+       if ((TS_EN_PM_BIT | TS_PRDY_BIT) & tapstatus) {
+               LOG_ERROR("%s transaction error tapstatus = %08" PRIx32
+                               , __func__, tapstatus);
+               return ERROR_FAIL;
+       } else {
+               return ERROR_OK;
+       }
+}
+
+static int submit_instruction(struct target *t, int num)
+{
+       int err = submit_instruction_pir(t, num);
+       if (err != ERROR_OK) {
+               LOG_ERROR("%s error submitting pir", __func__);
+               return err;
+       }
+       return err;
+}
+
+static int submit_reg_pir(struct target *t, int num)
+{
+       LOG_DEBUG("reg %s op=0x%016" PRIx64, regs[num].name, regs[num].op);
+       int err = submit_pir(t, regs[num].op);
+       if (err != ERROR_OK) {
+               LOG_ERROR("%s error submitting pir", __func__);
+               return err;
+       }
+       return err;
+}
+
+static int submit_instruction_pir(struct target *t, int num)
+{
+       LOG_DEBUG("%s op=0x%016" PRIx64, instructions[num].name,
+                       instructions[num].op);
+       int err = submit_pir(t, instructions[num].op);
+       if (err != ERROR_OK) {
+               LOG_ERROR("%s error submitting pir", __func__);
+               return err;
+       }
+       return err;
+}
+
+/*
+ * PIR (Probe Mode Instruction Register), SUBMITPIR is an "IR only" TAP
+ * command; there is no corresponding data register
+ */
+static int submit_pir(struct target *t, uint64_t op)
+{
+       struct x86_32_common *x86_32 = target_to_x86_32(t);
+
+       uint8_t op_buf[8];
+       buf_set_u64(op_buf, 0, 64, op);
+       int flush = x86_32->flush;
+       x86_32->flush = 0;
+       scan.out[0] = WRPIR;
+       if (irscan(t, scan.out, NULL, LMT_IRLEN) != ERROR_OK)
+               return ERROR_FAIL;
+       if (drscan(t, op_buf, scan.out, PIR_SIZE) != ERROR_OK)
+               return ERROR_FAIL;
+       scan.out[0] = SUBMITPIR;
+       x86_32->flush = flush;
+       if (irscan(t, scan.out, NULL, LMT_IRLEN) != ERROR_OK)
+               return ERROR_FAIL;
+       jtag_add_sleep(DELAY_SUBMITPIR);
+       return ERROR_OK;
+}
+
+int lakemont_init_target(struct command_context *cmd_ctx, struct target *t)
+{
+       lakemont_build_reg_cache(t);
+       t->state = TARGET_RUNNING;
+       t->debug_reason = DBG_REASON_NOTHALTED;
+       return ERROR_OK;
+}
+
+int lakemont_init_arch_info(struct target *t, struct x86_32_common *x86_32)
+{
+       x86_32->submit_instruction = submit_instruction;
+       x86_32->transaction_status = transaction_status;
+       x86_32->read_hw_reg = read_hw_reg;
+       x86_32->write_hw_reg = write_hw_reg;
+       x86_32->sw_bpts_supported = sw_bpts_supported;
+       x86_32->get_num_user_regs = get_num_user_regs;
+       x86_32->is_paging_enabled = is_paging_enabled;
+       x86_32->disable_paging = disable_paging;
+       x86_32->enable_paging = enable_paging;
+       return ERROR_OK;
+}
+
+int lakemont_poll(struct target *t)
+{
+       /* LMT1 PMCR register currently allows code breakpoints, data breakpoints,
+        * single stepping and shutdowns to be redirected to PM but does not allow
+        * redirecting into PM as a result of SMM enter and SMM exit
+        */
+       uint32_t ts = get_tapstatus(t);
+
+       if (ts == 0xFFFFFFFF && t->state != TARGET_DEBUG_RUNNING) {
+               /* something is wrong here */
+               LOG_ERROR("tapstatus invalid - scan_chain serialization or locked JTAG access issues");
+               /* TODO: Give a hint that unlocking is wrong or maybe a
+                * 'jtag arp_init' helps
+                */
+               t->state = TARGET_DEBUG_RUNNING;
+               return ERROR_OK;
+       }
+
+       if (t->state == TARGET_HALTED && (!(ts & TS_PM_BIT))) {
+               LOG_INFO("target running for unknown reason");
+               t->state = TARGET_RUNNING;
+       }
+
+       if (t->state == TARGET_RUNNING &&
+               t->state != TARGET_DEBUG_RUNNING) {
+
+               if ((ts & TS_PM_BIT) && (ts & TS_PMCR_BIT)) {
+
+                       LOG_DEBUG("redirect to PM, tapstatus=%08" PRIx32, get_tapstatus(t));
+
+                       t->state = TARGET_DEBUG_RUNNING;
+                       if (save_context(t) != ERROR_OK)
+                               return ERROR_FAIL;
+                       if (halt_prep(t) != ERROR_OK)
+                               return ERROR_FAIL;
+                       t->state = TARGET_HALTED;
+                       t->debug_reason = DBG_REASON_UNDEFINED;
+
+                       struct x86_32_common *x86_32 = target_to_x86_32(t);
+                       uint32_t eip = buf_get_u32(x86_32->cache->reg_list[EIP].value, 0, 32);
+                       uint32_t dr6 = buf_get_u32(x86_32->cache->reg_list[DR6].value, 0, 32);
+                       uint32_t hwbreakpoint = (uint32_t)-1;
+
+                       if (dr6 & DR6_BRKDETECT_0)
+                               hwbreakpoint = 0;
+                       if (dr6 & DR6_BRKDETECT_1)
+                               hwbreakpoint = 1;
+                       if (dr6 & DR6_BRKDETECT_2)
+                               hwbreakpoint = 2;
+                       if (dr6 & DR6_BRKDETECT_3)
+                               hwbreakpoint = 3;
+
+                       if (hwbreakpoint != (uint32_t)-1) {
+                               uint32_t dr7 = buf_get_u32(x86_32->cache->reg_list[DR7].value, 0, 32);
+                               uint32_t type = dr7 & (0x03 << (DR7_RW_SHIFT + hwbreakpoint*DR7_RW_LEN_SIZE));
+                               if (type == DR7_BP_EXECUTE) {
+                                       LOG_USER("hit hardware breakpoint (hwreg=%d) at 0x%08" PRIx32, hwbreakpoint, eip);
+                               } else {
+                                       uint32_t address = 0;
+                                       switch (hwbreakpoint) {
+                                       default:
+                                       case 0:
+                                               address = buf_get_u32(x86_32->cache->reg_list[DR0].value, 0, 32);
+                                       break;
+                                       case 1:
+                                               address = buf_get_u32(x86_32->cache->reg_list[DR1].value, 0, 32);
+                                       break;
+                                       case 2:
+                                               address = buf_get_u32(x86_32->cache->reg_list[DR2].value, 0, 32);
+                                       break;
+                                       case 3:
+                                               address = buf_get_u32(x86_32->cache->reg_list[DR3].value, 0, 32);
+                                       break;
+                                       }
+                                       LOG_USER("hit '%s' watchpoint for 0x%08" PRIx32 " (hwreg=%d) at 0x%08" PRIx32,
+                                                               type == DR7_BP_WRITE ? "write" : "access", address,
+                                                               hwbreakpoint, eip);
+                               }
+                               t->debug_reason = DBG_REASON_BREAKPOINT;
+                       } else {
+                               /* Check if the target hit a software breakpoint.
+                                * ! Watch out: EIP is currently pointing after the breakpoint opcode
+                                */
+                               struct breakpoint *bp = NULL;
+                               bp = breakpoint_find(t, eip-1);
+                               if (bp != NULL) {
+                                       t->debug_reason = DBG_REASON_BREAKPOINT;
+                                       if (bp->type == BKPT_SOFT) {
+                                               /* The EIP is now pointing the the next byte after the
+                                                * breakpoint instruction. This needs to be corrected.
+                                                */
+                                               buf_set_u32(x86_32->cache->reg_list[EIP].value, 0, 32, eip-1);
+                                               x86_32->cache->reg_list[EIP].dirty = 1;
+                                               x86_32->cache->reg_list[EIP].valid = 1;
+                                               LOG_USER("hit software breakpoint at 0x%08" PRIx32, eip-1);
+                                       } else {
+                                               /* it's not a hardware breakpoint (checked already in DR6 state)
+                                                * and it's also not a software breakpoint ...
+                                                */
+                                               LOG_USER("hit unknown breakpoint at 0x%08" PRIx32, eip);
+                                       }
+                               } else {
+
+                                       /* There is also the case that we hit an breakpoint instruction,
+                                        * which was not set by us. This needs to be handled be the
+                                        * application that introduced the breakpoint.
+                                        */
+
+                                       LOG_USER("unknown break reason at 0x%08" PRIx32, eip);
+                               }
+                       }
+
+                       return target_call_event_callbacks(t, TARGET_EVENT_HALTED);
+               }
+       }
+       return ERROR_OK;
+}
+
+int lakemont_arch_state(struct target *t)
+{
+       struct x86_32_common *x86_32 = target_to_x86_32(t);
+
+       LOG_USER("target halted due to %s at 0x%08" PRIx32 " in %s mode",
+                       debug_reason_name(t),
+                       buf_get_u32(x86_32->cache->reg_list[EIP].value, 0, 32),
+                       (buf_get_u32(x86_32->cache->reg_list[CR0].value, 0, 32) & CR0_PE) ? "protected" : "real");
+
+       return ERROR_OK;
+}
+
+int lakemont_halt(struct target *t)
+{
+       if (t->state == TARGET_RUNNING) {
+               t->debug_reason = DBG_REASON_DBGRQ;
+               if (do_halt(t) != ERROR_OK)
+                       return ERROR_FAIL;
+               return ERROR_OK;
+       } else {
+               LOG_ERROR("%s target not running", __func__);
+               return ERROR_FAIL;
+       }
+}
+
+int lakemont_resume(struct target *t, int current, uint32_t address,
+                       int handle_breakpoints, int debug_execution)
+{
+       struct breakpoint *bp = NULL;
+       struct x86_32_common *x86_32 = target_to_x86_32(t);
+
+       if (check_not_halted(t))
+               return ERROR_TARGET_NOT_HALTED;
+       /* TODO lakemont_enable_breakpoints(t); */
+       if (t->state == TARGET_HALTED) {
+
+               /* running away for a software breakpoint needs some special handling */
+               uint32_t eip = buf_get_u32(x86_32->cache->reg_list[EIP].value, 0, 32);
+               bp = breakpoint_find(t, eip);
+               if (bp != NULL /*&& bp->type == BKPT_SOFT*/) {
+                       /* the step will step over the breakpoint */
+                       if (lakemont_step(t, 0, 0, 1) != ERROR_OK) {
+                               LOG_ERROR("%s stepping over a software breakpoint at 0x%08" PRIx32 " "
+                                               "failed to resume the target", __func__, eip);
+                               return ERROR_FAIL;
+                       }
+               }
+
+               /* if breakpoints are enabled, we need to redirect these into probe mode */
+               struct breakpoint *activeswbp = t->breakpoints;
+               while (activeswbp != NULL && activeswbp->set == 0)
+                       activeswbp = activeswbp->next;
+               struct watchpoint *activehwbp = t->watchpoints;
+               while (activehwbp != NULL && activehwbp->set == 0)
+                       activehwbp = activehwbp->next;
+               if (activeswbp != NULL || activehwbp != NULL)
+                       buf_set_u32(x86_32->cache->reg_list[PMCR].value, 0, 32, 1);
+               if (do_resume(t) != ERROR_OK)
+                       return ERROR_FAIL;
+       } else {
+               LOG_USER("target not halted");
+               return ERROR_FAIL;
+       }
+       return ERROR_OK;
+}
+
+int lakemont_step(struct target *t, int current,
+                       uint32_t address, int handle_breakpoints)
+{
+       struct x86_32_common *x86_32 = target_to_x86_32(t);
+       uint32_t eflags = buf_get_u32(x86_32->cache->reg_list[EFLAGS].value, 0, 32);
+       uint32_t eip = buf_get_u32(x86_32->cache->reg_list[EIP].value, 0, 32);
+       uint32_t pmcr = buf_get_u32(x86_32->cache->reg_list[PMCR].value, 0, 32);
+       struct breakpoint *bp = NULL;
+       int retval = ERROR_OK;
+       uint32_t tapstatus = 0;
+
+       if (check_not_halted(t))
+               return ERROR_TARGET_NOT_HALTED;
+       bp = breakpoint_find(t, eip);
+       if (retval == ERROR_OK && bp != NULL/*&& bp->type == BKPT_SOFT*/) {
+               /* TODO: This should only be done for software breakpoints.
+                * Stepping from hardware breakpoints should be possible with the resume flag
+                * Needs testing.
+                */
+               retval = x86_32_common_remove_breakpoint(t, bp);
+       }
+
+       /* Set EFLAGS[TF] and PMCR[IR], exit pm and wait for PRDY# */
+       LOG_DEBUG("modifying PMCR = %d and EFLAGS = %08" PRIx32, pmcr, eflags);
+       eflags = eflags | (EFLAGS_TF | EFLAGS_RF);
+       buf_set_u32(x86_32->cache->reg_list[EFLAGS].value, 0, 32, eflags);
+       buf_set_u32(x86_32->cache->reg_list[PMCR].value, 0, 32, 1);
+       LOG_DEBUG("EFLAGS [TF] [RF] bits set=%08" PRIx32 ", PMCR=%d, EIP=%08" PRIx32,
+                       eflags, pmcr, eip);
+
+       tapstatus = get_tapstatus(t);
+
+       t->debug_reason = DBG_REASON_SINGLESTEP;
+       t->state = TARGET_DEBUG_RUNNING;
+       if (restore_context(t) != ERROR_OK)
+               return ERROR_FAIL;
+       if (exit_probemode(t) != ERROR_OK)
+               return ERROR_FAIL;
+
+       target_call_event_callbacks(t, TARGET_EVENT_RESUMED);
+
+       tapstatus = get_tapstatus(t);
+       if (tapstatus & (TS_PM_BIT | TS_EN_PM_BIT | TS_PRDY_BIT | TS_PMCR_BIT)) {
+               /* target has stopped */
+               if (save_context(t) != ERROR_OK)
+                       return ERROR_FAIL;
+               if (halt_prep(t) != ERROR_OK)
+                       return ERROR_FAIL;
+               t->state = TARGET_HALTED;
+
+               LOG_USER("step done from EIP 0x%08" PRIx32 " to 0x%08" PRIx32, eip,
+                               buf_get_u32(x86_32->cache->reg_list[EIP].value, 0, 32));
+               target_call_event_callbacks(t, TARGET_EVENT_HALTED);
+       } else {
+               /* target didn't stop
+                * I hope the poll() will catch it, but the deleted breakpoint is gone
+                */
+               LOG_ERROR("%s target didn't stop after executing a single step", __func__);
+               t->state = TARGET_RUNNING;
+               return ERROR_FAIL;
+       }
+
+       /* try to re-apply the breakpoint, even of step failed
+        * TODO: When a bp was set, we should try to stop the target - fix the return above
+        */
+       if (bp != NULL/*&& bp->type == BKPT_SOFT*/) {
+               /* TODO: This should only be done for software breakpoints.
+                * Stepping from hardware breakpoints should be possible with the resume flag
+                * Needs testing.
+                */
+               retval = x86_32_common_add_breakpoint(t, bp);
+       }
+
+       return retval;
+}
+
+/* TODO - implement resetbreak fully through CLTAP registers */
+int lakemont_reset_assert(struct target *t)
+{
+       LOG_DEBUG("-");
+       return ERROR_OK;
+}
+
+int lakemont_reset_deassert(struct target *t)
+{
+       LOG_DEBUG("-");
+       return ERROR_OK;
+}
diff --git a/src/target/lakemont.h b/src/target/lakemont.h
new file mode 100644 (file)
index 0000000..e63cab0
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright(c) 2013 Intel Corporation.
+ *
+ * Adrian Burns (adrian.burns@intel.com)
+ * Thomas Faust (thomas.faust@intel.com)
+ * Ivan De Cesaris (ivan.de.cesaris@intel.com)
+ * Julien Carreno (julien.carreno@intel.com)
+ * Jeffrey Maxwell (jeffrey.r.maxwell@intel.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Contact Information:
+ * Intel Corporation
+ */
+
+/*
+ * @file
+ * This is the interface to the probemode operations for Lakemont 1 (LMT1).
+ */
+
+#ifndef LAKEMONT_H
+#define LAKEMONT_H
+#include <jtag/jtag.h>
+
+/* The Intel Quark SoC X1000 Core is codenamed lakemont */
+
+#define LMT_IRLEN              8
+
+/* lakemont tap instruction opcodes */
+#define IDCODE                 2
+#define SUBMITPIR              3
+#define PROBEMODE              4
+#define WRPIR                  6
+#define RDWRPDR                        8
+#define TAPSTATUS              11
+#define BYPASS                 255
+#define NOT_NULL               2
+
+/* DR sizes */
+#define ID_SIZE                        32
+#define PM_SIZE                        1
+#define PIR_SIZE               64
+#define PDR_SIZE               32
+#define TS_SIZE                        32
+#define BP_SIZE                        1
+#define MAX_SCAN_SIZE  PIR_SIZE
+
+/* needed during lakemont probemode */
+#define NOT_PMREG              0xfe
+#define NOT_AVAIL_REG          0xff
+#define PM_DSB                 0x00000000
+#define PM_DSL                 0xFFFFFFFF
+#define PM_DSAR                        0x004F9300
+#define PM_DR7                 0x00000400
+#define DELAY_SUBMITPIR                0 /* for now 0 is working */
+
+/* lakemont tapstatus bits */
+#define TS_PRDY_BIT            0x00000001
+#define TS_EN_PM_BIT           0x00000002
+#define TS_PM_BIT              0x00000004
+#define TS_PMCR_BIT            0x00000008
+#define TS_SBP_BIT             0x00000010
+
+struct lakemont_core_reg {
+       uint32_t num;
+       struct target *target;
+       struct x86_32_common *x86_32_common;
+       uint64_t op;
+       uint8_t pm_idx;
+};
+
+struct scan_blk {
+       uint8_t out[MAX_SCAN_SIZE]; /* scanned out to the tap */
+       uint8_t in[MAX_SCAN_SIZE]; /* in to our capture buf */
+       struct scan_field field;
+};
+
+#define I(name) (((struct lakemont_core_reg *)x86_32->cache->reg_list[name].arch_info)->pm_idx)
+
+int lakemont_init_target(struct command_context *cmd_ctx, struct target *t);
+int lakemont_init_arch_info(struct target *t, struct x86_32_common *x86_32);
+int lakemont_poll(struct target *t);
+int lakemont_arch_state(struct target *t);
+int lakemont_halt(struct target *t);
+int lakemont_resume(struct target *t, int current, uint32_t address,
+                       int handle_breakpoints, int debug_execution);
+int lakemont_step(struct target *t, int current,
+                       uint32_t address, int handle_breakpoints);
+int lakemont_reset_assert(struct target *t);
+int lakemont_reset_deassert(struct target *t);
+
+#endif /* LAKEMONT_H */
diff --git a/src/target/quark_x10xx.c b/src/target/quark_x10xx.c
new file mode 100644 (file)
index 0000000..05818b7
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright(c) 2013 Intel Corporation.
+ *
+ * Adrian Burns (adrian.burns@intel.com)
+ * Thomas Faust (thomas.faust@intel.com)
+ * Ivan De Cesaris (ivan.de.cesaris@intel.com)
+ * Julien Carreno (julien.carreno@intel.com)
+ * Jeffrey Maxwell (jeffrey.r.maxwell@intel.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Contact Information:
+ * Intel Corporation
+ */
+
+/*
+ * @file
+ * Debugger for Intel Quark SoC X1000
+ * Intel Quark X10xx is the first product in the Quark family of SoCs.
+ * It is an IA-32 (Pentium x86 ISA) compatible SoC. The core CPU in the
+ * X10xx is codenamed Lakemont. Lakemont version 1 (LMT1) is used in X10xx.
+ * The CPU TAP (Lakemont TAP) is used for software debug and the CLTAP is
+ * used for SoC level operations.
+ * Useful docs are here: https://communities.intel.com/community/makers/documentation
+ * Intel Quark SoC X1000 OpenOCD/GDB/Eclipse App Note (web search for doc num 330015)
+ * Intel Quark SoC X1000 Debug Operations User Guide (web search for doc num 329866)
+ * Intel Quark SoC X1000 Datasheet (web search for doc num 329676)
+ *
+ * This file implements any Quark SoC specific features such as resetbreak (TODO)
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <helper/log.h>
+
+#include "target.h"
+#include "target_type.h"
+#include "lakemont.h"
+#include "x86_32_common.h"
+
+int quark_x10xx_target_create(struct target *t, Jim_Interp *interp)
+{
+       struct x86_32_common *x86_32 = calloc(1, sizeof(struct x86_32_common));
+       if (x86_32 == NULL) {
+               LOG_ERROR("%s out of memory", __func__);
+               return ERROR_FAIL;
+       }
+       x86_32_common_init_arch_info(t, x86_32);
+       lakemont_init_arch_info(t, x86_32);
+       return ERROR_OK;
+}
+
+int quark_x10xx_init_target(struct command_context *cmd_ctx, struct target *t)
+{
+       return lakemont_init_target(cmd_ctx, t);
+}
+
+struct target_type quark_x10xx_target = {
+       .name = "quark_x10xx",
+       /* Quark X1000 SoC */
+       .target_create = quark_x10xx_target_create,
+       .init_target = quark_x10xx_init_target,
+       /* lakemont probemode specific code */
+       .poll = lakemont_poll,
+       .arch_state = lakemont_arch_state,
+       .halt = lakemont_halt,
+       .resume = lakemont_resume,
+       .step = lakemont_step,
+       .assert_reset = lakemont_reset_assert,
+       .deassert_reset = lakemont_reset_deassert,
+       /* common x86 code */
+       .commands = x86_32_command_handlers,
+       .get_gdb_reg_list = x86_32_get_gdb_reg_list,
+       .read_memory = x86_32_common_read_memory,
+       .write_memory = x86_32_common_write_memory,
+       .add_breakpoint = x86_32_common_add_breakpoint,
+       .remove_breakpoint = x86_32_common_remove_breakpoint,
+       .add_watchpoint = x86_32_common_add_watchpoint,
+       .remove_watchpoint = x86_32_common_remove_watchpoint,
+       .virt2phys = x86_32_common_virt2phys,
+       .read_phys_memory = x86_32_common_read_phys_mem,
+       .write_phys_memory = x86_32_common_write_phys_mem,
+       .mmu = x86_32_common_mmu,
+};
index 43d2c6a7a737a441ac6d89e9ebcad10ce94e3db9..b2af96a3144d188cb3d9056c7c67e85b9ee4ef32 100644 (file)
@@ -102,6 +102,7 @@ extern struct target_type nds32_v2_target;
 extern struct target_type nds32_v3_target;
 extern struct target_type nds32_v3m_target;
 extern struct target_type or1k_target;
+extern struct target_type quark_x10xx_target;
 
 static struct target_type *target_types[] = {
        &arm7tdmi_target,
@@ -130,6 +131,7 @@ static struct target_type *target_types[] = {
        &nds32_v3_target,
        &nds32_v3m_target,
        &or1k_target,
+       &quark_x10xx_target,
        NULL,
 };
 
diff --git a/src/target/x86_32_common.c b/src/target/x86_32_common.c
new file mode 100644 (file)
index 0000000..34da39b
--- /dev/null
@@ -0,0 +1,1443 @@
+/*
+ * Copyright(c) 2013 Intel Corporation.
+ *
+ * Adrian Burns (adrian.burns@intel.com)
+ * Thomas Faust (thomas.faust@intel.com)
+ * Ivan De Cesaris (ivan.de.cesaris@intel.com)
+ * Julien Carreno (julien.carreno@intel.com)
+ * Jeffrey Maxwell (jeffrey.r.maxwell@intel.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Contact Information:
+ * Intel Corporation
+ */
+
+/*
+ * @file
+ * This implements generic x86 32 bit memory and breakpoint operations.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <helper/log.h>
+
+#include "target.h"
+#include "target_type.h"
+#include "register.h"
+#include "breakpoints.h"
+#include "x86_32_common.h"
+
+static int set_debug_regs(struct target *t, uint32_t address,
+                       uint8_t bp_num, uint8_t bp_type, uint8_t bp_length);
+static int unset_debug_regs(struct target *t, uint8_t bp_num);
+static int read_mem(struct target *t, uint32_t size,
+                       uint32_t addr, uint8_t *buf);
+static int write_mem(struct target *t, uint32_t size,
+                       uint32_t addr, const uint8_t *buf);
+static int calcaddr_pyhsfromlin(struct target *t, uint32_t addr,
+                       uint32_t *physaddr);
+static int read_phys_mem(struct target *t, uint32_t phys_address,
+                       uint32_t size, uint32_t count, uint8_t *buffer);
+static int write_phys_mem(struct target *t, uint32_t phys_address,
+                       uint32_t size, uint32_t count, const uint8_t *buffer);
+static int set_breakpoint(struct target *target,
+                       struct breakpoint *breakpoint);
+static int unset_breakpoint(struct target *target,
+                       struct breakpoint *breakpoint);
+static int set_watchpoint(struct target *target,
+                       struct watchpoint *watchpoint);
+static int unset_watchpoint(struct target *target,
+                       struct watchpoint *watchpoint);
+static int read_hw_reg_to_cache(struct target *t, int num);
+static int write_hw_reg_from_cache(struct target *t, int num);
+
+int x86_32_get_gdb_reg_list(struct target *t,
+                       struct reg **reg_list[], int *reg_list_size,
+                       enum target_register_class reg_class)
+{
+
+       struct x86_32_common *x86_32 = target_to_x86_32(t);
+       int i;
+       *reg_list_size = x86_32->cache->num_regs;
+       LOG_DEBUG("num_regs=%d, reg_class=%d", (*reg_list_size), reg_class);
+       *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size));
+       if (*reg_list == NULL) {
+               LOG_ERROR("%s out of memory", __func__);
+               return ERROR_FAIL;
+       }
+       /* this will copy the values from our reg list to gdbs */
+       for (i = 0; i < (*reg_list_size); i++) {
+               (*reg_list)[i] = &x86_32->cache->reg_list[i];
+               LOG_DEBUG("value %s = %08" PRIx32, x86_32->cache->reg_list[i].name,
+                               buf_get_u32(x86_32->cache->reg_list[i].value, 0, 32));
+       }
+       return ERROR_OK;
+}
+
+int x86_32_common_init_arch_info(struct target *t, struct x86_32_common *x86_32)
+{
+       t->arch_info = x86_32;
+       x86_32->common_magic = X86_32_COMMON_MAGIC;
+       x86_32->num_hw_bpoints = MAX_DEBUG_REGS;
+       x86_32->hw_break_list = calloc(x86_32->num_hw_bpoints,
+                               sizeof(struct x86_32_dbg_reg));
+       if (x86_32->hw_break_list == NULL) {
+               LOG_ERROR("%s out of memory", __func__);
+               return ERROR_FAIL;
+       }
+       x86_32->curr_tap = t->tap;
+       x86_32->fast_data_area = NULL;
+       x86_32->flush = 1;
+       x86_32->read_hw_reg_to_cache = read_hw_reg_to_cache;
+       x86_32->write_hw_reg_from_cache = write_hw_reg_from_cache;
+       return ERROR_OK;
+}
+
+int x86_32_common_mmu(struct target *t, int *enabled)
+{
+       *enabled = true;
+       return ERROR_OK;
+}
+
+int x86_32_common_virt2phys(struct target *t, uint32_t address, uint32_t *physical)
+{
+       struct x86_32_common *x86_32 = target_to_x86_32(t);
+
+       /*
+        * We need to ignore 'segmentation' for now, as OpenOCD can't handle
+        * segmented addresses.
+        * In protected mode that is almost OK, as (almost) any known OS is using
+        * flat segmentation. In real mode we use use the base of the DS segment,
+        * as we don't know better ...
+        */
+
+       uint32_t cr0 = buf_get_u32(x86_32->cache->reg_list[CR0].value, 0, 32);
+       if (!(cr0 & CR0_PG)) {
+               /* target halted in real mode */
+               /* TODO: needs validation !!! */
+               uint32_t dsb = buf_get_u32(x86_32->cache->reg_list[DSB].value, 0, 32);
+               *physical = dsb + address;
+
+       } else {
+               /* target halted in protected mode */
+               if (calcaddr_pyhsfromlin(t, address, physical) != ERROR_OK) {
+                       LOG_ERROR("%s failed to calculate physical address from 0x%08" PRIx32,
+                                       __func__, address);
+                       return ERROR_FAIL;
+               }
+       }
+       return ERROR_OK;
+}
+
+int x86_32_common_read_phys_mem(struct target *t, uint32_t phys_address,
+                       uint32_t size, uint32_t count, uint8_t *buffer)
+{
+       struct x86_32_common *x86_32 = target_to_x86_32(t);
+       int error;
+
+       error = read_phys_mem(t, phys_address, size, count, buffer);
+       if (error != ERROR_OK)
+               return error;
+
+       /* After reading memory from target, we must replace software breakpoints
+        * with the original instructions again.
+        */
+       struct swbp_mem_patch *iter = x86_32->swbbp_mem_patch_list;
+       while (iter != NULL) {
+               if (iter->physaddr >= phys_address && iter->physaddr < phys_address+(size*count)) {
+                       uint32_t offset = iter->physaddr - phys_address;
+                       buffer[offset] = iter->orig_byte;
+               }
+               iter = iter->next;
+       }
+       return ERROR_OK;
+}
+
+static int read_phys_mem(struct target *t, uint32_t phys_address,
+                       uint32_t size, uint32_t count, uint8_t *buffer)
+{
+       int retval = ERROR_OK;
+       bool pg_disabled = false;
+       LOG_DEBUG("addr=%08" PRIx32 ", size=%d, count=%d, buf=%p",
+                       phys_address, size, count, buffer);
+       struct x86_32_common *x86_32 = target_to_x86_32(t);
+
+       if (check_not_halted(t))
+               return ERROR_TARGET_NOT_HALTED;
+       if (!count || !buffer || !phys_address) {
+               LOG_ERROR("%s invalid params count=%d, buf=%p, addr=%08" PRIx32,
+                               __func__, count, buffer, phys_address);
+               return ERROR_COMMAND_ARGUMENT_INVALID;
+       }
+
+       /* to access physical memory, switch off the CR0.PG bit */
+       if (x86_32->is_paging_enabled(t)) {
+               retval = x86_32->disable_paging(t);
+               if (retval != ERROR_OK)
+                       return retval;
+               pg_disabled = true;
+       }
+
+       for (uint32_t i = 0; i < count; i++) {
+               switch (size) {
+               case BYTE:
+                       retval = read_mem(t, size, phys_address + i, buffer + i);
+                       break;
+               case WORD:
+                       retval = read_mem(t, size, phys_address + i * 2, buffer + i * 2);
+                       break;
+               case DWORD:
+                       retval = read_mem(t, size, phys_address + i * 4, buffer + i * 4);
+                       break;
+               default:
+                       LOG_ERROR("%s invalid read size", __func__);
+                       break;
+               }
+       }
+       /* restore CR0.PG bit if needed (regardless of retval) */
+       if (pg_disabled) {
+               retval = x86_32->enable_paging(t);
+               if (retval != ERROR_OK)
+                       return retval;
+               pg_disabled = true;
+       }
+       /* TODO: After reading memory from target, we must replace
+        * software breakpoints with the original instructions again.
+        * Solve this with the breakpoint fix
+        */
+       return retval;
+}
+
+int x86_32_common_write_phys_mem(struct target *t, uint32_t phys_address,
+                       uint32_t size, uint32_t count, const uint8_t *buffer)
+{
+       struct x86_32_common *x86_32 = target_to_x86_32(t);
+       int error = ERROR_OK;
+       uint8_t *newbuffer = NULL;
+
+       check_not_halted(t);
+       if (!count || !buffer || !phys_address) {
+               LOG_ERROR("%s invalid params count=%d, buf=%p, addr=%08" PRIx32,
+                               __func__, count, buffer, phys_address);
+               return ERROR_COMMAND_ARGUMENT_INVALID;
+       }
+       /* Before writing memory to target, we must update software breakpoints
+        * with the new instructions and patch the memory buffer with the
+        * breakpoint instruction.
+        */
+       newbuffer = malloc(size*count);
+       if (newbuffer == NULL) {
+               LOG_ERROR("%s out of memory", __func__);
+               return ERROR_FAIL;
+       }
+       memcpy(newbuffer, buffer, size*count);
+       struct swbp_mem_patch *iter = x86_32->swbbp_mem_patch_list;
+       while (iter != NULL) {
+               if (iter->physaddr >= phys_address && iter->physaddr < phys_address+(size*count)) {
+                       uint32_t offset = iter->physaddr - phys_address;
+                       newbuffer[offset] = SW_BP_OPCODE;
+
+                       /* update the breakpoint */
+                       struct breakpoint *pbiter = t->breakpoints;
+                       while (pbiter != NULL && pbiter->unique_id != iter->swbp_unique_id)
+                               pbiter = pbiter->next;
+                       if (pbiter)
+                               pbiter->orig_instr[0] = buffer[offset];
+               }
+               iter = iter->next;
+       }
+
+       error = write_phys_mem(t, phys_address, size, count, newbuffer);
+       free(newbuffer);
+       return error;
+}
+
+static int write_phys_mem(struct target *t, uint32_t phys_address,
+                       uint32_t size, uint32_t count, const uint8_t *buffer)
+{
+       int retval = ERROR_OK;
+       bool pg_disabled = false;
+       struct x86_32_common *x86_32 = target_to_x86_32(t);
+       LOG_DEBUG("addr=%08" PRIx32 ", size=%d, count=%d, buf=%p",
+                       phys_address, size, count, buffer);
+
+       check_not_halted(t);
+       if (!count || !buffer || !phys_address) {
+               LOG_ERROR("%s invalid params count=%d, buf=%p, addr=%08" PRIx32,
+                               __func__, count, buffer, phys_address);
+               return ERROR_COMMAND_ARGUMENT_INVALID;
+       }
+       /* TODO: Before writing memory to target, we must update
+        * software breakpoints with the new instructions and
+        * patch the memory buffer with the breakpoint instruction.
+        * Solve this with the breakpoint fix
+        */
+
+       /* to access physical memory, switch off the CR0.PG bit */
+       if (x86_32->is_paging_enabled(t)) {
+               retval = x86_32->disable_paging(t);
+               if (retval != ERROR_OK)
+                       return retval;
+               pg_disabled = true;
+       }
+       for (uint32_t i = 0; i < count; i++) {
+               switch (size) {
+               case BYTE:
+                       retval = write_mem(t, size, phys_address + i, buffer + i);
+                       break;
+               case WORD:
+                       retval = write_mem(t, size, phys_address + i * 2, buffer + i * 2);
+                       break;
+               case DWORD:
+                       retval = write_mem(t, size, phys_address + i * 4, buffer + i * 4);
+                       break;
+               default:
+                       LOG_DEBUG("invalid read size");
+                       break;
+               }
+       }
+       /* restore CR0.PG bit if needed (regardless of retval) */
+       if (pg_disabled) {
+               retval = x86_32->enable_paging(t);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+       return retval;
+}
+
+static int read_mem(struct target *t, uint32_t size,
+                       uint32_t addr, uint8_t *buf)
+{
+       struct x86_32_common *x86_32 = target_to_x86_32(t);
+
+       /* if CS.D bit=1 then its a 32 bit code segment, else 16 */
+       bool use32 = (buf_get_u32(x86_32->cache->reg_list[CSAR].value, 0, 32)) & CSAR_D;
+       int retval = x86_32->write_hw_reg(t, EAX, addr, 0);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("%s error write EAX", __func__);
+               return retval;
+       }
+
+       switch (size) {
+               case BYTE:
+                       if (use32)
+                               retval = x86_32->submit_instruction(t, MEMRDB32);
+                       else
+                               retval = x86_32->submit_instruction(t, MEMRDB16);
+                       break;
+               case WORD:
+                       if (use32)
+                               retval = x86_32->submit_instruction(t, MEMRDH32);
+                       else
+                               retval = x86_32->submit_instruction(t, MEMRDH16);
+                       break;
+               case DWORD:
+                       if (use32)
+                               retval = x86_32->submit_instruction(t, MEMRDW32);
+                       else
+                               retval = x86_32->submit_instruction(t, MEMRDW16);
+                       break;
+               default:
+                       LOG_ERROR("%s invalid read mem size", __func__);
+                       break;
+       }
+
+       /* read_hw_reg() will write to 4 bytes (uint32_t)
+        * Watch out, the buffer passed into read_mem() might be 1 or 2 bytes.
+        */
+       uint32_t regval;
+       retval = x86_32->read_hw_reg(t, EDX, &regval, 0);
+
+       if (retval != ERROR_OK) {
+               LOG_ERROR("%s error read EDX", __func__);
+               return retval;
+       }
+       for (uint8_t i = 0; i < size; i++)
+               buf[i] = (regval >> (i*8)) & 0x000000FF;
+
+       retval = x86_32->transaction_status(t);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("%s error on mem read", __func__);
+               return retval;
+       }
+       return retval;
+}
+
+static int write_mem(struct target *t, uint32_t size,
+                       uint32_t addr, const uint8_t *buf)
+{
+       uint32_t i = 0;
+       uint32_t buf4bytes = 0;
+       int retval = ERROR_OK;
+       struct x86_32_common *x86_32 = target_to_x86_32(t);
+
+       for (i = 0; i < size; ++i) {
+               buf4bytes = buf4bytes << 8; /* first time we only shift 0s */
+               buf4bytes += buf[(size-1)-i]; /* it was hard to write, should be hard to read! */
+       }
+       /* if CS.D bit=1 then its a 32 bit code segment, else 16 */
+       bool use32 = (buf_get_u32(x86_32->cache->reg_list[CSAR].value, 0, 32)) & CSAR_D;
+       retval = x86_32->write_hw_reg(t, EAX, addr, 0);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("%s error write EAX", __func__);
+               return retval;
+       }
+
+       /* write_hw_reg() will write to 4 bytes (uint32_t)
+        * Watch out, the buffer passed into write_mem() might be 1 or 2 bytes.
+        */
+       retval = x86_32->write_hw_reg(t, EDX, buf4bytes, 0);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("%s error write EDX", __func__);
+               return retval;
+       }
+       switch (size) {
+               case BYTE:
+                       if (use32)
+                               retval = x86_32->submit_instruction(t, MEMWRB32);
+                       else
+                               retval = x86_32->submit_instruction(t, MEMWRB16);
+                       break;
+               case WORD:
+                       if (use32)
+                               retval = x86_32->submit_instruction(t, MEMWRH32);
+                       else
+                               retval = x86_32->submit_instruction(t, MEMWRH16);
+                       break;
+               case DWORD:
+                       if (use32)
+                               retval = x86_32->submit_instruction(t, MEMWRW32);
+                       else
+                               retval = x86_32->submit_instruction(t, MEMWRW16);
+                       break;
+               default:
+                       LOG_ERROR("%s invalid write mem size", __func__);
+                       return ERROR_FAIL;
+       }
+       retval = x86_32->transaction_status(t);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("%s error on mem write", __func__);
+               return retval;
+       }
+       return retval;
+}
+
+int calcaddr_pyhsfromlin(struct target *t, uint32_t addr, uint32_t *physaddr)
+{
+       uint8_t entry_buffer[8];
+
+       if (physaddr == NULL || t == NULL)
+               return ERROR_FAIL;
+
+       struct x86_32_common *x86_32 = target_to_x86_32(t);
+
+       /* The 'user-visible' CR0.PG should be set - otherwise the function shouldn't be called
+        * (Don't check the CR0.PG on the target, this might be temporally disabled at this point)
+        */
+       uint32_t cr0 = buf_get_u32(x86_32->cache->reg_list[CR0].value, 0, 32);
+       if (!(cr0 & CR0_PG)) {
+               /* you are wrong in this function, never mind */
+               *physaddr = addr;
+               return ERROR_OK;
+       }
+
+       uint32_t cr4 = buf_get_u32(x86_32->cache->reg_list[CR4].value, 0, 32);
+       bool isPAE = cr4 & 0x00000020; /* PAE - Physical Address Extension */
+
+       uint32_t cr3 = buf_get_u32(x86_32->cache->reg_list[CR3].value, 0, 32);
+       if (isPAE) {
+               uint32_t pdpt_base = cr3 & 0xFFFFF000; /* lower 12 bits of CR3 must always be 0 */
+               uint32_t pdpt_index = (addr & 0xC0000000) >> 30; /* A[31:30] index to PDPT */
+               uint32_t pdpt_addr = pdpt_base + (8 * pdpt_index);
+               if (x86_32_common_read_phys_mem(t, pdpt_addr, 4, 2, entry_buffer) != ERROR_OK) {
+                       LOG_ERROR("%s couldn't read page directory pointer table entry at 0x%08" PRIx32,
+                                       __func__, pdpt_addr);
+                       return ERROR_FAIL;
+               }
+               uint64_t pdpt_entry = target_buffer_get_u64(t, entry_buffer);
+               if (!(pdpt_entry & 0x0000000000000001)) {
+                       LOG_ERROR("%s page directory pointer table entry at 0x%08" PRIx32 " is not present",
+                                       __func__, pdpt_addr);
+                       return ERROR_FAIL;
+               }
+
+               uint32_t pd_base = pdpt_entry & 0xFFFFF000; /* A[31:12] is PageTable/Page Base Address */
+               uint32_t pd_index = (addr & 0x3FE00000) >> 21; /* A[29:21] index to PD entry with PAE */
+               uint32_t pd_addr = pd_base + (8 * pd_index);
+               if (x86_32_common_read_phys_mem(t, pd_addr, 4, 2, entry_buffer) != ERROR_OK) {
+                       LOG_ERROR("%s couldn't read page directory entry at 0x%08" PRIx32,
+                                       __func__, pd_addr);
+                       return ERROR_FAIL;
+               }
+               uint64_t pd_entry = target_buffer_get_u64(t, entry_buffer);
+               if (!(pd_entry & 0x0000000000000001)) {
+                       LOG_ERROR("%s page directory entry at 0x%08" PRIx32 " is not present",
+                                       __func__, pd_addr);
+                       return ERROR_FAIL;
+               }
+
+               /* PS bit in PD entry is indicating 4KB or 2MB page size */
+               if (pd_entry & 0x0000000000000080) {
+
+                       uint32_t page_base = (uint32_t)(pd_entry & 0x00000000FFE00000); /* [31:21] */
+                       uint32_t offset = addr & 0x001FFFFF; /* [20:0] */
+                       *physaddr = page_base + offset;
+                       return ERROR_OK;
+
+               } else {
+
+                       uint32_t pt_base = (uint32_t)(pd_entry & 0x00000000FFFFF000); /*[31:12]*/
+                       uint32_t pt_index = (addr & 0x001FF000) >> 12; /*[20:12]*/
+                       uint32_t pt_addr = pt_base + (8 * pt_index);
+                       if (x86_32_common_read_phys_mem(t, pt_addr, 4, 2, entry_buffer) != ERROR_OK) {
+                               LOG_ERROR("%s couldn't read page table entry at 0x%08" PRIx32, __func__, pt_addr);
+                               return ERROR_FAIL;
+                       }
+                       uint64_t pt_entry = target_buffer_get_u64(t, entry_buffer);
+                       if (!(pt_entry & 0x0000000000000001)) {
+                               LOG_ERROR("%s page table entry at 0x%08" PRIx32 " is not present", __func__, pt_addr);
+                               return ERROR_FAIL;
+                       }
+
+                       uint32_t page_base = (uint32_t)(pt_entry & 0x00000000FFFFF000); /*[31:12]*/
+                       uint32_t offset =  addr & 0x00000FFF; /*[11:0]*/
+                       *physaddr = page_base + offset;
+                       return ERROR_OK;
+               }
+       } else {
+               uint32_t pd_base = cr3 & 0xFFFFF000; /* lower 12 bits of CR3 must always be 0 */
+               uint32_t pd_index = (addr & 0xFFC00000) >> 22; /* A[31:22] index to PD entry */
+               uint32_t pd_addr = pd_base + (4 * pd_index);
+               if (x86_32_common_read_phys_mem(t, pd_addr, 4, 1, entry_buffer) != ERROR_OK) {
+                       LOG_ERROR("%s couldn't read page directory entry at 0x%08" PRIx32, __func__, pd_addr);
+                       return ERROR_FAIL;
+               }
+               uint32_t pd_entry = target_buffer_get_u32(t, entry_buffer);
+               if (!(pd_entry & 0x00000001)) {
+                       LOG_ERROR("%s page directory entry at 0x%08" PRIx32 " is not present", __func__, pd_addr);
+                       return ERROR_FAIL;
+               }
+
+               /* Bit 7 in page directory entry is page size.
+                */
+               if (pd_entry & 0x00000080) {
+                       /* 4MB pages */
+                       uint32_t page_base = pd_entry & 0xFFC00000;
+                       *physaddr = page_base + (addr & 0x003FFFFF);
+
+               } else {
+                       /* 4KB pages */
+                       uint32_t pt_base = pd_entry & 0xFFFFF000; /* A[31:12] is PageTable/Page Base Address */
+                       uint32_t pt_index = (addr & 0x003FF000) >> 12; /* A[21:12] index to page table entry */
+                       uint32_t pt_addr = pt_base + (4 * pt_index);
+                       if (x86_32_common_read_phys_mem(t, pt_addr, 4, 1, entry_buffer) != ERROR_OK) {
+                               LOG_ERROR("%s couldn't read page table entry at 0x%08" PRIx32, __func__, pt_addr);
+                               return ERROR_FAIL;
+                       }
+                       uint32_t pt_entry = target_buffer_get_u32(t, entry_buffer);
+                       if (!(pt_entry & 0x00000001)) {
+                               LOG_ERROR("%s page table entry at 0x%08" PRIx32 " is not present", __func__, pt_addr);
+                               return ERROR_FAIL;
+                       }
+                       uint32_t page_base = pt_entry & 0xFFFFF000; /* A[31:12] is PageTable/Page Base Address */
+                       *physaddr = page_base + (addr & 0x00000FFF); /* A[11:0] offset to 4KB page in linear address */
+               }
+       }
+       return ERROR_OK;
+}
+
+int x86_32_common_read_memory(struct target *t, uint32_t addr,
+                       uint32_t size, uint32_t count, uint8_t *buf)
+{
+       int retval = ERROR_OK;
+       struct x86_32_common *x86_32 = target_to_x86_32(t);
+       LOG_DEBUG("addr=%08" PRIx32 ", size=%d, count=%d, buf=%p",
+                       addr, size, count, buf);
+       check_not_halted(t);
+       if (!count || !buf || !addr) {
+               LOG_ERROR("%s invalid params count=%d, buf=%p, addr=%08" PRIx32,
+                               __func__, count, buf, addr);
+               return ERROR_COMMAND_ARGUMENT_INVALID;
+       }
+
+       if (x86_32->is_paging_enabled(t)) {
+               /* all memory accesses from debugger must be physical (CR0.PG == 0)
+                * conversion to physical address space needed
+                */
+               retval = x86_32->disable_paging(t);
+               if (retval != ERROR_OK)
+                       return retval;
+               uint32_t physaddr = 0;
+               if (calcaddr_pyhsfromlin(t, addr, &physaddr) != ERROR_OK) {
+                       LOG_ERROR("%s failed to calculate physical address from 0x%08" PRIx32, __func__, addr);
+                       retval = ERROR_FAIL;
+               }
+               /* TODO: !!! Watch out for page boundaries
+                * for every 4kB, the physical address has to be re-calculated
+                * This should be fixed together with bulk memory reads
+                */
+
+               if (retval == ERROR_OK
+                       && x86_32_common_read_phys_mem(t, physaddr, size, count, buf) != ERROR_OK) {
+                       LOG_ERROR("%s failed to read memory from physical address 0x%08" PRIx32, __func__, physaddr);
+                       retval = ERROR_FAIL;
+               }
+               /* restore PG bit if it was cleared prior (regardless of retval) */
+               retval = x86_32->enable_paging(t);
+               if (retval != ERROR_OK)
+                       return retval;
+       } else {
+               /* paging is off - linear address is physical address */
+               if (x86_32_common_read_phys_mem(t, addr, size, count, buf) != ERROR_OK) {
+                       LOG_ERROR("%s failed to read memory from address 0%08" PRIx32, __func__, addr);
+                       retval = ERROR_FAIL;
+               }
+       }
+
+       return retval;
+}
+
+int x86_32_common_write_memory(struct target *t, uint32_t addr,
+                       uint32_t size, uint32_t count, const uint8_t *buf)
+{
+       int retval = ERROR_OK;
+       struct x86_32_common *x86_32 = target_to_x86_32(t);
+       LOG_DEBUG("addr=%08" PRIx32 ", size=%d, count=%d, buf=%p",
+                       addr, size, count, buf);
+       check_not_halted(t);
+       if (!count || !buf || !addr) {
+               LOG_ERROR("%s invalid params count=%d, buf=%p, addr=%08" PRIx32,
+                                       __func__, count, buf, addr);
+               return ERROR_COMMAND_ARGUMENT_INVALID;
+       }
+       if (x86_32->is_paging_enabled(t)) {
+               /* all memory accesses from debugger must be physical (CR0.PG == 0)
+                * conversion to physical address space needed
+                */
+               retval = x86_32->disable_paging(t);
+               if (retval != ERROR_OK)
+                       return retval;
+               uint32_t physaddr = 0;
+               if (calcaddr_pyhsfromlin(t, addr, &physaddr) != ERROR_OK) {
+                       LOG_ERROR("%s failed to calculate physical address from 0x%08" PRIx32,
+                                       __func__, addr);
+                       retval = ERROR_FAIL;
+               }
+               /* TODO: !!! Watch out for page boundaries
+                * for every 4kB, the physical address has to be re-calculated
+                * This should be fixed together with bulk memory reads
+                */
+               if (retval == ERROR_OK
+                       && x86_32_common_write_phys_mem(t, physaddr, size, count, buf) != ERROR_OK) {
+                       LOG_ERROR("%s failed to write memory to physical address 0x%08" PRIx32,
+                                       __func__, physaddr);
+                       retval = ERROR_FAIL;
+               }
+               /* restore PG bit if it was cleared prior (regardless of retval) */
+               retval = x86_32->enable_paging(t);
+               if (retval != ERROR_OK)
+                       return retval;
+       } else {
+
+               /* paging is off - linear address is physical address */
+               if (x86_32_common_write_phys_mem(t, addr, size, count, buf) != ERROR_OK) {
+                       LOG_ERROR("%s failed to write memory to address 0x%08" PRIx32,
+                                       __func__, addr);
+                       retval = ERROR_FAIL;
+               }
+       }
+       return retval;
+}
+
+int x86_32_common_read_io(struct target *t, uint32_t addr,
+                       uint32_t size, uint8_t *buf)
+{
+       struct x86_32_common *x86_32 = target_to_x86_32(t);
+       /* if CS.D bit=1 then its a 32 bit code segment, else 16 */
+       bool use32 = (buf_get_u32(x86_32->cache->reg_list[CSAR].value, 0, 32)) & CSAR_D;
+       int retval = ERROR_FAIL;
+       LOG_DEBUG("addr=%08" PRIx32 ", size=%d, buf=%p", addr, size, buf);
+       check_not_halted(t);
+       if (!buf || !addr) {
+               LOG_ERROR("%s invalid params buf=%p, addr=%08" PRIx32, __func__, buf, addr);
+               return retval;
+       }
+       retval = x86_32->write_hw_reg(t, EDX, addr, 0);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("%s error EDX write", __func__);
+               return retval;
+       }
+       switch (size) {
+               case BYTE:
+                       if (use32)
+                               retval = x86_32->submit_instruction(t, IORDB32);
+                       else
+                               retval = x86_32->submit_instruction(t, IORDB16);
+                       break;
+               case WORD:
+                       if (use32)
+                               retval = x86_32->submit_instruction(t, IORDH32);
+                       else
+                               retval = x86_32->submit_instruction(t, IORDH16);
+                       break;
+               case DWORD:
+                       if (use32)
+                               retval = x86_32->submit_instruction(t, IORDW32);
+                       else
+                               retval = x86_32->submit_instruction(t, IORDW16);
+                       break;
+               default:
+                       LOG_ERROR("%s invalid read io size", __func__);
+                       return ERROR_FAIL;
+       }
+       uint32_t regval = 0;
+       retval = x86_32->read_hw_reg(t, EAX, &regval, 0);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("%s error on read EAX", __func__);
+               return retval;
+       }
+       for (uint8_t i = 0; i < size; i++)
+               buf[i] = (regval >> (i*8)) & 0x000000FF;
+       retval = x86_32->transaction_status(t);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("%s error on io read", __func__);
+               return retval;
+       }
+       return retval;
+}
+
+int x86_32_common_write_io(struct target *t, uint32_t addr,
+                       uint32_t size, const uint8_t *buf)
+{
+       struct x86_32_common *x86_32 = target_to_x86_32(t);
+       /* if CS.D bit=1 then its a 32 bit code segment, else 16 */
+       bool use32 = (buf_get_u32(x86_32->cache->reg_list[CSAR].value, 0, 32)) & CSAR_D;
+       LOG_DEBUG("addr=%08" PRIx32 ", size=%d, buf=%p", addr, size, buf);
+       check_not_halted(t);
+       int retval = ERROR_FAIL;
+       if (!buf || !addr) {
+               LOG_ERROR("%s invalid params buf=%p, addr=%08" PRIx32, __func__, buf, addr);
+               return retval;
+       }
+       /* no do the write */
+       retval = x86_32->write_hw_reg(t, EDX, addr, 0);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("%s error on EDX write", __func__);
+               return retval;
+       }
+       uint32_t regval = 0;
+       for (uint8_t i = 0; i < size; i++)
+               regval += (buf[i] << (i*8));
+       retval = x86_32->write_hw_reg(t, EAX, regval, 0);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("%s error on EAX write", __func__);
+               return retval;
+       }
+       switch (size) {
+               case BYTE:
+                       if (use32)
+                               retval = x86_32->submit_instruction(t, IOWRB32);
+                       else
+                               retval = x86_32->submit_instruction(t, IOWRB16);
+                       break;
+               case WORD:
+                       if (use32)
+                               retval = x86_32->submit_instruction(t, IOWRH32);
+                       else
+                               retval = x86_32->submit_instruction(t, IOWRH16);
+                       break;
+               case DWORD:
+                       if (use32)
+                               retval = x86_32->submit_instruction(t, IOWRW32);
+                       else
+                               retval = x86_32->submit_instruction(t, IOWRW16);
+                       break;
+               default:
+                       LOG_ERROR("%s invalid write io size", __func__);
+                       return ERROR_FAIL;
+       }
+       retval = x86_32->transaction_status(t);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("%s error on io write", __func__);
+               return retval;
+       }
+       return retval;
+}
+
+int x86_32_common_add_watchpoint(struct target *t, struct watchpoint *wp)
+{
+       check_not_halted(t);
+       /* set_watchpoint() will return ERROR_TARGET_RESOURCE_NOT_AVAILABLE if all
+        * hardware registers are gone
+        */
+       return set_watchpoint(t, wp);
+}
+
+int x86_32_common_remove_watchpoint(struct target *t, struct watchpoint *wp)
+{
+       if (check_not_halted(t))
+               return ERROR_TARGET_NOT_HALTED;
+       if (wp->set)
+               unset_watchpoint(t, wp);
+       return ERROR_OK;
+}
+
+int x86_32_common_add_breakpoint(struct target *t, struct breakpoint *bp)
+{
+       LOG_DEBUG("type=%d, addr=%08" PRIx32, bp->type, bp->address);
+       if (check_not_halted(t))
+               return ERROR_TARGET_NOT_HALTED;
+       /* set_breakpoint() will return ERROR_TARGET_RESOURCE_NOT_AVAILABLE if all
+        * hardware registers are gone (for hardware breakpoints)
+        */
+       return set_breakpoint(t, bp);
+}
+
+int x86_32_common_remove_breakpoint(struct target *t, struct breakpoint *bp)
+{
+       LOG_DEBUG("type=%d, addr=%08" PRIx32, bp->type, bp->address);
+       if (check_not_halted(t))
+               return ERROR_TARGET_NOT_HALTED;
+       if (bp->set)
+               unset_breakpoint(t, bp);
+
+       return ERROR_OK;
+}
+
+static int set_debug_regs(struct target *t, uint32_t address,
+                       uint8_t bp_num, uint8_t bp_type, uint8_t bp_length)
+{
+       struct x86_32_common *x86_32 = target_to_x86_32(t);
+       LOG_DEBUG("addr=%08" PRIx32 ", bp_num=%d, bp_type=%d, pb_length=%d",
+                       address, bp_num, bp_type, bp_length);
+
+       /* DR7 - set global enable */
+       uint32_t dr7 = buf_get_u32(x86_32->cache->reg_list[DR7].value, 0, 32);
+
+       if (bp_length != 1 && bp_length != 2 && bp_length != 4)
+               return ERROR_FAIL;
+
+       if (DR7_BP_FREE(dr7, bp_num))
+               DR7_GLOBAL_ENABLE(dr7, bp_num);
+       else {
+               LOG_ERROR("%s dr7 error, already enabled, val=%08" PRIx32, __func__, dr7);
+               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+       }
+
+       switch (bp_type) {
+               case 0:
+                       /* 00 - only on instruction execution */
+                       DR7_SET_EXE(dr7, bp_num);
+                       DR7_SET_LENGTH(dr7, bp_num, bp_length);
+               break;
+               case 1:
+                       /* 01 - only on data writes */
+                       DR7_SET_WRITE(dr7, bp_num);
+                       DR7_SET_LENGTH(dr7, bp_num, bp_length);
+               break;
+               case 2:
+                       /* 10 UNSUPPORTED - an I/O read and I/O write */
+                       LOG_ERROR("%s unsupported feature bp_type=%d", __func__, bp_type);
+                       return ERROR_FAIL;
+               break;
+               case 3:
+                       /* on data read or data write */
+                       DR7_SET_ACCESS(dr7, bp_num);
+                       DR7_SET_LENGTH(dr7, bp_num, bp_length);
+               break;
+               default:
+                       LOG_ERROR("%s invalid request [only 0-3] bp_type=%d", __func__, bp_type);
+                       return ERROR_FAIL;
+       }
+
+       /* update regs in the reg cache ready to be written to hardware
+        * when we exit PM
+       */
+       buf_set_u32(x86_32->cache->reg_list[bp_num+DR0].value, 0, 32, address);
+       x86_32->cache->reg_list[bp_num+DR0].dirty = 1;
+       x86_32->cache->reg_list[bp_num+DR0].valid = 1;
+       buf_set_u32(x86_32->cache->reg_list[DR6].value, 0, 32, PM_DR6);
+       x86_32->cache->reg_list[DR6].dirty = 1;
+       x86_32->cache->reg_list[DR6].valid = 1;
+       buf_set_u32(x86_32->cache->reg_list[DR7].value, 0, 32, dr7);
+       x86_32->cache->reg_list[DR7].dirty = 1;
+       x86_32->cache->reg_list[DR7].valid = 1;
+       return ERROR_OK;
+}
+
+static int unset_debug_regs(struct target *t, uint8_t bp_num)
+{
+       struct x86_32_common *x86_32 = target_to_x86_32(t);
+       LOG_DEBUG("bp_num=%d", bp_num);
+
+       uint32_t dr7 = buf_get_u32(x86_32->cache->reg_list[DR7].value, 0, 32);
+
+       if (!(DR7_BP_FREE(dr7, bp_num))) {
+               DR7_GLOBAL_DISABLE(dr7, bp_num);
+       } else {
+               LOG_ERROR("%s dr7 error, not enabled, val=%08" PRIx32, __func__, dr7);
+               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+       }
+       /* this will clear rw and len bits */
+       DR7_RESET_RWLEN_BITS(dr7, bp_num);
+
+       /* update regs in the reg cache ready to be written to hardware
+        * when we exit PM
+       */
+       buf_set_u32(x86_32->cache->reg_list[bp_num+DR0].value, 0, 32, 0);
+       x86_32->cache->reg_list[bp_num+DR0].dirty = 1;
+       x86_32->cache->reg_list[bp_num+DR0].valid = 1;
+       buf_set_u32(x86_32->cache->reg_list[DR6].value, 0, 32, PM_DR6);
+       x86_32->cache->reg_list[DR6].dirty = 1;
+       x86_32->cache->reg_list[DR6].valid = 1;
+       buf_set_u32(x86_32->cache->reg_list[DR7].value, 0, 32, dr7);
+       x86_32->cache->reg_list[DR7].dirty = 1;
+       x86_32->cache->reg_list[DR7].valid = 1;
+       return ERROR_OK;
+}
+
+static int set_hwbp(struct target *t, struct breakpoint *bp)
+{
+       struct x86_32_common *x86_32 = target_to_x86_32(t);
+       struct x86_32_dbg_reg *debug_reg_list = x86_32->hw_break_list;
+       uint8_t hwbp_num = 0;
+
+       while (debug_reg_list[hwbp_num].used && (hwbp_num < x86_32->num_hw_bpoints))
+               hwbp_num++;
+       if (hwbp_num >= x86_32->num_hw_bpoints) {
+               LOG_ERROR("%s no free hw breakpoint bpid=%d", __func__, bp->unique_id);
+               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+       }
+       if (set_debug_regs(t, bp->address, hwbp_num, DR7_BP_EXECUTE, 1) != ERROR_OK)
+               return ERROR_FAIL;
+       bp->set = hwbp_num + 1;
+       debug_reg_list[hwbp_num].used = 1;
+       debug_reg_list[hwbp_num].bp_value = bp->address;
+       LOG_USER("%s hardware breakpoint %d set at 0x%08" PRIx32 " (hwreg=%d)", __func__,
+                       bp->unique_id, debug_reg_list[hwbp_num].bp_value, hwbp_num);
+       return ERROR_OK;
+}
+
+static int unset_hwbp(struct target *t, struct breakpoint *bp)
+{
+       struct x86_32_common *x86_32 = target_to_x86_32(t);
+       struct x86_32_dbg_reg *debug_reg_list = x86_32->hw_break_list;
+       int hwbp_num = bp->set - 1;
+
+       if ((hwbp_num < 0) || (hwbp_num >= x86_32->num_hw_bpoints)) {
+               LOG_ERROR("%s invalid breakpoint number=%d, bpid=%d",
+                               __func__, hwbp_num, bp->unique_id);
+               return ERROR_OK;
+       }
+
+       if (unset_debug_regs(t, hwbp_num) != ERROR_OK)
+               return ERROR_FAIL;
+       debug_reg_list[hwbp_num].used = 0;
+       debug_reg_list[hwbp_num].bp_value = 0;
+
+       LOG_USER("%s hardware breakpoint %d removed from 0x%08" PRIx32 " (hwreg=%d)",
+                       __func__, bp->unique_id, bp->address, hwbp_num);
+       return ERROR_OK;
+}
+
+static int set_swbp(struct target *t, struct breakpoint *bp)
+{
+       struct x86_32_common *x86_32 = target_to_x86_32(t);
+       LOG_DEBUG("id %d", bp->unique_id);
+       uint32_t physaddr;
+       uint8_t opcode = SW_BP_OPCODE;
+       uint8_t readback;
+
+       if (calcaddr_pyhsfromlin(t, bp->address, &physaddr) != ERROR_OK)
+               return ERROR_FAIL;
+       if (read_phys_mem(t, physaddr, 1, 1, bp->orig_instr))
+               return ERROR_FAIL;
+
+       LOG_DEBUG("set software breakpoint - orig byte=%02" PRIx8 "", *bp->orig_instr);
+
+       /* just write the instruction trap byte */
+       if (write_phys_mem(t, physaddr, 1, 1, &opcode))
+               return ERROR_FAIL;
+
+       /* verify that this is not invalid/read-only memory */
+       if (read_phys_mem(t, physaddr, 1, 1, &readback))
+               return ERROR_FAIL;
+
+       if (readback != SW_BP_OPCODE) {
+               LOG_ERROR("%s software breakpoint error at 0x%08" PRIx32 ", check memory",
+                               __func__, bp->address);
+               LOG_ERROR("%s readback=%02" PRIx8 " orig=%02" PRIx8 "",
+                               __func__, readback, *bp->orig_instr);
+               return ERROR_FAIL;
+       }
+       bp->set = SW_BP_OPCODE; /* just non 0 */
+
+       /* add the memory patch */
+       struct swbp_mem_patch *new_patch = malloc(sizeof(struct swbp_mem_patch));
+       if (new_patch == NULL) {
+               LOG_ERROR("%s out of memory", __func__);
+               return ERROR_FAIL;
+       }
+       new_patch->next = NULL;
+       new_patch->orig_byte = *bp->orig_instr;
+       new_patch->physaddr = physaddr;
+       new_patch->swbp_unique_id = bp->unique_id;
+
+       struct swbp_mem_patch *addto = x86_32->swbbp_mem_patch_list;
+       if (addto == NULL)
+               x86_32->swbbp_mem_patch_list = new_patch;
+       else {
+               while (addto->next != NULL)
+                       addto = addto->next;
+               addto->next = new_patch;
+       }
+       LOG_USER("%s software breakpoint %d set at 0x%08" PRIx32,
+                       __func__, bp->unique_id, bp->address);
+       return ERROR_OK;
+}
+
+static int unset_swbp(struct target *t, struct breakpoint *bp)
+{
+       struct x86_32_common *x86_32 = target_to_x86_32(t);
+       LOG_DEBUG("id %d", bp->unique_id);
+       uint32_t physaddr;
+       uint8_t current_instr;
+
+       /* check that user program has not modified breakpoint instruction */
+       if (calcaddr_pyhsfromlin(t, bp->address, &physaddr) != ERROR_OK)
+               return ERROR_FAIL;
+       if (read_phys_mem(t, physaddr, 1, 1, &current_instr))
+               return ERROR_FAIL;
+
+       if (current_instr == SW_BP_OPCODE) {
+               if (write_phys_mem(t, physaddr, 1, 1, bp->orig_instr))
+                       return ERROR_FAIL;
+       } else {
+               LOG_ERROR("%s software breakpoint remove error at 0x%08" PRIx32 ", check memory",
+                               __func__, bp->address);
+               LOG_ERROR("%s current=%02" PRIx8 " orig=%02" PRIx8 "",
+                               __func__, current_instr, *bp->orig_instr);
+               return ERROR_FAIL;
+       }
+
+       /* remove from patch */
+       struct swbp_mem_patch *iter = x86_32->swbbp_mem_patch_list;
+       if (iter != NULL) {
+               if (iter->swbp_unique_id == bp->unique_id) {
+                       /* it's the first item */
+                       x86_32->swbbp_mem_patch_list = iter->next;
+                       free(iter);
+               } else {
+                       while (iter->next != NULL && iter->next->swbp_unique_id != bp->unique_id)
+                               iter = iter->next;
+                       if (iter->next != NULL) {
+                               /* it's the next one */
+                               struct swbp_mem_patch *freeme = iter->next;
+                               iter->next = iter->next->next;
+                               free(freeme);
+                       }
+               }
+       }
+
+       LOG_USER("%s software breakpoint %d removed from 0x%08" PRIx32,
+                       __func__, bp->unique_id, bp->address);
+       return ERROR_OK;
+}
+
+static int set_breakpoint(struct target *t, struct breakpoint *bp)
+{
+       int error = ERROR_OK;
+       struct x86_32_common *x86_32 = target_to_x86_32(t);
+       LOG_DEBUG("type=%d, addr=%08" PRIx32, bp->type, bp->address);
+       if (bp->set) {
+               LOG_ERROR("breakpoint already set");
+               return error;
+       }
+       if (bp->type == BKPT_HARD) {
+               error = set_hwbp(t, bp);
+               if (error != ERROR_OK) {
+                       LOG_ERROR("%s error setting hardware breakpoint at 0x%08" PRIx32,
+                                       __func__, bp->address);
+                       return error;
+               }
+       } else {
+               if (x86_32->sw_bpts_supported(t)) {
+                       error = set_swbp(t, bp);
+                       if (error != ERROR_OK) {
+                               LOG_ERROR("%s error setting software breakpoint at 0x%08" PRIx32,
+                                               __func__, bp->address);
+                               return error;
+                       }
+               } else {
+                       LOG_ERROR("%s core doesn't support SW breakpoints", __func__);
+                       error = ERROR_FAIL;
+                       return ERROR_FAIL;
+               }
+       }
+       return error;
+}
+
+static int unset_breakpoint(struct target *t, struct breakpoint *bp)
+{
+       LOG_DEBUG("type=%d, addr=%08" PRIx32, bp->type, bp->address);
+       if (!bp->set) {
+               LOG_WARNING("breakpoint not set");
+               return ERROR_OK;
+       }
+
+       if (bp->type == BKPT_HARD) {
+               if (unset_hwbp(t, bp) != ERROR_OK) {
+                       LOG_ERROR("%s error removing hardware breakpoint at 0x%08" PRIx32,
+                                       __func__, bp->address);
+                       return ERROR_FAIL;
+               }
+       } else {
+               if (unset_swbp(t, bp) != ERROR_OK) {
+                       LOG_ERROR("%s error removing software breakpoint at 0x%08" PRIx32,
+                                       __func__, bp->address);
+                       return ERROR_FAIL;
+               }
+       }
+       bp->set = 0;
+       return ERROR_OK;
+}
+
+static int set_watchpoint(struct target *t, struct watchpoint *wp)
+{
+       struct x86_32_common *x86_32 = target_to_x86_32(t);
+       struct x86_32_dbg_reg *debug_reg_list = x86_32->hw_break_list;
+       int wp_num = 0;
+       LOG_DEBUG("type=%d, addr=%08" PRIx32, wp->rw, wp->address);
+
+       if (wp->set) {
+               LOG_ERROR("%s watchpoint already set", __func__);
+               return ERROR_OK;
+       }
+
+       if (wp->rw == WPT_READ) {
+               LOG_ERROR("%s no support for 'read' watchpoints, use 'access' or 'write'"
+                               , __func__);
+               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+       }
+
+       while (debug_reg_list[wp_num].used && (wp_num < x86_32->num_hw_bpoints))
+               wp_num++;
+       if (wp_num >= x86_32->num_hw_bpoints) {
+               LOG_ERROR("%s no debug registers left", __func__);
+               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+       }
+
+       if (wp->length != 4 && wp->length != 2 && wp->length != 1) {
+               LOG_ERROR("%s only watchpoints of length 1, 2 or 4 are supported", __func__);
+               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+       }
+
+       switch (wp->rw) {
+               case WPT_WRITE:
+                       if (set_debug_regs(t, wp->address, wp_num,
+                                               DR7_BP_WRITE, wp->length) != ERROR_OK) {
+                               return ERROR_FAIL;
+                       }
+                       break;
+               case WPT_ACCESS:
+                       if (set_debug_regs(t, wp->address, wp_num, DR7_BP_READWRITE,
+                                               wp->length) != ERROR_OK) {
+                               return ERROR_FAIL;
+                       }
+                       break;
+               default:
+                       LOG_ERROR("%s only 'access' or 'write' watchpoints are supported", __func__);
+                       break;
+       }
+       wp->set = wp_num + 1;
+       debug_reg_list[wp_num].used = 1;
+       debug_reg_list[wp_num].bp_value = wp->address;
+       LOG_USER("'%s' watchpoint %d set at 0x%08" PRIx32 " with length %d (hwreg=%d)",
+                       wp->rw == WPT_READ ? "read" : wp->rw == WPT_WRITE ?
+                       "write" : wp->rw == WPT_ACCESS ? "access" : "?",
+                       wp->unique_id, wp->address, wp->length, wp_num);
+       return ERROR_OK;
+}
+
+static int unset_watchpoint(struct target *t, struct watchpoint *wp)
+{
+       struct x86_32_common *x86_32 = target_to_x86_32(t);
+       struct x86_32_dbg_reg *debug_reg_list = x86_32->hw_break_list;
+       LOG_DEBUG("type=%d, addr=%08" PRIx32, wp->rw, wp->address);
+       if (!wp->set) {
+               LOG_WARNING("watchpoint not set");
+               return ERROR_OK;
+       }
+
+       int wp_num = wp->set - 1;
+       if ((wp_num < 0) || (wp_num >= x86_32->num_hw_bpoints)) {
+               LOG_DEBUG("Invalid FP Comparator number in watchpoint");
+               return ERROR_OK;
+       }
+       if (unset_debug_regs(t, wp_num) != ERROR_OK)
+               return ERROR_FAIL;
+
+       debug_reg_list[wp_num].used = 0;
+       debug_reg_list[wp_num].bp_value = 0;
+       wp->set = 0;
+
+       LOG_USER("'%s' watchpoint %d removed from 0x%08" PRIx32 " with length %d (hwreg=%d)",
+                       wp->rw == WPT_READ ? "read" : wp->rw == WPT_WRITE ?
+                       "write" : wp->rw == WPT_ACCESS ? "access" : "?",
+                       wp->unique_id, wp->address, wp->length, wp_num);
+
+       return ERROR_OK;
+}
+
+static int read_hw_reg_to_cache(struct target *t, int num)
+{
+       uint32_t reg_value;
+       struct x86_32_common *x86_32 = target_to_x86_32(t);
+
+       if (check_not_halted(t))
+               return ERROR_TARGET_NOT_HALTED;
+       if ((num < 0) || (num >= x86_32->get_num_user_regs(t)))
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       if (x86_32->read_hw_reg(t, num, &reg_value, 1) != ERROR_OK) {
+               LOG_ERROR("%s fail for %s", x86_32->cache->reg_list[num].name, __func__);
+               return ERROR_FAIL;
+       }
+       LOG_DEBUG("reg %s value 0x%08" PRIx32,
+                       x86_32->cache->reg_list[num].name, reg_value);
+       return ERROR_OK;
+}
+
+static int write_hw_reg_from_cache(struct target *t, int num)
+{
+       struct x86_32_common *x86_32 = target_to_x86_32(t);
+       if (check_not_halted(t))
+               return ERROR_TARGET_NOT_HALTED;
+       if ((num < 0) || (num >= x86_32->get_num_user_regs(t)))
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       if (x86_32->write_hw_reg(t, num, 0, 1) != ERROR_OK) {
+               LOG_ERROR("%s fail for %s", x86_32->cache->reg_list[num].name, __func__);
+               return ERROR_FAIL;
+       }
+       LOG_DEBUG("reg %s value 0x%08" PRIx32, x86_32->cache->reg_list[num].name,
+                       buf_get_u32(x86_32->cache->reg_list[num].value, 0, 32));
+       return ERROR_OK;
+}
+
+/* x86 32 commands */
+static void handle_iod_output(struct command_context *cmd_ctx,
+               struct target *target, uint32_t address, unsigned size,
+               unsigned count, const uint8_t *buffer)
+{
+       const unsigned line_bytecnt = 32;
+       unsigned line_modulo = line_bytecnt / size;
+
+       char output[line_bytecnt * 4 + 1];
+       unsigned output_len = 0;
+
+       const char *value_fmt;
+       switch (size) {
+       case 4:
+               value_fmt = "%8.8x ";
+               break;
+       case 2:
+               value_fmt = "%4.4x ";
+               break;
+       case 1:
+               value_fmt = "%2.2x ";
+               break;
+       default:
+               /* "can't happen", caller checked */
+               LOG_ERROR("%s invalid memory read size: %u", __func__, size);
+               return;
+       }
+
+       for (unsigned i = 0; i < count; i++) {
+               if (i % line_modulo == 0) {
+                       output_len += snprintf(output + output_len,
+                                       sizeof(output) - output_len,
+                                       "0x%8.8x: ",
+                                       (unsigned)(address + (i*size)));
+               }
+
+               uint32_t value = 0;
+               const uint8_t *value_ptr = buffer + i * size;
+               switch (size) {
+               case 4:
+                       value = target_buffer_get_u32(target, value_ptr);
+                       break;
+               case 2:
+                       value = target_buffer_get_u16(target, value_ptr);
+                       break;
+               case 1:
+                       value = *value_ptr;
+               }
+               output_len += snprintf(output + output_len,
+                               sizeof(output) - output_len,
+                               value_fmt, value);
+
+               if ((i % line_modulo == line_modulo - 1) || (i == count - 1)) {
+                       command_print(cmd_ctx, "%s", output);
+                       output_len = 0;
+               }
+       }
+}
+
+COMMAND_HANDLER(handle_iod_command)
+{
+       if (CMD_ARGC != 1)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       uint32_t address;
+       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address);
+       if (address > 0xffff) {
+               LOG_ERROR("%s IA-32 I/O space is 2^16, %08" PRIx32 " exceeds max", __func__, address);
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+
+       unsigned size = 0;
+       switch (CMD_NAME[2]) {
+       case 'w':
+               size = 4;
+               break;
+       case 'h':
+               size = 2;
+               break;
+       case 'b':
+               size = 1;
+               break;
+       default:
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+       unsigned count = 1;
+       uint8_t *buffer = calloc(count, size);
+       struct target *target = get_current_target(CMD_CTX);
+       int retval = x86_32_common_read_io(target, address, size, buffer);
+       if (ERROR_OK == retval)
+               handle_iod_output(CMD_CTX, target, address, size, count, buffer);
+       free(buffer);
+       return retval;
+}
+
+static int target_fill_io(struct target *target,
+               uint32_t address,
+               unsigned data_size,
+               /* value */
+               uint32_t b)
+{
+       LOG_DEBUG("address=%08X, data_size=%d, b=%08X",
+                       address, data_size, b);
+       uint8_t target_buf[data_size];
+       switch (data_size) {
+       case 4:
+               target_buffer_set_u32(target, target_buf, b);
+               break;
+       case 2:
+               target_buffer_set_u16(target, target_buf, b);
+               break;
+       case 1:
+               target_buf[0] = (b & 0x0ff);
+               break;
+       default:
+               exit(-1);
+       }
+       return x86_32_common_write_io(target, address, data_size, target_buf);
+}
+
+COMMAND_HANDLER(handle_iow_command)
+{
+       if (CMD_ARGC != 2)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       uint32_t address;
+       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address);
+       uint32_t value;
+       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value);
+       struct target *target = get_current_target(CMD_CTX);
+
+       unsigned wordsize;
+       switch (CMD_NAME[2]) {
+               case 'w':
+                       wordsize = 4;
+                       break;
+               case 'h':
+                       wordsize = 2;
+                       break;
+               case 'b':
+                       wordsize = 1;
+                       break;
+               default:
+                       return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+       return target_fill_io(target, address, wordsize, value);
+}
+
+static const struct command_registration x86_32_exec_command_handlers[] = {
+       {
+               .name = "iww",
+               .mode = COMMAND_EXEC,
+               .handler = handle_iow_command,
+               .help = "write I/O port word",
+               .usage = "port data[word]",
+       },
+       {
+               .name = "iwh",
+               .mode = COMMAND_EXEC,
+               .handler = handle_iow_command,
+               .help = "write I/O port halfword",
+               .usage = "port data[halfword]",
+       },
+       {
+               .name = "iwb",
+               .mode = COMMAND_EXEC,
+               .handler = handle_iow_command,
+               .help = "write I/O port byte",
+               .usage = "port data[byte]",
+       },
+       {
+               .name = "idw",
+               .mode = COMMAND_EXEC,
+               .handler = handle_iod_command,
+               .help = "display I/O port word",
+               .usage = "port",
+       },
+       {
+               .name = "idh",
+               .mode = COMMAND_EXEC,
+               .handler = handle_iod_command,
+               .help = "display I/O port halfword",
+               .usage = "port",
+       },
+       {
+               .name = "idb",
+               .mode = COMMAND_EXEC,
+               .handler = handle_iod_command,
+               .help = "display I/O port byte",
+               .usage = "port",
+       },
+
+       COMMAND_REGISTRATION_DONE
+};
+
+const struct command_registration x86_32_command_handlers[] = {
+       {
+               .name = "x86_32",
+               .mode = COMMAND_ANY,
+               .help = "x86_32 target commands",
+               .usage = "",
+               .chain = x86_32_exec_command_handlers,
+       },
+       COMMAND_REGISTRATION_DONE
+};
diff --git a/src/target/x86_32_common.h b/src/target/x86_32_common.h
new file mode 100644 (file)
index 0000000..ef5a9cc
--- /dev/null
@@ -0,0 +1,323 @@
+/*
+ * Copyright(c) 2013 Intel Corporation.
+ *
+ * Adrian Burns (adrian.burns@intel.com)
+ * Thomas Faust (thomas.faust@intel.com)
+ * Ivan De Cesaris (ivan.de.cesaris@intel.com)
+ * Julien Carreno (julien.carreno@intel.com)
+ * Jeffrey Maxwell (jeffrey.r.maxwell@intel.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Contact Information:
+ * Intel Corporation
+ */
+
+/*
+ * @file
+ * This is the interface to the x86 32 bit memory and breakpoint operations.
+ */
+
+#ifndef X86_32_COMMON_H
+#define X86_32_COMMON_H
+
+#include <jtag/jtag.h>
+#include <helper/command.h>
+
+extern const struct command_registration x86_32_command_handlers[];
+
+/* for memory access */
+#define BYTE                   1
+#define WORD                   2
+#define DWORD                  4
+
+#define EFLAGS_TF              0x00000100 /* Trap Flag */
+#define EFLAGS_IF              0x00000200 /* Interrupt Flag */
+#define EFLAGS_RF              0x00010000 /* Resume Flag */
+#define EFLAGS_VM86            0x00020000 /* Virtual 8086 Mode */
+
+#define CSAR_DPL               0x00006000
+#define CSAR_D                 0x00400000
+#define SSAR_DPL               0x00006000
+
+#define CR0_PE                 0x00000001 /* Protected Mode Enable */
+#define CR0_NW                 0x20000000 /* Non Write-Through */
+#define CR0_CD                 0x40000000 /* Cache Disable */
+#define CR0_PG                 0x80000000 /* Paging Enable */
+
+/* TODO - move back to PM specific file */
+#define PM_DR6                 0xFFFF0FF0
+
+#define DR6_BRKDETECT_0                0x00000001 /* B0 through B3 */
+#define DR6_BRKDETECT_1                0x00000002 /* breakpoint condition detected */
+#define DR6_BRKDETECT_2                0x00000004
+#define DR6_BRKDETECT_3                0x00000008
+
+enum {
+       /* general purpose registers */
+       EAX = 0,
+       ECX,
+       EDX,
+       EBX,
+       ESP,
+       EBP,
+       ESI,
+       EDI,
+       /* instruction pointer & flags */
+       EIP,
+       EFLAGS,
+
+       /* segment registers */
+       CS,
+       SS,
+       DS,
+       ES,
+       FS,
+       GS,
+
+       /* floating point unit registers */
+       ST0,
+       ST1,
+       ST2,
+       ST3,
+       ST4,
+       ST5,
+       ST6,
+       ST7,
+       FCTRL,
+       FSTAT,
+       FTAG,
+       FISEG,
+       FIOFF,
+       FOSEG,
+       FOOFF,
+       FOP,
+
+       /* control registers */
+       CR0,
+       CR2,
+       CR3,
+       CR4,
+
+       /* debug registers */
+       DR0,
+       DR1,
+       DR2,
+       DR3,
+       DR6,
+       DR7,
+
+       /* descriptor tables */
+       IDTB,
+       IDTL,
+       IDTAR,
+       GDTB,
+       GDTL,
+       GDTAR,
+       TR,
+       LDTR,
+       LDTB,
+       LDTL,
+       LDTAR,
+
+       /* segment registers */
+       CSB,
+       CSL,
+       CSAR,
+       DSB,
+       DSL,
+       DSAR,
+       ESB,
+       ESL,
+       ESAR,
+       FSB,
+       FSL,
+       FSAR,
+       GSB,
+       GSL,
+       GSAR,
+       SSB,
+       SSL,
+       SSAR,
+       TSSB,
+       TSSL,
+       TSSAR,
+
+       /* PM control reg */
+       PMCR,
+};
+
+#define X86_32_COMMON_MAGIC 0x86328632
+
+enum {
+       /* memory read/write */
+       MEMRDB32 = 0,
+       MEMRDB16,
+       MEMRDH32,
+       MEMRDH16,
+       MEMRDW32,
+       MEMRDW16,
+       MEMWRB32,
+       MEMWRB16,
+       MEMWRH32,
+       MEMWRH16,
+       MEMWRW32,
+       MEMWRW16,
+       /* IO read/write */
+       IORDB32,
+       IORDB16,
+       IORDH32,
+       IORDH16,
+       IORDW32,
+       IORDW16,
+       IOWRB32,
+       IOWRB16,
+       IOWRH32,
+       IOWRH16,
+       IOWRW32,
+       IOWRW16,
+       /* lakemont1 core shadow ram access opcodes */
+       SRAMACCESS,
+       SRAM2PDR,
+       PDR2SRAM,
+       WBINVD,
+};
+
+struct swbp_mem_patch {
+       uint8_t orig_byte;
+       uint32_t swbp_unique_id;
+       uint32_t physaddr;
+       struct swbp_mem_patch *next;
+};
+
+/* TODO - probemode specific - consider removing */
+#define NUM_PM_REGS            18 /* regs used in save/restore */
+
+struct x86_32_common {
+       uint32_t common_magic;
+       void *arch_info;
+       struct reg_cache *cache;
+       struct jtag_tap *curr_tap;
+       uint32_t stored_pc;
+       int flush;
+
+       /* pm_regs are for probemode save/restore state */
+       uint32_t pm_regs[NUM_PM_REGS];
+
+       /* working area for fastdata access */
+       struct working_area *fast_data_area;
+
+       int num_hw_bpoints;
+       struct x86_32_dbg_reg *hw_break_list;
+       struct swbp_mem_patch *swbbp_mem_patch_list;
+
+       /* core probemode implementation dependent functions */
+       uint8_t (*get_num_user_regs)(struct target *t);
+       bool (*is_paging_enabled)(struct target *t);
+       int (*disable_paging)(struct target *t);
+       int (*enable_paging)(struct target *t);
+       bool (*sw_bpts_supported)(struct target *t);
+       int (*transaction_status)(struct target *t);
+       int (*submit_instruction)(struct target *t, int num);
+       int (*read_hw_reg)(struct target *t, int reg, uint32_t *regval, uint8_t cache);
+       int (*write_hw_reg)(struct target *t, int reg,
+                               uint32_t regval, uint8_t cache);
+
+       /* register cache to processor synchronization */
+       int (*read_hw_reg_to_cache)(struct target *target, int num);
+       int (*write_hw_reg_from_cache)(struct target *target, int num);
+};
+
+static inline struct x86_32_common *
+target_to_x86_32(struct target *target)
+{
+       return target->arch_info;
+}
+bool check_not_halted(const struct target *t);
+
+/* breakpoint defines */
+#define MAX_DEBUG_REGS         4
+#define SW_BP_OPCODE           0xf1
+#define MAX_SW_BPTS            20
+
+struct x86_32_dbg_reg {
+       int used;
+       uint32_t bp_value;
+};
+
+#define DR7_G_ENABLE_SHIFT             1
+#define DR7_ENABLE_SIZE                        2 /* 2 bits per debug reg */
+#define DR7_RW_SHIFT                   16
+#define DR7_LENGTH_SHIFT               18
+#define DR7_RW_LEN_SIZE                        4
+#define DR7_BP_EXECUTE                 0 /* 00 - only on instruction execution*/
+#define DR7_BP_WRITE                   1 /* 01 - only on data writes */
+/*#define DR7_RW_IORW                  2 UNSUPPORTED 10 - an I/O read and I/O write */
+#define DR7_BP_READWRITE               3 /* on data read or data write */
+#define DR7_BP_LENGTH_1                        0 /* 00 - 1 byte length */
+#define DR7_BP_LENGTH_2                        1 /* 01 - 2 byte length */
+#define DR7_BP_LENGTH_4                        3 /* 11 - 4 byte length */
+
+#define DR7_GLOBAL_ENABLE(val, regnum) \
+       (val |= (1 << (DR7_G_ENABLE_SHIFT + (DR7_ENABLE_SIZE * (regnum)))))
+
+#define DR7_GLOBAL_DISABLE(val, regnum) \
+       (val &= ~(3 << (DR7_ENABLE_SIZE * (regnum))))
+
+#define DR7_BP_FREE(val, regnum) \
+       ((val & (3 << (DR7_ENABLE_SIZE * (regnum)))) == 0)
+
+#define DR7_RESET_RWLEN_BITS(val, regnum) \
+       (val &= ~(0x0f << (DR7_RW_SHIFT + DR7_RW_LEN_SIZE * (regnum))))
+
+#define DR7_SET_EXE(val, regnum) \
+       (val &= ~(0x0f << (DR7_RW_SHIFT + DR7_RW_LEN_SIZE * (regnum))))
+
+#define DR7_SET_WRITE(val, regnum) \
+       (val |= (DR7_BP_WRITE << (DR7_RW_SHIFT + DR7_RW_LEN_SIZE * (regnum))))
+
+#define DR7_SET_ACCESS(val, regnum) \
+       (val |= (DR7_BP_READWRITE << (DR7_RW_SHIFT + DR7_RW_LEN_SIZE * (regnum))))
+
+#define DR7_SET_LENGTH(val, regnum, len) \
+       (val |= (len == 1) ? (DR7_BP_LENGTH_1 << (DR7_LENGTH_SHIFT + DR7_RW_LEN_SIZE * (regnum))) : \
+       (len == 2) ? (DR7_BP_LENGTH_2 << (DR7_LENGTH_SHIFT + DR7_RW_LEN_SIZE * (regnum))) : \
+       (DR7_BP_LENGTH_4 << (DR7_LENGTH_SHIFT + DR7_RW_LEN_SIZE * (regnum))))
+
+/* public interface */
+int x86_32_get_gdb_reg_list(struct target *t,
+                       struct reg **reg_list[], int *reg_list_size,
+                       enum target_register_class reg_class);
+int x86_32_common_init_arch_info(struct target *target,
+                       struct x86_32_common *x86_32);
+int x86_32_common_mmu(struct target *t, int *enabled);
+int x86_32_common_virt2phys(struct target *t, uint32_t address, uint32_t *physical);
+int x86_32_common_read_phys_mem(struct target *t, uint32_t phys_address,
+                       uint32_t size, uint32_t count, uint8_t *buffer);
+int x86_32_common_write_phys_mem(struct target *t, uint32_t phys_address,
+                       uint32_t size, uint32_t count, const uint8_t *buffer);
+int x86_32_common_read_memory(struct target *t, uint32_t addr,
+                       uint32_t size, uint32_t count, uint8_t *buf);
+int x86_32_common_write_memory(struct target *t, uint32_t addr,
+                       uint32_t size, uint32_t count, const uint8_t *buf);
+int x86_32_common_read_io(struct target *t, uint32_t addr,
+                       uint32_t size, uint8_t *buf);
+int x86_32_common_write_io(struct target *t, uint32_t addr,
+                       uint32_t size, const uint8_t *buf);
+int x86_32_common_add_breakpoint(struct target *t, struct breakpoint *bp);
+int x86_32_common_remove_breakpoint(struct target *t, struct breakpoint *bp);
+int x86_32_common_add_watchpoint(struct target *t, struct watchpoint *wp);
+int x86_32_common_remove_watchpoint(struct target *t, struct watchpoint *wp);
+
+#endif /* X86_32_COMMON_H */
diff --git a/tcl/board/quark_x10xx_board.cfg b/tcl/board/quark_x10xx_board.cfg
new file mode 100644 (file)
index 0000000..8dc600b
--- /dev/null
@@ -0,0 +1,9 @@
+# There are many Quark boards that can host the quark_x10xx SoC
+# Galileo is an example board
+
+source [find target/quark_x10xx.cfg]
+
+#default frequency but this can be adjusted at runtime
+adapter_khz 4000
+
+reset_config trst_only
diff --git a/tcl/target/quark_x10xx.cfg b/tcl/target/quark_x10xx.cfg
new file mode 100644 (file)
index 0000000..a5bbfb4
--- /dev/null
@@ -0,0 +1,52 @@
+if { [info exists CHIPNAME] } {
+   set _CHIPNAME $CHIPNAME
+} else {
+   set _CHIPNAME quark_x10xx
+}
+
+if { [info exists ENDIAN] } {
+   set _ENDIAN $ENDIAN
+} else {
+   set _ENDIAN little
+}
+
+
+if { [info exists CPUTAPID] } {
+   set _CPUTAPID $CPUTAPID
+} else {
+   set _CPUTAPID 0x18289013
+}
+
+jtag newtap quark_x10xx cpu   -irlen 8  -irmask 0xff  -expected-id   $_CPUTAPID  -disable
+jtag newtap quark_x10xx cltap -irlen 8  -irmask 0xff  -expected-id   0x0e681013  -enable
+
+#openocd puts tap at front of chain not end of chain
+proc quark_x10xx_tapenable {} {
+       echo "enabling core tap"
+       irscan quark_x10xx.cltap 0x11
+       drscan quark_x10xx.cltap 64 1
+       runtest 10
+}
+
+proc quark_x10xx_tapdisable {} {
+       echo "disabling core tap"
+       irscan quark_x10xx.cltap 0x11
+       drscan quark_x10xx.cltap 64 0
+       runtest 10
+}
+
+proc quark_x10xx_setup {} {
+       jtag tapenable quark_x10xx.cpu
+}
+
+jtag configure $_CHIPNAME.cpu -event tap-enable \
+   "quark_x10xx_tapenable"
+
+jtag configure $_CHIPNAME.cpu -event tap-disable \
+   "quark_x10xx_tapdisable"
+
+set _TARGETNAME $_CHIPNAME.cpu
+target create quark_x10xx.cpu quark_x10xx -endian $_ENDIAN -chain-position quark_x10xx.cpu
+
+jtag configure $_CHIPNAME.cpu -event setup \
+   "quark_x10xx_setup"

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)