// SPDX-License-Identifier: MPL-2.0
#include "std/malloc.h"
#include "memory/page.h"
#include "memory/heap.h"
#include "memory/vmem_layout.h"
#include "kernel/log.h"
#include "std/smp.h"
sh_SPIN_LOCK malloc_lock=SH_LOCK();
SH_STATUS last_status=0;
SH_STATUS sh_malloc_get_last_status() {
  return last_status;
}
void* sh_malloc(sh_uint64 size) {
  if (size==0) return SH_NULLPTR;
  sh_spin_lock(&malloc_lock);
  sh_page_VIRTUAL_ADDRESS va=0;
  SH_STATUS status;
  if (size<=1024) {
    status=sh_heap_allocate_object((sh_uint32)size,&va);
  } else {
    sh_uint32 pages=(sh_uint32)((size+4095LL)/4096LL);
    status=sh_heap_allocate_pages(pages,&va);
  }
  last_status=status;
  sh_spin_unlock(&malloc_lock);
  return (sh_status_error(status))?SH_NULLPTR:(void*)va;
}
void sh_free(void *ptr) {
  if (ptr == SH_NULLPTR) return;
  sh_spin_lock(&malloc_lock);
  sh_page_VIRTUAL_ADDRESS va=(sh_page_VIRTUAL_ADDRESS)ptr;
  SH_STATUS status=SH_STATUS_SUCCESS;
  if (va>=SH_VMEM_LAYOUT_HEAP_SLAB_LEVEL_0_VA && va<SH_VMEM_LAYOUT_HEAP_SLAB_LEVEL_7_VA+SH_VMEM_LAYOUT_HEAP_SLAB_LEVEL_7_SIZE_BYTES) {
    status=sh_heap_free_object(va);
  } else if (va>=SH_VMEM_LAYOUT_HEAP_BIG_VA && va<SH_VMEM_LAYOUT_HEAP_SLAB_LEVEL_0_VA) {
    status=sh_heap_free_pages(va);
    if (sh_status_error(status)) sh_log_fcritical(SH_LOG_SOURCE_HEAP,"Couldn't free pages at va=0x%x\n",va);
  } else {
    sh_log_fcritical(SH_LOG_SOURCE_HEAP, "va=0x%x doesn't come from heap\n", va);
  }
  last_status=status;
  sh_spin_unlock(&malloc_lock);
}
