diff --git a/sys/arch/x86/conf/files.x86 b/sys/arch/x86/conf/files.x86
index 17ccac2..1b14f08 100644
--- a/sys/arch/x86/conf/files.x86
+++ b/sys/arch/x86/conf/files.x86
@@ -25,7 +25,7 @@ define  ipmibus {}
# CPU features
#
device cpu: cpufeaturebus
-attach cpu at cpubus
+attach cpu at cpubus with lapic
file   arch/x86/x86/cpu.c              cpu
file   arch/x86/x86/cpu_rng.c          cpu

diff --git a/sys/arch/x86/include/cpu.h b/sys/arch/x86/include/cpu.h
index bd6e7cf..778c547 100644
--- a/sys/arch/x86/include/cpu.h
+++ b/sys/arch/x86/include/cpu.h
@@ -335,6 +335,10 @@ void cpu_load_pmap(struct pmap *, struct pmap *);
void cpu_broadcast_halt(void);
void cpu_kick(struct cpu_info *);

+void cpu_attach_common(device_t, device_t, void *);
+int cpu_rescan(device_t, const char *, const int *);
+void cpu_childdetached(device_t, device_t);
+
#define        curcpu()                x86_curcpu()
#define        curlwp                  x86_curlwp()
#define        curpcb                  ((struct pcb *)lwp_getpcb(curlwp))
diff --git a/sys/arch/x86/include/cpuvar.h b/sys/arch/x86/include/cpuvar.h
index c0ea0c5..8dfdd64 100644
--- a/sys/arch/x86/include/cpuvar.h
+++ b/sys/arch/x86/include/cpuvar.h
@@ -95,6 +95,12 @@ struct cpufeature_attach_args {
       const char *name;
};

+struct cpu_softc {
+       device_t sc_dev;                /* device tree glue */
+       struct cpu_info *sc_info;       /* pointer to CPU info */
+       bool sc_wasonline;
+};
+
#ifdef _KERNEL
#include <sys/kcpuset.h>
#if defined(_KERNEL_OPT)
diff --git a/sys/arch/x86/include/i82489var.h b/sys/arch/x86/include/i82489var.h
index fd2be1e..f34693a 100644
--- a/sys/arch/x86/include/i82489var.h
+++ b/sys/arch/x86/include/i82489var.h
@@ -88,7 +88,6 @@ struct cpu_info;
extern void lapic_boot_init(paddr_t);
extern void lapic_set_lvt(void);
extern void lapic_enable(void);
-extern void lapic_calibrate_timer(struct cpu_info *ci);
extern void lapic_initclocks(void);

extern uint32_t lapic_readreg(u_int);
diff --git a/sys/arch/x86/x86/cpu.c b/sys/arch/x86/x86/cpu.c
index 4f31ee4..66ce4aa 100644
--- a/sys/arch/x86/x86/cpu.c
+++ b/sys/arch/x86/x86/cpu.c
@@ -124,19 +124,11 @@ __KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.132 2017/07/28 14:12:26 riastradh Exp $");
static int     cpu_match(device_t, cfdata_t, void *);
static void    cpu_attach(device_t, device_t, void *);
static void    cpu_defer(device_t);
-static int     cpu_rescan(device_t, const char *, const int *);
-static void    cpu_childdetached(device_t, device_t);
static bool    cpu_stop(device_t);
static bool    cpu_suspend(device_t, const pmf_qual_t *);
static bool    cpu_resume(device_t, const pmf_qual_t *);
static bool    cpu_shutdown(device_t, int);

-struct cpu_softc {
-       device_t sc_dev;                /* device tree glue */
-       struct cpu_info *sc_info;       /* pointer to CPU info */
-       bool sc_wasonline;
-};
-
#ifdef MULTIPROCESSOR
int mp_cpu_start(struct cpu_info *, paddr_t);
void mp_cpu_start_cleanup(struct cpu_info *);
@@ -296,15 +288,20 @@ cpu_attach(device_t parent, device_t self, void *aux)
{
       struct cpu_softc *sc = device_private(self);
       struct cpu_attach_args *caa = aux;
+       sc->sc_dev = self;
+
+       cpu_attach_common(parent, self, caa);
+}
+void
+cpu_attach_common(device_t parent, device_t self, void *aux)
+{
+       struct cpu_softc *sc = device_private(self);
+       struct cpu_attach_args *caa = aux;
       struct cpu_info *ci;
       uintptr_t ptr;
-#if NLAPIC > 0
-       int cpunum = caa->cpu_number;
-#endif
+
       static bool again;
-
-       sc->sc_dev = self;
-
+
       if (ncpu == maxcpus) {
#ifndef _LP64
               aprint_error(": too many CPUs, please use NetBSD/amd64\n");
@@ -338,22 +335,6 @@ cpu_attach(device_t parent, device_t self, void *aux)
               aprint_naive(": %s Processor\n",
                   caa->cpu_role == CPU_ROLE_SP ? "Single" : "Boot");
               ci = &cpu_info_primary;
-#if NLAPIC > 0
-               if (cpunum != lapic_cpu_number()) {
-                       /* XXX should be done earlier. */
-                       uint32_t reg;
-                       aprint_verbose("\n");
-                       aprint_verbose_dev(self, "running CPU at apic %d"
-                           " instead of at expected %d", lapic_cpu_number(),
-                           cpunum);
-                       reg = lapic_readreg(LAPIC_ID);
-                       lapic_writereg(LAPIC_ID, (reg & ~LAPIC_ID_MASK) |
-                           (cpunum << LAPIC_ID_SHIFT));
-               }
-               if (cpunum != lapic_cpu_number()) {
-                       aprint_error_dev(self, "unable to reset apic id\n");
-               }
-#endif
       }

       ci->ci_self = ci;
@@ -397,14 +378,6 @@ cpu_attach(device_t parent, device_t self, void *aux)
               cpu_init(ci);
               cpu_set_tss_gates(ci);
               pmap_cpu_init_late(ci);
-#if NLAPIC > 0
-               if (caa->cpu_role != CPU_ROLE_SP) {
-                       /* Enable lapic. */
-                       lapic_enable();
-                       lapic_set_lvt();
-                       lapic_calibrate_timer(ci);
-               }
-#endif
               /* Make sure DELAY() is initialized. */
               DELAY(1);
               again = true;
@@ -490,7 +463,7 @@ cpu_defer(device_t self)
       cpu_rescan(self, NULL, NULL);
}

