📄 dld_memmgr.c
字号:
/* * dsp_dld/arm/dld_memmgr.c * * DSP Dynamic Loader Daemon: dld_memmgr.c * * Copyright (C) 2003-2005 Nokia Corporation * * Written by Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * 2005/07/07: DSP Gateway version 3.3 */#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <string.h>#include <fcntl.h>#include <sys/ioctl.h>#include "list.h"#include "dsp_dld.h"#include "dld_malloc.h"#include "dld_daemon.h"#include "dld_cmd.h"#include "dld_taskent.h"#include <asm/arch/dsp.h>#define PLACE_MODE_BASENAME 0x1#define PLACE_MODE_EXACTNAME 0x0#define PLACE_MODE_ANYWHERE 0x2#define place_mode_basename(mode) (mode & PLACE_MODE_BASENAME)#define place_mode_exactname(mode) (!(mode & PLACE_MODE_BASENAME))#define place_mode_anywhere(mode) (mode & PLACE_MODE_ANYWHERE)#define DSPADDR_ILLEGAL 0xffffffff#define ceil_int(n,align) (((n)+(align)-1)&~((align)-1))#define floor_int(n,align) ((n)&~((align)-1))static LIST_HEAD(g_memlist);static struct memmgr *memmgr_default(void);static u32 memmgr_malloc(struct memmgr *mem, struct taskent *te, u32 size, u32 align);static void memmgr_freeseg(struct memseg *seg);int memmgr_exmap(struct list_head *list);struct memmgr *memmgr_range_user(struct list_head *list, u32 base, u32 size);int space_find_by_addr(u32 addr, u32 size);static struct memmgr *placescn(struct taskent *te, struct section *scn, struct lkcmd *lkcmd, unsigned int mode);static struct memseg *memseg_new(u32 base, u32 size);static void memseg_freelist(struct list_head *list);/* * default directive */static struct directive directive_default = { .list_head = LIST_HEAD_INIT(directive_default.list_head), .scnnm = "default", .iscnlist = LIST_HEAD_INIT(directive_default.iscnlist), .load = { .stype = 0, .align = 0, .block = 0, .fill = 0, .mem = NULL, .addr = 0 }, .run = { .stype = 0, .align = 0, .block = 0, .fill = 0, .mem = NULL, .addr = 0 },};/* * default memmgr */static struct memmgr *memmgr_default(void){ /* first element of memmgr list */ return list_entry(g_memlist.next, struct memmgr, list_head);}static u32 memmgr_malloc(struct memmgr *mem, struct taskent *te, u32 size, u32 align){ struct memseg *seg; if (size == 0) return mem->base; memseg_for_each(seg, &mem->seglist) { u32 allocbase, allocend; allocbase = ceil_int(seg->wp, align); allocend = allocbase + size; if (allocend <= seg->end) { if (seg->cobj == te->cobj) { seg->wp = allocend; } else { struct memseg *newseg = dld_malloc(sizeof(struct memseg), "memseg"); newseg->base = allocbase; newseg->wp = allocend; newseg->end = seg->end; newseg->cobj = te->cobj; seg->end = allocbase; list_add(&newseg->list_head, &seg->list_head); } return allocbase; } } return DSPADDR_ILLEGAL;}static void memmgr_freeseg(struct memseg *seg){ struct memseg *prev; prev = list_entry(seg->list_head.prev, struct memseg, list_head); prev->end = seg->end; list_del(&seg->list_head); dld_free(seg, "memseg");}struct memmgr *memmgr_new(char *name, u32 base, u32 size){ struct memmgr *mem; struct memseg *seg; mem = dld_malloc(sizeof(struct memmgr), "memmgr"); if (mem == NULL) return NULL; mem->name = dld_strdup(name, "memmgr->name"); if (mem->name == NULL) goto fail; mem->base = base; mem->size = size;#ifdef DSP_EMULATION mem->img = dld_malloc(mem->size, "memmgr->img"); if (mem->img == NULL) goto fail;#else /* DSP_EMULATION */ mem->exmap_size = 0; /* set later */#endif /* DSP_EMULATION */ mem->seg_base = base; INIT_LIST_HEAD(&mem->seglist); seg = memseg_new(base, size); if (seg == NULL) goto fail; list_add_tail(&seg->list_head, &mem->seglist); mem->lkcmd = NULL; return mem;fail: if (mem->name) dld_free(mem->name, "memmgr->name");#ifdef DSP_EMULATION if (mem->img) dld_free(mem->name, "memmgr->img");#endif if (mem) dld_free(mem, "memmgr"); if (seg) dld_free(seg, "memseg"); return NULL;}int memmgr_validate(struct memmgr *mem){ struct memmgr *mem_user; char *name = mem->name; u32 base = mem->base; u32 size = mem->size; int space = space_find_by_addr(base, size); if ((((mem_user = memmgr_range_user(NULL, base, size))) != NULL) || (((mem_user = taskent_mem_range_user(base, size))) != NULL)) { prmsg("MEMORY segment %s has overlap with " "previously defined one:\n" " new seg -- %s: base = 0x%06lx, size = 0x%lx\n" " old user -- %s (@ %s): base = 0x%06lx, size = 0x%lx\n", name, name, base, size, mem_user->name, mem_user->lkcmd ? mem_user->lkcmd->fn : "base command file", mem_user->base, mem_user->size); return 0; } if (space == SPACE_CROSSING) { prmsg("MEMORY segment %s is crossing " "memory boundary of DSP hardware!\n" "base = 0x%06lx, size = 0x%lx\n", name, base, size); return 0; } return 1;}/* * if list == NULL in following handlers, it is for g_memlist. */void memmgr_freelist(struct list_head *list){ struct memmgr *mem, *tmp; if (list == NULL) list = &g_memlist; memmgr_for_each_safe(mem, tmp, list) { list_del(&mem->list_head);#ifdef DSP_EMULATION if (mem->img) dld_free(mem->img, "memmgr->img");#else /* DSP_EMULATION */ if (mem->exmap_size > 0) { int fd; if ((fd = open(DEVNAME_DSPMEM, O_RDWR)) < 0) { prmsg("%s open failed at %s line %d\n", DEVNAME_CONTROL, __FILE__, __LINE__); goto unmap_done; } prmsg("releasing external memory map: adr = 0x%06lx\n", mem->base); ioctl(fd, OMAP_DSP_MEM_IOCTL_EXUNMAP, mem->base); close(fd); }unmap_done:#endif /* DSP_EMULATION */ if (mem->name) dld_free(mem->name, "memmgr->name"); memseg_freelist(&mem->seglist); dld_free(mem, "memmgr"); }}void memmgr_add(struct list_head *list, struct memmgr *mem){ if (list == NULL) list = &g_memlist; list_add_tail(&mem->list_head, list);}int memmgr_register_global(struct list_head *list){ struct memmgr *mem, *tmp; if (!list_empty(&g_memlist)) { prmsg("g_memlist is not empty at %s line %d\n", __FILE__, __LINE__); } memmgr_for_each_safe(mem, tmp, list) { if (!memmgr_validate(mem)) return -1; mem->lkcmd = NULL; list_del(&mem->list_head); list_add_tail(&mem->list_head, &g_memlist); }#ifndef DSP_EMULATION memmgr_exmap(&g_memlist);#endif return 0;}#ifndef DSP_EMULATION#define need_exmap(mem) \ (((mem)->exmap_size > 0) && (strcmp((mem)->name, "FRAMEBUFFER")))int memmgr_exmap(struct list_head *list){ struct memmgr *mem1, *mem2; int ret = 0; int fd; if (list == NULL) list = &g_memlist; if ((fd = open(DEVNAME_DSPMEM, O_RDWR)) < 0) { prmsg("%s open failed at %s line %d\n", DEVNAME_CONTROL, __FILE__, __LINE__); return -1; } memmgr_for_each(mem1, list) { if (space_find_by_addr(mem1->base, mem1->size) == SPACE_EXTERN) mem1->exmap_size = mem1->size; } /* * join consecutive memory sections for one exmap. */ memmgr_for_each(mem1, list) { if (!need_exmap(mem1)) continue; memmgr_for_each(mem2, list) { if (!need_exmap(mem2)) continue; if (mem1->base + mem1->exmap_size == mem2->base) { /* join */ mem1->exmap_size += mem2->size; mem2->exmap_size = 0; } } } memmgr_for_each(mem1, list) { if (mem1->exmap_size == 0) continue; if (!strcmp(mem1->name, "FRAMEBUFFER")) { /* * export framebuffer */ u32 base = mem1->base; prmsg("exporting framebuffer to 0x%06lx\n", base); if (ioctl(fd, OMAP_DSP_MEM_IOCTL_FBEXPORT, &base) < 0) { prmsg("FBEXPORT failed\n"); ret = -1; goto out; } prmsg(" (actual address = 0x%06lx)\n", base); } else { /* * allocate new memory */ struct omap_dsp_mapinfo mapinfo = { mem1->base, mem1->exmap_size }; prmsg("mapping external memory: " "adr = 0x%06lx, size = 0x%lx\n", mem1->base, mem1->exmap_size); if (ioctl(fd, OMAP_DSP_MEM_IOCTL_EXMAP, &mapinfo) < 0) { prmsg("EXMAP failed\n"); ret = -1; goto out; } } }out: close(fd); return ret;}#endif /* !DSP_EMULATION */struct memmgr *memmgr_range_user(struct list_head *list, u32 base, u32 size){ struct memmgr *mem; if (list == NULL) list = &g_memlist; memmgr_for_each(mem, list) { if ((base < mem->base + mem->size) && (base + size > mem->base)) /* overlapping */ return mem; } /* no overlap */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -