symbian-qemu-0.9.1-12/qemu-symbian-svp/plugins/syborg_nvmemorydevice.py
author Gareth Stockwell <gareth.stockwell@accenture.com>
Mon, 06 Sep 2010 16:25:43 +0100
changeset 107 3bc1a978be44
parent 93 07b904f40417
permissions -rw-r--r--
Fix for Bug 3671 - QEMU GDB stub listens on IPv6-only port on Windows 7 The connection string used by the GDB stub does not specify which version of the Internet Protocol should be used by the port on which it listens. On host platforms with IPv6 support, such as Windows 7, this means that the stub listens on an IPv6-only port. Since the GDB client uses IPv4, this means that the client cannot connect to QEMU.

#
# Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
# All rights reserved.
# This component and the accompanying materials are made available
# under the terms of "Eclipse Public License v1.0"
# which accompanies this distribution, and is available
# at the URL "http://www.eclipse.org/legal/epl-v10.html".
#
# Initial Contributors:
# Nokia Corporation - initial contribution.
#
# Contributors:
#
# Description: syborg_nvmemorydevice.py
# A simple non volatile memory device nvmemory.dll python wrapper
# Represents a non volatile memory device register interface for quest OS in QEMU Syborg environment.
#
# Gets the following from devicetree (.dtb configuration file) 
#       drive_size - the size of the non volatile memory array to be created if there is no such thing available when the system is started
#       sector_size - the size of the sector for the memory device
#       drive_image_name - the name of the image to be used
#
# Creates an empty image of specified size and name if there is not image available when the system is started
#

import ctypes
import qemu
import sys
import os
import array
import platform
import re

