74
|
1 |
#
|
|
2 |
# Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
|
3 |
# All rights reserved.
|
|
4 |
# This component and the accompanying materials are made available
|
|
5 |
# under the terms of "Eclipse Public License v1.0"
|
|
6 |
# which accompanies this distribution, and is available
|
|
7 |
# at the URL "http://www.eclipse.org/legal/epl-v10.html".
|
|
8 |
#
|
|
9 |
# Initial Contributors:
|
|
10 |
# Nokia Corporation - initial contribution.
|
|
11 |
#
|
|
12 |
# Contributors:
|
|
13 |
#
|
|
14 |
# Description: syborg_nvmemorydevice.py
|
|
15 |
# A simple non volatile memory device nvmemory.dll python wrapper
|
|
16 |
# Represents a non volatile memory device register interface for quest OS in QEMU Syborg environment.
|
|
17 |
#
|
|
18 |
# Gets the following from devicetree (.dtb configuration file)
|
|
19 |
# 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
|
|
20 |
# sector_size - the size of the sector for the memory device
|
|
21 |
# drive_image_name - the name of the image to be used
|
|
22 |
#
|
|
23 |
# Creates an empty image of specified size and name if there is not image available when the system is started
|
|
24 |
#
|
|
25 |
|
|
26 |
import ctypes
|
|
27 |
import qemu
|
|
28 |
import sys
|
|
29 |
import os
|
|
30 |
import array
|
|
31 |
|
|
32 |
class syborg_nvmemorydevice(qemu.devclass):
|
|
33 |
# 256 MB default empty drive size if there is no readymade image available
|
|
34 |
DEFAULT_DRIVE_SIZE = 0x10000000
|
|
35 |
DEVICE_SECTOR_SIZE = 0x200
|
|
36 |
DRIVE_NAME = "qemudrive.img"
|
|
37 |
DRIVE_PATH = "nvmemory"
|
|
38 |
|
|
39 |
# Memory device registers
|
|
40 |
R_NVMEM_ID = 0x0000
|
|
41 |
R_NVMEM_TRANSACTION_OFFSET = 0x0004
|
|
42 |
R_NVMEM_TRANSACTION_SIZE = 0x0008
|
|
43 |
R_NVMEM_TRANSACTION_DIRECTION = 0x000c
|
|
44 |
R_NVMEM_TRANSACTION_EXECUTE = 0x0010
|
|
45 |
R_NVMEM_SHARED_MEMORY_BASE = 0x0014
|
|
46 |
R_NVMEM_NV_MEMORY_SIZE = 0x0018
|
|
47 |
R_NVMEM_SHARED_MEMORY_SIZE = 0x001c
|
|
48 |
R_NVMEM_STATUS = 0x0020
|
|
49 |
R_NVMEM_ENABLE = 0x0024
|
|
50 |
R_NVMEM_LASTREG = 0x0028 # not a register, address of last register
|
|
51 |
|
|
52 |
NVMEM_TRANSACTION_READ = 1
|
|
53 |
NVMEM_TRANSACTION_WRITE = 2
|
|
54 |
# Variables to store the information for current transaction
|
|
55 |
shared_memory_base = 0
|
|
56 |
shared_memory_size = 0
|
|
57 |
transaction_offset = 0
|
|
58 |
transaction_size = 0
|
|
59 |
transaction_direction = 0
|
|
60 |
# Variables to validate transaction
|
|
61 |
transaction_offset_set = 0
|
|
62 |
transaction_size_set = 0
|
|
63 |
transaction_direction_set = 0
|
|
64 |
nvmemory_sector_count = 0
|
|
65 |
|
|
66 |
drive_size = 0
|
|
67 |
sector_size = 0
|
|
68 |
drive_image_name = ""
|
|
69 |
|
|
70 |
def create(self):
|
|
71 |
print "syborg_nvmemorydevice: create\n"
|
|
72 |
|
|
73 |
# Get properties
|
|
74 |
self.drive_size = self.properties["drive_size"]
|
|
75 |
self.sector_size = self.properties["sector_size"]
|
|
76 |
self.drive_image_name = self.properties["drive_image_name"]
|
|
77 |
|
|
78 |
print "drive size: ", self.drive_size
|
|
79 |
print "sector size: ", self.sector_size
|
|
80 |
print "drive name: ", self.drive_image_name
|
|
81 |
|
|
82 |
drive_path_and_name = self.DRIVE_PATH + "\\" + self.drive_image_name
|
|
83 |
# Save working directory
|
|
84 |
self.working_dir = os.getcwd()
|
|
85 |
|
|
86 |
# Open the nvmemory library
|
|
87 |
try:
|
|
88 |
self.nvmemlib = ctypes.CDLL("nvmemmory.dll")
|
|
89 |
except:
|
|
90 |
sys.exit("syborg_nvmemorydevice: nvmemmory.dll load failed")
|
|
91 |
|
|
92 |
# Create an instance of non volatile memory handler class
|
|
93 |
self.obj = self.nvmemlib.nvmem_create( self.sector_size )
|
|
94 |
self.nvmemlib.nvmem_reset( self.obj )
|
|
95 |
|
|
96 |
# Create drive image path
|
|
97 |
try:
|
|
98 |
print "syborg_nvmemorydevice: Check drive image path\n"
|
|
99 |
os.mkdir( self.DRIVE_PATH )
|
|
100 |
except:
|
|
101 |
# Here we could check why we failed - usually because the path already exists \n"
|
|
102 |
pass
|
|
103 |
try:
|
|
104 |
self.filehandle = os.open( drive_path_and_name, os.O_RDWR|os.O_BINARY )
|
|
105 |
os.close( self.filehandle )
|
|
106 |
except:
|
|
107 |
print "syborg_nvmemorydevice: drive image not found - create\n"
|
|
108 |
self.filehandle = open( drive_path_and_name, "wb" )
|
|
109 |
# Initialize file with zeroes. This may take a while
|
|
110 |
temparray = array.array("B", [0,0,0,0,0,0,0,0])
|
|
111 |
arraylength = temparray.buffer_info()[1] * temparray.itemsize
|
|
112 |
multiplier = self.drive_size / arraylength / 128
|
|
113 |
temparray = temparray * multiplier
|
|
114 |
arraylength = temparray.buffer_info()[1] * temparray.itemsize
|
|
115 |
print "array length: ", arraylength
|
|
116 |
index = 0
|
|
117 |
while index < 128:
|
|
118 |
temparray.tofile(self.filehandle)
|
|
119 |
index = index+1
|
|
120 |
|
|
121 |
# Create path and get handle to the raw memory array
|
|
122 |
imagepath = self.working_dir + "\\" + drive_path_and_name
|
|
123 |
print "imagepath: ", imagepath
|
|
124 |
self.nvmemhandle = self.nvmemlib.nvmem_open( self.obj, imagepath )
|
|
125 |
if( self.nvmemhandle < 0 ):
|
|
126 |
error_msg = "syborg_nvmemorydevice: nvmem_open error: ", self.nvmemhandle
|
|
127 |
sys.exit( error_msg )
|
|
128 |
|
|
129 |
# Initialize callback and get memory sector count
|
|
130 |
self.initialize_nvmem_callback()
|
|
131 |
self.nvmemory_sector_count = self.nvmemlib.nvmem_get_sector_count( self.obj, self.nvmemhandle )
|
|
132 |
print "syborg_nvmemorydevice: created\n"
|
|
133 |
|
|
134 |
def updateIrq(self,new_value):
|
|
135 |
self.set_irq_level(0, new_value)
|
|
136 |
|
|
137 |
def nvmem_request_callback(self, result):
|
|
138 |
#print "graphics_request_callback: " , result
|
|
139 |
self.status_reg = result
|
|
140 |
self.updateIrq(1)
|
|
141 |
return 0
|
|
142 |
|
|
143 |
def initialize_nvmem_callback(self):
|
|
144 |
self.CALLBACKFUNC = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int)
|
|
145 |
self.nvmem_callback = self.CALLBACKFUNC(self.nvmem_request_callback)
|
|
146 |
self.nvmemlib.nvmem_set_callback( self.obj, self.nvmem_callback )
|
|
147 |
|
|
148 |
def read_reg(self, offset):
|
|
149 |
offset >>= 2
|
|
150 |
#print "read register: 0x%x" % (offset)
|
|
151 |
if offset == self.R_NVMEM_ID:
|
|
152 |
return 0xDEADBEEF
|
|
153 |
elif offset == self.R_NVMEM_TRANSACTION_OFFSET:
|
|
154 |
return self.transaction_offset
|
|
155 |
elif offset == self.R_NVMEM_TRANSACTION_SIZE:
|
|
156 |
return self.transaction_size
|
|
157 |
elif offset == self.R_NVMEM_TRANSACTION_DIRECTION:
|
|
158 |
return self.transaction_direction
|
|
159 |
elif offset == self.R_NVMEM_SHARED_MEMORY_BASE:
|
|
160 |
return self.shared_memory_base
|
|
161 |
elif offset == self.R_NVMEM_SHARED_MEMORY_SIZE:
|
|
162 |
return self.shared_memory_size
|
|
163 |
elif offset == self.R_NVMEM_NV_MEMORY_SIZE:
|
|
164 |
return self.nvmemory_sector_count
|
|
165 |
elif offset == self.R_NVMEM_STATUS:
|
|
166 |
self.updateIrq(0)
|
|
167 |
return self.status_reg
|
|
168 |
else:
|
|
169 |
reg_read_error = "syborg_nvmemorydevice: Illegal register read at: ", offset
|
|
170 |
sys.exit( reg_read_error )
|
|
171 |
|
|
172 |
def write_reg(self, offset, value):
|
|
173 |
offset >>= 2
|
|
174 |
#print "write register: 0x%x value: 0x%x" % (offset, value)
|
|
175 |
if offset == self.R_NVMEM_TRANSACTION_OFFSET:
|
|
176 |
self.transaction_offset = value
|
|
177 |
self.transaction_offset_set = 1
|
|
178 |
elif offset == self.R_NVMEM_TRANSACTION_SIZE:
|
|
179 |
self.transaction_size = value
|
|
180 |
self.transaction_size_set = 1
|
|
181 |
elif offset == self.R_NVMEM_TRANSACTION_DIRECTION:
|
|
182 |
self.transaction_direction = value
|
|
183 |
self.transaction_direction_set = 1
|
|
184 |
elif offset == self.R_NVMEM_TRANSACTION_EXECUTE:
|
|
185 |
if( (self.transaction_offset_set == 0) | (self.transaction_size_set == 0) | (self.transaction_direction_set == 0) ):
|
|
186 |
error_msg = "syborg_nvmemorydevice: Illegal transaction! All the required parameters are not set"
|
|
187 |
sys.exit( error_msg )
|
|
188 |
elif(self.transaction_size == 0 ):
|
|
189 |
error_msg = "syborg_nvmemorydevice: Zero size transaction issued!"
|
|
190 |
sys.exit( error_msg )
|
|
191 |
else:
|
|
192 |
if( self.transaction_direction == self.NVMEM_TRANSACTION_READ ):
|
|
193 |
self.nvmemlib.nvmem_read( self.obj, self.nvmemory_sharedmemory_host_address, self.nvmemhandle, self.transaction_offset, self.transaction_size )
|
|
194 |
elif( self.transaction_direction == self.NVMEM_TRANSACTION_WRITE ):
|
|
195 |
self.nvmemlib.nvmem_write( self.obj, self.nvmemory_sharedmemory_host_address, self.nvmemhandle, self.transaction_offset, self.transaction_size )
|
|
196 |
else:
|
|
197 |
error_msg = "syborg_nvmemorydevice: Transaction direction not set!"
|
|
198 |
sys.exit( error_msg )
|
|
199 |
self.transaction_offset_set = 0
|
|
200 |
self.transaction_size_set = 0
|
|
201 |
self.transaction_direction_set = 0
|
|
202 |
elif offset == self.R_NVMEM_SHARED_MEMORY_BASE:
|
|
203 |
self.shared_memory_base = value
|
|
204 |
elif offset == self.R_NVMEM_SHARED_MEMORY_SIZE:
|
|
205 |
self.shared_memory_size = value
|
|
206 |
elif offset == self.R_NVMEM_ENABLE:
|
|
207 |
if( value > 0 ):
|
|
208 |
self.nvmemory_memregion = qemu.memregion( self.shared_memory_base, self.shared_memory_size )
|
|
209 |
self.nvmemory_sharedmemory_host_address = self.nvmemory_memregion.region_host_addr()
|
|
210 |
print"syborg_nvmemorydevice: host addr: 0x%08x" % (self.nvmemory_sharedmemory_host_address)
|
|
211 |
else:
|
|
212 |
reg_write_error = "syborg_nvmemorydevice: Illegal register write to: ", offset
|
|
213 |
sys.exit( reg_write_error )
|
|
214 |
|
|
215 |
# Device class properties
|
|
216 |
regions = [qemu.ioregion(0x1000, readl=read_reg, writel=write_reg)]
|
|
217 |
irqs = 1
|
|
218 |
name = "syborg,nvmemorydevice"
|
|
219 |
properties = {"drive_size":DEFAULT_DRIVE_SIZE, "sector_size":DEVICE_SECTOR_SIZE, "drive_image_name":DRIVE_NAME}
|
|
220 |
|
|
221 |
qemu.register_device(syborg_nvmemorydevice)
|