diff options
| author | Michael Brown | 2006-05-19 17:06:51 +0200 |
|---|---|---|
| committer | Michael Brown | 2006-05-19 17:06:51 +0200 |
| commit | d48d0fb1bb53262bf44a03dbe8388529f1566a1c (patch) | |
| tree | 31081f33dbeb48c42d2e4cf806570853162781d9 /src/arch | |
| parent | Use typeof(sizeof(...)) to define a size_t. This stops gcc complaining (diff) | |
| download | ipxe-d48d0fb1bb53262bf44a03dbe8388529f1566a1c.tar.gz ipxe-d48d0fb1bb53262bf44a03dbe8388529f1566a1c.tar.xz ipxe-d48d0fb1bb53262bf44a03dbe8388529f1566a1c.zip | |
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).
Diffstat (limited to 'src/arch')
| -rw-r--r-- | src/arch/i386/core/pic8259.c | 2 | ||||
| -rw-r--r-- | src/arch/i386/include/bits/uaccess.h | 6 | ||||
| -rw-r--r-- | src/arch/i386/include/librm.h | 63 | ||||
| -rw-r--r-- | src/arch/i386/include/old_realmode.h | 22 | ||||
| -rw-r--r-- | src/arch/i386/include/realmode.h | 19 | ||||
| -rw-r--r-- | src/arch/i386/interface/pcbios/int13.c | 34 |
6 files changed, 105 insertions, 41 deletions
diff --git a/src/arch/i386/core/pic8259.c b/src/arch/i386/core/pic8259.c index 5c00deede..411e9419f 100644 --- a/src/arch/i386/core/pic8259.c +++ b/src/arch/i386/core/pic8259.c @@ -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; diff --git a/src/arch/i386/include/bits/uaccess.h b/src/arch/i386/include/bits/uaccess.h new file mode 100644 index 000000000..9c6d0c214 --- /dev/null +++ b/src/arch/i386/include/bits/uaccess.h @@ -0,0 +1,6 @@ +#ifndef _BITS_UACCESS_H +#define _BITS_UACCESS_H + +#include <realmode.h> + +#endif /* _BITS_UACCESS_H */ diff --git a/src/arch/i386/include/librm.h b/src/arch/i386/include/librm.h index af1470b91..17fcc78ba 100644 --- a/src/arch/i386/include/librm.h +++ b/src/arch/i386/include/librm.h @@ -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 ); diff --git a/src/arch/i386/include/old_realmode.h b/src/arch/i386/include/old_realmode.h new file mode 100644 index 000000000..3dde8c810 --- /dev/null +++ b/src/arch/i386/include/old_realmode.h @@ -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 */ diff --git a/src/arch/i386/include/realmode.h b/src/arch/i386/include/realmode.h index 07d41e544..10a28b237 100644 --- a/src/arch/i386/include/realmode.h +++ b/src/arch/i386/include/realmode.h @@ -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 */ diff --git a/src/arch/i386/interface/pcbios/int13.c b/src/arch/i386/interface/pcbios/int13.c index d4d15c16a..d87428f7f 100644 --- a/src/arch/i386/interface/pcbios/int13.c +++ b/src/arch/i386/interface/pcbios/int13.c @@ -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; } |