class syborg_nvmemorydevice(qemu.devclass):
    # 256 MB default empty drive size if there is no readymade image available
    DEFAULT_DRIVE_SIZE = 0x10000000
    DEVICE_SECTOR_SIZE = 0x200
    DRIVE_NAME = "qemudrive.img"
    DRIVE_PATH = "nvmemory"
    
    # Memory device registers
    R_NVMEM_ID                                = 0x0000
    R_NVMEM_TRANSACTION_OFFSET                = 0x0004
    R_NVMEM_TRANSACTION_SIZE                  = 0x0008
    R_NVMEM_TRANSACTION_DIRECTION             = 0x000c
    R_NVMEM_TRANSACTION_EXECUTE               = 0x0010
    R_NVMEM_SHARED_MEMORY_BASE                = 0x0014
    R_NVMEM_NV_MEMORY_SIZE                    = 0x0018
    R_NVMEM_SHARED_MEMORY_SIZE                = 0x001c
    R_NVMEM_STATUS                            = 0x0020
    R_NVMEM_ENABLE                            = 0x0024
    R_NVMEM_LASTREG                           = 0x0028  # not a register, address of last register
    
    NVMEM_TRANSACTION_READ              = 1
    NVMEM_TRANSACTION_WRITE             = 2
    # Variables to store the information for current transaction
    shared_memory_base                  = 0
    shared_memory_size                  = 0
    transaction_offset                  = 0
    transaction_size                    = 0
    transaction_direction               = 0
    # Variables to validate transaction
    transaction_offset_set              = 0
    transaction_size_set                = 0
    transaction_direction_set           = 0
    nvmemory_sector_count                = 0
    
    drive_size                          = 0
    sector_size                         = 0
    drive_image_name                    = ""
    host_plat = platform.platform();

    def create(self):
        print "syborg_nvmemorydevice: create\n"
        
        # Get properties
        self.drive_size = self.properties["drive_size"]
        self.sector_size = self.properties["sector_size"]
        self.drive_image_name = self.properties["drive_image_name"]
        
        print "drive size: ", self.drive_size
        print "sector size: ", self.sector_size
        print "drive name: ", self.drive_image_name

        drive_path_and_name = os.path.join(self.DRIVE_PATH, self.drive_image_name)  
        # Save working directory
        self.working_dir = os.getcwd()
        nvmem_lib = ""
        open_mode = 0
        if re.match('^linux',self.host_plat,re.I):
			nvmemlib_name = "libnvmemmory.so"
			open_mode = os.O_RDWR
        else:
			nvmemlib_name = "nvmemmory.dll"
			open_mode = os.O_RDWR|os.O_BINARY			
        
        # Open the nvmemory library
        try:
            self.nvmemlib = ctypes.CDLL(nvmemlib_name)
        except Exception, e:
            print repr(e)
            sys.exit("syborg_nvmemorydevice: nvmemmory load failed")
        
        # Create an instance of non volatile memory handler class
        self.obj = self.nvmemlib.nvmem_create( self.sector_size )
        self.nvmemlib.nvmem_reset( self.obj )
        
        # Create drive image path
        try:
            print "syborg_nvmemorydevice: Check drive image path\n"
            os.mkdir( self.DRIVE_PATH )
        except:
            # Here we could check why we failed - usually because the path already exists \n"
            pass
        try:
            self.filehandle = os.open( drive_path_and_name, open_mode )
            os.close( self.filehandle )
        except:
            print "syborg_nvmemorydevice: drive image not found - create\n"
            self.filehandle = open( drive_path_and_name, "wb" )
            # Initialize file with zeroes. This may take a while
            temparray = array.array("B", [0,0,0,0,0,0,0,0])
            arraylength = temparray.buffer_info()[1] * temparray.itemsize
            multiplier = self.drive_size / arraylength / 128
            temparray = temparray * multiplier
            arraylength = temparray.buffer_info()[1] * temparray.itemsize
            print "array length: ", arraylength
            index = 0
            while index < 128:
                temparray.tofile(self.filehandle)
                index = index+1
        
        # Create path and get handle to the raw memory array
        imagepath = os.path.join(self.working_dir, drive_path_and_name)
        print "imagepath: ", imagepath
        self.nvmemhandle = self.nvmemlib.nvmem_open( self.obj, imagepath )
        if( self.nvmemhandle < 0 ):
            error_msg = "syborg_nvmemorydevice: nvmem_open error: ", self.nvmemhandle
            sys.exit( error_msg )
        
        # Initialize callback and get memory sector count
        self.initialize_nvmem_callback()
        self.nvmemory_sector_count = self.nvmemlib.nvmem_get_sector_count( self.obj, self.nvmemhandle )
        print "syborg_nvmemorydevice: created\n"
            
    def updateIrq(self,new_value):
        self.set_irq_level(0, new_value)

    def nvmem_request_callback(self, result):
        #print "graphics_request_callback: " , result
        self.status_reg = result
        self.updateIrq(1)
        return 0
        
    def initialize_nvmem_callback(self):
        self.CALLBACKFUNC = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int)
        self.nvmem_callback = self.CALLBACKFUNC(self.nvmem_request_callback)
        self.nvmemlib.nvmem_set_callback( self.obj, self.nvmem_callback )

    def read_reg(self, offset):
        offset >>= 2
        #print "read register: 0x%x" % (offset) 
        if offset == self.R_NVMEM_ID:
            return 0xDEADBEEF
        elif offset == self.R_NVMEM_TRANSACTION_OFFSET:
            return self.transaction_offset
        elif offset == self.R_NVMEM_TRANSACTION_SIZE:
            return self.transaction_size
        elif offset == self.R_NVMEM_TRANSACTION_DIRECTION:
            return self.transaction_direction
        elif offset == self.R_NVMEM_SHARED_MEMORY_BASE:
            return self.shared_memory_base
        elif offset == self.R_NVMEM_SHARED_MEMORY_SIZE:
            return self.shared_memory_size
        elif offset == self.R_NVMEM_NV_MEMORY_SIZE:
            return self.nvmemory_sector_count
        elif offset == self.R_NVMEM_STATUS:
            self.updateIrq(0)
            return self.status_reg
        else:
            reg_read_error = "syborg_nvmemorydevice: Illegal register read at: ", offset 
            sys.exit( reg_read_error )

    def write_reg(self, offset, value):
        offset >>= 2
        #print "write register: 0x%x value: 0x%x" % (offset, value) 
        if offset == self.R_NVMEM_TRANSACTION_OFFSET:
            self.transaction_offset = value
            self.transaction_offset_set = 1
        elif offset == self.R_NVMEM_TRANSACTION_SIZE:
            self.transaction_size = value
            self.transaction_size_set = 1
        elif offset == self.R_NVMEM_TRANSACTION_DIRECTION:
            self.transaction_direction = value
            self.transaction_direction_set = 1
        elif offset == self.R_NVMEM_TRANSACTION_EXECUTE:
            if( (self.transaction_offset_set == 0) | (self.transaction_size_set == 0) | (self.transaction_direction_set == 0) ):
                error_msg = "syborg_nvmemorydevice: Illegal transaction! All the required parameters are not set" 
                sys.exit( error_msg )
            elif(self.transaction_size == 0 ):
                error_msg = "syborg_nvmemorydevice: Zero size transaction issued!" 
                sys.exit( error_msg )
            else:
                if( self.transaction_direction == self.NVMEM_TRANSACTION_READ ):
                    self.nvmemlib.nvmem_read(  self.obj, self.nvmemory_sharedmemory_host_address, self.nvmemhandle, self.transaction_offset, self.transaction_size )
                elif( self.transaction_direction == self.NVMEM_TRANSACTION_WRITE ):
                    self.nvmemlib.nvmem_write(  self.obj, self.nvmemory_sharedmemory_host_address, self.nvmemhandle, self.transaction_offset, self.transaction_size )
                else:
                    error_msg = "syborg_nvmemorydevice: Transaction direction not set!" 
                    sys.exit( error_msg )
                self.transaction_offset_set = 0
                self.transaction_size_set = 0
                self.transaction_direction_set = 0
        elif offset == self.R_NVMEM_SHARED_MEMORY_BASE:
            self.shared_memory_base = value
        elif offset == self.R_NVMEM_SHARED_MEMORY_SIZE:
            self.shared_memory_size = value
        elif offset == self.R_NVMEM_ENABLE:
            if( value > 0 ):
                self.nvmemory_memregion = qemu.memregion( self.shared_memory_base, self.shared_memory_size )
                self.nvmemory_sharedmemory_host_address = self.nvmemory_memregion.region_host_addr()
                print"syborg_nvmemorydevice: host addr: 0x%08x" % (self.nvmemory_sharedmemory_host_address)
        else:
            reg_write_error = "syborg_nvmemorydevice: Illegal register write to: ", offset 
            sys.exit( reg_write_error )

    # Device class properties
    regions = [qemu.ioregion(0x1000, readl=read_reg, writel=write_reg)]
    irqs = 1
    name = "syborg,nvmemorydevice"
    properties = {"drive_size":DEFAULT_DRIVE_SIZE, "sector_size":DEVICE_SECTOR_SIZE, "drive_image_name":DRIVE_NAME}

qemu.register_device(syborg_nvmemorydevice)