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