diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index ff324c393f23..7b368d7b8a22 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -722,7 +722,8 @@ ALL_TARGET_OBS = \
 	windows-tdep.o \
 	linux-record.o \
 	ravenscar-thread.o \
-	lkd-main.o lkd-process.o
+	lkd-main.o lkd-process.o \
+	lkd-arm.o
 
 # Host-dependent makefile fragment comes in here.
 @host_makefile_frag@
@@ -2728,6 +2729,8 @@ py-varobj.o: $(srcdir)/python/py-varobj.c
 lkd-main.o: $(srcdir)/lkd/lkd-main.c
 lkd-process.o: $(srcdir)/lkd/lkd-process.c
 
+lkd-arm.o: $(srcdir)/lkd/lkd-arm.c
+
 # Generalised lkd-compile rule
 lkd-%:
 	$(COMPILE) $<
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index 8a685afe5c1e..ea0d0d2a540c 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -730,6 +730,10 @@ done
 # Add linux kernel awareness obs and set no default OS ABI
 if test x"$enable_linux_kernel_aware" = xyes; then
   gdb_target_obs="$gdb_target_obs lkd-main.o lkd-process.o"
+  case "${targ}" in
+  arm*-*-linux*)
+	  gdb_target_obs="$gdb_target_obs lkd-arm.o" ;;
+  esac
   gdb_osabi=
 fi
 
