Browse Source

Add the concept of a "user pointer" (similar to the void __user * in

the kernel), which encapsulates the information needed to refer to an
external buffer.  Under normal operation, this can just be a void *
equivalent, but under -DKEEP_IT_REAL it would be a segoff_t equivalent.

Use this concept to avoid the need for bounce buffers in int13.c,
which reduces memory usage and opens up the possibility of using
multi-sector reads.

Extend the block-device API and the SCSI block device implementation
to support multi-sector reads.

Update iscsi.c to use user buffers.

Move the obsolete portions of realmode.h to old_realmode.h.

MS-DOS now boots an order of magnitude faster over iSCSI (~10 seconds
from power-up to C:> prompt in bochs).
tags/v0.9.3
Michael Brown 18 years ago
parent
commit
d48d0fb1bb

+ 1
- 1
src/arch/i386/core/pic8259.c View File

@@ -6,7 +6,7 @@
6 6
 
7 7
 #include <etherboot.h>
8 8
 #include "pic8259.h"
9
-#include "realmode.h"
9
+#include "old_realmode.h"
10 10
 
11 11
 /* State of trivial IRQ handler */
12 12
 irq_t trivial_irq_installed_on = IRQ_NONE;

+ 6
- 0
src/arch/i386/include/bits/uaccess.h View File

@@ -0,0 +1,6 @@
1
+#ifndef _BITS_UACCESS_H
2
+#define _BITS_UACCESS_H
3
+
4
+#include <realmode.h>
5
+
6
+#endif /* _BITS_UACCESS_H */

+ 63
- 0
src/arch/i386/include/librm.h View File

