def METHOD_NAME(ql: Qiling, address: int, params):
    heap = ql.loader.smm_context.heap
    # get a copy of smm heap chunks list sorted by starting address
    chunks = sorted(heap.chunks, key=lambda c: c.address)
    # turn chunks objects into 3-item entries: [start, end, inuse]
    chunks = [[ch.address, ch.address + ch.size, ch.inuse] for ch in chunks]
    # if first chunk does not start at heap start, add a dummy free chunk there
    if chunks[0][0] != heap.start_address:
        chunks.insert(0, [heap.start_address, chunks[0].address, False])
    # if last chunk does not end at heap end, add a dummy free chunk there
    if (chunks[-1][1]) != heap.end_address:
        chunks.append([chunks[-1][1], heap.end_address, False])
    # coalesce adjacent free / used chunks on the list
    chunks = _coalesce(chunks)
    size = len(chunks) * EFI_SMRAM_DESCRIPTOR.sizeof()
    MmramMapSize = params["MmramMapSize"]
    if utils.read_int64(ql, MmramMapSize) < size:
        # since the caller cannot predict how much memory would be required for storing
        # the memory map, this method is normally called twice. the first one passes a
        # zero size only to determine the expected size, then the caller allocates the
        # required amount of memory and call it again.
        #
        # our memory map is managed differently from the real one, and memory allocations
        # are likely to generate an additional "map block" (or two, if allocated somewhere
        # in the last free heap chunk). because the caller allocates a new memory chunk
        # between the two calls, that would cause the second call to always complain the
        # buffer is too small.
        #
        # to work around that, we have the first call return a larger number than it should
        # have, to compensate on the coming allocation.
        extra = 2 * EFI_SMRAM_DESCRIPTOR.sizeof()
        utils.write_int64(ql, MmramMapSize, size + extra)
        return EFI_BUFFER_TOO_SMALL
    MmramMap = params["MmramMap"]
    state = EFI_CACHEABLE
    state |= EFI_SMRAM_OPEN if ql.loader.smm_context.tseg_open else EFI_SMRAM_CLOSED
    state |= EFI_SMRAM_LOCKED if ql.loader.smm_context.tseg_locked else 0
    for i, ch in enumerate(chunks):
        desc = EFI_SMRAM_DESCRIPTOR()
        desc.PhysicalStart = ch[0]
        desc.CpuStart = ch[0]
        desc.PhysicalSize = ch[1] - ch[0]
        desc.RegionState = state | (EFI_ALLOCATED if ch[2] else 0)
        desc.saveTo(ql, MmramMap + (i * desc.sizeof()))
    return EFI_SUCCESS