239 lines
5.4 KiB
C
239 lines
5.4 KiB
C
/*
|
|
* Cisco router simulation platform.
|
|
* Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr)
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) yajin 2008 <yajinzhou@gmail.com >
|
|
*
|
|
* This file is part of the virtualmips distribution.
|
|
* See LICENSE file for terms of the license.
|
|
*
|
|
*/
|
|
|
|
#define _GNU_SOURCE
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/mman.h>
|
|
#include <fcntl.h>
|
|
#include <assert.h>
|
|
|
|
#include "cpu.h"
|
|
#include "vm.h"
|
|
#include "mips_memory.h"
|
|
#include "device.h"
|
|
|
|
#define DEBUG_DEV_ACCESS 0
|
|
|
|
/* Get device by ID */
|
|
struct vdevice *dev_get_by_id (vm_instance_t * vm, u_int dev_id)
|
|
{
|
|
if (!vm || (dev_id >= VM_DEVICE_MAX))
|
|
return NULL;
|
|
|
|
return (vm->dev_array[dev_id]);
|
|
}
|
|
|
|
/* Get device by name */
|
|
struct vdevice *dev_get_by_name (vm_instance_t * vm, char *name)
|
|
{
|
|
struct vdevice *dev;
|
|
|
|
if (!vm)
|
|
return NULL;
|
|
|
|
for (dev = vm->dev_list; dev; dev = dev->next)
|
|
if (!strcmp (dev->name, name))
|
|
return dev;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/* Device lookup by physical address */
|
|
//struct vdevice *dev_lookup(vm_instance_t *vm,m_pa_t phys_addr,int cached)
|
|
struct vdevice *dev_lookup (vm_instance_t * vm, m_pa_t phys_addr)
|
|
{
|
|
struct vdevice *dev;
|
|
|
|
if (!vm)
|
|
return NULL;
|
|
|
|
for (dev = vm->dev_list; dev; dev = dev->next) {
|
|
// if (cached && !(dev->flags & VDEVICE_FLAG_CACHING))
|
|
// continue;
|
|
|
|
if ((phys_addr >= dev->phys_addr)
|
|
&& ((phys_addr - dev->phys_addr) < dev->phys_len))
|
|
return dev;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/* Find the next device after the specified address */
|
|
//struct vdevice *dev_lookup_next(vm_instance_t *vm,m_pa_t phys_addr,
|
|
// struct vdevice *dev_start,int cached)
|
|
struct vdevice *dev_lookup_next (vm_instance_t * vm, m_pa_t phys_addr,
|
|
struct vdevice *dev_start)
|
|
{
|
|
struct vdevice *dev;
|
|
|
|
if (!vm)
|
|
return NULL;
|
|
|
|
dev = (dev_start != NULL) ? dev_start : vm->dev_list;
|
|
for (; dev; dev = dev->next) {
|
|
//if (cached && !(dev->flags & VDEVICE_FLAG_CACHING))
|
|
// continue;
|
|
|
|
if (dev->phys_addr > phys_addr)
|
|
return dev;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/* Initialize a device */
|
|
void dev_init (struct vdevice *dev)
|
|
{
|
|
memset (dev, 0, sizeof (*dev));
|
|
dev->fd = -1;
|
|
}
|
|
|
|
/* reset all devices */
|
|
void dev_reset_all (vm_instance_t * vm)
|
|
{
|
|
struct vdevice *dev;
|
|
for (dev = vm->dev_list; dev; dev = dev->next) {
|
|
ASSERT (dev->reset_handler != NULL,
|
|
"reset_handler is NULL. name %s\n", dev->name);
|
|
dev->reset_handler (vm->boot_cpu, dev);
|
|
}
|
|
}
|
|
|
|
/* Allocate a device */
|
|
struct vdevice *dev_create (char *name)
|
|
{
|
|
struct vdevice *dev;
|
|
|
|
if (!(dev = malloc (sizeof (*dev)))) {
|
|
fprintf (stderr,
|
|
"dev_create: insufficient memory to " "create device '%s'.\n",
|
|
name);
|
|
return NULL;
|
|
}
|
|
|
|
dev_init (dev);
|
|
dev->name = name;
|
|
return dev;
|
|
}
|
|
|
|
/* Remove a device */
|
|
void dev_remove (vm_instance_t * vm, struct vdevice *dev)
|
|
{
|
|
if (dev == NULL)
|
|
return;
|
|
|
|
vm_unbind_device (vm, dev);
|
|
|
|
vm_log (vm, "DEVICE",
|
|
"Removal of device %s, fd=%d, host_addr=0x%" LL "x, flags=%d\n",
|
|
dev->name, dev->fd, (m_uint64_t) dev->host_addr, dev->flags);
|
|
|
|
if (dev->flags & VDEVICE_FLAG_REMAP) {
|
|
dev_init (dev);
|
|
return;
|
|
}
|
|
|
|
if (dev->fd != -1) {
|
|
/* Unmap memory mapped file */
|
|
if (dev->host_addr) {
|
|
|
|
vm_log (vm, "MMAP", "unmapping of device '%s', "
|
|
"fd=%d, host_addr=0x%" LL "x, len=0x%x\n",
|
|
dev->name, dev->fd, (m_uint64_t) dev->host_addr,
|
|
dev->phys_len);
|
|
munmap ((void *) dev->host_addr, dev->phys_len);
|
|
}
|
|
|
|
close (dev->fd);
|
|
} else {
|
|
/* Use of malloc'ed host memory: free it */
|
|
if (dev->host_addr)
|
|
free ((void *) dev->host_addr);
|
|
}
|
|
|
|
/* reinitialize the device to a clean state */
|
|
dev_init (dev);
|
|
}
|
|
|
|
/* Show properties of a device */
|
|
void dev_show (struct vdevice *dev)
|
|
{
|
|
if (!dev)
|
|
return;
|
|
|
|
printf (" %-18s: 0x%12.12" LL "x (0x%8.8x)\n", dev->name,
|
|
dev->phys_addr, dev->phys_len);
|
|
}
|
|
|
|
/* Show the device list */
|
|
void dev_show_list (vm_instance_t * vm)
|
|
{
|
|
struct vdevice *dev;
|
|
|
|
printf ("\nVM \"%s\" () Device list:\n", vm->name);
|
|
|
|
for (dev = vm->dev_list; dev; dev = dev->next)
|
|
dev_show (dev);
|
|
|
|
printf ("\n");
|
|
}
|
|
|
|
/* Remap a device at specified physical address */
|
|
struct vdevice *dev_remap (char *name, struct vdevice *orig, m_pa_t paddr,
|
|
m_uint32_t len)
|
|
{
|
|
struct vdevice *dev;
|
|
|
|
if (!(dev = dev_create (name)))
|
|
return NULL;
|
|
|
|
dev->phys_addr = paddr;
|
|
dev->phys_len = len;
|
|
dev->flags = orig->flags | VDEVICE_FLAG_REMAP;
|
|
dev->fd = orig->fd;
|
|
dev->host_addr = orig->host_addr;
|
|
dev->handler = orig->handler;
|
|
//dev->sparse_map = orig->sparse_map;
|
|
return dev;
|
|
}
|
|
|
|
/* Create a RAM device */
|
|
struct vdevice *dev_create_ram (vm_instance_t * vm, char *name, m_pa_t paddr,
|
|
m_uint32_t len)
|
|
{
|
|
struct vdevice *dev;
|
|
|
|
if (!(dev = dev_create (name)))
|
|
return NULL;
|
|
|
|
dev->phys_addr = paddr;
|
|
dev->phys_len = len;
|
|
//dev->flags = VDEVICE_FLAG_CACHING;
|
|
dev->host_addr = (m_iptr_t) m_memalign (4096, dev->phys_len);
|
|
memset ((void*) dev->host_addr, 0, dev->phys_len);
|
|
|
|
if (!dev->host_addr) {
|
|
free (dev);
|
|
return NULL;
|
|
}
|
|
|
|
vm_bind_device (vm, dev);
|
|
return dev;
|
|
}
|