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

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

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
 #define put_real put_real_librm
92
 #define put_real put_real_librm
93
 #define get_real get_real_librm
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
 /* Copy to/from real-mode stack */
158
 /* Copy to/from real-mode stack */
96
 extern uint16_t copy_to_rm_stack ( void *data, size_t size );
159
 extern uint16_t copy_to_rm_stack ( void *data, size_t size );
97
 extern void remove_from_rm_stack ( void *data, size_t size );
160
 extern void remove_from_rm_stack ( void *data, size_t size );

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

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
  * "(discard)" in the above code.
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
 #endif /* ASSEMBLY */
152
 #endif /* ASSEMBLY */
172
 
153
 
173
 #endif /* REALMODE_H */
154
 #endif /* REALMODE_H */

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

93
 	lba = ( ( ( ( cylinder * drive->heads ) + head )
93
 	lba = ( ( ( ( cylinder * drive->heads ) + head )
94
 		  * drive->sectors_per_track ) + sector - 1 );
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
 	      cylinder, head, sector, lba );
97
 	      cylinder, head, sector, lba );
98
 
98
 
99
 	return lba;
99
 	return lba;
111
 static int int13_read ( struct int13_drive *drive, uint64_t lba,
111
 static int int13_read ( struct int13_drive *drive, uint64_t lba,
112
 			struct segoff data, unsigned long count ) {
112
 			struct segoff data, unsigned long count ) {
113
 	struct block_device *blockdev = drive->blockdev;
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
 	int rc;
115
 	int rc;
117
 
116
 
118
 	DBG ( "Read %lx sectors from %llx to %04x:%04x\n", count,
117
 	DBG ( "Read %lx sectors from %llx to %04x:%04x\n", count,
119
 	      ( unsigned long long ) lba, data.segment, data.offset );
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
 	return 0;
123
 	return 0;
128
 }
124
 }
129
 
125
 
139
 static int int13_write ( struct int13_drive *drive, uint64_t lba,
135
 static int int13_write ( struct int13_drive *drive, uint64_t lba,
140
 			 struct segoff data, unsigned long count ) {
136
 			 struct segoff data, unsigned long count ) {
141
 	struct block_device *blockdev = drive->blockdev;
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
 	int rc;
139
 	int rc;
145
 
140
 
146
 	DBG ( "Write %lx sectors from %04x:%04x to %llx\n", count,
141
 	DBG ( "Write %lx sectors from %04x:%04x to %llx\n", count,
147
 	      data.segment, data.offset, ( unsigned long long ) lba );
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
 	return 0;
147
 	return 0;
156
 }
148
 }
157
 
149
 
202
 	};
194
 	};
203
 
195
 
204
 	if ( drive->blockdev->blksize != INT13_BLKSIZE ) {
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
 		      drive->blockdev->blksize );
198
 		      drive->blockdev->blksize );
207
 		return INT13_STATUS_INVALID;
199
 		return INT13_STATUS_INVALID;
208
 	}
200
 	}
233
 	};
225
 	};
234
 
226
 
235
 	if ( drive->blockdev->blksize != INT13_BLKSIZE ) {
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
 		      drive->blockdev->blksize );
229
 		      drive->blockdev->blksize );
238
 		return INT13_STATUS_INVALID;
230
 		return INT13_STATUS_INVALID;
239
 	}
231
 	}

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

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

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

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

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

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

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

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
 #include <byteswap.h>
24
 #include <byteswap.h>
25
 #include <gpxe/scsi.h>
25
 #include <gpxe/scsi.h>
26
 #include <gpxe/process.h>
26
 #include <gpxe/process.h>
27
+#include <gpxe/uaccess.h>
27
 #include <gpxe/iscsi.h>
28
 #include <gpxe/iscsi.h>
28
 
29
 
29
 /** @file
30
 /** @file
130
 	assert ( iscsi->command != NULL );
131
 	assert ( iscsi->command != NULL );
131
 	assert ( iscsi->command->data_in != NULL );
132
 	assert ( iscsi->command->data_in != NULL );
132
 	assert ( ( offset + len ) <= iscsi->command->data_in_len );
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
 	/* Record SCSI status, if present */
136
 	/* Record SCSI status, if present */
136
 	if ( data_in->flags & ISCSI_DATA_FLAG_STATUS )
137
 	if ( data_in->flags & ISCSI_DATA_FLAG_STATUS )
234
 	assert ( iscsi->command->data_out != NULL );
235
 	assert ( iscsi->command->data_out != NULL );
235
 	assert ( ( offset + len ) <= iscsi->command->data_out_len );
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