qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

memory_hotplug.c (26685B)


      1 #include "qemu/osdep.h"
      2 #include "hw/acpi/memory_hotplug.h"
      3 #include "hw/mem/pc-dimm.h"
      4 #include "hw/qdev-core.h"
      5 #include "migration/vmstate.h"
      6 #include "trace.h"
      7 #include "qapi/error.h"
      8 #include "qapi/qapi-events-acpi.h"
      9 #include "qapi/qapi-events-machine.h"
     10 #include "qapi/qapi-events-qdev.h"
     11 
     12 #define MEMORY_SLOTS_NUMBER          "MDNR"
     13 #define MEMORY_HOTPLUG_IO_REGION     "HPMR"
     14 #define MEMORY_SLOT_ADDR_LOW         "MRBL"
     15 #define MEMORY_SLOT_ADDR_HIGH        "MRBH"
     16 #define MEMORY_SLOT_SIZE_LOW         "MRLL"
     17 #define MEMORY_SLOT_SIZE_HIGH        "MRLH"
     18 #define MEMORY_SLOT_PROXIMITY        "MPX"
     19 #define MEMORY_SLOT_ENABLED          "MES"
     20 #define MEMORY_SLOT_INSERT_EVENT     "MINS"
     21 #define MEMORY_SLOT_REMOVE_EVENT     "MRMV"
     22 #define MEMORY_SLOT_EJECT            "MEJ"
     23 #define MEMORY_SLOT_SLECTOR          "MSEL"
     24 #define MEMORY_SLOT_OST_EVENT        "MOEV"
     25 #define MEMORY_SLOT_OST_STATUS       "MOSC"
     26 #define MEMORY_SLOT_LOCK             "MLCK"
     27 #define MEMORY_SLOT_STATUS_METHOD    "MRST"
     28 #define MEMORY_SLOT_CRS_METHOD       "MCRS"
     29 #define MEMORY_SLOT_OST_METHOD       "MOST"
     30 #define MEMORY_SLOT_PROXIMITY_METHOD "MPXM"
     31 #define MEMORY_SLOT_EJECT_METHOD     "MEJ0"
     32 #define MEMORY_SLOT_NOTIFY_METHOD    "MTFY"
     33 #define MEMORY_HOTPLUG_DEVICE        "MHPD"
     34 
     35 static ACPIOSTInfo *acpi_memory_device_status(int slot, MemStatus *mdev)
     36 {
     37     ACPIOSTInfo *info = g_new0(ACPIOSTInfo, 1);
     38 
     39     info->slot_type = ACPI_SLOT_TYPE_DIMM;
     40     info->slot = g_strdup_printf("%d", slot);
     41     info->source = mdev->ost_event;
     42     info->status = mdev->ost_status;
     43     if (mdev->dimm) {
     44         DeviceState *dev = DEVICE(mdev->dimm);
     45         if (dev->id) {
     46             info->device = g_strdup(dev->id);
     47             info->has_device = true;
     48         }
     49     }
     50     return info;
     51 }
     52 
     53 void acpi_memory_ospm_status(MemHotplugState *mem_st, ACPIOSTInfoList ***list)
     54 {
     55     ACPIOSTInfoList ***tail = list;
     56     int i;
     57 
     58     for (i = 0; i < mem_st->dev_count; i++) {
     59         QAPI_LIST_APPEND(*tail,
     60                          acpi_memory_device_status(i, &mem_st->devs[i]));
     61     }
     62 }
     63 
     64 static uint64_t acpi_memory_hotplug_read(void *opaque, hwaddr addr,
     65                                          unsigned int size)
     66 {
     67     uint32_t val = 0;
     68     MemHotplugState *mem_st = opaque;
     69     MemStatus *mdev;
     70     Object *o;
     71 
     72     if (mem_st->selector >= mem_st->dev_count) {
     73         trace_mhp_acpi_invalid_slot_selected(mem_st->selector);
     74         return 0;
     75     }
     76 
     77     mdev = &mem_st->devs[mem_st->selector];
     78     o = OBJECT(mdev->dimm);
     79     switch (addr) {
     80     case 0x0: /* Lo part of phys address where DIMM is mapped */
     81         val = o ? object_property_get_uint(o, PC_DIMM_ADDR_PROP, NULL) : 0;
     82         trace_mhp_acpi_read_addr_lo(mem_st->selector, val);
     83         break;
     84     case 0x4: /* Hi part of phys address where DIMM is mapped */
     85         val =
     86             o ? object_property_get_uint(o, PC_DIMM_ADDR_PROP, NULL) >> 32 : 0;
     87         trace_mhp_acpi_read_addr_hi(mem_st->selector, val);
     88         break;
     89     case 0x8: /* Lo part of DIMM size */
     90         val = o ? object_property_get_uint(o, PC_DIMM_SIZE_PROP, NULL) : 0;
     91         trace_mhp_acpi_read_size_lo(mem_st->selector, val);
     92         break;
     93     case 0xc: /* Hi part of DIMM size */
     94         val =
     95             o ? object_property_get_uint(o, PC_DIMM_SIZE_PROP, NULL) >> 32 : 0;
     96         trace_mhp_acpi_read_size_hi(mem_st->selector, val);
     97         break;
     98     case 0x10: /* node proximity for _PXM method */
     99         val = o ? object_property_get_uint(o, PC_DIMM_NODE_PROP, NULL) : 0;
    100         trace_mhp_acpi_read_pxm(mem_st->selector, val);
    101         break;
    102     case 0x14: /* pack and return is_* fields */
    103         val |= mdev->is_enabled   ? 1 : 0;
    104         val |= mdev->is_inserting ? 2 : 0;
    105         val |= mdev->is_removing  ? 4 : 0;
    106         trace_mhp_acpi_read_flags(mem_st->selector, val);
    107         break;
    108     default:
    109         val = ~0;
    110         break;
    111     }
    112     return val;
    113 }
    114 
    115 static void acpi_memory_hotplug_write(void *opaque, hwaddr addr, uint64_t data,
    116                                       unsigned int size)
    117 {
    118     MemHotplugState *mem_st = opaque;
    119     MemStatus *mdev;
    120     ACPIOSTInfo *info;
    121     DeviceState *dev = NULL;
    122     HotplugHandler *hotplug_ctrl = NULL;
    123     Error *local_err = NULL;
    124 
    125     if (!mem_st->dev_count) {
    126         return;
    127     }
    128 
    129     if (addr) {
    130         if (mem_st->selector >= mem_st->dev_count) {
    131             trace_mhp_acpi_invalid_slot_selected(mem_st->selector);
    132             return;
    133         }
    134     }
    135 
    136     switch (addr) {
    137     case 0x0: /* DIMM slot selector */
    138         mem_st->selector = data;
    139         trace_mhp_acpi_write_slot(mem_st->selector);
    140         break;
    141     case 0x4: /* _OST event  */
    142         mdev = &mem_st->devs[mem_st->selector];
    143         if (data == 1) {
    144             /* TODO: handle device insert OST event */
    145         } else if (data == 3) {
    146             /* TODO: handle device remove OST event */
    147         }
    148         mdev->ost_event = data;
    149         trace_mhp_acpi_write_ost_ev(mem_st->selector, mdev->ost_event);
    150         break;
    151     case 0x8: /* _OST status */
    152         mdev = &mem_st->devs[mem_st->selector];
    153         mdev->ost_status = data;
    154         trace_mhp_acpi_write_ost_status(mem_st->selector, mdev->ost_status);
    155         /* TODO: implement memory removal on guest signal */
    156 
    157         info = acpi_memory_device_status(mem_st->selector, mdev);
    158         qapi_event_send_acpi_device_ost(info);
    159         qapi_free_ACPIOSTInfo(info);
    160         break;
    161     case 0x14: /* set is_* fields  */
    162         mdev = &mem_st->devs[mem_st->selector];
    163         if (data & 2) { /* clear insert event */
    164             mdev->is_inserting  = false;
    165             trace_mhp_acpi_clear_insert_evt(mem_st->selector);
    166         } else if (data & 4) {
    167             mdev->is_removing = false;
    168             trace_mhp_acpi_clear_remove_evt(mem_st->selector);
    169         } else if (data & 8) {
    170             if (!mdev->is_enabled) {
    171                 trace_mhp_acpi_ejecting_invalid_slot(mem_st->selector);
    172                 break;
    173             }
    174 
    175             dev = DEVICE(mdev->dimm);
    176             hotplug_ctrl = qdev_get_hotplug_handler(dev);
    177             /* call pc-dimm unplug cb */
    178             hotplug_handler_unplug(hotplug_ctrl, dev, &local_err);
    179             if (local_err) {
    180                 trace_mhp_acpi_pc_dimm_delete_failed(mem_st->selector);
    181 
    182                 /*
    183                  * Send both MEM_UNPLUG_ERROR and DEVICE_UNPLUG_GUEST_ERROR
    184                  * while the deprecation of MEM_UNPLUG_ERROR is
    185                  * pending.
    186                  */
    187                 qapi_event_send_mem_unplug_error(dev->id ? : "",
    188                                                  error_get_pretty(local_err));
    189                 qapi_event_send_device_unplug_guest_error(!!dev->id, dev->id,
    190                                                           dev->canonical_path);
    191                 error_free(local_err);
    192                 break;
    193             }
    194             object_unparent(OBJECT(dev));
    195             trace_mhp_acpi_pc_dimm_deleted(mem_st->selector);
    196         }
    197         break;
    198     default:
    199         break;
    200     }
    201 
    202 }
    203 static const MemoryRegionOps acpi_memory_hotplug_ops = {
    204     .read = acpi_memory_hotplug_read,
    205     .write = acpi_memory_hotplug_write,
    206     .endianness = DEVICE_LITTLE_ENDIAN,
    207     .valid = {
    208         .min_access_size = 1,
    209         .max_access_size = 4,
    210     },
    211 };
    212 
    213 void acpi_memory_hotplug_init(MemoryRegion *as, Object *owner,
    214                               MemHotplugState *state, hwaddr io_base)
    215 {
    216     MachineState *machine = MACHINE(qdev_get_machine());
    217 
    218     state->dev_count = machine->ram_slots;
    219     if (!state->dev_count) {
    220         return;
    221     }
    222 
    223     state->devs = g_malloc0(sizeof(*state->devs) * state->dev_count);
    224     memory_region_init_io(&state->io, owner, &acpi_memory_hotplug_ops, state,
    225                           "acpi-mem-hotplug", MEMORY_HOTPLUG_IO_LEN);
    226     memory_region_add_subregion(as, io_base, &state->io);
    227 }
    228 
    229 /**
    230  * acpi_memory_slot_status:
    231  * @mem_st: memory hotplug state
    232  * @dev: device
    233  * @errp: set in case of an error
    234  *
    235  * Obtain a single memory slot status.
    236  *
    237  * This function will be called by memory unplug request cb and unplug cb.
    238  */
    239 static MemStatus *
    240 acpi_memory_slot_status(MemHotplugState *mem_st,
    241                         DeviceState *dev, Error **errp)
    242 {
    243     Error *local_err = NULL;
    244     int slot = object_property_get_int(OBJECT(dev), PC_DIMM_SLOT_PROP,
    245                                        &local_err);
    246 
    247     if (local_err) {
    248         error_propagate(errp, local_err);
    249         return NULL;
    250     }
    251 
    252     if (slot >= mem_st->dev_count) {
    253         char *dev_path = object_get_canonical_path(OBJECT(dev));
    254         error_setg(errp, "acpi_memory_slot_status: "
    255                    "device [%s] returned invalid memory slot[%d]",
    256                     dev_path, slot);
    257         g_free(dev_path);
    258         return NULL;
    259     }
    260 
    261     return &mem_st->devs[slot];
    262 }
    263 
    264 void acpi_memory_plug_cb(HotplugHandler *hotplug_dev, MemHotplugState *mem_st,
    265                          DeviceState *dev, Error **errp)
    266 {
    267     MemStatus *mdev;
    268     DeviceClass *dc = DEVICE_GET_CLASS(dev);
    269 
    270     if (!dc->hotpluggable) {
    271         return;
    272     }
    273 
    274     mdev = acpi_memory_slot_status(mem_st, dev, errp);
    275     if (!mdev) {
    276         return;
    277     }
    278 
    279     mdev->dimm = dev;
    280     mdev->is_enabled = true;
    281     if (dev->hotplugged) {
    282         mdev->is_inserting = true;
    283         acpi_send_event(DEVICE(hotplug_dev), ACPI_MEMORY_HOTPLUG_STATUS);
    284     }
    285 }
    286 
    287 void acpi_memory_unplug_request_cb(HotplugHandler *hotplug_dev,
    288                                    MemHotplugState *mem_st,
    289                                    DeviceState *dev, Error **errp)
    290 {
    291     MemStatus *mdev;
    292 
    293     mdev = acpi_memory_slot_status(mem_st, dev, errp);
    294     if (!mdev) {
    295         return;
    296     }
    297 
    298     mdev->is_removing = true;
    299     acpi_send_event(DEVICE(hotplug_dev), ACPI_MEMORY_HOTPLUG_STATUS);
    300 }
    301 
    302 void acpi_memory_unplug_cb(MemHotplugState *mem_st,
    303                            DeviceState *dev, Error **errp)
    304 {
    305     MemStatus *mdev;
    306 
    307     mdev = acpi_memory_slot_status(mem_st, dev, errp);
    308     if (!mdev) {
    309         return;
    310     }
    311 
    312     mdev->is_enabled = false;
    313     mdev->dimm = NULL;
    314 }
    315 
    316 static const VMStateDescription vmstate_memhp_sts = {
    317     .name = "memory hotplug device state",
    318     .version_id = 1,
    319     .minimum_version_id = 1,
    320     .fields      = (VMStateField[]) {
    321         VMSTATE_BOOL(is_enabled, MemStatus),
    322         VMSTATE_BOOL(is_inserting, MemStatus),
    323         VMSTATE_UINT32(ost_event, MemStatus),
    324         VMSTATE_UINT32(ost_status, MemStatus),
    325         VMSTATE_END_OF_LIST()
    326     }
    327 };
    328 
    329 const VMStateDescription vmstate_memory_hotplug = {
    330     .name = "memory hotplug state",
    331     .version_id = 1,
    332     .minimum_version_id = 1,
    333     .fields      = (VMStateField[]) {
    334         VMSTATE_UINT32(selector, MemHotplugState),
    335         VMSTATE_STRUCT_VARRAY_POINTER_UINT32(devs, MemHotplugState, dev_count,
    336                                              vmstate_memhp_sts, MemStatus),
    337         VMSTATE_END_OF_LIST()
    338     }
    339 };
    340 
    341 void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem,
    342                               const char *res_root,
    343                               const char *event_handler_method,
    344                               AmlRegionSpace rs, hwaddr memhp_io_base)
    345 {
    346     int i;
    347     Aml *ifctx;
    348     Aml *method;
    349     Aml *dev_container;
    350     Aml *mem_ctrl_dev;
    351     char *mhp_res_path;
    352 
    353     mhp_res_path = g_strdup_printf("%s." MEMORY_HOTPLUG_DEVICE, res_root);
    354     mem_ctrl_dev = aml_device("%s", mhp_res_path);
    355     {
    356         Aml *crs;
    357 
    358         aml_append(mem_ctrl_dev, aml_name_decl("_HID", aml_string("PNP0A06")));
    359         aml_append(mem_ctrl_dev,
    360             aml_name_decl("_UID", aml_string("Memory hotplug resources")));
    361 
    362         crs = aml_resource_template();
    363         if (rs == AML_SYSTEM_IO) {
    364             aml_append(crs,
    365                 aml_io(AML_DECODE16, memhp_io_base, memhp_io_base, 0,
    366                        MEMORY_HOTPLUG_IO_LEN)
    367             );
    368         } else {
    369             aml_append(crs, aml_memory32_fixed(memhp_io_base,
    370                             MEMORY_HOTPLUG_IO_LEN, AML_READ_WRITE));
    371         }
    372         aml_append(mem_ctrl_dev, aml_name_decl("_CRS", crs));
    373 
    374         aml_append(mem_ctrl_dev, aml_operation_region(
    375             MEMORY_HOTPLUG_IO_REGION, rs,
    376             aml_int(memhp_io_base), MEMORY_HOTPLUG_IO_LEN)
    377         );
    378 
    379     }
    380     aml_append(table, mem_ctrl_dev);
    381 
    382     dev_container = aml_device(MEMORY_DEVICES_CONTAINER);
    383     {
    384         Aml *field;
    385         Aml *one = aml_int(1);
    386         Aml *zero = aml_int(0);
    387         Aml *ret_val = aml_local(0);
    388         Aml *slot_arg0 = aml_arg(0);
    389         Aml *slots_nr = aml_name(MEMORY_SLOTS_NUMBER);
    390         Aml *ctrl_lock = aml_name(MEMORY_SLOT_LOCK);
    391         Aml *slot_selector = aml_name(MEMORY_SLOT_SLECTOR);
    392         char *mmio_path = g_strdup_printf("%s." MEMORY_HOTPLUG_IO_REGION,
    393                                           mhp_res_path);
    394 
    395         aml_append(dev_container, aml_name_decl("_HID", aml_string("PNP0A06")));
    396         aml_append(dev_container,
    397             aml_name_decl("_UID", aml_string("DIMM devices")));
    398 
    399         assert(nr_mem <= ACPI_MAX_RAM_SLOTS);
    400         aml_append(dev_container,
    401             aml_name_decl(MEMORY_SLOTS_NUMBER, aml_int(nr_mem))
    402         );
    403 
    404         field = aml_field(mmio_path, AML_DWORD_ACC,
    405                           AML_NOLOCK, AML_PRESERVE);
    406         aml_append(field, /* read only */
    407             aml_named_field(MEMORY_SLOT_ADDR_LOW, 32));
    408         aml_append(field, /* read only */
    409             aml_named_field(MEMORY_SLOT_ADDR_HIGH, 32));
    410         aml_append(field, /* read only */
    411             aml_named_field(MEMORY_SLOT_SIZE_LOW, 32));
    412         aml_append(field, /* read only */
    413             aml_named_field(MEMORY_SLOT_SIZE_HIGH, 32));
    414         aml_append(field, /* read only */
    415             aml_named_field(MEMORY_SLOT_PROXIMITY, 32));
    416         aml_append(dev_container, field);
    417 
    418         field = aml_field(mmio_path, AML_BYTE_ACC,
    419                           AML_NOLOCK, AML_WRITE_AS_ZEROS);
    420         aml_append(field, aml_reserved_field(160 /* bits, Offset(20) */));
    421         aml_append(field, /* 1 if enabled, read only */
    422             aml_named_field(MEMORY_SLOT_ENABLED, 1));
    423         aml_append(field,
    424             /*(read) 1 if has a insert event. (write) 1 to clear event */
    425             aml_named_field(MEMORY_SLOT_INSERT_EVENT, 1));
    426         aml_append(field,
    427             /* (read) 1 if has a remove event. (write) 1 to clear event */
    428             aml_named_field(MEMORY_SLOT_REMOVE_EVENT, 1));
    429         aml_append(field,
    430             /* initiates device eject, write only */
    431             aml_named_field(MEMORY_SLOT_EJECT, 1));
    432         aml_append(dev_container, field);
    433 
    434         field = aml_field(mmio_path, AML_DWORD_ACC,
    435                           AML_NOLOCK, AML_PRESERVE);
    436         aml_append(field, /* DIMM selector, write only */
    437             aml_named_field(MEMORY_SLOT_SLECTOR, 32));
    438         aml_append(field, /* _OST event code, write only */
    439             aml_named_field(MEMORY_SLOT_OST_EVENT, 32));
    440         aml_append(field, /* _OST status code, write only */
    441             aml_named_field(MEMORY_SLOT_OST_STATUS, 32));
    442         aml_append(dev_container, field);
    443         g_free(mmio_path);
    444 
    445         method = aml_method("_STA", 0, AML_NOTSERIALIZED);
    446         ifctx = aml_if(aml_equal(slots_nr, zero));
    447         {
    448             aml_append(ifctx, aml_return(zero));
    449         }
    450         aml_append(method, ifctx);
    451         /* present, functioning, decoding, not shown in UI */
    452         aml_append(method, aml_return(aml_int(0xB)));
    453         aml_append(dev_container, method);
    454 
    455         aml_append(dev_container, aml_mutex(MEMORY_SLOT_LOCK, 0));
    456 
    457         method = aml_method(MEMORY_SLOT_SCAN_METHOD, 0, AML_NOTSERIALIZED);
    458         {
    459             Aml *else_ctx;
    460             Aml *while_ctx;
    461             Aml *idx = aml_local(0);
    462             Aml *eject_req = aml_int(3);
    463             Aml *dev_chk = aml_int(1);
    464 
    465             ifctx = aml_if(aml_equal(slots_nr, zero));
    466             {
    467                 aml_append(ifctx, aml_return(zero));
    468             }
    469             aml_append(method, ifctx);
    470 
    471             aml_append(method, aml_store(zero, idx));
    472             aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
    473             /* build AML that:
    474              * loops over all slots and Notifies DIMMs with
    475              * Device Check or Eject Request notifications if
    476              * slot has corresponding status bit set and clears
    477              * slot status.
    478              */
    479             while_ctx = aml_while(aml_lless(idx, slots_nr));
    480             {
    481                 Aml *ins_evt = aml_name(MEMORY_SLOT_INSERT_EVENT);
    482                 Aml *rm_evt = aml_name(MEMORY_SLOT_REMOVE_EVENT);
    483 
    484                 aml_append(while_ctx, aml_store(idx, slot_selector));
    485                 ifctx = aml_if(aml_equal(ins_evt, one));
    486                 {
    487                     aml_append(ifctx,
    488                                aml_call2(MEMORY_SLOT_NOTIFY_METHOD,
    489                                          idx, dev_chk));
    490                     aml_append(ifctx, aml_store(one, ins_evt));
    491                 }
    492                 aml_append(while_ctx, ifctx);
    493 
    494                 else_ctx = aml_else();
    495                 ifctx = aml_if(aml_equal(rm_evt, one));
    496                 {
    497                     aml_append(ifctx,
    498                         aml_call2(MEMORY_SLOT_NOTIFY_METHOD,
    499                                   idx, eject_req));
    500                     aml_append(ifctx, aml_store(one, rm_evt));
    501                 }
    502                 aml_append(else_ctx, ifctx);
    503                 aml_append(while_ctx, else_ctx);
    504 
    505                 aml_append(while_ctx, aml_add(idx, one, idx));
    506             }
    507             aml_append(method, while_ctx);
    508             aml_append(method, aml_release(ctrl_lock));
    509             aml_append(method, aml_return(one));
    510         }
    511         aml_append(dev_container, method);
    512 
    513         method = aml_method(MEMORY_SLOT_STATUS_METHOD, 1, AML_NOTSERIALIZED);
    514         {
    515             Aml *slot_enabled = aml_name(MEMORY_SLOT_ENABLED);
    516 
    517             aml_append(method, aml_store(zero, ret_val));
    518             aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
    519             aml_append(method,
    520                 aml_store(aml_to_integer(slot_arg0), slot_selector));
    521 
    522             ifctx = aml_if(aml_equal(slot_enabled, one));
    523             {
    524                 aml_append(ifctx, aml_store(aml_int(0xF), ret_val));
    525             }
    526             aml_append(method, ifctx);
    527 
    528             aml_append(method, aml_release(ctrl_lock));
    529             aml_append(method, aml_return(ret_val));
    530         }
    531         aml_append(dev_container, method);
    532 
    533         method = aml_method(MEMORY_SLOT_CRS_METHOD, 1, AML_SERIALIZED);
    534         {
    535             Aml *mr64 = aml_name("MR64");
    536             Aml *mr32 = aml_name("MR32");
    537             Aml *crs_tmpl = aml_resource_template();
    538             Aml *minl = aml_name("MINL");
    539             Aml *minh = aml_name("MINH");
    540             Aml *maxl =  aml_name("MAXL");
    541             Aml *maxh =  aml_name("MAXH");
    542             Aml *lenl = aml_name("LENL");
    543             Aml *lenh = aml_name("LENH");
    544 
    545             aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
    546             aml_append(method, aml_store(aml_to_integer(slot_arg0),
    547                                          slot_selector));
    548 
    549             aml_append(crs_tmpl,
    550                 aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED,
    551                                  AML_CACHEABLE, AML_READ_WRITE,
    552                                  0, 0x0, 0xFFFFFFFFFFFFFFFEULL, 0,
    553                                  0xFFFFFFFFFFFFFFFFULL));
    554             aml_append(method, aml_name_decl("MR64", crs_tmpl));
    555             aml_append(method,
    556                 aml_create_dword_field(mr64, aml_int(14), "MINL"));
    557             aml_append(method,
    558                 aml_create_dword_field(mr64, aml_int(18), "MINH"));
    559             aml_append(method,
    560                 aml_create_dword_field(mr64, aml_int(38), "LENL"));
    561             aml_append(method,
    562                 aml_create_dword_field(mr64, aml_int(42), "LENH"));
    563             aml_append(method,
    564                 aml_create_dword_field(mr64, aml_int(22), "MAXL"));
    565             aml_append(method,
    566                 aml_create_dword_field(mr64, aml_int(26), "MAXH"));
    567 
    568             aml_append(method,
    569                 aml_store(aml_name(MEMORY_SLOT_ADDR_HIGH), minh));
    570             aml_append(method,
    571                 aml_store(aml_name(MEMORY_SLOT_ADDR_LOW), minl));
    572             aml_append(method,
    573                 aml_store(aml_name(MEMORY_SLOT_SIZE_HIGH), lenh));
    574             aml_append(method,
    575                 aml_store(aml_name(MEMORY_SLOT_SIZE_LOW), lenl));
    576 
    577             /* 64-bit math: MAX = MIN + LEN - 1 */
    578             aml_append(method, aml_add(minl, lenl, maxl));
    579             aml_append(method, aml_add(minh, lenh, maxh));
    580             ifctx = aml_if(aml_lless(maxl, minl));
    581             {
    582                 aml_append(ifctx, aml_add(maxh, one, maxh));
    583             }
    584             aml_append(method, ifctx);
    585             ifctx = aml_if(aml_lless(maxl, one));
    586             {
    587                 aml_append(ifctx, aml_subtract(maxh, one, maxh));
    588             }
    589             aml_append(method, ifctx);
    590             aml_append(method, aml_subtract(maxl, one, maxl));
    591 
    592             /* return 32-bit _CRS if addr/size is in low mem */
    593             /* TODO: remove it since all hotplugged DIMMs are in high mem */
    594             ifctx = aml_if(aml_equal(maxh, zero));
    595             {
    596                 crs_tmpl = aml_resource_template();
    597                 aml_append(crs_tmpl,
    598                     aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED,
    599                                      AML_MAX_FIXED, AML_CACHEABLE,
    600                                      AML_READ_WRITE,
    601                                      0, 0x0, 0xFFFFFFFE, 0,
    602                                      0xFFFFFFFF));
    603                 aml_append(ifctx, aml_name_decl("MR32", crs_tmpl));
    604                 aml_append(ifctx,
    605                     aml_create_dword_field(mr32, aml_int(10), "MIN"));
    606                 aml_append(ifctx,
    607                     aml_create_dword_field(mr32, aml_int(14), "MAX"));
    608                 aml_append(ifctx,
    609                     aml_create_dword_field(mr32, aml_int(22), "LEN"));
    610                 aml_append(ifctx, aml_store(minl, aml_name("MIN")));
    611                 aml_append(ifctx, aml_store(maxl, aml_name("MAX")));
    612                 aml_append(ifctx, aml_store(lenl, aml_name("LEN")));
    613 
    614                 aml_append(ifctx, aml_release(ctrl_lock));
    615                 aml_append(ifctx, aml_return(mr32));
    616             }
    617             aml_append(method, ifctx);
    618 
    619             aml_append(method, aml_release(ctrl_lock));
    620             aml_append(method, aml_return(mr64));
    621         }
    622         aml_append(dev_container, method);
    623 
    624         method = aml_method(MEMORY_SLOT_PROXIMITY_METHOD, 1,
    625                             AML_NOTSERIALIZED);
    626         {
    627             Aml *proximity = aml_name(MEMORY_SLOT_PROXIMITY);
    628 
    629             aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
    630             aml_append(method, aml_store(aml_to_integer(slot_arg0),
    631                                          slot_selector));
    632             aml_append(method, aml_store(proximity, ret_val));
    633             aml_append(method, aml_release(ctrl_lock));
    634             aml_append(method, aml_return(ret_val));
    635         }
    636         aml_append(dev_container, method);
    637 
    638         method = aml_method(MEMORY_SLOT_OST_METHOD, 4, AML_NOTSERIALIZED);
    639         {
    640             Aml *ost_evt = aml_name(MEMORY_SLOT_OST_EVENT);
    641             Aml *ost_status = aml_name(MEMORY_SLOT_OST_STATUS);
    642 
    643             aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
    644             aml_append(method, aml_store(aml_to_integer(slot_arg0),
    645                                          slot_selector));
    646             aml_append(method, aml_store(aml_arg(1), ost_evt));
    647             aml_append(method, aml_store(aml_arg(2), ost_status));
    648             aml_append(method, aml_release(ctrl_lock));
    649         }
    650         aml_append(dev_container, method);
    651 
    652         method = aml_method(MEMORY_SLOT_EJECT_METHOD, 2, AML_NOTSERIALIZED);
    653         {
    654             Aml *eject = aml_name(MEMORY_SLOT_EJECT);
    655 
    656             aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
    657             aml_append(method, aml_store(aml_to_integer(slot_arg0),
    658                                          slot_selector));
    659             aml_append(method, aml_store(one, eject));
    660             aml_append(method, aml_release(ctrl_lock));
    661         }
    662         aml_append(dev_container, method);
    663 
    664         /* build memory devices */
    665         for (i = 0; i < nr_mem; i++) {
    666             Aml *dev;
    667             const char *s;
    668 
    669             dev = aml_device("MP%02X", i);
    670             aml_append(dev, aml_name_decl("_UID", aml_string("0x%02X", i)));
    671             aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C80")));
    672 
    673             method = aml_method("_CRS", 0, AML_NOTSERIALIZED);
    674             s = MEMORY_SLOT_CRS_METHOD;
    675             aml_append(method, aml_return(aml_call1(s, aml_name("_UID"))));
    676             aml_append(dev, method);
    677 
    678             method = aml_method("_STA", 0, AML_NOTSERIALIZED);
    679             s = MEMORY_SLOT_STATUS_METHOD;
    680             aml_append(method, aml_return(aml_call1(s, aml_name("_UID"))));
    681             aml_append(dev, method);
    682 
    683             method = aml_method("_PXM", 0, AML_NOTSERIALIZED);
    684             s = MEMORY_SLOT_PROXIMITY_METHOD;
    685             aml_append(method, aml_return(aml_call1(s, aml_name("_UID"))));
    686             aml_append(dev, method);
    687 
    688             method = aml_method("_OST", 3, AML_NOTSERIALIZED);
    689             s = MEMORY_SLOT_OST_METHOD;
    690             aml_append(method,
    691                        aml_call4(s, aml_name("_UID"), aml_arg(0),
    692                                  aml_arg(1), aml_arg(2)));
    693             aml_append(dev, method);
    694 
    695             method = aml_method("_EJ0", 1, AML_NOTSERIALIZED);
    696             s = MEMORY_SLOT_EJECT_METHOD;
    697             aml_append(method,
    698                        aml_call2(s, aml_name("_UID"), aml_arg(0)));
    699             aml_append(dev, method);
    700 
    701             aml_append(dev_container, dev);
    702         }
    703 
    704         /* build Method(MEMORY_SLOT_NOTIFY_METHOD, 2) {
    705          *     If (LEqual(Arg0, 0x00)) {Notify(MP00, Arg1)} ... }
    706          */
    707         method = aml_method(MEMORY_SLOT_NOTIFY_METHOD, 2, AML_NOTSERIALIZED);
    708         for (i = 0; i < nr_mem; i++) {
    709             ifctx = aml_if(aml_equal(aml_arg(0), aml_int(i)));
    710             aml_append(ifctx,
    711                 aml_notify(aml_name("MP%.02X", i), aml_arg(1))
    712             );
    713             aml_append(method, ifctx);
    714         }
    715         aml_append(dev_container, method);
    716     }
    717     aml_append(table, dev_container);
    718 
    719     if (event_handler_method) {
    720         method = aml_method(event_handler_method, 0, AML_NOTSERIALIZED);
    721         aml_append(method, aml_call0(MEMORY_DEVICES_CONTAINER "."
    722                                      MEMORY_SLOT_SCAN_METHOD));
    723         aml_append(table, method);
    724     }
    725 
    726     g_free(mhp_res_path);
    727 }