Index: /trunk/src/VBox/Devices/PC/DevACPI.cpp
===================================================================
--- /trunk/src/VBox/Devices/PC/DevACPI.cpp	(revision 12427)
+++ /trunk/src/VBox/Devices/PC/DevACPI.cpp	(revision 12428)
@@ -159,5 +159,6 @@
     uint16_t            pm1a_sts;
     uint16_t            pm1a_ctl;
-    uint16_t            Alignment0;
+    /** Number of logical CPUs in guest */
+    uint16_t            cCpus;
     int64_t             pm_timer_initial;
     PTMTIMERR3          tsR3;
@@ -199,8 +200,4 @@
     /** Pointer to the driver connector interface */
     R3PTRTYPE(PPDMIACPICONNECTOR) pDrv;
-#if 0
-  /** Number of logical CPUs in guest */
-    uint16_t             cCpus;
-#endif
 };
 
@@ -403,4 +400,116 @@
 
 /** Multiple APIC Description Table */
+#ifdef VBOX_WITH_SMP_GUESTS
+
+#define PCAT_COMPAT     0x1                     /**< system has also a dual-8259 setup */
+
+/*
+ * This structure looks somewhat convoluted due layout of MADT table in MP case.
+ * There extpected to be multiple LAPIC records for each CPU, thus we cannot 
+ * use regular C structure and proxy to raw memory instead.
+ */
+class ACPITBLMADT
+{
+    /*
+     * All actual data stored in dynamically allocated memory pointed by this field.
+     */
+    uint8_t*            pData;
+    /*
+     * Number of CPU entries in this MADT.
+     */
+    uint32_t            cCpus;
+    
+ public:
+    /*
+     * Address of ACPI header
+     */
+    inline ACPITBLHEADER* header_addr() const
+    {
+        return (ACPITBLHEADER*)pData;
+    }
+    
+    /*
+     * Address of local APIC for each CPU. Note that different CPUs address different LAPICs,
+     * although address is the same for all of them.
+     */
+    inline uint32_t* u32LAPIC_addr() const
+    {
+        return  (uint32_t*)(header_addr() + 1);
+    }
+    
+    /*
+     * Address of APIC flags
+     */
+    inline uint32_t* u32Flags_addr() const
+    {
+        return (uint32_t*)(u32LAPIC_addr() + 1);
+    }
+    
+    /*
+     * Address of per-CPU LAPIC descriptions
+     */
+    inline ACPITBLLAPIC* LApics_addr() const
+    {
+        return (ACPITBLLAPIC*)(u32Flags_addr() + 1);
+    }
+
+    /*
+     * Address of IO APIC description
+     */
+    inline ACPITBLIOAPIC* IOApic_addr() const
+    {
+        return (ACPITBLIOAPIC*)(LApics_addr() + cCpus);
+    }
+
+    /*
+     * Size of MADT.
+     * Note that this function assumes IOApic to be the last field in structure.
+     */
+    inline uint32_t size() const
+    {
+        return (uint8_t*)(IOApic_addr() + 1)-(uint8_t*)header_addr();
+    }
+
+    /*
+     * Raw data of MADT.
+     */
+    inline const uint8_t* data() const
+    {
+        return pData;
+    }
+
+    /*
+     * Size of MADT for given ACPI config, useful to compute layout.
+     */
+    static uint32_t sizeFor(ACPIState *s)
+    {
+        return ACPITBLMADT(s->cCpus).size();
+    }
+
+    /*
+     * Constructor, only works in Ring 3, doesn't look like a big deal.
+     */
+    ACPITBLMADT(uint16_t cpus)
+    {
+        cCpus = cpus;
+        pData = 0;
+#ifdef IN_RING3
+        uint32_t sSize = size();
+        pData = (uint8_t*)RTMemAllocZ(sSize);
+#else
+        AssertMsgFailed(("cannot use in inner rings"));
+#endif
+    }
+
+    ~ACPITBLMADT()
+    {
+#ifdef IN_RING3
+        RTMemFree(pData);
+#else
+        AssertMsgFailed(("cannot use in inner rings"));
+#endif
+    }
+};
+#else 
 struct ACPITBLMADT
 {
@@ -413,4 +522,5 @@
 };
 AssertCompileSize(ACPITBLMADT, 64);
+#endif
 
 #pragma pack()
@@ -644,4 +754,37 @@
 static void acpiSetupMADT (ACPIState *s, RTGCPHYS32 addr)
 {
+#if VBOX_WITH_SMP_GUESTS
+    uint16_t cpus = s->cCpus;
+    ACPITBLMADT madt(cpus);
+
+    acpiPrepareHeader(madt.header_addr(), "APIC", madt.size(), 2);
+    
+    *madt.u32LAPIC_addr()          = RT_H2LE_U32(0xfee00000);
+    *madt.u32Flags_addr()          = RT_H2LE_U32(PCAT_COMPAT);
+    
+    ACPITBLLAPIC* lapic = madt.LApics_addr();
+    for (uint16_t i = 0; i < cpus; i++)
+    {
+        lapic->u8Type      = 0;
+        lapic->u8Length    = sizeof(ACPITBLLAPIC);
+        lapic->u8ProcId    = i;
+        lapic->u8ApicId    = i;
+        lapic->u32Flags    = RT_H2LE_U32(LAPIC_ENABLED);
+        lapic++;
+    }
+
+    ACPITBLIOAPIC* ioapic = madt.IOApic_addr();
+
+    ioapic->u8Type     = 1;
+    ioapic->u8Length   = sizeof(ACPITBLIOAPIC);
+    ioapic->u8IOApicId = cpus;
+    ioapic->u8Reserved = 0;
+    ioapic->u32Address = RT_H2LE_U32(0xfec00000);
+    ioapic->u32GSIB    = RT_H2LE_U32(0);
+
+    madt.header_addr()->u8Checksum = acpiChecksum (madt.data(), madt.size());
+    acpiPhyscpy (s, addr, madt.data(), madt.size());
+
+#else
     ACPITBLMADT madt;
 
@@ -670,4 +813,5 @@
     madt.header.u8Checksum = acpiChecksum ((uint8_t*)&madt, sizeof(madt));
     acpiPhyscpy (s, addr, &madt, sizeof(madt));
+#endif
 }
 
