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).
This commit is contained in:
Michael Brown
2006-05-19 15:06:51 +00:00
parent 0ab92faedb
commit d48d0fb1bb
11 changed files with 154 additions and 54 deletions

View File

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

View File

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

View File

@@ -92,6 +92,69 @@ copy_from_real_librm ( void *dest, unsigned int src_seg,
#define put_real put_real_librm
#define get_real get_real_librm
/**
* A pointer to a user buffer
*
* Even though we could just use a void *, we use an intptr_t so that
* attempts to use normal pointers show up as compiler warnings. Such
* code is actually valid for librm, but not for libkir (i.e. under
* KEEP_IT_REAL), so it's good to have the warnings even under librm.
*/
typedef intptr_t userptr_t;
/**
* Copy data to user buffer
*
* @v buffer User buffer
* @v offset Offset within user buffer
* @v src Source
* @v len Length
*/
static inline __attribute__ (( always_inline )) void
copy_to_user ( userptr_t buffer, off_t offset, const void *src, size_t len ) {
memcpy ( ( void * ) buffer + offset, src, len );
}
/**
* Copy data from user buffer
*
* @v dest Destination
* @v buffer User buffer
* @v offset Offset within user buffer
* @v len Length
*/
static inline __attribute__ (( always_inline )) void
copy_from_user ( void *dest, userptr_t buffer, off_t offset, size_t len ) {
memcpy ( dest, ( void * ) buffer + offset, len );
}
/**
* Convert virtual address to user buffer
*
* @v virtual Virtual address
* @ret buffer User buffer
*
* This constructs a user buffer from an ordinary pointer. Use it
* when you need to pass a pointer to an internal buffer to a function
* that expects a @c userptr_t.
*/
static inline __attribute__ (( always_inline )) userptr_t
virt_to_user ( void * virtual ) {
return ( ( intptr_t ) virtual );
}
/**
* Convert segment:offset address to user buffer
*
* @v segment Real-mode segment
* @v offset Real-mode offset
* @ret buffer User buffer
*/
static inline __attribute__ (( always_inline )) userptr_t
real_to_user ( unsigned int segment, unsigned int offset ) {
return virt_to_user ( VIRTUAL ( segment, offset ) );
}
/* Copy to/from real-mode stack */
extern uint16_t copy_to_rm_stack ( void *data, size_t size );
extern void remove_from_rm_stack ( void *data, size_t size );

View File

@@ -0,0 +1,22 @@
#ifndef _OLD_REALMODE_H
#define _OLD_REALMODE_H
#include <realmode.h>
#warning "Anything including this header is obsolete and must be rewritten"
/* Just for now */
#define SEGMENT(x) ( virt_to_phys ( x ) >> 4 )
#define OFFSET(x) ( virt_to_phys ( x ) & 0xf )
#define SEGOFF(x) { OFFSET(x), SEGMENT(x) }
/* To make basemem.c compile */
extern int lock_real_mode_stack;
extern char *real_mode_stack;
extern char real_mode_stack_size[];
#define RM_FRAGMENT(name,asm) \
void name ( void ) {} \
extern char name ## _size[];
#endif /* _OLD_REALMODE_H */

View File

@@ -149,25 +149,6 @@ typedef struct segoff segoff_t;
* "(discard)" in the above code.
*/
#warning "realmode.h contains placeholders for obsolete macros"
/* Just for now */
#define SEGMENT(x) ( virt_to_phys ( x ) >> 4 )
#define OFFSET(x) ( virt_to_phys ( x ) & 0xf )
#define SEGOFF(x) { OFFSET(x), SEGMENT(x) }
/* To make basemem.c compile */
extern int lock_real_mode_stack;
extern char *real_mode_stack;
extern char real_mode_stack_size[];
#define RM_FRAGMENT(name,asm) \
void name ( void ) {} \
extern char name ## _size[];
#endif /* ASSEMBLY */
#endif /* REALMODE_H */

View File

@@ -93,7 +93,7 @@ static unsigned long chs_to_lba ( struct int13_drive *drive,
lba = ( ( ( ( cylinder * drive->heads ) + head )
* drive->sectors_per_track ) + sector - 1 );
DBG ( "C/H/S address %x/%x/%x -> LBA %x\n",
DBG ( "C/H/S address %x/%x/%x -> LBA %lx\n",
cylinder, head, sector, lba );
return lba;
@@ -111,19 +111,15 @@ static unsigned long chs_to_lba ( struct int13_drive *drive,
static int int13_read ( struct int13_drive *drive, uint64_t lba,
struct segoff data, unsigned long count ) {
struct block_device *blockdev = drive->blockdev;
size_t blksize = blockdev->blksize;
uint8_t buffer[blksize];
userptr_t buffer = real_to_user ( data.segment, data.offset );
int rc;
DBG ( "Read %lx sectors from %llx to %04x:%04x\n", count,
( unsigned long long ) lba, data.segment, data.offset );
while ( count-- ) {
if ( ( rc = blockdev->read ( blockdev, lba, buffer ) ) != 0 )
return INT13_STATUS_READ_ERROR;
copy_to_real ( data.segment, data.offset, buffer, blksize );
data.offset += blksize;
lba++;
}
if ( ( rc = blockdev->read ( blockdev, lba, count, buffer ) ) != 0 )
return INT13_STATUS_READ_ERROR;
return 0;
}
@@ -139,19 +135,15 @@ static int int13_read ( struct int13_drive *drive, uint64_t lba,
static int int13_write ( struct int13_drive *drive, uint64_t lba,
struct segoff data, unsigned long count ) {
struct block_device *blockdev = drive->blockdev;
size_t blksize = blockdev->blksize;
uint8_t buffer[blksize];
userptr_t buffer = real_to_user ( data.segment, data.offset );
int rc;
DBG ( "Write %lx sectors from %04x:%04x to %llx\n", count,
data.segment, data.offset, ( unsigned long long ) lba );
while ( count-- ) {
copy_from_real ( buffer, data.segment, data.offset, blksize );
if ( ( rc = blockdev->write ( blockdev, lba, buffer ) ) != 0 )
return INT13_STATUS_WRITE_ERROR;
data.offset += blksize;
lba++;
}
if ( ( rc = blockdev->write ( blockdev, lba, count, buffer ) ) != 0 )
return INT13_STATUS_WRITE_ERROR;
return 0;
}
@@ -202,7 +194,7 @@ static int int13_read_sectors ( struct int13_drive *drive,
};
if ( drive->blockdev->blksize != INT13_BLKSIZE ) {
DBG ( "Invalid blocksize (%d) for non-extended read\n",
DBG ( "Invalid blocksize (%zd) for non-extended read\n",
drive->blockdev->blksize );
return INT13_STATUS_INVALID;
}
@@ -233,7 +225,7 @@ static int int13_write_sectors ( struct int13_drive *drive,
};
if ( drive->blockdev->blksize != INT13_BLKSIZE ) {
DBG ( "Invalid blocksize (%d) for non-extended write\n",
DBG ( "Invalid blocksize (%zd) for non-extended write\n",
drive->blockdev->blksize );
return INT13_STATUS_INVALID;
}