Goto sanos source index

//
// kmem.c
//
// Kernel memory page allocator
//
// Copyright (C) 2002 Michael Ringgaard. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 
// 1. Redistributions of source code must retain the above copyright 
//    notice, this list of conditions and the following disclaimer.  
// 2. Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.  
// 3. Neither the name of the project nor the names of its contributors
//    may be used to endorse or promote products derived from this software
//    without specific prior written permission. 
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
// SUCH DAMAGE.
// 

#include <os/krnl.h>

#define OSVMAP_PAGES 1
#define OSVMAP_ENTRIES (OSVMAP_PAGES * PAGESIZE / sizeof(struct rmap))

#define KMODMAP_PAGES 1
#define KMODMAP_ENTRIES (KMODMAP_PAGES * PAGESIZE / sizeof(struct rmap))

struct rmap *osvmap = (struct rmap *) OSVMAP_ADDRESS;
struct rmap *kmodmap = (struct rmap *) KMODMAP_ADDRESS;

void *alloc_pages(int pages, unsigned long tag) {
  char *vaddr;
  int i;
  unsigned long pfn;

  if (tag == 0) tag = 'KMEM';
  vaddr = (char *) PTOB(rmap_alloc(osvmap, pages));
  for (i = 0; i < pages; i++) {
    pfn = alloc_pageframe(tag);
    map_page(vaddr + PTOB(i), pfn, PT_WRITABLE | PT_PRESENT);
  }

  //kprintf("alloc kmem %dK @ %p (%d KB free)\n", pages * (PAGESIZE / K), vaddr, freemem * (PAGESIZE / K));
  return vaddr;
}

void *alloc_pages_align(int pages, int align, unsigned long tag)
{
  char *vaddr;
  int i;
  unsigned long pfn;

  if (tag == 0) tag = 'KMEM';
  vaddr = (char *) PTOB(rmap_alloc_align(osvmap, pages, align));
  for (i = 0; i < pages; i++) {
    pfn = alloc_pageframe(tag);
    map_page(vaddr + PTOB(i), pfn, PT_WRITABLE | PT_PRESENT);
  }

  //kprintf("alloc kmem %dK @ %p (align %dK, %d KB free)\n", pages * (PAGESIZE / K), vaddr, align * (PAGESIZE / K), freemem * (PAGESIZE / K));
  return vaddr;
}

void *alloc_pages_linear(int pages, unsigned long tag)
{
  char *vaddr;
  int i;
  unsigned long pfn;

  if (tag == 0) tag = 'KMEM';
  pfn = alloc_linear_pageframes(pages, tag);
  if (pfn == 0xFFFFFFFF) return 0;
  vaddr = (char *) PTOB(rmap_alloc(osvmap, pages));
  for (i = 0; i < pages; i++) {
    map_page(vaddr + PTOB(i), pfn, PT_WRITABLE | PT_PRESENT);
    pfn++;
  }

  //kprintf("alloc kmem linear %dK @ %p (%d KB free)\n", pages * (PAGESIZE / K), vaddr, freemem * (PAGESIZE / K));

  return vaddr;
}

void free_pages(void *addr, int pages)
{
  int i;
  unsigned long pfn;

  //kprintf("free kmem %dK @ %p\n", pages * PAGESIZE / K, addr);

  for (i = 0; i < pages; i++) {
    pfn = BTOP(virt2phys((char *) addr + PTOB(i)));
    free_pageframe(pfn);
    unmap_page((char *) addr + PTOB(i));
  }

  rmap_free(osvmap, BTOP(addr), pages);
}

void *iomap(unsigned long addr, int size) {
  char *vaddr;
  int i;
  int pages = PAGES(size);

  vaddr = (char *) PTOB(rmap_alloc(osvmap, pages));
  for (i = 0; i < pages; i++) {
    map_page(vaddr + PTOB(i), BTOP(addr) + i, PT_WRITABLE | PT_PRESENT);
  }

  return vaddr;
}

