|
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) |