@@ -92,6 +92,69 @@ copy_from_real_librm ( void *dest, unsigned int src_seg,
92 92
 #define put_real put_real_librm
93 93
 #define get_real get_real_librm
94 94
 
95
+/**
96
+ * A pointer to a user buffer
97
+ *
98
+ * Even though we could just use a void *, we use an intptr_t so that
99
+ * attempts to use normal pointers show up as compiler warnings.  Such
100
+ * code is actually valid for librm, but not for libkir (i.e. under
101
+ * KEEP_IT_REAL), so it's good to have the warnings even under librm.
102
+ */
103
+typedef intptr_t userptr_t;
104
+
105
+/**
106
+ * Copy data to user buffer
107
+ *
108
+ * @v buffer	User buffer
109
+ * @v offset	Offset within user buffer
110
+ * @v src	Source
111
+ * @v len	Length
112
+ */
113
+static inline __attribute__ (( always_inline )) void
114
+copy_to_user ( userptr_t buffer, off_t offset, const void *src, size_t len ) {
115
+	memcpy ( ( void * ) buffer + offset, src, len );
116
+}
117
+
118
+/**
119
+ * Copy data from user buffer
120
+ *
121
+ * @v dest	Destination
122
+ * @v buffer	User buffer
123
+ * @v offset	Offset within user buffer
124
+ * @v len	Length
125
+ */
126
+static inline __attribute__ (( always_inline )) void
127
+copy_from_user ( void *dest, userptr_t buffer, off_t offset, size_t len ) {
128
+	memcpy ( dest, ( void * ) buffer + offset, len );
129
+}
130
+
131
+/**
132
+ * Convert virtual address to user buffer
133
+ *
134
+ * @v virtual	Virtual address
135
+ * @ret buffer	User buffer
136
+ *
137
+ * This constructs a user buffer from an ordinary pointer.  Use it
138
+ * when you need to pass a pointer to an internal buffer to a function
139
+ * that expects a @c userptr_t.
140
+ */
141
+static inline __attribute__ (( always_inline )) userptr_t
142
+virt_to_user ( void * virtual ) {
143
+	return ( ( intptr_t ) virtual );
144
+}
145
+
146
+/**
147
+ * Convert segment:offset address to user buffer
148
+ *
149
+ * @v segment	Real-mode segment
150
+ * @v offset	Real-mode offset
151
+ * @ret buffer	User buffer
152
+ */
153
+static inline __attribute__ (( always_inline )) userptr_t
154
+real_to_user ( unsigned int segment, unsigned int offset ) {
155
+	return virt_to_user ( VIRTUAL ( segment, offset ) );
156
+}
157
+
95 158
 /* Copy to/from real-mode stack */
96 159
 extern uint16_t copy_to_rm_stack ( void *data, size_t size );
97 160
 extern void remove_from_rm_stack ( void *data, size_t size );

+ 22
- 0
src/arch/i386/include/old_realmode.h View File

@@ -0,0 +1,22 @@
1
+#ifndef _OLD_REALMODE_H
2
+#define _OLD_REALMODE_H
3
+
4
+#include <realmode.h>
5
+
6
+#warning "Anything including this header is obsolete and must be rewritten"
7
+
8
+/* Just for now */
9
+#define SEGMENT(x) ( virt_to_phys ( x ) >> 4 )
10
+#define OFFSET(x) ( virt_to_phys ( x ) & 0xf )
11
+#define SEGOFF(x) { OFFSET(x), SEGMENT(x) }
12
+
13
+/* To make basemem.c compile */
14
+extern int lock_real_mode_stack;
15
+extern char *real_mode_stack;
16
+extern char real_mode_stack_size[];
17
+
18
+#define RM_FRAGMENT(name,asm) \
19
+	void name ( void ) {} \
20
+	extern char name ## _size[];
21
+
22
+#endif /* _OLD_REALMODE_H */

+ 0
- 19
src/arch/i386/include/realmode.h View File

@@ -149,25 +149,6 @@ typedef struct segoff segoff_t;
149 149
  * "(discard)" in the above code.
150 150
  */
151 151
 
152
-#warning "realmode.h contains placeholders for obsolete macros"
153
-
154
-
155
-/* Just for now */
156
-#define SEGMENT(x) ( virt_to_phys ( x ) >> 4 )
157
-#define OFFSET(x) ( virt_to_phys ( x ) & 0xf )
158
-#define SEGOFF(x) { OFFSET(x), SEGMENT(x) }
159
-
160
-/* To make basemem.c compile */
161
-extern int lock_real_mode_stack;
162
-extern char *real_mode_stack;
163
-extern char real_mode_stack_size[];
164
-
165
-#define RM_FRAGMENT(name,asm) \
166
-	void name ( void ) {} \
167
-	extern char name ## _size[];
168
-
169
-
170
-
171 152
 #endif /* ASSEMBLY */
172 153
 
173 154
 #endif /* REALMODE_H */

+ 13
- 21
src/arch/i386/interface/pcbios/int13.c View File

@@ -93,7 +93,7 @@ static unsigned long chs_to_lba ( struct int13_drive *drive,
93 93
 	lba = ( ( ( ( cylinder * drive->heads ) + head )
94 94
 		  * drive->sectors_per_track ) + sector - 1 );
95 95
 
96
-	DBG ( "C/H/S address %x/%x/%x -> LBA %x\n",
96
+	DBG ( "C/H/S address %x/%x/%x -> LBA %lx\n",
97 97
 	      cylinder, head, sector, lba );
98 98
 
99 99
 	return lba;
@@ -111,19 +111,15 @@ static unsigned long chs_to_lba ( struct int13_drive *drive,
111 111
 static int int13_read ( struct int13_drive *drive, uint64_t lba,
112 112
 			struct segoff data, unsigned long count ) {
113 113
 	struct block_device *blockdev = drive->blockdev;
114
-	size_t blksize = blockdev->blksize;
115
-	uint8_t buffer[blksize];
114
+	userptr_t buffer = real_to_user ( data.segment, data.offset );
116 115
 	int rc;
117 116
 
118 117
 	DBG ( "Read %lx sectors from %llx to %04x:%04x\n", count,
119 118
 	      ( unsigned long long ) lba, data.segment, data.offset );
120
-	while ( count-- ) {
121
-		if ( ( rc = blockdev->read ( blockdev, lba, buffer ) ) != 0 )
122
-			return INT13_STATUS_READ_ERROR;
123
-		copy_to_real ( data.segment, data.offset, buffer, blksize );
124
-		data.offset += blksize;
125
-		lba++;
126
-	}
119
+	
120
+	if ( ( rc = blockdev->read ( blockdev, lba, count, buffer ) ) != 0 )
121
+		return INT13_STATUS_READ_ERROR;
122
+
127 123
 	return 0;
128 124
 }
129 125
 
@@ -139,19 +135,15 @@ static int int13_read ( struct int13_drive *drive, uint64_t lba,
139 135
 static int int13_write ( struct int13_drive *drive, uint64_t lba,
140 136
 			 struct segoff data, unsigned long count ) {
141 137
 	struct block_device *blockdev = drive->blockdev;
142
-	size_t blksize = blockdev->blksize;
143
-	uint8_t buffer[blksize];
138
+	userptr_t buffer = real_to_user ( data.segment, data.offset );
144 139
 	int rc;
145 140
 
146 141
 	DBG ( "Write %lx sectors from %04x:%04x to %llx\n", count,
147 142
 	      data.segment, data.offset, ( unsigned long long ) lba );
148
-	while ( count-- ) {
149
-		copy_from_real ( buffer, data.segment, data.offset, blksize );
150
-		if ( ( rc = blockdev->write ( blockdev, lba, buffer ) ) != 0 )
151
-			return INT13_STATUS_WRITE_ERROR;
152
-		data.offset += blksize;
153
-		lba++;
154
-	}
143
+
144
+	if ( ( rc = blockdev->write ( blockdev, lba, count, buffer ) ) != 0 )
145
+		return INT13_STATUS_WRITE_ERROR;
146
+
155 147
 	return 0;
156 148
 }
157 149
 
@@ -202,7 +194,7 @@ static int int13_read_sectors ( struct int13_drive *drive,
202 194
 	};
203 195
 
204 196
 	if ( drive->blockdev->blksize != INT13_BLKSIZE ) {
205
-		DBG ( "Invalid blocksize (%d) for non-extended read\n",
197
+		DBG ( "Invalid blocksize (%zd) for non-extended read\n",
206 198
 		      drive->blockdev->blksize );
207 199
 		return INT13_STATUS_INVALID;
208 200
 	}
@@ -233,7 +225,7 @@ static int int13_write_sectors ( struct int13_drive *drive,
233 225
 	};
234 226
 
235 227
 	if ( drive->blockdev->blksize != INT13_BLKSIZE ) {
236
-		DBG ( "Invalid blocksize (%d) for non-extended write\n",
228
+		DBG ( "Invalid blocksize (%zd) for non-extended write\n",
237 229
 		      drive->blockdev->blksize );
238 230
 		return INT13_STATUS_INVALID;
239 231
 	}

+ 9
- 7
src/drivers/block/scsi.c View File

@@ -50,11 +50,12 @@ static int scsi_command ( struct scsi_device *scsi,
50 50
  *
51 51
  * @v blockdev		Block device
52 52
  * @v block		LBA block number
53
+ * @v count		Block count
53 54
  * @v buffer		Data buffer
54 55
  * @ret rc		Return status code
55 56
  */
56 57
 static int scsi_read ( struct block_device *blockdev, uint64_t block,
57
-		       void *buffer ) {
58
+		       unsigned long count, userptr_t buffer ) {
58 59
 	struct scsi_device *scsi = block_to_scsi ( blockdev );
59 60
 	struct scsi_command command;
60 61
 	struct scsi_cdb_read_16 *cdb = &command.cdb.read16;
@@ -63,9 +64,9 @@ static int scsi_read ( struct block_device *blockdev, uint64_t block,
63 64
 	memset ( &command, 0, sizeof ( command ) );
64 65
 	cdb->opcode = SCSI_OPCODE_READ_16;
65 66
 	cdb->lba = cpu_to_be64 ( block );
66
-	cdb->len = cpu_to_be32 ( 1 ); /* always a single block */
67
+	cdb->len = cpu_to_be32 ( count );
67 68
 	command.data_in = buffer;
68
-	command.data_in_len = blockdev->blksize;
69
+	command.data_in_len = ( count * blockdev->blksize );
69 70
 	return scsi_command ( scsi, &command );
70 71
 }
71 72
 
@@ -74,11 +75,12 @@ static int scsi_read ( struct block_device *blockdev, uint64_t block,
74 75
  *
75 76
  * @v blockdev		Block device
76 77
  * @v block		LBA block number
78
+ * @v count		Block count
77 79
  * @v buffer		Data buffer
78 80
  * @ret rc		Return status code
79 81
  */
80 82
 static int scsi_write ( struct block_device *blockdev, uint64_t block,
81
-			const void *buffer ) {
83
+		        unsigned long count, userptr_t buffer ) {
82 84
 	struct scsi_device *scsi = block_to_scsi ( blockdev );
83 85
 	struct scsi_command command;
84 86
 	struct scsi_cdb_write_16 *cdb = &command.cdb.write16;
@@ -87,9 +89,9 @@ static int scsi_write ( struct block_device *blockdev, uint64_t block,
87 89
 	memset ( &command, 0, sizeof ( command ) );
88 90
 	cdb->opcode = SCSI_OPCODE_WRITE_16;
89 91
 	cdb->lba = cpu_to_be64 ( block );
90
-	cdb->len = cpu_to_be32 ( 1 ); /* always a single block */
92
+	cdb->len = cpu_to_be32 ( count );
91 93
 	command.data_out = buffer;
92
-	command.data_out_len = blockdev->blksize;
94
+	command.data_out_len = ( count * blockdev->blksize );
93 95
 	return scsi_command ( scsi, &command );
94 96
 }
95 97
 
@@ -111,7 +113,7 @@ static int scsi_read_capacity ( struct block_device *blockdev ) {
111 113
 	cdb->opcode = SCSI_OPCODE_SERVICE_ACTION_IN;
112 114
 	cdb->service_action = SCSI_SERVICE_ACTION_READ_CAPACITY_16;
113 115
 	cdb->len = cpu_to_be32 ( sizeof ( capacity ) );
114
-	command.data_in = &capacity;
116
+	command.data_in = virt_to_user ( &capacity );
115 117
 	command.data_in_len = sizeof ( capacity );
116 118
 
117 119
 	if ( ( rc = scsi_command ( scsi, &command ) ) != 0 )

+ 6
- 2
src/include/gpxe/blockdev.h View File

@@ -8,6 +8,8 @@
8 8
  *
9 9
  */
10 10
 
11
+#include <gpxe/uaccess.h>
12
+
11 13
 /** A block device */
12 14
 struct block_device {
13 15
 	/** Block size */
@@ -19,21 +21,23 @@ struct block_device {
19 21
 	 *
20 22
 	 * @v blockdev	Block device
21 23
 	 * @v block	Block number
24
+	 * @v count	Block count
22 25
 	 * @v buffer	Data buffer
23 26
 	 * @ret rc	Return status code
24 27
 	 */
25 28
 	int ( * read ) ( struct block_device *blockdev, uint64_t block,
26
-			 void *buffer );
29
+			 unsigned long count, userptr_t buffer );
27 30
 	/**
28 31
 	 * Write block
29 32
 	 *
30 33
 	 * @v blockdev	Block device
31 34
 	 * @v block	Block number
35
+	 * @v count	Block count
32 36
 	 * @v buffer	Data buffer
33 37
 	 * @ret rc	Return status code
34 38
 	 */
35 39
 	int ( * write ) ( struct block_device *blockdev, uint64_t block,
36
-			  const void *buffer );
40
+			  unsigned long count, userptr_t buffer );
37 41
 };
38 42
 
39 43
 #endif /* _GPXE_BLOCKDEV_H */

+ 3
- 2
src/include/gpxe/scsi.h View File

@@ -3,6 +3,7 @@
3 3
 
4 4
 #include <stdint.h>
5 5
 #include <gpxe/blockdev.h>
6
+#include <gpxe/uaccess.h>
6 7
 
7 8
 /**
8 9
  * @defgroup scsiops SCSI operation codes
@@ -123,14 +124,14 @@ struct scsi_command {
123 124
 	/** CDB for this command */
124 125
 	union scsi_cdb cdb;
125 126
 	/** Data-out buffer (may be NULL) */
126
-	const void *data_out;
127
+	userptr_t data_out;
127 128
 	/** Data-out buffer length
128 129
 	 *
129 130
 	 * Must be zero if @c data_out is NULL
130 131
 	 */
131 132
 	size_t data_out_len;
132 133
 	/** Data-in buffer (may be NULL) */
133
-	void *data_in;
134
+	userptr_t data_in;
134 135
 	/** Data-in buffer length
135 136
 	 *
136 137
 	 * Must be zero if @c data_in is NULL

+ 24
- 0
src/include/gpxe/uaccess.h View File

@@ -0,0 +1,24 @@
1
+#ifndef _GPXE_UACCESS_H
2
+#define _GPXE_UACCESS_H
3
+
4
+/**
5
+ * @file
6
+ *
7
+ * Access to external ("user") memory
8
+ *
9
+ * gPXE often needs to transfer data between internal and external
10
+ * buffers.  On i386, the external buffers may require access via a
11
+ * different segment, and the buffer address cannot be encoded into a
12
+ * simple void * pointer.  The @c userptr_t type encapsulates the
13
+ * information needed to identify an external buffer, and the
14
+ * copy_to_user() and copy_from_user() functions provide methods for
15
+ * transferring data between internal and external buffers.
16
+ *
17
+ * Note that userptr_t is an opaque type; in particular, performing
18
+ * arithmetic upon a userptr_t is not allowed.
19
+ *
20
+ */
21
+
22
+#include <bits/uaccess.h>
23
+
24
+#endif /* _GPXE_UACCESS_H */

+ 7
- 2
src/net/tcp/iscsi.c View File

@@ -24,6 +24,7 @@
24 24
 #include <byteswap.h>
25 25
 #include <gpxe/scsi.h>
26 26
 #include <gpxe/process.h>
27
+#include <gpxe/uaccess.h>
27 28
 #include <gpxe/iscsi.h>
28 29
 
29 30
 /** @file
@@ -130,7 +131,7 @@ static void iscsi_rx_data_in ( struct iscsi_session *iscsi, void *data,
130 131
 	assert ( iscsi->command != NULL );
131 132
 	assert ( iscsi->command->data_in != NULL );
132 133
 	assert ( ( offset + len ) <= iscsi->command->data_in_len );
133
-	memcpy ( ( iscsi->command->data_in + offset ), data, len );
134
+	copy_to_user ( iscsi->command->data_in, offset, data, len );
134 135
 
135 136
 	/* Record SCSI status, if present */
136 137
 	if ( data_in->flags & ISCSI_DATA_FLAG_STATUS )
@@ -234,7 +235,11 @@ static void iscsi_tx_data_out ( struct iscsi_session *iscsi ) {
234 235
 	assert ( iscsi->command->data_out != NULL );
235 236
 	assert ( ( offset + len ) <= iscsi->command->data_out_len );
236 237
 	
237
-	tcp_send ( &iscsi->tcp, iscsi->command->data_out + offset, len );
238
+	if ( len > tcp_buflen )
239
+		len = tcp_buflen;
240
+	copy_from_user ( tcp_buffer, iscsi->command->data_out, offset, len );
241
+
242
+	tcp_send ( &iscsi->tcp, tcp_buffer, len );
238 243
 }
239 244
 
240 245
 /****************************************************************************

Loading…
Cancel
Save