diff --git a/gdb/lkd/lkd-arm.c b/gdb/lkd/lkd-arm.c
new file mode 100644
index 000000000000..f734b3cb89df
--- /dev/null
+++ b/gdb/lkd/lkd-arm.c
@@ -0,0 +1,312 @@
+/*
+  Copyright 2011-2013 STMicroelectronics.
+
+  This file contains the ARM specific part of the Linux
+  Awareness layer for GDB.
+
+  The Linux Awareness layer allows GDB boot or attach-to and debug
+  a Linux kernel through a H/W link (presumably JTAG).
+
+  see file linux-awareness.c for more details.
+*/
+
+#include "defs.h"
+#include "block.h"
+#include "command.h"
+#include "frame.h"
+#include "frame-unwind.h"
+#include "gdb_assert.h"
+#include "gdbarch.h"
+#include "gdbcmd.h"
+#include "gdbcore.h"
+#include "gdbtypes.h"
+#include "gdb_obstack.h"
+#include "inferior.h"
+#include "objfiles.h"
+#include "regcache.h"
+#include "user-regs.h"
+#include "symtab.h"
+#include "target.h"
+#include "top.h"
+#include "value.h"
+#include "gdbthread.h"
+
+#include "arm-tdep.h"
+
+#include "lkd.h"
+#include "lkd-process.h"
+
+/* Addresses used by the ARM specific linux awareness. */
+
+DECLARE_ADDR (ret_from_fork);
+DECLARE_ADDR (ret_fast_syscall);
+
+/* Fields used by the ARM specific linux awareness. */
+DECLARE_FIELD (mm_struct, pgd);
+DECLARE_FIELD (task_struct, mm);
+DECLARE_FIELD (task_struct, thread);
+DECLARE_FIELD (task_struct, stack);
+DECLARE_FIELD (thread_info, cpu_context);
+
+
+struct pt_regs
+{
+  uint32_t uregs[18];
+};
+
+static int
+arch_can_write (CORE_ADDR addr, CORE_ADDR task_struct)
+{
+  return 0;
+}
+
+static inline int
+is_special_addr (CORE_ADDR addr)
+{
+  /* ret_fast_syscall is a special address (both sp _and_ pc)
+     used to link user and kernel spaces */
+  return HAS_ADDR (ret_fast_syscall) && addr == ADDR (ret_fast_syscall);
+}
+
+static int
+arch_is_user_address (CORE_ADDR addr)
+{
+  return (addr < linux_awareness_ops->kernel_offset)
+    || is_special_addr (addr);
+}
+
+static int
+arch_is_kernel_address (CORE_ADDR addr)
+{
+  return !arch_is_user_address (addr) || is_special_addr (addr);
+}
+
+
+/*****************************************************************************/
+/*                              TASK AWARENESS                               */
+/*****************************************************************************/
+
+/* This function gets the register values that the schedule() routine
+ * has stored away to be able to restart an asleep task later.
+ * this must match the layout in arm/include/asm/thread_info.h
+ *
+ **/
+static CORE_ADDR
+fetch_context_register_real (CORE_ADDR task_struct)
+{
+  struct regcache *regcache;
+  int offset = 0, val, i;
+  uint32_t thread_info_addr;
+  uint32_t cpsr;
+  struct cpu_context_save
+  {
+    uint32_t r4;
+    uint32_t r5;
+    uint32_t r6;
+    uint32_t r7;
+    uint32_t r8;
+    uint32_t r9;
+    uint32_t sl;
+    uint32_t fp;
+    uint32_t sp;
+    uint32_t pc;
+  } cpu_cxt;
+
+  /*get thread_info address */
+  thread_info_addr = read_unsigned_field (task_struct, task_struct, stack);
+
+  /*get cpu_context as saved by scheduled */
+  read_memory ((CORE_ADDR) thread_info_addr +
+	       F_OFFSET (thread_info, cpu_context),
+	       (gdb_byte *) & cpu_cxt, sizeof (struct cpu_context_save));
+
+  DEBUG (TASK, 4, "fetch_context_register_real (%x)\n", thread_info_addr);
+
+  regcache = get_current_regcache ();
+
+  regcache_raw_supply (regcache, ARM_PC_REGNUM, &cpu_cxt.pc);
+  regcache_raw_supply (regcache, ARM_SP_REGNUM, &cpu_cxt.sp);
+  regcache_raw_supply (regcache, ARM_FP_REGNUM, &cpu_cxt.fp);
+
+  /*general purpose registers */
+  regcache_raw_supply (regcache, 10, &cpu_cxt.sl);
+  regcache_raw_supply (regcache, 9, &cpu_cxt.r9);
+  regcache_raw_supply (regcache, 8, &cpu_cxt.r8);
+  regcache_raw_supply (regcache, 7, &cpu_cxt.r7);
+  regcache_raw_supply (regcache, 6, &cpu_cxt.r6);
+  regcache_raw_supply (regcache, 5, &cpu_cxt.r5);
+  regcache_raw_supply (regcache, 4, &cpu_cxt.r4);
+
+  /* Fake a value for cpsr:T bit.  */
+#define IS_THUMB_ADDR(addr)	((addr) & 1)
+  cpsr = IS_THUMB_ADDR(cpu_cxt.pc) ? arm_psr_thumb_bit (target_gdbarch ()) : 0;
+  regcache_raw_supply (regcache, ARM_PS_REGNUM, &cpsr);
+
+  for (i = 0; i < gdbarch_num_regs (target_gdbarch ()); i++)
+    if (REG_VALID != regcache_register_status (regcache, i))
+      /* Mark other registers as unavailable.  */
+      regcache_invalidate (regcache, i);
+
+  return cpu_cxt.pc;
+}
+
+static int
+arch_fetch_context_register (int regno, CORE_ADDR task_struct)
+{
+  CORE_ADDR pc;
+  DEBUG (TASK, 4, "fetch_context_register(%i,%x)\n",
+	 regno, (unsigned int) task_struct);
+
+  if (REG_VALID != regcache_register_status (get_current_regcache (),
+					     ARM_PC_REGNUM))
+    {
+
+      pc = fetch_context_register_real (task_struct);
+
+      if (lkd_params.skip_schedule_frame
+	  && !(HAS_ADDR (ret_from_fork) && pc == ADDR (ret_from_fork)))
+	{
+	  int arm_num_regs = gdbarch_num_regs (target_gdbarch ());
+	  struct frame_info *f = get_current_frame ();
+	  int level = frame_relative_level(f);
+
+	   /* skip this frame, unwind to the next
+	    **/
+	  while (f && (level++ < lkd_params.skip_schedule_frame))
+		  f = get_prev_frame (f);
+
+	  if (f != NULL)
+	    {
+	      int i;
+	      gdb_byte buf[12];
+	      int optimized, unavailable;
+	      CORE_ADDR addr;
+	      int realnum;
+	      enum lval_type lval;
+	      unsigned long *new_registers = xcalloc (arm_num_regs,
+						      sizeof (unsigned long));
+	      char *new_registers_valid = xcalloc (arm_num_regs, 1);
+
+	      for (i = 0; i < arm_num_regs; ++i)
+		{
+		  frame_register_unwind (f, i, &optimized, &unavailable,
+					 &lval, &addr, &realnum, buf);
+		  if (!optimized && !unavailable)
+		    {
+		      memcpy (&new_registers[i], buf, 4);
+		      new_registers_valid[i] = 1;
+		    }
+		}
+
+	      reinit_frame_cache ();
+
+	      for (i = 0; i < arm_num_regs; ++i)
+		{
+		  if (new_registers_valid[i])
+		    regcache_raw_supply
+		      (get_current_regcache (), i, &new_registers[i]);
+		  else
+		    /* Mark other registers as unavailable. */
+		    regcache_invalidate (get_current_regcache (), i);
+		}
+
+	      xfree (new_registers);
+	      xfree (new_registers_valid);
+	    }
+	}
+    }
+
+  return 1;
+}
+
+// FIXME
+static int
+arch_store_context_register (int regno, CORE_ADDR task_struct)
+{
+  DEBUG (TASK, 3, "store_context_register(%i,%x)\n",
+	 regno, (unsigned int) task_struct);
+  warning ("ARM/store_context_register not implemented yet");
+  return 1;
+}
+
+static void
+arch_clear_cache (void)
+{
+}
+
+
+static void
+arch_close (void)
+{
+  arch_clear_cache ();
+}
+
+
+/*
+ * default op handler for STGDI (non-remote)
+ **/
+static void
+arch_post_load (char *prog, int fromtty)
+{
+  CORE_ADDR addr_phys_offset;
+
+  DEBUG (D_INIT, 1, "ARM: arch_post_load\n");
+
+
+  DEBUG (TARGET, 1, "Assuming 0x%08x as MODULES_VADDR.\n",
+	 linux_awareness_ops->kernel_offset);
+
+  /* this installs what ever LKD specific handling is required
+   * in the gdb arch data. */
+
+  /* lkd_params.loaded will be set later */
+}
+
+static int
+arch_init (void)
+{
+  DEBUG (D_INIT, 1, "ARM: arch_init.\n");
+
+  return 1;
+}
+
+static int
+arch_check_kernel (void)
+{
+  int res = HAS_FIELD (mm_struct, pgd)
+    && HAS_FIELD (task_struct, stack)
+    && HAS_FIELD (task_struct, thread)
+    && HAS_FIELD (task_struct, mm) && HAS_FIELD (thread_info, cpu_context);
+  return res;
+}
+
+//#define ARMv7_PAGESHIFT       12
+
+struct linux_awareness_ops arm_linux_awareness_ops = {
+  .name = "armv7",
+  .lo_check_kernel = arch_check_kernel,
+  .lo_init = arch_init,
+  .lo_close = arch_close,
+  .lo_post_load = arch_post_load,
+  .lo_can_write = arch_can_write,
+  .lo_is_user_address = arch_is_user_address,
+  .lo_is_kernel_address = arch_is_kernel_address,
+  .lo_single_step_destination = NULL,
+  .lo_clear_cache = arch_clear_cache,
+  .lo_fetch_context_register = arch_fetch_context_register,
+  .lo_store_context_register = arch_store_context_register,
+  .kernel_offset = 0x0,
+};
+
+
+/* -Wmissing-prototypes */
+extern initialize_file_ftype _initialize_armv7_lkd;
+
+/* _initialize_xxx routines are added to the ugly autogenerates init code
+ * see gdb makefile.
+ **/
+void
+_initialize_armv7_lkd (void)
+{
+  linux_awareness_ops = &arm_linux_awareness_ops;
+}