@@ -1512,5 +1656,4 @@
                                 N_("Configuration error: Invalid \"RamSize\", maximum allowed "
                                    "value is 4095MB"));
-
     rsdt_addr = 0;
     xsdt_addr = RT_ALIGN_32 (rsdt_addr + rsdt_tbl_len, 16);
@@ -1520,5 +1663,13 @@
     {
         apic_addr = RT_ALIGN_32 (facs_addr + sizeof(ACPITBLFACS), 16);
+#ifdef VBOX_WITH_SMP_GUESTS
+        /* 
+         * @todo r=nike maybe some refactoring needed to compute tables layout, 
+         * but as this code is executed only once it doesn't make sense to optimize much
+         */
+        dsdt_addr = RT_ALIGN_32 (apic_addr + ACPITBLMADT::sizeFor(s), 16);
+#else
         dsdt_addr = RT_ALIGN_32 (apic_addr + sizeof(ACPITBLMADT), 16);
+#endif
     }
     else
@@ -1598,10 +1749,8 @@
                                 N_("Configuration error: Failed to read \"IOAPIC\""));
 
-#if 0
     rc = CFGMR3QueryU16Def(pCfgHandle, "NumCPUs", &s->cCpus, 1);
     if (RT_FAILURE(rc))
         return PDMDEV_SET_ERROR(pDevIns, rc,
                                 N_("Configuration error: Querying \"NumCPUs\" as integer failed"));
-#endif
 
     /* query whether we are supposed to present an FDC controller */
Index: /trunk/src/VBox/Devices/PC/DevPcBios.cpp
===================================================================
--- /trunk/src/VBox/Devices/PC/DevPcBios.cpp	(revision 12427)
+++ /trunk/src/VBox/Devices/PC/DevPcBios.cpp	(revision 12428)
@@ -1397,6 +1397,5 @@
 
 #ifdef VBOX_WITH_SMP_GUESTS
-    pThis->cCpus = 2;
-    LogRel(("Running with %d CPUs\n", pThis->cCpus));
+    LogRel(("[SMP] BIOS with %d CPUs\n", pThis->cCpus));
 #else
     if (pThis->cCpus != 1)
Index: /trunk/src/VBox/Main/ConsoleImpl2.cpp
===================================================================
--- /trunk/src/VBox/Main/ConsoleImpl2.cpp	(revision 12427)
+++ /trunk/src/VBox/Main/ConsoleImpl2.cpp	(revision 12428)
@@ -134,4 +134,10 @@
     hrc = pMachine->COMGETTER(MemorySize)(&cRamMBs);                                H();
 
+#ifdef VBOX_WITH_SMP_GUESTS
+    /* @todo: r=nike: Testing code, should use actual getter when ready */
+    uint16_t cNumCpus = 2;
+#else
+    uint16_t cNumCpus = 1;
+#endif
 
     /*
@@ -151,4 +157,5 @@
     rc = CFGMR3InsertBytes(pRoot,   "UUID", pUuid, sizeof(*pUuid));                 RC_CHECK();
     rc = CFGMR3InsertInteger(pRoot, "RamSize",              cRamMBs * _1M);         RC_CHECK();
+    rc = CFGMR3InsertInteger(pRoot, "NumCPUs",              cNumCpus);              RC_CHECK();
     rc = CFGMR3InsertInteger(pRoot, "TimerMillies",         10);                    RC_CHECK();
     rc = CFGMR3InsertInteger(pRoot, "RawR3Enabled",         1);     /* boolean */   RC_CHECK();
@@ -272,4 +279,5 @@
     rc = CFGMR3InsertNode(pInst,    "Config", &pBiosCfg);                           RC_CHECK();
     rc = CFGMR3InsertInteger(pBiosCfg,  "RamSize",              cRamMBs * _1M);     RC_CHECK();
+    rc = CFGMR3InsertInteger(pBiosCfg,  "NumCPUs",              cNumCpus);          RC_CHECK();
     rc = CFGMR3InsertString(pBiosCfg,   "HardDiskDevice",       "piix3ide");        RC_CHECK();
     rc = CFGMR3InsertString(pBiosCfg,   "FloppyDevice",         "i82078");          RC_CHECK();
@@ -457,4 +465,6 @@
         rc = CFGMR3InsertNode(pInst,    "Config", &pCfg);                           RC_CHECK();
         rc = CFGMR3InsertInteger(pCfg,  "RamSize",          cRamMBs * _1M);         RC_CHECK();
+        rc = CFGMR3InsertInteger(pCfg,  "NumCPUs",          cNumCpus);              RC_CHECK();
+
         rc = CFGMR3InsertInteger(pCfg,  "IOAPIC", fIOAPIC);                         RC_CHECK();
         rc = CFGMR3InsertInteger(pCfg,  "FdcEnabled", fFdcEnabled);                 RC_CHECK();