void iounmap(void *addr, int size) {
  int i;
  int pages = PAGES(size);

  for (i = 0; i < pages; i++) unmap_page((char *) addr + PTOB(i));
  rmap_free(osvmap, BTOP(addr), pages);
}

void *alloc_module_mem(int pages) {
  char *vaddr;
  int i;
  unsigned long pfn;

  vaddr = (char *) PTOB(rmap_alloc(kmodmap, pages));
  for (i = 0; i < pages; i++) {
    pfn = alloc_pageframe('KMOD');
    map_page(vaddr + PTOB(i), pfn, PT_WRITABLE | PT_PRESENT);
    memset(vaddr + PTOB(i), 0, PAGESIZE);
  }

  //kprintf("alloc mod mem %dK @ %p\n", pages * PAGESIZE / K, vaddr);

  return vaddr;
}

void free_module_mem(void *addr, int pages) {
  int i;
  unsigned long pfn;

  //kprintf("free mod mem %dK @ %p\n", pages * PAGESIZE / K, addr);

  for (i = 0; i < pages; i++) {
    pfn = BTOP(virt2phys((char *) addr + PTOB(i)));
    free_pageframe(pfn);
    unmap_page((char *) addr + PTOB(i));
  }

  rmap_free(kmodmap, BTOP(addr), pages);
}

void init_kmem() {
  int pfn;
  struct image_header *imghdr;

  // Allocate page frame for kernel heap resource map and map into syspages
  pfn = alloc_pageframe('SYS');
  map_page(osvmap, pfn, PT_WRITABLE | PT_PRESENT);

  // Initialize resource map for kernel heap
  rmap_init(osvmap, OSVMAP_ENTRIES);

  // Add kernel heap address space to osvmap
  rmap_free(osvmap, BTOP(KHEAPBASE), BTOP(KHEAPSIZE));

  // Allocate page frame for kernel module map and map into syspages
  pfn = alloc_pageframe('SYS');
  map_page(kmodmap, pfn, PT_WRITABLE | PT_PRESENT);

  // Initialize resource map for kernel module area
  rmap_init(kmodmap, KMODMAP_ENTRIES);

  // Add kernel heap address space to kmodmap
  imghdr = get_image_header((hmodule_t) OSBASE);
  rmap_free(kmodmap, BTOP(OSBASE), BTOP(KMODSIZE));
  rmap_reserve(kmodmap, BTOP(OSBASE), BTOP(imghdr->optional.size_of_image));
}

int list_memmap(struct proc_file *pf, struct rmap *rmap, unsigned int startpos)
{
  struct rmap *r;
  struct rmap *rlim;
  unsigned int pos = startpos;
  unsigned int total = 0;
  struct pdirstat stat;

  pprintf(pf, "   start      end      size committed  readonly       gap\n");
  pprintf(pf, "-------- -------- --------- --------- --------- ---------\n");

  rlim = &rmap[rmap->offset];

  for (r = &rmap[1]; r <= rlim; r++)  {
    unsigned int size = r->offset - pos;

    if (size > 0) {
      pdir_stat((void *) (pos * PAGESIZE), size * PAGESIZE, &stat);
      pprintf(pf, "%08X %08X %8dK %8dK %8dK %8dK\n", 
              pos * PAGESIZE, 
              r->offset * PAGESIZE - 1, 
              size * (PAGESIZE / 1024), 
              stat.present * (PAGESIZE / 1024), 
              stat.readonly * (PAGESIZE / 1024), 
              r->size * (PAGESIZE / 1024));

      total += size;
    }
    pos = r->offset + r->size;
  }
  pprintf(pf, "Total: %dK\n", total * PAGESIZE / 1024);
  return 0;
}

int kmem_proc(struct proc_file *pf, void *arg) {
  return list_memmap(pf, osvmap, BTOP(KHEAPBASE));
}

int kmodmem_proc(struct proc_file *pf, void *arg) {
  return list_memmap(pf, kmodmap, BTOP(OSBASE));
}