|
@@ -8,6 +8,8 @@
|
8
|
8
|
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
9
|
9
|
|
10
|
10
|
#include <stdint.h>
|
|
11
|
+#include <strings.h>
|
|
12
|
+#include <assert.h>
|
11
|
13
|
#include <ipxe/profile.h>
|
12
|
14
|
#include <realmode.h>
|
13
|
15
|
#include <pic8259.h>
|
|
@@ -176,6 +178,123 @@ void __attribute__ (( regparm ( 1 ) )) interrupt ( int intr ) {
|
176
|
178
|
profile_exclude ( profiler );
|
177
|
179
|
}
|
178
|
180
|
|
|
181
|
+/**
|
|
182
|
+ * Map pages for I/O
|
|
183
|
+ *
|
|
184
|
+ * @v bus_addr Bus address
|
|
185
|
+ * @v len Length of region
|
|
186
|
+ * @ret io_addr I/O address
|
|
187
|
+ */
|
|
188
|
+static void * ioremap_pages ( unsigned long bus_addr, size_t len ) {
|
|
189
|
+ unsigned long start;
|
|
190
|
+ unsigned int count;
|
|
191
|
+ unsigned int stride;
|
|
192
|
+ unsigned int first;
|
|
193
|
+ unsigned int i;
|
|
194
|
+ size_t offset;
|
|
195
|
+ void *io_addr;
|
|
196
|
+
|
|
197
|
+ DBGC ( &io_pages, "IO mapping %08lx+%zx\n", bus_addr, len );
|
|
198
|
+
|
|
199
|
+ /* Sanity check */
|
|
200
|
+ assert ( len != 0 );
|
|
201
|
+
|
|
202
|
+ /* Round down start address to a page boundary */
|
|
203
|
+ start = ( bus_addr & ~( IO_PAGE_SIZE - 1 ) );
|
|
204
|
+ offset = ( bus_addr - start );
|
|
205
|
+ assert ( offset < IO_PAGE_SIZE );
|
|
206
|
+
|
|
207
|
+ /* Calculate number of pages required */
|
|
208
|
+ count = ( ( offset + len + IO_PAGE_SIZE - 1 ) / IO_PAGE_SIZE );
|
|
209
|
+ assert ( count != 0 );
|
|
210
|
+ assert ( count < ( sizeof ( io_pages.page ) /
|
|
211
|
+ sizeof ( io_pages.page[0] ) ) );
|
|
212
|
+
|
|
213
|
+ /* Round up number of pages to a power of two */
|
|
214
|
+ stride = ( 1 << ( fls ( count ) - 1 ) );
|
|
215
|
+ assert ( count <= stride );
|
|
216
|
+
|
|
217
|
+ /* Allocate pages */
|
|
218
|
+ for ( first = 0 ; first < ( sizeof ( io_pages.page ) /
|
|
219
|
+ sizeof ( io_pages.page[0] ) ) ;
|
|
220
|
+ first += stride ) {
|
|
221
|
+
|
|
222
|
+ /* Calculate I/O address */
|
|
223
|
+ io_addr = ( IO_BASE + ( first * IO_PAGE_SIZE ) + offset );
|
|
224
|
+
|
|
225
|
+ /* Check that page table entries are available */
|
|
226
|
+ for ( i = first ; i < ( first + count ) ; i++ ) {
|
|
227
|
+ if ( io_pages.page[i] & PAGE_P ) {
|
|
228
|
+ io_addr = NULL;
|
|
229
|
+ break;
|
|
230
|
+ }
|
|
231
|
+ }
|
|
232
|
+ if ( ! io_addr )
|
|
233
|
+ continue;
|
|
234
|
+
|
|
235
|
+ /* Create page table entries */
|
|
236
|
+ for ( i = first ; i < ( first + count ) ; i++ ) {
|
|
237
|
+ io_pages.page[i] = ( start | PAGE_P | PAGE_RW |
|
|
238
|
+ PAGE_US | PAGE_PWT | PAGE_PCD |
|
|
239
|
+ PAGE_PS );
|
|
240
|
+ start += IO_PAGE_SIZE;
|
|
241
|
+ }
|
|
242
|
+
|
|
243
|
+ /* Mark last page as being the last in this allocation */
|
|
244
|
+ io_pages.page[ i - 1 ] |= PAGE_LAST;
|
|
245
|
+
|
|
246
|
+ /* Return I/O address */
|
|
247
|
+ DBGC ( &io_pages, "IO mapped %08lx+%zx to %p using PTEs "
|
|
248
|
+ "[%d-%d]\n", bus_addr, len, io_addr, first,
|
|
249
|
+ ( first + count - 1 ) );
|
|
250
|
+ return io_addr;
|
|
251
|
+ }
|
|
252
|
+
|
|
253
|
+ DBGC ( &io_pages, "IO could not map %08lx+%zx\n", bus_addr, len );
|
|
254
|
+ return NULL;
|
|
255
|
+}
|
|
256
|
+
|
|
257
|
+/**
|
|
258
|
+ * Unmap pages for I/O
|
|
259
|
+ *
|
|
260
|
+ * @v io_addr I/O address
|
|
261
|
+ */
|
|
262
|
+static void iounmap_pages ( volatile const void *io_addr ) {
|
|
263
|
+ volatile const void *invalidate = io_addr;
|
|
264
|
+ unsigned int first;
|
|
265
|
+ unsigned int i;
|
|
266
|
+ int is_last;
|
|
267
|
+
|
|
268
|
+ DBGC ( &io_pages, "IO unmapping %p\n", io_addr );
|
|
269
|
+
|
|
270
|
+ /* Calculate first page table entry */
|
|
271
|
+ first = ( ( io_addr - IO_BASE ) / IO_PAGE_SIZE );
|
|
272
|
+
|
|
273
|
+ /* Clear page table entries */
|
|
274
|
+ for ( i = first ; ; i++ ) {
|
|
275
|
+
|
|
276
|
+ /* Sanity check */
|
|
277
|
+ assert ( io_pages.page[i] & PAGE_P );
|
|
278
|
+
|
|
279
|
+ /* Check if this is the last page in this allocation */
|
|
280
|
+ is_last = ( io_pages.page[i] & PAGE_LAST );
|
|
281
|
+
|
|
282
|
+ /* Clear page table entry */
|
|
283
|
+ io_pages.page[i] = 0;
|
|
284
|
+
|
|
285
|
+ /* Invalidate TLB for this page */
|
|
286
|
+ __asm__ __volatile__ ( "invlpg (%0)" : : "r" ( invalidate ) );
|
|
287
|
+ invalidate += IO_PAGE_SIZE;
|
|
288
|
+
|
|
289
|
+ /* Terminate if this was the last page */
|
|
290
|
+ if ( is_last )
|
|
291
|
+ break;
|
|
292
|
+ }
|
|
293
|
+
|
|
294
|
+ DBGC ( &io_pages, "IO unmapped %p using PTEs [%d-%d]\n",
|
|
295
|
+ io_addr, first, i );
|
|
296
|
+}
|
|
297
|
+
|
179
|
298
|
PROVIDE_UACCESS_INLINE ( librm, phys_to_user );
|
180
|
299
|
PROVIDE_UACCESS_INLINE ( librm, user_to_phys );
|
181
|
300
|
PROVIDE_UACCESS_INLINE ( librm, virt_to_user );
|
|
@@ -186,3 +305,6 @@ PROVIDE_UACCESS_INLINE ( librm, memmove_user );
|
186
|
305
|
PROVIDE_UACCESS_INLINE ( librm, memset_user );
|
187
|
306
|
PROVIDE_UACCESS_INLINE ( librm, strlen_user );
|
188
|
307
|
PROVIDE_UACCESS_INLINE ( librm, memchr_user );
|
|
308
|
+PROVIDE_IOMAP_INLINE ( pages, io_to_bus );
|
|
309
|
+PROVIDE_IOMAP ( pages, ioremap, ioremap_pages );
|
|
310
|
+PROVIDE_IOMAP ( pages, iounmap, iounmap_pages );
|