-static int
+int
cpu_rescan(device_t self, const char *ifattr, const int *locators)
{
       struct cpu_softc *sc = device_private(self);
@@ -530,7 +503,7 @@ cpu_rescan(device_t self, const char *ifattr, const int *locators)
       return 0;
}

-static void
+void
cpu_childdetached(device_t self, device_t child)
{
       struct cpu_softc *sc = device_private(self);
diff --git a/sys/arch/x86/x86/lapic.c b/sys/arch/x86/x86/lapic.c
index 9c341bc..79d5416 100644
--- a/sys/arch/x86/x86/lapic.c
+++ b/sys/arch/x86/x86/lapic.c
@@ -92,6 +92,7 @@ extern int ddb_vec;
/* Referenced from vector.S */
void           lapic_clockintr(void *, struct intrframe *);

+static void lapic_calibrate_timer(device_t);
static void    lapic_delay(unsigned int);
static uint32_t lapic_gettick(void);
static void    lapic_setup_bsp(paddr_t);
@@ -601,8 +602,8 @@ extern void (*initclock_func)(void); /* XXX put in header file */
 *
 * We're actually using the IRQ0 timer.  Hmm.
 */
-void
-lapic_calibrate_timer(struct cpu_info *ci)
+static void
+lapic_calibrate_timer(device_t dev)
{
       unsigned int seen, delta, initial_i8254, initial_lapic;
       unsigned int cur_i8254, cur_lapic;
@@ -610,7 +611,7 @@ lapic_calibrate_timer(struct cpu_info *ci)
       int i;
       char tbuf[9];

-       aprint_debug_dev(ci->ci_dev, "calibrating local timer\n");
+       aprint_debug_dev(dev, "calibrating local timer\n");

       /*
        * Configure timer to one-shot, interrupt masked,
@@ -642,7 +643,7 @@ lapic_calibrate_timer(struct cpu_info *ci)

       humanize_number(tbuf, sizeof(tbuf), lapic_per_second, "Hz", 1000);

-       aprint_debug_dev(ci->ci_dev, "apic clock running at %s\n", tbuf);
+       aprint_debug_dev(dev, "apic clock running at %s\n", tbuf);

       if (lapic_per_second != 0) {
               /*
@@ -935,3 +936,64 @@ lapic_dump(void)
       apic_format_redir(device_xname(ci->ci_dev), "err", 0, 0,
           lapic_readreg(LAPIC_LVERR));
}
+
+/*
+ * cpu attach helpers
+ * These are called via x86/mpacpi.c or x86/mpbios.c
+ */
+
+static int     lapic_match(device_t, cfdata_t, void *);
+static void    lapic_attach(device_t, device_t, void *);
+
+CFATTACH_DECL2_NEW(lapic, sizeof(struct cpu_softc),
+    lapic_match, lapic_attach, NULL, NULL, cpu_rescan, cpu_childdetached);
+
+static int
+lapic_match(device_t parent, cfdata_t match, void *aux)
+{
+       /* XXX: "detect" lapic ? */
+       return 1;
+}
+
+static void
+lapic_attach(device_t parent, device_t self, void *aux)
+{
+       struct cpu_softc *sc = device_private(self);
+       struct cpu_attach_args *caa = aux;
+
+       int cpunum = caa->cpu_number;
+
+       static bool again;
+
+       sc->sc_dev = self;
+
+       cpu_attach_common(parent, self, caa);
+
+       if (caa->cpu_role != CPU_ROLE_AP) {
+               if (cpunum != lapic_cpu_number()) {
+                       /* XXX should be done earlier. */
+                       uint32_t reg;
+                       aprint_verbose("\n");
+                       aprint_verbose_dev(self, "running CPU at apic %d"
+                           " instead of at expected %d", lapic_cpu_number(),
+                           cpunum);
+                       reg = lapic_readreg(LAPIC_ID);
+                       lapic_writereg(LAPIC_ID, (reg & ~LAPIC_ID_MASK) |
+                           (cpunum << LAPIC_ID_SHIFT));
+               }
+               if (cpunum != lapic_cpu_number()) {
+                       aprint_error_dev(self, "unable to reset apic id\n");
+               }
+       }
+
+       if (!again) {
+               if (caa->cpu_role != CPU_ROLE_SP) {
+                       /* Enable lapic. */
+                       lapic_enable();
+                       lapic_set_lvt();
+                       lapic_calibrate_timer(self);
+               }
+
+               again = true;
+       }
+}